跳转到帖子

游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

TheHackerWorld官方

渗透技能——“隐藏”更多的注册表测试

精选回复

发布于

0x00 前言

上一篇文章《渗透技巧——”隐藏”注册表的创建》介绍了Poweliks使用的注册表隐藏技术,分析了原理,并编写C程序实现了该功能。

本文将进一步测试并分享一种更“隐蔽”的方法(这种方法还没有找到公开信息,待定)。

0x01 简介

本文将介绍以下内容:

使用Win32 API读取时出错

当“\0”位于字符串中间时

其他原生API的应用(如NtCreateFile)

一种更微妙的利用方法

防御探测

0x02 隐藏原理

对于Windows系统,“\ 0”(0x 0000)被识别为字符串的终止符。

所以在读取这个字符串的过程中,开头的“\0”会被解释为终止符,会被提前截断,导致读取错误。

要使用Native API设置注册表,需要使用OBJECT_ATTRIBUTES结构作为参数来指定读取字符串的长度。

只要长度设置正常,就可以读取正确的字符串,避免这个bug。

利用的关键:

使用Native API还有一个额外的参数,可以指定读取字符串的长度。

那么,在进一步思考这个问题之后,就会有下面的测试。

0x03 使用Win32 API读取时,具体是什么样的错误?

使用HiddenNtRegistry创建测试注册表键值,C调用代码如下:

printf('=================普通键==================\ n ');

printf('1。create key:\ n ');

MyCreateKey(' \ \ Registry \ \ Machine \ \ Software \ \ test1 ');

printf('2。open key:\ n ');

hKey=MyOpenKey(' \ \ Registry \ \ Machine \ \ Software \ \ test1 ');

printf('3。SetValueKey:\ n ');

MySetValueKey(hKey,' test1 ',' 0123456789abcdef ',REG _ SZ);

printf('==================隐藏键=================\ n ');

printf('1。open key:\ n ');

hKey=MyOpenKey(' \ \ Registry \ \ Machine \ \ Software \ \ test1 ');

printf('2。SetHiddenValueKey:\ n ');

MySetHiddenValueKey(hKey,' \0test1 ',' hidden0123456789abcdef ',REG _ SZ);

printf('3。QueryHiddenValueKey:\ n ');

MyQueryHiddenValueKeyString(hKey,' \ 0 test 1 ');

该程序实现了以下功能:

创建内容为0123456789abcdef的注册表项test1。

创建内容为hidden0123456789abcdef的注册表项\0test1。

按如下方式运行

2-1.png

使用Win32 API RegQueryValueEx尝试读取上述两个注册表项。

关键代码如下:

LONG lReturnCode=0;

HKEY HKEY;

LPCTSTR RegPath=_ T(' Software \ \ test1 ');

if(ERROR _ SUCCESS==:RegOpenKeyEx(HKEY _ LOCAL _ MACHINE,RegPath,0,KEY_READ,HKEY))

{

char dw value[1024];

DWORD dwSzType=REG _ SZ

DWORD dwSize=sizeof(dw value);

lReturnCode=:regqueryvalueeex(HKEY,_T('test1 '),0,dwSzType,(LPBYTE)dwValue,dw size);

if(lReturnCode!=错误_成功)

{

printf('lReturnCode:%d\n ',lReturnCode);

if(lReturnCode=2)

printf(' ERROR _ FILE _ NOT _ FOUND \ n ');

返回0;

}

printf(' regquery value:');

for(int I=0;我

读取注册表项test1,并成功获取内容。

读取注册表项\0test1,并按如下方式修改代码:

lReturnCode=:regqueryvalueeex(HKEY,_T('\0test1 ')),0,dwSzType,(LPBYTE)dwValue,dw size);

读取失败,返回ERROR_FILE_NOT_FOUND。

验证了上面的原理:由于“\0”的作用,字符串被提前截断,识别为空字符,因此无法获得名称。

然后再做进一步的尝试。

0x04 “\0”放在字符串中间会怎样?

HiddenNtRegistry的代码是:

printf('1。open key:\ n ');

hKey=MyOpenKey(' \ \ Registry \ \ Machine \ \ Software \ \ test 2 ');

printf('2。SetHiddenValueKey:\ n ');

mysethiddenvaluey 2(hKey,' test2\0abc ',' hidden0123456789abcdef ',REG _ SZ);

printf('3。QueryHiddenValueKey:\ n ');

myqueryhiddenvaluekeystring 2(hKey,' test 2 \ 0 ABC ');

注:

需要适当修改原项目HiddenNtRegistry中的MySetHiddenValueKey函数和MyQueryHiddenValueKeyString函数来重新计算字符串长度。新函数被命名为MySetHiddenValueKey2string2和MyQueryHiddenValueKeyString2。

该程序实现了以下功能:

创建注册表项test2\0abc,内容为hidden0123456789abcdef。

阅读注册表项test2\0abc的内容

按如下方式运行

2-2.png

使用regedit.exe查询键值,得不到弹出提示,如下图所示。

2-3.png

这里有一个大胆的尝试:

既然test2\0abc中的”\0”会截断字符串,那么我们再创建一个名为test2的键值会怎么样呢?

创建注册表项test2,内容为0123456789abcdef,键码如下:

hKey=MyOpenKey(' \ \ Registry \ \ Machine \ \ Software \ \ test 2 ');

MySetValueKey(hKey,' test2 ',' 0123456789abcdef ',REG _ SZ);

使用regedit.exe再次检查注册表,有趣的事情发生了,如下图所示。

2-4.png

查询注册表键值\ registry \ machine \ software \ test2不再弹出并报错,而是显示两个名为test2的键值,都是0123456789abcdef。

我们知道,在注册表中不允许创建两个同名的注册表项,但是上面测试生成的两个同名的注册表项,其实是因为其中一个被误截断,导致同名,键内容相同,是0123456789abcdef(其实内容是hidden0123456789abcdef)。

因此,我们有另一种“隐藏”注册表的方法。这种隐藏方法与之前在第一位填充“\0”的方法相比,最大的优点是用regedit.exe查看键值时不会弹出框报错,隐藏效果更好。同时具有欺骗性,和正常的键值一样。

比如下面这张图

2-5.png

显示的键值是0123456789abcdef,实际是hidden0123456789abcdef。

0x05 其他Native API(如NtCreateFile)能否应用?

参考NtCreateKey的实现思路,测试一下其他Native API,比如NtCreateFile,在创建文件时是否也有同样的问题?

使用NtCreateFile创建一个特殊文件:\0c:\1\test.txt,其关键代码如下:

HMODULE hModule=NULL

NTCREATEFILE NtCreateFile=NULL

UNICODE_STRING文件名={ 0 };

OBJECT_ATTRIBUTES对象属性={ 0 };

HANDLE hFile1=NULL

IO _ STATUS _ BLOCK IOsb={ 0 };

HANDLE hfile 2=INVALID _ HANDLE _ VALUE;

PWCHAR pBuffer=NULL

DWORD dwRet=0;

h module=LoadLibrary(_ T(' ntdll . dll '));

如果(!hModule)

{

printf('无法获取NTDLL的ModuleHandle。DLL’);

返回FALSE

}

NtCreateFile=(NtCreateFile)GetProcAddress(h module,' NtCreateFile ');

如果(!NtCreateFile)

{

printf('在NTDLL中找不到NtCreateFile入口点。DLL’);

返回FALSE

}

char * Path=' \ \ Device \ \ \ hard disk volume 1 \ \ 1 \ \ test . txt ';

char * TempBuff

TempBuff=(char *)malloc(strlen(Path 2)* 2);

for(int I=0;我

返回错误c000003b,指示STATUS_OBJECT_PATH_SYNTAX_BAD。

调试器,跟踪到InitializeObjectAttributes,并检查结构ObjectAttributes的参数,如下图所示

3-1.png

检查内存中缓冲区的内容,如下图所示

3-2.png

与实现NtCreateKey时的参数结构相同。

对于NtCreateFile,暂时不能应用。

0x06 利用思路与检测

Poweliks使用的注册表隐藏技术最大的问题是,使用regedit.exe打开时,会弹出一个框,报错。如果在字符串中间插入\0,并在\0之前创建一个同名的新键值,就可以避免这个问题。

对此,检测思路是找到这个不寻常的注册表项,检查注册表项下是否有两个同名的项。

如果您以这种方式在启动键位置创建了一个新的注册表键值,则可以使用Autoruns检测到它。

0x07 小结

在本文中,我们进一步测试了Poweliks使用的注册表隐藏技术,分享了一个更加隐蔽的利用方法,并给出了防御检测的思路。对于其他原生API应用,需要更多的测试。

留下回复

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。