0x00 背景


[email protected]JavaScript BackDoor中提到了利用rundll32.exe執行一段JavaScript代碼即可反彈一個Http Shell,這里將之前看到的對其原理進行分析的文章翻譯和大家分享。

links: http://thisissecurity.net/2014/08/20/poweliks-command-line-confusion/

最近,hFireF0X在逆向工程論壇kernelmode.info上發表了對Win32/Poweeliks惡意軟件詳細調查的文章。這個惡意軟件的特別之處就是它存在于window注冊表中并且使用rundll32.exe來執行JavaScript代碼。

我發現很有趣的是我顯然不是唯一一個發現可以通過rundll32來執行一些JavaScript代碼的人。

p1

當我們第一次發現命令行執行JavaScript,我們很好奇它是如何工作的。

在接下來的文章中,我們會分析JavaScript代碼時如何執以及為什么會在調用這樣簡單的命令行代碼時執行:

#!bash
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";alert(‘foo’);

0x01 Rundll32介紹


關于rundll32.dll的使用在MSDN上有專門的文檔;它往往被用來調用一個DLL文件的輸出函數,可以通過以下的命令來實現:

#!bash
RUNDLL32.EXE <dllname>,<entrypoint> <optional arguments>

entrypoint就是輸出函數;它的函數原型應該是如下所示:

#!cpp
void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);

參數lpszCmdLine是由rundll32.exe命令語句中的<optional arguments>值確定的。

我們會嘗試指出rundll32.exe是如何能夠調用被mshtml.dll輸出的函數RunHTMLApplication,以及“Javascript”前綴是如何被用來執行實際的JavaScript代碼的。

0x02 Rundll32.exe分析


a.參數

rundll32.exe做的第一件事就是使用內置的ParseCommand命令來對命令進行解析。這個函數會查找一個逗號(‘,’,0x2c)來定位dll的名稱和一個空格(‘ ’,0x20)來定位入口點名稱

p2

當使用我們的樣本命令時,ParseCommand會返回javascript:"\..\mshtml作為DLL名稱,返回RunHTMLApplication作為入口點。

p3

0x03 Dll loader


rundll32.exe會嘗試幾種方法來從最初的“JavaScript:"\..\mshtml”加載實際的DLL。

第一次測試使用了函數GetFileAttributes("javascript:"\..\mshtml")。這個函數最終會接近C:\Windows\system32\mshtml。如果這個文件沒有被發現,那么這個函數就會返回-1。

p4

接下來SearchPath會被調用來確定DLL的名稱。這個函數會讀取注冊表鍵值HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode。微軟對于這個鍵值的定義是:

當這個REG_DWORD類型的注冊表鍵值被設為1,SearchPath會首先搜索系統路徑中指定的文件夾,然后會搜索當前工作的文件夾。當這個注冊表鍵值被設為0時,電腦首先會搜索當前工作的文件夾,然后再去搜索系統路徑中指定的文件夾。系統對于這個注冊表鍵的默認值是0。

在默認情況下,這個注冊表鍵值是不存在的(在win xp、7、8下),所以SearchPath會優先嘗試在rundll32.dll的當前目錄中加載文件mshtml,其次才會嘗試在系統路徑中進行定位。

p5

如果所有的嘗試都失敗了,那么rundll32.exe就會進行下一步。GetFileAttribute將再次被調用來給模塊查找manifest文件:javascript:"\..\mshtml.manifest

若所有的之前的步驟都失敗了,rundll32.exe最終會調用Loadlibrary("javascript:"\..\mshtml")

LoadLibrary只是位于ntdll.dll中的一個對LdrLoadDLL的簡單封裝。在內部,LdrLoadDll會添加默認的擴展dll并且把結果字串(javascript:”\..\mshtml.dll)作為路徑來解析。“..”代表再向上一層文件夾:它就解析成了mshtml.dll

mshtml.dll已經被確定了,LdrLoadDll就可以加載系統目錄中的lib庫了。

p6

rundll32.exe接下來會使用之前提取的入口點名稱RunHTMLApplication調用GetProcAddress

這個時候我們可以發現,javascript:前綴看起來毫無用處:LoadLibrary("foobar:\"\..\mshtml")工作的很好。所以,為什么要加這么一個前綴呢?

0x04 協議處理


一旦入口地址已經被解析出來,rundll32.dll會調用函數mshtml.dll!RunHTMLApplication

即使沒有被記錄,實際的RunHTMLApplication也能從c:\windows\system32\mshta.exe的調用中推斷出來(這個應用專門來啟動一個.hta文件)。

#!cpp
HRESULT RunHTMLApplication(
HINSTANCE hinst,
HINSTANCE hPrevInst,
LPSTR szCmdLine,
int nCmdShow
);

這和期望的rundll32.exe的入口點地址很相似:

#!cpp
void CALLBACK EntryPoint(
HWND hwnd,
HINSTANCE hinst,
LPSTR lpszCmdLine,
int nCmdShow
);

RunHTMLApplication接受一個窗口的句柄而不是一個模塊的句柄作為第一個參數。這個參數會在mshml登記一個窗口類或者為一個類創建窗口時被使用。傳遞一個同實際的實例并不相一致的值并不會給user32帶來很大影響。

第二個參數完全沒有被使用,所以這個不匹配并不重要。

最后一個參數,nCmdShow,被RunHTMLApplication函數用來展示代管這個HTML應用的主機窗口。rundll32經常使用值SW_SHOWDEFAULT來調用入口點函數來指示任何可能打開的窗口使用窗口默認配置。

在我們的例子中,可能更讓人感興趣的參數是 lpszCmdLine (";alert('foo'))

p7

這顯然會導致問題,因為這并不是一個有效的JavaScript語句(注意在語句末尾丟掉的雙引號)。但是它仍然有效,因為RunHTMLApplication忽略給定的參數,并且更傾向于從windows API GetCommandLine中重新請求原始的命令(封裝在GetCmdKLine函數的一個調用中)。

p8

完整的命令包含了可執行文件和參數的名稱:GetCmdLine通過整理可執行規范來提取參數。

p9

在這之后,RunHTMLApplication會調用CreateURLMonitor:

p10

這也是需要字符串“javascript”的地方。

CreateURLMonitor解析命令行來提取char”:”(0x3A)之前的字符串:“javascript”。

p11

CreateUrlMoniker會爬取注冊表鍵值HKCR\SOFTWARE\Classes\PROTOCOLS\Handler\。這些鍵值和一個協議集以及它們的CLSID有關。

CreateUrlMoniker會發現一個合適的協議處理器來對Javascript的協議進行處理(HKCR\SOFTWARE\Classes\PROTOCOLS\Handler\javascript):

p12

CLSID{3050F3B2-98B5-11CF-BB82-00AA00BDCE0B}符合微軟“Microsoft HTML Javascript Pluggable Protocol”規范。

p13

這也是為什么字符串“javascript”必須在參數的開始部分的原因。

相同的機制在人們在IE的導航欄輸入javascript:alert(‘alert’)時也會起作用。

p14

位于“:”分隔符之后的字符串會被JavaScript URL moniker解釋成JavaScript指令:

#!js
"\..\mshtml,RunHTMLApplication ";alert(‘foo’);

這是一個帶有字符串"\..\mshtml,RunHTMLApplication "和函數(alert)的無效JavaScript語句(因為雙引號會跳過所有之前的步驟!)。

最終RunHTMLApplication會調用CHTMLApp::Run,這條JavaScript語句也會被執行:

p15

0x05 安全影響


從安全的角度來看,通過rundll32來執行JavaScript就像執行一個HTML應用。

換句話說,我們可以使用IE的全部權利。當區域安全被關閉,允許跨域腳本訪問,我們就可以擁有讀寫客戶端機器文件和注冊表的權力。

通過這個技巧,JavaScript可以在IE外部被執行,并且腳本沒有任何安全概念的約束,比如保護模式\沙盒。

0x06 結論


按照我們的理解,這個技術語序繞過一些信任內置的rundll32的行為的安全產品。

0x07 本文相關


  1. https://twitter.com/hFireF0X
  2. http://www.kernelmode.info/forum/viewtopic.php?f=16&t=3377
  3. http://support.microsoft.com/kb/164787/en
  4. http://msdn.microsoft.com/enus/library/windows/desktop/aa365527%28v=vs.85%29.aspx
  5. https://thisiscybersec.files.wordpress.com/2014/08/capture-d_c3a9cran-2014-08-20-c3a0-16-16-36.png
  6. https://thisiscybersec.files.wordpress.com/2014/08/capture-d_c3a9cran-2014-08-20-c3a0-16-16-36.png

您的支持將鼓勵我們繼續創作!

[微信] 掃描二維碼打賞

[支付寶] 掃描二維碼打賞