Page cover

Encoding

Reconnaissonce

As always ports scanning comes first, to know which service are running on these ports.

Quick scan (more in depth scans are coming, this one just to get a quick view on the machine)

nmap -sC -sV -O 10.10.11.198s
  • -sC: Use default scanning script

  • -sV: Probe open ports to determine service/version info

  • -O: Enable OS detection

  • -v: Increase verbosity level

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 4fe3a667a227f9118dc30ed773a02c28 (ECDSA)
|_  256 816e78766b8aea7d1babd436b7f8ecc4 (ED25519)
80/tcp open  http    Apache httpd 2.4.52 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_http-server-header: Apache/2.4.52 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 4fe3a667a227f9118dc30ed773a02c28 (ECDSA)
|_  256 816e78766b8aea7d1babd436b7f8ecc4 (ED25519)
80/tcp open  http    Apache httpd 2.4.52 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_http-server-header: Apache/2.4.52 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).

now we need to leave some scans run on the background so we make sure that we cover all the bases and didn't miss anything:

Starting with full TCP ports scan:

Follwed by full UPD ports scan:

As we can see port 22 (running OpenSSH 8.9p1) and port 80 (running Apache httpd 2.4.52) are open.

We start checking the webpage that is ruuning on port 80.

Enumeration:

The one thing i always do is set the proxy on burpsuite with the intercept off and start browsing the page and clicking everywhere, then check HTTP history on burpsuite and start analyzing requests (some times some POST requests are missing so i turn on intercept and do that manually). Plus running some directory fuzzing on the page on the background to see if anything is hidden(which is always true xd) and subdomain fuzzing also since we have already api.haxtables.htb

One page got my attention, where the creator describe how this api works (not an actual api).

We will then create this request to communicate with the server by simply taking another intercepted request and make the necessary changes:

Response:

Another thing got my attention was this:

We can see that we can send an url. WAIT I know what you are thinking "SSRF" (going to be there in a minute) but let me test if this really works by listening on port 80

that actually works but we didn't get any useful information from the request.

Let's play with that a little:

Here we are using file:// which is a protocol used to access files on a local or network file system using a URL (Uniform Resource Locator).

Boom! we got the passwd file but it is in hex format (doesn't matter)

now since we can read files we will take a look at the apache default config file that may give us an idea about the web app location:

We can see from the config file that api.haxtables.htb files are stored at /var/www/api &

we found out that there is another subdomain called image.haxtables.htb which its Document Root is /var/www/image If we check our previous scan for subdomains we will already find that subdomain have been found:

we add that to /etc/host:

  • tee - read from standard input and write to standard output and files

  • -a, --append append to the given FILEs, do not overwrite

We try to visit this site:

OK what's next?. We should see what is in inside of /var/www/image to see that i'm going to write a script that does the job for me. By the way i watched both Ippsec and 0xdf build a flask server to play the role of an intermediate and that was very helpful since it's my first flask server app check em Ippsec's Video & 0xdf's. But i wanted to build something similar in functionally but with my own touch so here it is :

as you can see we are using the file:// trick we used previously & here is the result:

we notice the .git directory, so we're in a git repository, so all we need to do now is to dump that repository using git-dumper.py. Now we need that flask server:

now we need to to activate the server:

and run the git-dumper on the /var/www/image directory:

now we have all this:

after analyzing the repository for a while, if we take a look at action_handler.php

We can see that this code is vulnerable to unsanitized input from an HTTP parameter page.

So in order to make a use of this vulnerability we need to make sure that we can interact with action_handler.php . For example if we craft an url it should look like this:

we copy that and paste it to the file_url parameter:

Response:

that doesn't work why?. If we can take a look at utils.php we can see this function:

which is preventing any connection to localhost.

So from this point we have 2 possibilities i will go through each one.

First Method (Ippsec found this which is the unintended way):

let's focus on this function parse_url($url, PHP_URL_HOST).

This function parses a URL and returns an associative array containing any of the various components of the URL that are present. So for example:

but the bug is in removing http:// part so let's try that:

as we can see it doesn't return anything so we can bypass this condition

let's try and send that:

Response:

Second method:

In this method we will be using the convesrtion request:

We can assume that at the backend it is append the uri_path to the url. something like this:

http://api.haxtables.htb${URI_PATH} so the trick here is to use the @ (in URLS it seperates the username and the domain) so if we write http://api.haxtables.htb@10.10.14.5 what will happen here is the connection will be redirected to us with the username api.haxtables.htb.

let's try that:

and we listen on port 80

if we decode the Authorization parametre:

we can see how this worked.

so now we can revisit image.haxtables.htb/actions/action_handler.php?page=/etc/passwd with applying our trick.

it didn't work. So let's change this to our ip addresss and see how the request looks like:

We can see that is appending /index.php at the end so we just need to add & to seperate parameters so it should look like this:

Now let's try if this works:

Yes it did.

So now we can work with any of the 2 methods to get a reverse shell. Luckily there is PHP filters chain . In this step we will need php_filter_chain_generator.py to generate our exploit chain.

Foothold

We start by generating our php filter chain (we need to escape some special characters as we can see in the payload so this can work):

We give the php chain to the page parameter:

We set a listener on port 1337:

And we send the request. BOOM we're in:

We need to upgrade our shell with the pty trick:

as we can see we our connected as www-data so we don't hvae that much privileges s let's escalate our privileges:

Privilege Escalation

SVC USER

We can see that we can run this script as svc user. so let's take a look at it:

long story short, we need make to changes at /var/www/image so we can reach the commit. But the problem is we don't have write permission on /var/www/image.

So the trick is:

This command attempts to add the file /etc/hostname to the Git staging area, assuming that /etc is the root of the Git repository. The --work-tree option specifies the working directory of the Git repository, which is /etc in this case.

let's try that:

OK we did that but how we can escalate our privilege? that's where this directory ./.git/hooks

comes to place what are hooks:

if we take a look:

so if we can change any of those should work right? No it doesn't go that way. Because those are runned only when certain functions are called but in our script we worked only with commit and add and since add doesn't have a hook we will work with commit. We can see the pre-commit.sample that will not work also because we have this argument --no-verify on the commit whch skips any pre-commit hooks that may be configured in the repository. So the plan is to create our post-commit.sample. First copy the body of pre-commit to post-commit:

The plan is to create an ssh key at /home/svc/.ssh/authorized_keys so we can ssh to the box.

First let's create our key:

now we have 2 keys svc (private key) & svc.pub (public key). We are goign to store the public in this file /home/svc/.ssh/authorized_keys and ssh to the box as svc.

post-commit.sample

now we need to remove the .sample part and set it as executable:

So we do the changes on the repo as we did before with(why we are repeating this is because there is a cron which reset everything, you will notice while doing the machine):

It worked so let's try and ssh with the private key:

ROOT:

As we can see we can restart any service managed by systemd that's what systemctl command do. So let's check if we can write a service:

it seems we have write permission on this both directories

We have only write and execute permission on system so we can't read its content. But as www-data we have read and execute so let's check it:

We have found services and different types of files. As we said we are interested in services only so we can modify or create our own servie. So let's create our own service instead of changing an old service because that may affect the behaviour of the machine. By going to GTFOBins and searching for systemctl we can see that we can create a service by simply doing this:

so let's create our service in /etc/systemd/system directory:

We are inserting the public key we ade into the root ssh authorized_keys so we can ssh as root

it did work let't try and ssh as root:

And we finally rooted the machine.

I hope this walkthrough was helpful. I tried to explain as much as i can so everyone can understand what i'm doing step by step.

Last updated