Lessons from a Live Hacking event

I recently participated in a virtual Live Hacking event organized by bugbountyhunter.com. This was my first ever Hackevent and I learned a lot of new things and made a bunch of new friends. I thought I'd share some of my findings and learnings from the event through this post.

Massive shoutout to zseano for organizing this event. Sean was not well during the entire week the event was live but still managed to successfully host it. Oh and also, thanks again Sean for permitting me to disclose some of my findings through this blog post.

The numbers

Leaderboard

At the end of the event, I finished 4th on the global leaderboard. I was quite happy with 4th, considering this was my first ever Hackevent. I spent a total of 30 hours, 28 minutes and 6 seconds hacking the web app. And in that time, I reported a total of 28 bugs, of which 27 were valid and one ended up being rejected. I was late to the party and only really started testing the application two days after the event started, so the majority of my bugs ended up being duplicates.

I reported 12 Stored XSS, 4 Reflected XSS, 1 Blind XSS, 4 Application/Business logic issues, 2 Authentication issues, 1 Broken Access Control, 1 CSRF and a couple of other miscellaneous bugs.

The rules

The event rules were pretty clear - Only manual testing was allowed. You couldn't use any automated scanners like Burp or ZAP (You could still use Burp proxy and other features, just not the Active scan). You could also do limited contextual fuzzing, once you get to know the application. But randomly picking a 1-million-directories wordlist from Github & running ffuf was a NO-NO.

The first bug

The first bug I found was probably the easiest one I came across. Funnily enough, once I started testing, it took me less than 30 seconds to find it. I navigated through the application's homepage, and started looking for requests in Burp's history. I found a request to the endpoint /sample-endpoint.html, which redirected the user to /sample-endpoint.php. I looked at the source code of the response, and found the following code:

<script>

    var curUrl = window.location.search;
    var params = new URLSearchParams(curUrl);
    var redirect_url = params.get('redirect_url');

    if (redirect_url == null) {
        top.location.href='sample-endpoint.php';
    } else {
         top.location.href=redirect_url;
    }

</script>

And that was it, my first Reflected XSS. It is technically a client side Open Redirect bug, as the application doesn't validate the value of parameter redirect_url, and so a malicious entity could redirect a user to any URL by crafting a malicious URL like /sample-endpoint.html?redirect_url=https://evil.com

Luckily for us, the parameter accepts the javascript: URL scheme, so we can escalate this to a Reflected XSS by crafting a URL like /sample-endpoint.html?redirect_url=javascript:alert(document.cookie)

Other interesting finds

1) Blind XSS: I had never found a Blind XSS before. And this one was very straightforward. On the login page, there was a message saying "Attempts to login will be logged". This made me suspect that there is surely something around logging that could be exploited here.
I could think of two things to try here: log4j or Blind XSS. The application was built in PHP, so that ruled out any log4j stuff. I tried some Blind XSS payloads in the username field, and 15 hours later, received a pingback on my email. The Blind XSS had fired on an internal panel and I received a screenshot as well as some other details of the URL, IP and DOM of the internal panel via the script hosted on my XSS hunter instance.

2) Modifying the unmodifiable: The application had a feature where there were some existing user profiles that you could modify. Every user profile had a few attributes like bio and name that could be edited but the profile picture of the user was not editable. So I started looking into ways to modify the profile picture.

I edited the bio and intercepted the request in Burp. After a lot of failed attempts at guessing the parameter that could magically update the profile picture, I decided to send the request to ParamMiner. But unfortunately, ParamMiner couldn't find anything either. Then I thought, what if I change this to a GET request. I changed the request method, moved parameters from POST body to GET request query parameters, and once again sent the request to ParamMiner.

And voila! ParamMiner detected a parameter "photo". I resent the request with the parameter "photo" and the server decided to help me out here. The server replied with "Invalid photo parameter provided. It must be photoUrl". I then sent the request with the "photoUrl" parameter, added a relative URL of another existing image on the server and the application changed the profile picture of the user!

3) Could this be escalated to XSS though?
Sure, being able to modify the profile picture is a functional bug in itself but is that the worst thing that could happen here? Probably not.

I started thinking about the things I could do by updating the profile picture - the initial idea was to upload an SVG file with an XSS payload in it as the profile picture. But there was a problem - as highlighted above, the application was only accepting relative URLs, meaning you could only change the profile picture to an existing image on the server. I tried bypassing this relative URL restriction but I was not able to (at the end of the event I did get to know that someone else was able to bypass this though).

Anyway, I reached out to a friend for some help on this and we ended up collaborating on this report (more on this later). He realized that this profile picture was also reflected on another endpoint that displayed the user's profile image in the following manner in the DOM:
<img src="images/user_1.png">

So then, I sent the edit profile request with the value /xxx"+onerror="alert(document.domain)" and it escaped out of the src attribute, executing the XSS.
<img src="/xxx" onerror=alert(1)"">

And now we have security impact! From a functional bug to a security vulnerability.

Collaboration

My biggest takeaway from this event is that collaboration is key. You will always achieve more success if you're hunting in packs. Out of the 27 bugs I reported, I needed a nudge from my friends for at least 5 bugs.

All of us look at things differently. There is a strong chance that something that may look like completely secure functionality to you, is a high-severity bug in someone else's eyes. Believe it or not, I may have finished 4th in the event but I missed the easiest bug (Authentication Bypass using default credentials) until someone pointed it out to me when I was stuck.

This was the first time I collaborated with people and I certainly enjoyed the experience. Sure, it's important to establish trust before collaborating and set the rules of collaboration straight before starting, but it's worth it. I look forward to collaborating with more people in the future.

Did you find this article valuable?

Support Mohammed Arbaaz Shaikh by becoming a sponsor. Any amount is appreciated!