系统安全及免杀(2) DLL旁加载

前言

书接上回,dll相关可以涉及到的最基本的安全问题就是这个了,白 exe 加黑 dll,比直接做 exe 马更加隐蔽,因为很多只有最基本计算机基础的用户可能知道 exe,安了软件会找 exe 运行打开,不会去检查那许多的 dll 那些“乱七八糟的文件”

浅浅记录一下吧

DLL 旁加载

DLL 旁加载,就是把原本的软件调用到的 dll 替换成我们自己的 dll,并且在不影响原本软件运行的情况下(明显的异样会影响隐蔽效果,钓鱼效果大打折扣)

这个手法基于的一个大前提是:程序使用相对路径而不是绝对路径加载 DLL。例如:

LoadLibrary("./math.dll")

但是这不能算是所谓的漏洞,毕竟一个软件应用的开发者也不知道用户会把应用放在什么目录,没可能使用绝对目录的,应用要保证用户把他安在哪都能运行

因此将一个受信任的合法软件的 dll 做替换,置入后门,我们的后门便可以借由有证书的、被信任的程序跑起来

头脑风暴

几个先决条件

那话虽如此,怎么才能找到一个适合进行操作的应用呢

程序必须有一些我们可以植入后门的 DLL(软件自身的 DLL,不是系统 DLL)

​ 意外的调用系统功能非常容易被 edr 等安全软件/设备抓包

可以旁加载

​ 如上一小节所说,可以把软件整个目录复制到另一个地方,随后把原来的软件卸载干净(包括注册表信息等)随后试图运行复制过去 的软件,如果可以运行并且没有功能受到影响,那便是极好的,这也是主要的测试思路

本身高度可信

​ 越知名的软件被怀疑的风险越低,最好是带有可信的数字签名(最近看到的一个紫狐的样本就伪装成了咪咕视频,虽然技术不同但是 包装成知名软件的思路是相同的)

手法

如上一小节在“可以旁加载”中所说

那如果重新去运行,崩溃或不是所有功能都正常工作,那就不行了。该应用可能在安装的时候会向注册表或系统固定位置的配置文件写入了一些值,运行时需要这些值。这会阻止我们将 DLL 旁加载作为初始访问向量。实际上,除了手动测试别无他法,因为一切都取决于应用开发者的设计决定,我们也不知道怎么设计的

另一个问题是当我们把做好的🐎给已经安装了该应用的用户时会发生什么

最可能我们的 EXE 开始使用安装位置的原始 DLL。这意味着我们的后门可能不会被启动或代理的函数不会生效。

如果有可能,也要先安装软件再先试运行一下进行测试

LOLBIN

一个名词,说到这个也是因为这是利用受信任文件借刀杀人的老朋友了

lolbin 不是单独的一个名字,而是指一类文件,懒得组织语言打字了,我们来问问豆包吧

该术语全称为 “Living Off the Land Binaries”,中文可译为 “合法系统程序滥用”。这是黑客常用的一种攻击技术,核心是利用操作系统自带的合法程序文件来实施恶意行为。由于这些程序是系统原生的,往往会被安全防护机制信任,黑客借助它们执行恶意代码,能轻松绕过传统杀毒软件等检测手段,常被用于无文件攻击等场景,增加攻击的隐蔽性。像 Windows 系统中的 PowerShell、wmic、regsvr32 等程序,都曾被黑客当作 LOLBin 工具使用。

在寻找 dll 旁加载的目标的时候,这类文件自然也是极好的

但情况略有不同,有些 LOLBIN 并没有自己的库,只使用默认的系统库。对于 LOLBIN 的 DLL,旁加载就不那么确定了,通常位于固定且有文档记录的位置,理论上可以使用绝对路径来引用其库,因为它们的位置通常不会改变。

这就不得不提到这块技术很权威的一个查询的网站了:https://hijacklibs.net/

如上图,有一些由微软签名且使用相对路径加载其库的 LOLBIN,搜索栏选择 sideloading 选项就能找到它们。

挑选合适的DLL

这里就是需要用到书接上回的查询 dll 方法了,快速的把程序的 dll 都列出来,这边用 process monitor 比较适合

以 notepad++ 这个工具为例子,这也是后面要进行试验的程序

植入 dll 后门

假设我们决定在 Notepad++ 中安装后门。使用 Process Monitor 对程序的分析显示 NppConverter.dll 库是动态加载的

在实际进行操作前总结一下行动纲领:

编写一个同名库,可以执行后门,并且不会影响到应用原本的 dll 的功能

那不难想到,比较容易实现的思路就是用后门 dll 冒名顶替,运行后门,并再确保原本 dll 的功能不变,类似于插入一个代理

工具引入

用到 DllShimmer 这个工具,GitHub 地址:https://github.com/CyVenom/CyVen_DllShimmer

工具的介绍(About)如是说:Weaponize DLL hijacking easily. Backdoor any function in any DLL.

software.exe: 被植入 dll 后门的应用程序

绿色 original.dll: 被挑选为目标的 dll

original.dll.cpp: 被工具反编译出的 cpp 模板

红色 original.dll: 被添加了后门的冒名顶替原本 dll 的我们写的 dll

original2.dll: 将原本的 dll 改名

这图片还是挺直观的

开始操作

把工具和 NppConverter.dll 放在同个目录下(提前创建好 ./project 目录)

命令:(github页面也有使用教程)

DllShimmer.exe -i NppConverter.dll -o project/ -x 'NppConverter2.dll' -m

如图就是运行成功了

输出的文件就在 project 里面,看一下 cpp

// Generated by DllShimmer (github.com/Print3M/DllShimmer)
// 
// Author: Print3M (print3m.github.io/)
#include "dllshimmer.h"
#include <windows.h>
#include <stdio.h>

// beNotified
extern "C" UINT64 beNotifiedFwd(PARAMS) {
    #ifdef DEBUG
        dbgf("beNotified called");
    #endif
    
    if (MUTEX("Global\\beNotified__0")) {
        // Put your code here...
    }

    return PROXY_FUNCTION("beNotified");
}

// getFuncsArray
extern "C" UINT64 getFuncsArrayFwd(PARAMS) {
    #ifdef DEBUG
        dbgf("getFuncsArray called");
    #endif
    
    if (MUTEX("Global\\getFuncsArray__1")) {
        // Put your code here...
    }

    return PROXY_FUNCTION("getFuncsArray");
}

// getName
extern "C" UINT64 getNameFwd(PARAMS) {
    #ifdef DEBUG
        dbgf("getName called");
    #endif
    
    if (MUTEX("Global\\getName__2")) {
        // Put your code here...
    }

    return PROXY_FUNCTION("getName");
}

// isUnicode
extern "C" UINT64 isUnicodeFwd(PARAMS) {
    #ifdef DEBUG
        dbgf("isUnicode called");
    #endif
    
    if (MUTEX("Global\\isUnicode__3")) {
        // Put your code here...
    }

    return PROXY_FUNCTION("isUnicode");
}

// messageProc
extern "C" UINT64 messageProcFwd(PARAMS) {
    #ifdef DEBUG
        dbgf("messageProc called");
    #endif
    
    if (MUTEX("Global\\messageProc__4")) {
        // Put your code here...
    }

    return PROXY_FUNCTION("messageProc");
}

// setInfo
extern "C" UINT64 setInfoFwd(PARAMS) {
    #ifdef DEBUG
        dbgf("setInfo called");
    #endif
    
    if (MUTEX("Global\\setInfo__5")) {
        // Put your code here...
    }

    return PROXY_FUNCTION("setInfo");
}


BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { 

    switch (fdwReason) {
    case DLL_PROCESS_ATTACH: {
        #ifdef DEBUG
            dbgf("DLL_PROCESS_ATTACH");
        #endif
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }

    return TRUE;
}

不算太长,就全放上来了,注意到最后的 DllMain ,加载 DLL 到内存后会自动执行 DllMain

那后门植入在哪?

首先不推荐 DllMain ,因为它限制了不能创建新线程),使其很难用于执行 shellcode

那其他的函数如此多,我们该挑选哪个呢?不必猜测。DllShimmer 会在生成的 .cpp 文件中添加大量调试信息。我们所要做的就是编译生成的 C++ 代码,将我们的代理 DLL 替换到合适位置,然后我们就能得到已执行函数的完整转储

//之后的步骤没能实际做出来,只是把预期中的理想状况写出来。替换回去之后 notepad++ 就一直报告 dll 不适配,不知是最新版本的软件加强了这块的检测还是 dllshimmer 本身出的问题,之后大概不会再用这个工具了,这个报错问题真的折磨了我许久/(ㄒoㄒ)/~~

之后将原始 dll 的名称改为 NppConverter2.dll(根据在 DllShimmer 中生成项目时写的),并把我们的代理 NppConverter.dll 放到同一目录。完成后,我们可以启动 Notepad++,这时候就可以在日志 txt 中看到了

这样开启日志记录:

--debug-file 'yourpath/xxx.txt'

在用 dllshimmer 创建项目的时候加上这条参数(

之后根据 txt 中的内容可以看到哪些函数被调用了,getName 看起来不错

之后在 sh 中删除掉 -D DEBUG=1,重新编译,并替换回去,便可以成功植入后门了

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇