From Burnout to RCE: Getting out of the rat race

The write up starts from explaining the burnout from bug bounties to greybox testing to a thorough explanation and coordinated disclosure of CVE-2021-27902 and CVE-2021-27903 that can be chained together to gain Remote Code Execution in CraftCMS. The articles is divided into sections. You can skip and read what you feel like or just read from top to bottom.

The Burnout

Hacking has always been for the lulz for me and I never really considered it as a career. I knew about bug bounties as well as the exploit market. I knew some people in whitehat community and could pursue a career in the security field quite easily. But somehow I ended up being a backend developer. None the less, I succeeded as a developer and learned a lot about PHP and server side. But the 2020 pandemic forced me to leave the job and do bug bounties. Sure I was in luck that my experience helped me find valid bugs and report them on HackerOne.

After several successful reports, it occurred. Somehow, I was no longer finding any bugs. I was (and still am) in this phase of feeling drudgery and boredom while doing bug bounties. Hacking was never boring to me, but bug bounties is making me feel like I am not giving my best. After reading a lot of articles, watching some talks on YouTube and talking to the community on burnout, I realized why not many people succeed in the bug bounties.

Buzzy buzzy buzz words. Burnout is just the stress you are facing. This stress is normal when you work a lot but reach nowhere. It is like running in the rat race and trying to compete with other hunters for the money. The first one takes the prize and burnout is natural. Give me a break.

The Real Problem

You see, hacking is hard. It gets easy when you know what you are doing. Most people do not even know what they want. Money is complementary. The real prize that you want is to have that adventure of hacking. The problem occurs when you try to look for money but money comes from the vulnerabilities you report. But you are not looking for the vulnerabilities, you are after money. Money is important. But you can’t find money in HTTP responses.

Another thing that people miss is that they keep digging without any hint. Its like a treasure hunt. You need to find hints to find the treasure. But what if there is no hint? Would you be digging holes in someone’s backyard or park blindly just to find a treasure chest that you don’t even have any clue whether it exists or not?

Sometimes, people fail to completely understand bug bounty hunting. Lemme explain in a brief.

From a company’s perspective, the bug bounty hunting can be seen as a testing strategy, a marketing stunt, or a way to shut mouths. But as a researcher, we are more interested in the testing strategy. Bug hunting is just a buzz word that means testing. The bug hunters do monkey testing or gorilla testing or both to find security vulnerabilities and report them. There is a catch though. Monkey and gorilla testing in bug bounty hunting is done on the user level ie. on the final product. The tester is not given a full understanding of what the software actually does. The tester ie. the bounty hunter tries to find patterns in the illusion of outputs to understand what the software is actually doing under the hood.

Sometimes, source code is provided. This is where whitebox testing comes into play. Whitebox testing is kinda clean. Tester is provided the source code, he dissects the source code and tries to find vulnerable code. This is quite advantageous. But then, You need to know how code works. In fact, to be a hacker, programming is necessary. Hackers do testing but testing is not hacking. Those who tell you that they hack but don’t know programming are simply lying to you. Either they know programming or they are not hacking. A hacker may not know any computer language, but they see the logic behind and the underlying patterns and that is programming. Hacker is someone who sees how an action is being done and take advantage of that to perform another action ie. reprogram a software not rewrite. Tools and utilities are complementary, not necessary. But understanding the logic is the basis of programming as well as hacking and is a must.

The Buzz Word

Another reason why people don’t succeed in bug bounties is the frustration of duplicates and N/A. The reason why you mostly find duplicates or N/A is not because you are reporting low hanging bugs but because you are reporting bugs and not vulnerabilities. Lemme explain.

With the bug bounty boom, people are more relatable with the buzz word “Bug Hunting” rather than the testing or auditing and the exploits are “surprisingly” known as bugs. The problem with this “Bug” word is that a bug can be anything. From a for loop missing the last iteration to an overflow that led to an RCE. An unrestricted file upload is a bug, but uploading a shell to execute code is a vulnerability. The exploits utilize bugs, but bugs are not exploits. Bugs are faults in the software. Exploits on the other hand, are security vulnerabilities. Depending on how many people know it, the exploits are labelled as zero day, 1-day or n-day ie. known exploits are not zero days and zero days are not known and bugs are not exploits but exploits are built on top of those bugs.

Coming back to the burnout, what companies are doing with bug bounties is that they are giving you a target and asking you to report the bugs in that target. Now when you report any kind of bugs without enough impact, they can say these bugs are not impactful. So they will not fix them. Since they are not fixing the bugs but expecting a bug, they are creating a dilemma for the newcomers. What to consider a bug and what to not. A simple way to come out of it is to see every bug as bug. And not call them bug when they are security vulnerability. There is a difference and that difference defines what is impactful and what is not. A bug can be a security vulnerability. But a security vulnerability is a bug. It is all about treating the bugs as bugs and vulnerabilities as vulnerabilities. XSS is a vulnerability not a bug. Unfiltered Input is a bug.

Let’s combine this new perspective with our treasure hunt analogy. The hints you need to find treasure are bugs. But the treasure is not a bug nor a bounty but a successful exploitation of a vulnerability. Using the bugs, you have to perform an exploitation.

Another thing, they won’t even pay for a theoretical vulnerability. You need to prove it by exploiting it to a reasonable limit. Found an XXE, can you pop a shell? Found an XSS, can you steal the cookies? Found a leak, is it PII? Found access token in public repo, can you login with them? Found an open redirect, can you take over the account? Found a potential subdomain takeover, well go ahead and take over that subdomain.

So instead of reporting bugs, you should try to successfully exploit the bugs that can result in something impactful without going beyond the policy ofcourse. That is known as chaining. Chaining those bugs, you can find other bugs that can give something impactful. But be cautious of the thin line and not to damage anything while going up the chain and stay within the policy.

The wrong start

I believe, there is no wrong, no right but a matter of perspective. And from my perspective, people often start wrong as they jump right onto the blackbox testing aka bug bounty hunting on end products and don’t care to understand what is happening behind the curtain. As I said before, you must learn to program to become a hacker. There is no way around this. Many celebrities will tell you how they became a hacker without writing a single line of python. Hey, you were not writing a line of python but were you a hacker at that time? And now that you are a hacker, did you still not learn at least one language? In the end, did any hacker (not the larps) called you a hacker?

Blackbox testing is great but if you are looking forward to learning how code works, this is where greybox testing comes in. Since you get access to the source code, you can see how code works and find vulnerabilities without bombarding your bests on a wall for nothing. Whitebox testing combined with a blackbox testing can yield impactful exploits which you couldn’t find with only blackbox testing. If you are good enough, you can find some great zero days and sell them to zero day acquisition companies like Zerodium and Zeroday Initiative for much much higher prices. Also, these zero days can be reported to the bug bounty programs and after the disclosure, the same zero day becomes an n-day and many targets still have not fixed these common exploits that only you know of.

Starting gradually with Greybox Testing

Everyone has their own way of starting. But if you are stuck in blackbox testing or maybe you wanna learn code review. Either way, I will explain how to do greybox testing my way. Note that this is not a set methodology of doing things. It is just how I do it.

  1. Choose a target software.
  2. Install it or get an installed instance (the one you have permissions to hack kek)
  3. Find potential vulnerable code like functions with system calls, file handles, vulnerable inputs and their outputs.
  4. Find inputs that can allow you to inject payloads to that potential code.
  5. Exploit the vulnerabilities and write a PoC.
  6. Report the vulnerability.

Choosing a Target

Choosing a target for greybox testing is completely dependent over your language of choice and having the environment for installing the software. For example, If you know JavaScript, very likely you will be auditing a software that heavily uses JavaScript. But if you know swift but do not have any Mac to run that code, you cannot test it.

Finding targets

Bug Bounty Platforms : Targets can be found in many bug bounty platforms. But there are not many companies which have their code as open source to allow a third party tester like you to test it. You can find them with the “Source Code” tag in bug bounty platforms.

Self Hosted Bug Bounty Programs : Many companies run their own bug bounty program which are not so popular. You can find them on the company’s website or using some public databases like ([].

Open Source Software : The best possible target for whitebox testing is Open Source Software. Yes if it is open source or free, you have a right to test it given you are not distributing the found vulnerabilities (which is also fine with some licenses, if my understanding of them is correct). You do not need a policy to break into your own copy of code.

Installing it


Finding the vulnerable code

Depending on your target, there are many ways a vulnerability can exist in the code. From a system call function visible in plain sight to overflows hidden behind those off-by-one errors in for loops, there are plenty. You just need to be proficient in your language of choice and find vulnerabilities.

Finding inputs

These inputs can be found by following the code flow. You see, code has a flow and it runs from instruction to instruction. Even if its multithreaded, object oriented or event driven, it still runs from one instruction to another line by line. This flow can be followed to the top where the human interface fills in the input and understand how it is processed down to the vulnerable code. If the payload reaches the vulnerable code, you might be able to exploit the vulnerability.

Exploiting and writing a PoC

While normal vulnerabilities are fine too, If you are hunting for zero-days, you must try to reach the maximum impact like RCE or SQLi. So if you have found a smaller bug that can be chained, don’t rush to report it. Try to escalate it to something bigger. Reading the code can give you the bigger view of what is possible. Also, writing a good proof of concept is as important as the report itself. A few days ago, I used a payload and reported the vulnerability. But then I forgot to give a clean payload in my report and the fixer couldn’t reproduce the issue. Even a one-line report can go a long way if your PoC is precise.

Report the vulnerability

Before jumping into reporting the zero days, you should know whom to report. Usually, you wanna sell the vulnerability to the right buyer. First understand how big player your target is ie. see how many people use that code. Is the target being used by millions of people like WordPress? Or maybe it is only used by the company itself.

Zero-day Acquisition Companies : It is worth to look at the scope of Zero day acquisition companies as well as getting in contact with them if you think your target is big enough. Even if its not in their scope, they might accept it.

Bug Bounty Program : If your target runs a bug bounty program, you are in luck. There are chances that the maintainer of an open source program might be running a vulnerability disclosure program and not bug bounty program ie. they don’t pay. If that is the case, you can either earn a good will or submit your report via a third party like is a bug bounty platform that pays a significantly smaller amount of 40$ per report and 40$ for the fix but they pay for literally every valid report and every valid fix you submit. This is a good way to earn while you are learning. I personally see the potential in to grow into something as big as HackerOne in the nearby future and maybe get some private companies to host their own bug bounty program on


So you made it! Or maybe skimmed your way to here. Anyways as a closing thought, I am explaining my n-day in Craft CMS that can help you understand how to perform greybox testing and also earn from Open Source bug hunting. This is a great example as the exploit chain is a result of 3 vulnerabilities ie. Stored Cross Site Scripting, Server Side Template Injection and finally, Arbitrary Code Execution, and 4 bugs ie. Broken Access Control, Unrestricted File Upload, Deserialization of Untrusted Data, and Misconfiguration. The bug resulted in monetary reward and 2 CVEs, namely, CVE-2021-27902 and CVE-2021-27903. The vulnerabilities has been fixed in 3.6+ and I have taken permission from the Craft CMS team to publicly disclose them. If you are using Craft CMS, you should upgrade to the latest version of Craft CMS and also follow the security standards of Craft CMS. The exploit depends on user interaction So if you are aware of cross site scripting and follow security measures, you will be fine.

Knowing the Application

Before starting the audit, the first thing I do is understand the application. It starts with installing the application and see how it works. In a blackbox test, we often do not have admin privileges and we cannot see what is behind that authentication wall. But in greybox testing, we can simply login and see the admin area. So that is the step two. Login and see behind the walls and understand the application.

Finding the first bug – Unrestricted File Upload

As I tinkered with Craft CMS, first thing I noticed there was an Asset section which allowed you to upload files. Testing it, I started uploading PHP files as many CMS’s often have unrestricted file uploads. But no luck. Then I thought maybe I can get XSS via SVG files. Interestingly, file was uploaded. But the CMS was using enshrined/svg-sanitize a filtration library that is quite good at its job. I tried every possible payload but SVG didn’t work. Finally I decided to look at the code. After auditing where file uploads are being blocked, I found that there is src/config/GeneralConfig.php file which contains a list of allowed file extensions. I saw that it had HTML files as valid file uploads! And here I was trynna pop an alert from SVG files. I uploaded an HTML file, see its link and it worked! The bug here was Unrestricted File Upload that resulted in a Cross Site Scripting vulnerability.

Turning Unrestricted File Upload into Vulnerability

But this can be categorized as self XSS because only privileged users are capable of uploading a file. Remember that Craft is a CMS and its job is to allow people to make a website. So there must be a way to allow file uploads from the frontend. I started searching for ways on the google to upload a file from unauthenticated pages. Sooner, I found that there is a functionality to create content, that is entries. With more research on how it works, I found that Craft CMS uses a creative concept of volumes that allows users to upload files to different directories. I configured the volume and started testing uploads. I created upload fields for the entry and tried using it. I was able to create entries and upload HTML files but it was still using the admin account. So I searched more and more and found this plugin called Guest Entries. I installed it and after reading its documentation, I created the following form to upload the files from the frontend.

{% macro errorList(errors) %}
    {% if errors %}
        <ul class="errors">
            {% for error in errors %}
                <li>{{ error }}</li>
            {% endfor %}
    {% endif %}
{% endmacro %}

{% from _self import errorList %}

<form method="post" accept-charset="UTF-8" enctype="multipart/form-data">
    {{ csrfInput() }}
    <input type="hidden" name="action" value="guest-entries/save">
    <input type="hidden" name="sectionId" value="2">
    <input type="hidden" name="enabled" value="1">
    {{ redirectInput('{uri}') }}

    <label for="title">Title</label>
    <input id="title" type="text" name="title"
        {%- if entry is defined %} value="{{ entry.title }}"{% endif -%}>

    {% if entry is defined %}
        {{ errorList(entry.getErrors('title')) }}
    {% endif %}

    <input type="file" name="fields[asset]">
    <input type="submit" value="Publish">

and configuring the volume and entries a little, I was able to upload the file from the frontend! But how would an attacker know where the file went?

To supplement the bug, I had to create an entries page that showed the link to uploaded files. Note that this is quite common for theme developers to create such forms and show the images/files uploaded from frontend:


{% set rel = %}
{% if rel %}
    <p><a href="{{ rel.url }}">{{ rel.filename }}</a></p>
{% endif %}

By configuring both templates correctly, I was able to upload XSS and get its URL. Payday! But I didn’t bothered to report it.

Finding the second bug – Broken Access Control

Even after finding the stored XSS, I was still playing around with the CMS as it was quite interesting. While checking the settings, I came across a nice feature called aliases. I was interested in what these aliases can do, I kept on learning about them. From the source code audit, I came to know that this is actually a part of Yii2 framework. But what can I do with it? I tried finding the inputs where I could put them and sooner I found how dumb I was. I have been using these aliases this whole time in the volume configurations. I tried to go one step back with .. to point the volume outside the public directory and tried uploading a file, it worked! This broken access control bug can allow me to write a file anywhere I want!

Finding the third bug – Deserialization of Unstrusted Data

I was already hyped after finding this. I rushed to see the directory structure and tried uploading files everywhere I can. The end goal as always was RCE. So I uploaded files in vendor directories, tried overwriting the composer.json but I could not upload any PHP file. So I was stuck. Then I tried to upload twig templates within the twig directory but still, no luck. After getting tired of goofing around with uploading files, it came to my mind that I could also point a route to it. So I uploaded an SVG file and pointed a route to it. No surprise it worked.

Turning Broken Access Control and Deserialization of Untrusted Data into Server Side Template Injection

So I was able to upload files in templates directory and load it on the server as well. Obviously I ended up putting the famous {{7 * 7}} in the SVG and there it was! An SSTI using a chain of two bugs ie. the aliases shouldn’t have allowed uploading to templates directory and twig shouldn’t be rendering content from non twig templates. Note that both bugs can only be performed by an admin and no guest user would be able to do it.

Finding the fourth bug – Misconfiguration

After finding the SSTI, we are still within the sandbox of Twig so this is quite a locked up situation where you can only perform simple text manipulations. I tried every possible payload available for escaping the sandbox but no luck. Then I asked my team to help me and our best in the wild zeroday ninja gave the payload {{ ['id']|filter('system') }} which I was trying again and again with no success. But when I copy pasted it just worked. Maybe I was doing a typo. None the less, it worked and now was the time to write the PoC!

Connecting the dots and completing the PoC

With the misconfigured twig engine that didn’t implemented the sandbox configuration, I was able to remote code execution. Since I already had an XSS, I could simply let the JavaScript do all the manual work on behalf of the admin. So I wrote an exploit in JavaScript that automates all the stuff and uploads a shell when the XSS triggers. I won’t be disclosing the exploit itself but here is the PoC video:

All these vulnerabilities have been fixed. Long live the Open Source!