滲透技巧——」隱藏」註冊表的建立

導語:知名惡意軟件Poweliks曾使用過的一個後門技術,在註冊表啓動位置建立一個特殊的註冊表鍵值,經過mshta來執行payload。對於這個特殊的註冊表鍵值,在正常狀況下沒法對其訪問,這其中的原理是什麼呢?如何讀取、建立以及如何刪除呢?javascript

 

0x00 前言java

知名惡意軟件Poweliks曾使用過的一個後門技術,在註冊表啓動位置建立一個特殊的註冊表鍵值,經過mshta來執行payloadgit

對於這個特殊的註冊表鍵值,在正常狀況下沒法對其訪問,這其中的原理是什麼呢?如何讀取、建立以及如何刪除呢?本文將要一一介紹github

0x01 簡介shell

本文將要介紹如下內容:api

·隱藏註冊表的原理數組

·隱藏註冊表的實現工具

·程序編寫上須要注意的問題post

0x02 原理測試

註冊表鍵值名稱通過特殊構造: 以」\\0」做爲開頭,後面加上任意字符(不能爲數字)

對於Windows系統,」\\0」(即0x0000)會被識別爲字符串的結束符,因此在對該字符串讀取的過程當中,遇到開頭的」\\0」,會被解析成結束符,提早截斷,致使讀取錯誤

而使用Native API設定註冊表,須要使用結構體OBJECT_ATTRIBUTES做爲參數, 指定讀取的字符串長度

只要長度設定正常,就可以讀取正確的字符串,避免這個bug

因此,咱們能夠經過Native API來建立這個特殊的註冊表名

更爲重要的是,像regedit.exe和其餘對註冊表的操做,一般會調用Win32 API,這就致使該註冊表沒法被讀取,也就實現了所謂的」隱藏」

綜上,建立方法爲: 經過Native API建立一個以」\\0」開頭的鍵值

0x03 編寫程序實現

經過Native API實現對註冊表的操做,可供參考的工程地址:

https://www.codeproject.com/Articles/14508/Registry-Manipulation-Using-NT-Native-APIs

做者Dan Madden,他的代碼使用了類的封裝

我的傾向於使用最基本的api實現,因而參考他的代碼,從新設計

對於Native API,須要的結構以下:

1.獲取Native API的地址

註冊表操做的相關Native API可從ntdll.dll中得到

關鍵代碼以下:

HINSTANCE hinstStub = GetModuleHandle(_T("ntdll.dll"));
NtOpenKey = (LPNTOPENKEY)GetProcAddress(hinstStub, "NtOpenKey");

2.Native API的重定義和聲明

Native API在使用前須要重定義和聲明

部分關鍵代碼以下:

typedef NTSTATUS (STDAPICALLTYPE NTOPENKEY)
(
    IN HANDLE               KeyHandle,
    IN ULONG                DesiredAccess,
    IN POBJECT_ATTRIBUTES   ObjectAttributes
);
typedef NTOPENKEY FAR * LPNTOPENKEY;
LPNTOPENKEY                 NtOpenKey;

3. 特殊結構體的使用

註冊表操做相關Native API會使用到以下結構體,須要定義和聲明

·InitializeObjectAttributes
·_STRING
·_UNICODE_STRING
·_OBJECT_ATTRIBUTES
·_KEY_INFORMATION_CLASS
·_KEY_BASIC_INFORMATION
·_KEY_VALUE_PARTIAL_INFORMATION
·_KEY_VALUE_INFORMATION_CLASS·
·RtlInitAnsiString
·RtlAnsiStringToUnicodeString

Dan Madden的工程實現了建立隱藏註冊表項(註冊表項名稱以\\0開頭),該註冊表項下的鍵值經過正常的Native API實現建立、讀取、刪除

經過最基本api的實現過程再也不贅述,封裝好的API源代碼可參考文末給出的連接

測試Dan Madden工程包含的功能:

1.建立隱藏註冊表項

MyCreateHiddenKey("\\\\Registry\\\\Machine\\\\Software\\\\testhidden");

使用註冊表工具regedit.exe沒法打開該鍵值,以下圖

滲透技巧——」隱藏」註冊表的建立

2.在該註冊表下建立註冊表鍵值

先得到該註冊表項的句柄:

hKey = MyOpenHiddenKey("\\\\Registry\\\\Machine\\\\Software\\\\testhidden");

建立註冊表項下的鍵值test1並賦值:

MySetValueKey(hKey,"test1","0123456789abcdef",REG_SZ);

讀取該註冊表項下鍵值test1的內容:

MyQueryValueKeyString(hKey,"test1");

刪除該註冊表項下的鍵值test1:

MyDeleteValueKey(hKey,"test1");

刪除註冊表項:

MyDeleteKey(hKey);

程序輸出以下圖,成功對隱藏註冊表項下的正常鍵值進行操做

滲透技巧——」隱藏」註冊表的建立

接下來,對Dan Madden的工程添加新的功能:建立、讀取、刪除隱藏註冊表鍵值,思路以下:

對於註冊表項的隱藏,在註冊表項的名稱首位填」\\0」便可

對應註冊表鍵值的隱藏,原理上也是在鍵值的名稱首位填」\\0」,但在參數傳遞上須要注意更多問題

1.不須要修改的功能

建立註冊表鍵、打開註冊表鍵和刪除註冊表鍵的功能不須要修改,使用正常的名稱便可

2.設置註冊表鍵值

對應源代碼中的MySetHiddenValueKey

傳入參數使用char型數組,,用來定義註冊表鍵值名稱,內容爲」\\0abcd」

因爲」\\0」的存在,因此沒法直接使用strlen計算數組長度

變通方法:

計算從偏移1開始的數組長度,最終再加1

即len = strlen(buf+1)+1

Native API NtSetValueKey用來設定鍵值,定義以下:

typedef NTSTATUS (STDAPICALLTYPE NTSETVALUEKEY)
(
    IN HANDLE           KeyHandle,
    IN PUNICODE_STRING  ValueName,
    IN ULONG            TitleIndex,         /* optional */
    IN ULONG            Type,
    IN PVOID            Data,
    IN ULONG            DataSize
);

第二個參數指定鍵值名稱,須要使用結構體UNICODE_STRING

正常狀況下,咱們須要先使用RtlInitAnsiString將傳入的buf數組轉換成結構體ANSI_STRING,再使用RtlAnsiStringToUnicodeString將其轉換成結構體UNICODE_STRING,做爲參數

因爲」\\0」的存在,沒法使用RtlAnsiStringToUnicodeString

因此,咱們須要本身實現結構體ANSI_STRING向結構體UNICODE_STRING的轉換

ANSI向UNICODE的轉換,在長度計算上,乘以2便可

數組內容上,奇數位賦值,偶數爲填0x00

固然,咱們須要一箇中轉數組TempBuff實現數組內容的轉換

關鍵代碼以下:

ValueName.Length = asName.Length*2;
ValueName.MaximumLength = asName.MaximumLength*2;
char *TempBuff;
TempBuff = (char*)malloc(ValueName.Length);
for(int i=0;i<asName.Length;i++)
{
    TempBuff[i*2] = asName.Buffer[i];
    TempBuff[i*2+1] = 0x00;
}
ValueName.Buffer = (WCHAR *)TempBuff;

第四個參數,指定鍵值內容,須要將傳入的char數組轉換爲WCHAR

關鍵代碼:

WCHAR wszValue[1024];
unsigned int n ;
for (n=0; n<strlen(csData); n++) {
    wszValue[n] = (WCHAR)csData[n];
}
wszValue[n++] = L'\\0';

3.讀取註冊表鍵值

對應源代碼中的MyQueryHiddenValueKeyString

參照2,須要注意」\\0」的影響

四、刪除註冊表鍵值

對應源代碼中的MyDeleteHiddenValueKey

參照2,須要注意」\\0」的影響

實際測試:

建立註冊表項test2,建立隱藏註冊表鍵值\\0test2,建立正常註冊表鍵值test2

直接打開,以下圖

滲透技巧——」隱藏」註冊表的建立

可以正常訪問註冊表鍵值test2,但沒法訪問註冊表鍵值\\0test2

以下圖

滲透技巧——」隱藏」註冊表的建立

而咱們編寫的程序可以正常讀取,以下圖

滲透技巧——」隱藏」註冊表的建立

至此,成功實現對註冊表鍵值的隱藏

以上功能代碼已開源,地址以下:

https://github.com/3gstudent/HiddenNtRegistry

0x04 powershell實現

可參考Brian Reitz的工程,地址以下:

https://gist.github.com/brianreitz/feb4e14bd45dd2e4394c225b17df5741

具體說明可參考:

https://posts.specterops.io/hiding-registry-keys-with-psreflect-b18ec5ac8353?source=collection_archive———2—————-

實現了在HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run下建立鍵值\\0abcd,內容爲mshta javascript:alert(1)

使用咱們編寫的程序成功讀取該鍵值,以下圖

滲透技巧——」隱藏」註冊表的建立

0x05 補充

PSReflect-Functions包含多個經過powershell調用API的實例代碼,地址以下:

https://github.com/jaredcatkinson/PSReflect-Functions

0x06 小結

本文介紹了Poweliks使用過的註冊表隱藏技術,分析原理,編寫c程序實現功能,測試powershell實現代碼

相關文章
相關標籤/搜索