【Day 29】我这不是来了吗 - 侦测指令混淆

环境

  • Windows 10 19043
  • Python 3.9

前情提要

【Day 27】Cmd 指令很乱,主办单位要不要管一下 (上) - Cmd 指令混淆【Day 28】Cmd 指令很乱,主办单位要不要管一下 (下) - Cmd 指令混淆我们终於把指令混淆的技巧全部认识完毕。

这篇要介绍用来做指令混淆的工具,以及侦测指令是否被混淆的方法。

Invoke-DOSfuscation

了解了基本的指令混淆原理後,可以来玩玩看专案 Invoke-DOSfuscation。这是个用 PowerShell 写的专案,可以用来混淆 Cmd、PowerShell 指令,这个工具当初做出来是为了要让资安研究员能够使用这个工具制造出混淆过的 Cmd 指令的测试资料。

介面

直接来看看它的使用方法,以下是它十分酷炫的启动画面。

         ___                 _
        |_ _|_ ____   _____ | | _____
         | || '_ \ \ / / _ \| |/ / _ \____
         | || | | \ V / (_) |   <  __/____|
        |___|_| |_|\_/_\___/|_|\_\___|             _   _
        |  _ \ / _ \/ ___| / _|_   _ ___  ___ __ _| |_(_) ___  _ __
        | | | | | | \___ \| |_| | | / __|/ __/ _` | __| |/ _ \| '_ \
        | |_| | |_| |___) |  _| |_| \__ \ (_| (_| | |_| | (_) | | | |
        |____/ \___/|____/|_|  \__,_|___/\___\__,_|\__|_|\___/|_| |_|

        Tool    :: Invoke-DOSfuscation
        Author  :: Daniel Bohannon (DBO)
        Twitter :: @danielhbohannon
        Blog    :: http://danielbohannon.com
        Github  :: https://github.com/danielbohannon/Invoke-DOSfuscation
        Version :: 1.0
        License :: Apache License, Version 2.0
        Notes   :: if (-not $caffeinated) { exit }


HELP MENU :: Available options shown below:

[*]  Tutorial of how to use this tool             TUTORIAL
[*]  Show this Help Menu                          HELP,GET-HELP,?,-?,/?,MENU
[*]  Show options for payload to obfuscate        SHOW OPTIONS,SHOW,OPTIONS
[*]  Clear screen                                 CLEAR,CLEAR-HOST,CLS
[*]  Execute ObfuscatedCommand locally            EXEC,EXECUTE,TEST,RUN
[*]  Copy ObfuscatedCommand to clipboard          COPY,CLIP,CLIPBOARD
[*]  Write ObfuscatedCommand Out to disk          OUT
[*]  Reset ALL obfuscation for ObfuscatedCommand  RESET
[*]  Undo LAST obfuscation for ObfuscatedCommand  UNDO
[*]  Go Back to previous obfuscation menu         BACK,CD ..
[*]  Quit Invoke-DOSfuscation                     QUIT,EXIT
[*]  return to Home Menu                          HOME,MAIN


Choose one of the below options:

[*] BINARY      Obfuscated binary syntax for cmd.exe & powershell.exe
[*] ENCODING    Environment variable encoding
[*] PAYLOAD     Obfuscated payload via DOSfuscation


Invoke-DOSfuscation>

输入 Tutorial 会有基本的使用教学。简单来说就是可以用 set command 选择要混淆的指令,然後搭配三种混淆选项 BINARYENCODINGPAYLOAD。然後混淆的选项是可以叠加的,所以可以用 undo 回到上一个混淆状态,也可以使用 test 执行目前的混淆结果。

TUTORIAL :: Here is a quick tutorial showing you how to get your DOSfuscation on:

1) Load a Cmd/PowerShell command (SET COMMAND) or a path/URL to a command.
   SET COMMAND dir C:\Windows\System32\ | findstr calc\.exe
   Or
   SET COMMANDPATH https://bit.ly/L3g1t

2) (Optional) Set FinalBinary (SET FINALBINARY) to be Cmd, PowerShell or None.
   NOTE: If setting a PowerShell command, FinalBinary must be set to PowerShell.
   SET FINALBINARY PowerShell

3) Navigate through the obfuscation menus where the options are in YELLOW.
   GREEN options apply obfuscation.
   Enter BACK/CD .. to go to previous menu and HOME/MAIN to go to home menu.
   E.g. Enter PAYLOAD,CONCAT & then 1 to apply basic concatenation obfuscation.

4) Enter TEST/EXEC to test the obfuscated command locally.
   Enter SHOW to see the currently obfuscated command.

5) Enter COPY/CLIP to copy obfuscated command out to your clipboard.
   Enter OUT to write obfuscated command out to disk.

6) Enter RESET to remove all obfuscation and start over.
   Enter UNDO to undo last obfuscation.
   Enter HELP/? for help menu.

And finally the obligatory "Don't use this for evil, please" :)

BINARY\CMD\1

BINARY 混淆选项的两种可以选,分别是 CMDPOWERSHELL。先看看单独使用 BINARY\CMD\1 混淆结果,每次执行结果不同。以下例子使用了环境变数取出子字串的混淆技巧,从两个环境变数 CommonProgramFiles(x86)CommonProgramFiles 分别取出 Cm,再补上一个 d 构出 Cmd

%CommonProgramFiles(x86):~23,1%%CommonProgramFiles:~-9,-8%d

BINARY\CMD\2

BINARY\CMD\1 挺简单的,再来看看单独使用 BINARY\CMD\2 的结果。下面例子使用了 For Loop Value Extraction 混淆技巧,从 ftype 出取出 cmd 指令。

FOR /F "tokens=1 delims=fU" %r IN ('ftype^|findstr mdfi')DO %r

BINARY\CMD\3

最後再看看 BINARY\CMD\3。就只是把 BINARY\CMD\2 再加上一些垃圾字元而已,包含 ,;在指令参数之间的空白,然後再放一些 ^ 在指令中。

^f^O^r  ;   ,   ;   ,    /^F    ;  ;   ;   ,  ;  ;   ;  "   delims=fLaCK   tokens=    1   "  ,   ;   ;    ,   ,    ;  ;  %8   ,    ,  ;   ;  ^in   ;  ,  ;   ,    ;   (  ;  ,  ,  ,   ,   ,  ,   '   ,   ;    ;  ; Ft^^Y^^p^^E    ;   ;  ,    ^|  ,   ,   ;   ,  ,    F^^iND^^S^^T^^R   ,    ,  ,    ^^m^^df   '  ;   ,    ,  ,   )  ,  ;  ,   ,  ,  ;  DO   ;   ,  ,    %8

BINARY\CMD\3 + PAYLOAD\CONCAT\1

所以只要懂了混淆技巧的原理,混淆指令其实仔细看就能看懂了,是吗?我们把 BINARY\CMD\3 的结果再叠加 PAYLOAD\CONCAT\1 看看。一生悬命的看也许还是能勉强理解下面例子使用了环境变数把字串拼接,中间夹杂着一大堆垃圾。

cmd.exe /V:ON/C"set Gry=  ,    ,   ;  ,    ^^^^^^^|  ;   ;    ;   , &&set lvz=;  ; &&set Jc9L= ;    ,  &&set GDZ=  ;   &&set B3Vy=   &&set sXnb=^^^^lC&&set 7Bu=o^^^^^^^^C&&set GA=,   ^^^^iN   &&set yqa= ;  , &&set cEVZ=token&&set eZ=^^^^IN^^^^^^^^d^^^^^^^^s^^^^^^^^t^^^^^^^^r&&set hJ=   ,  ;  /^^^^F &&set MO= ;  ;&&set sXH1=  ^^^^^^^^f^^^^&&set Yh= ,  "" &&set Ge=  "" &&set yYMo=;   &&set R5uh=   ,    &&set Zqrd=  &&set mJVE=wt4 &&set 8OU=""&&set Gdf=(  ;&&set ou=  ,  ,  &&set aYH=  &&set 8s=;  ;&&set oe=  &&set 1NU= ,  )  &&set 8ID= ;  ;  ,  %m&&set 9Pa= ,   ;  ,   &&set t6y=;    , &&set Wi=   &&set Vc= ,  ^^^^D^^^^&&set cFM3= &&set CN= ,   &&set CvJ2=  ,   ;   ,  &&set sio=  ,   &&set yU=  ;    ;  &&set shC=,  &&set zyP==l&&set 8i=s&&set 6Y=^^^^^^^^m      '  &&set 1R=;    ;&&set voQ= ,   ,  ^^^^^^^^&&set JLe6=,  ;   ; &&set etCN=  deli&&set RS=,  ,  ;   ;   ,   ^^^^^^^^l^^^^&&set LIYD=    &&set wx8y=  5     &&set 6ov= &&set b3E=  ;  &&set tA=^^^^f^^^^O^^^^R&&set q2MN= &&set ZI=s= &&set 9PRI='    ;&&set 6PiG=m&&set Zyf=  ;  ,&&set oekv= , &&set o5WB=%m &&set qz=A^^^^^^^^s^^^^^^^^s^^^^^^^^&&set hJtC=O  &&call set j0p=%tA%%CvJ2%%1R%%hJ%%yU%%Yh%%oe%%etCN%%6PiG%%8i%%zyP%%mJVE%%B3Vy%%q2MN%%Zqrd%%cEVZ%%ZI%%wx8y%%Ge%%b3E%%ou%%9Pa%%shC%%o5WB%%MO%%cFM3%%sio%%oekv%%Zyf%%Wi%%GA%%8s%%GDZ%%CN%%Gdf%%aYH%%Jc9L%%yYMo%%9PRI%%LIYD%%lvz%%6ov%%t6y%%voQ%%qz%%7Bu%%Gry%%sXH1%%eZ%%R5uh%%RS%%sXnb%%6Y%%JLe6%%1NU%%yqa%%Vc%%hJtC%%8ID%&&cmd.exe /C %j0p:""=!8OU:~1,97!%"

BINARY\CMD\3 + PAYLOAD\CONCAT\1 + PAYLOAD\REVERSE\1

最後再给个魔王题当作这个段落的结尾, BINARY\CMD\3+PAYLOAD\CONCAT\1+PAYLOAD\REVERSE\1

cmd /V:ON/C"set C2S=^^^^^^^^d&&set 1aS= ;   ;   &&set fLZ=^^^^&&set 3O= ,  ,&&set FzM=,   ,&&set B9R=  ;   ,&&set 0RIg= ; &&set biOK=""&&set YM6=  ;  ""     tokens=      1   &&set XQS= ;&&set GvAF= &&set Ng=^^^^S^^^^&&set Xs=;   ,&&set czG=   ,  ;&&set dxSn=.aXS=""   ,&&set 39C= &&set 0G=  ; &&set x5= ;  ;   ;   ,&&set 4W30=  ,  &&set 0U7W=^^^^O  ;&&set C0= ;&&set POS5=   ;  ^^^^^^^^a^^^^^^^^S^^^^^^^^S^^^^^^^^oC    ;  ,  ;  ,  ^^^^^^^|  ;  ,&&set hu=/^^^^f    ;  ;  ,   &&set C2a1=   ,  ,  , &&set ho= &&set fK5w= ;   ;   ^^^^D&&set bJ=   &&set H82I=  %w  &&set GTr=  ;   ;   ,   ,  (  &&set ukZx= &&set 1q=ms=&&set 62=;  ^^^^^^^^m^^^^^^^^d^^^^^^^^&&set NT1M=  ;    ^^^^^^^^F^^^^&&set 9G=  ,&&set Zuq=,  &&set RdQM=^^^^IN&&set F97Y=^^^^=^^^^^^^^c    '&&set TJ=  ,  &&set Pl=  &&set aw1= ;   ,   %w&&set 3Qu='  , &&set 94I=  &&set VlL= in&&set c8J=,  ; &&set VP=   deli&&set 1k=^^^^Fo^^^^R&&set ABbl=  , &&set Ahx= ;  ,  &&set tr19= &&set Dn= &&set 6AP=  &&set hI93=  &&set Hf= ,   &&set 5kI= ; &&set Nzt=  ;  ;  )  &&set fz6m=;  ;&&set 0C3= &&set Xu=^^^^r   ,   ; &&set afF5=^^^^t^^^^&&call set HFmo=%1k%%94I%%ABbl%%1aS%%x5%%6AP%%hu%%FzM%%YM6%%ukZx%%VP%%1q%%dxSn%%hI93%%B9R%%bJ%%3O%%9G%%0G%%H82I%%Zuq%%Ahx%%GvAF%%VlL%%4W30%%GTr%%C0%%39C%%5kI%%C2a1%%Hf%%3Qu%%Xs%%POS5%%0C3%%NT1M%%RdQM%%C2S%%fLZ%%Ng%%afF5%%Xu%%ho%%62%%F97Y%%TJ%%XQS%%czG%%Nzt%%c8J%%0RIg%%fK5w%%0U7W%%Pl%%fz6m%%Dn%%tr19%%aw1%&&cmd /C %HFmo:""=!biOK:~0,-1!%"

侦测混淆

经过 Invoke-DOSfuscation 的洗礼,相信大家都明白不太可能用肉眼看出混淆後的指令。不过如果只是要辨认指令有没有被混淆的话会不会比较容易呢?在 FireEye 的一篇文章 Obfuscated Command Line Detection Using Machine Learning 有比较传统的侦测混淆与机器学习的方法。

检查特徵

使用 Regular Expression 的方式找出被混淆的指令,假设我要找到使用环境变数拼接的混淆技巧,写出来的规则可能如下。

(set [a-zA-Z0-9]+=.*&&)+(call set [a-zA-Z0-9]+=%[a-zA-Z0-9%]+%).*call %.*%

如此一来,类似如下的混淆指令就会被侦测。

cmd /c "set a=i&&set b=am&&set c=who&&call set d=%c%%b%%a%&&call %d%"

然而这种方式却很容易被绕过,例如我在上述例子的第一个 &&set 中间插入一个逗号。这麽做的话上面写的规则就不适用了。

cmd /c "set a=i&&,set b=am&&set c=who&&call set d=%c%%b%%a%&&call %d%"

设定规则

设定规则的方法比检查特徵好一些,毕竟规则不会订得这麽紧。规则除了也可以使用 Regular Expression 之外,也可以透过判断一些条件决定指令是否被混淆,例如某些字串的数量或指令的总长度。

if length() >= 20 and COUNT("&") > 8 and MATCHES_REGEXP(...)

不过这个方法比起单纯的 Regular Expression 更难维护与测试。

机器学习

FireEye

机器学习的侦测方法比起前两种更有弹性,不过能不能用还是要建立在准确度上。根据 FireEye 文章所述,它分别尝试使用 CNN 做非监督式学习与 Gradient-Boosted Tree-Based Model 做监督式学习。测试资料使用 Invoke-DOSfuscation 产生的混淆指令,不过没说正常指令的测试资料怎麽产生的。

实作的细节并没有透漏太多,只知道 CNN 的部分是直接喂原始指令,并在第一层做 Embedding。Gradient-Boosted Tree-Based Model 则是取出以下几个特徵,分别是指令长度、^ 数量、| 数量、空白键比例、特殊字元比例、字串的 Entropy、字串 cmdpower 出现的频率。

结论是 Gradient-Boosted Tree-Based Model 准确度趋近於 1,而 CNN 稍差,这也证实机器学习对於辨识混淆指令是有帮助的。

Adobe

另一篇是来自 Adobe 部落格的 Using Deep Learning to Better Detect Command Obfuscation,程序码有开源 adobe/obfuscation-detection

实作原理也是 CNN,一开始先把指令转成 One-hot Vector。接着在每一层同时看三个字元,所以第一层每一项会一次看到三个字元,第二层就一次会看五个字元,以此类推。在最後一层会把上一层的每一列个别加总变成一个 Vector,然後经过 Fully Connected Layer 转成输出。输出是一个二维 Vector,第一项代表预测没混淆的机率,第二项代表预测混淆的机率,看哪个比较大结果就是什麽。

这项工具测试结果 F1 Score 为 0.9891,声称比 FireEye 的测试结果更好。不过文章中有说在混淆做得不够多的情况下会有些 False Negative。

使用方法也很简单,它有 Python Package 直接装 pip install obfuscation-detection。同时支援 Windows 和 Linux 的指令混淆侦测。以下是它的使用范例。

import obfuscation_detection as od

oc = od.ObfuscationClassifier(od.PlatformType.ALL)
commands = ['cmd.exe /c "echo Invoke-DOSfuscation"',
            'cm%windir:~ -4, -3%.e^Xe,;^,/^C",;,S^Et ^^o^=fus^cat^ion&,;,^se^T ^ ^ ^B^=o^ke-D^OS&&,;,s^Et^^ d^=ec^ho I^nv&&,;,C^Al^l,;,^%^D%^%B%^%o^%"',
            'cat /etc/passwd']
classifications = oc(commands)

# 1 is obfuscated, 0 is non-obfuscated
print(classifications) # [0, 1, 0]

参考资料


<<:  Log Agent - Fluent Bit Multiline Parsing

>>:  Day 30 工作排程与打包

javascript物件教学2

接下来我们使用物件来写一个游戏中的玩家设计 ...

EP30 - 最後但不是终点

今天是第三十天, 真的要写其实还有很多东西可以写, 但我的确累了, 铁人赛的这三十天像是兼两份差, ...

【C language part 3】条件&回圈

条件判断 Decision Control Statement 为了应付程序可能遇到的各种状况,C ...

Day 09 「世事难预料」单元测试与例外处理

世事难预料,写程序总会遇到例外。例外该怎麽处理,逻辑该怎麽验测,本篇将进行讨论。 图片撷取自网路 「...

(特别篇)统计学的陷阱区,用资料绘制盒须—爬虫D3做成D3(下)

前言 本日主要内容包含另一个网路撷取资料方式Convert HTML Tables To JSON、...