Black Hat CTF Writeups
Last updated
Last updated
Although this was an easy challenge but it took us too much time and effort to solve it.
When we first open the challenge we see this search panel :
Using normal SQL injection payloads like ' or 1=1-- -;
, " or 1=1-- -;
, ' or 1=1#;
didn't work .
Performing directory search we see robots.txt
that revealed hidden admin panel :
Trying all authentication bypass on this panel did not work , Until we figured out that it maybe returning the results in the search bar using keywords like like
so to match one character we can use %
Now we want to get all records , so if we typed only %
it will through us an error to write 5 characters so by typing %%%%%
:
We got all the records ! opening the source reveals the password and then we can easily login to the admin panel :
When we first open the challenge we see a normal login page
The actions that could be taken here are many, like trying auth bypass or create an account or common credentials ... etc , However the first thing i'd like to do is to see the source code :
We see this hint in the source, by providing this parameter we get the source code :
Let's see what is going on :
First it checks for the request method - should be POST - .
It then takes 2 post parameters email and password the email value should be admin@naruto.com
A variable called x is declared and gets it's value from post parameter called test
an additional check is applied to the password as it removes any non alpha-numerical character and the new value gets stored in a variable called $inp
.
If the value of inp
contains the value SuperSecRetPassw0rd
directly then it will not work, but if it - somehow - equals the value of SuperSecRetPassw0rd
it will echo the flag .
So here is the work, how could we get into the admin account without giving the parameter password
the correct value ?
$x=$_POST["test"];
if we noticed, this variable did not appear again in the code, but it is here for a reason right ? so we can assign the value of the password to the post parameter test as follow :
The value will be reflected to the variable x
, we can now assign the value of the post parameter password
to be $x
:
And this will work :
When we first open the URL we see a fancy meme generator that takes the search engine and the search query as an input, in the right bottom we see a button the gives us the source code :
The /api/generate
route :
It takes the search engine and query search as post parameters and then uses the function take_screenshot
, I searched for public exploits for this function but no luck .
The /flag
route :
It checks if the request made to this endpoint was done from the local host and the URL starts with http://l0calhost
Returning to the main application to see the functionality , If I typed any thing as follow :
We see the following result :
So our search query value is reflected to in the search bar , It does not search for it so we cannot for example use file://
schema or perform a usual SSRF .
But since the value is reflected let's try some vulns like SSTI , I used this payload {{7*7}}
but it wasn't evaluated to 49 , After trials and errors we can see that if we used the following payload : test" + "query
the web application actually concatenates our string :
Another one -> test" + (1+1) + "
:
This confirms that our query is executed within eval()
statement, I've tried python functions like dir()
, open()
and even type()
but none worked so i opened the source code to see if anything is happening :
I saw this script , So now the data is being handled using javascript not python. To make sure i used JS functions like document.write()
as follow :
And the output was :
Now for the part to get the flag, we know that any request done by the search engine will have the remote address of 127.0.0.1
which meets the first condition to get the flag, the second condition is that the URL starts with l0calhost
, The domain localtest.me
accepts any subdomain and will also points to local host : l0calhost.localtest.me
=== localtest.me
.
Finally we can render the request to the /flag
endpoint using JS as follow :
When we open the challenge we see this home page :
The source code shows nothing, so let's create an account and login
It allows us to write notes , let's intercept the request see if any thing hidden occurs
Nothing weird except for the notes
cookie, The decoded value of the cookie is the notes :
I used this code which will generate our payload :
This basically will generate a payload that reads the current directory files
Final Payload :
We then base64 encode it and replace it as the value of notes
cookie
However there is no any result , so let's try to use return
keyword to return the result :
It worked ! But no flag here, climbing up the directory we found the flag file in the /
directory
Now we can read it by just replacing the payload with : return require('fs').readFileSync('/ranDom_fl4gImportant.txt')
:
This was the last and the only hard challenge, It also had source code files to download.
This challenge actually was solved by my teammates as I wasn't available at the time, but let's see the approach taken.
When we open the page we see this homepage with the option to register and login, let's try to register :
It asks me for username and then creates a key for me using the username to be username.key
let's see how this function operates from the source code :
We see the database initialized and a user called jimmy_jammy
registered with admin privileges.
We can that the register function takes the username and then gets the key from the keys
directory to be /dirname/keys/username.key
but since there are no validations on the username we can use path traversal to get the key for the user jimmy .
Now we got the access key for the user jimmy we can login easily , as it checks whether the access key for the user is correct or not .
We can see that a new option was add to us after gaining admin access :
If we opened any article we see the following message :
If we returned to the source to see what happens in the edit.ejs
template :
We see that it actually includes the flag but why does it appears like that ? Surfing the files we see a file called nginx.conf
:
What this file actually does is replacing the real value of the flag by the statement we saw , so we need a way to bypass this. Back again to the source code to see this snippet :
In the first snippet, GET request to the route /edit
but we can see that it applies parseInt
to the id
parameter , no matter what we pass it will be converted to integer leaving no room for file inclusion.
In the second one, POST request to the same route but this time the id parameter is not parsed which would allow us to overwrite files right ? so for example :
?id=../views/navbar.ejs
would allow us to overwrite the navigator template and then we can include the flag using the template notation -> <%= %>
The following request would overwrite the article template and by including the flag we expect to see it :
But no, because nginx will replace the flag if it saw the flag value - The real value - so we can use btoa()
function to base64 encode the flag so that nginx would not replace it :
Final Result :
This is a pretty strange way to store the notes, however since wappalyzer
shows us that the programming language is node
we are dealing with node deserialization I've solved a similar challenge here :