Oct 21, 2017 - BSidesPDX CTF : MakeIcon

Author: dade

Publish Date: 2017-10-21

Category: Web

Points: 300

Description:

It's free, as in baby.

Host: ab743120bb6ae11e7ac800aee00def00-1664391948.eu-central-1.elb.amazonaws.com

Note

The BSidesPDX organizers have made the source code for all of their challenges freely available so that you can run them at home and follow along. You can find more information here.

Investigation

Upon loading the screen, we are presented with a file upload and a button to make a jpeg icon. We also note that the version string indicates it was made in 2016, with a version of Version 2016.3717. After playing around with it for a little while, I thought about how there was that ImageMagick bug last year that let you execute code remotely. I wasn’t sure it would work, but it was worth a shot.

As I hunted down the ImageMagick bug, it became painfully apparent that the Version string provided to us was also the CVE number associated with the ImageTragick bug.

From the ImageTragick site, I decided to take the read_file.mvg file and tweak it to meet my needs.

push graphic-context
viewbox 0 0 64 48
image over 0,0 0,0 'label:@/flag'
pop graphic-context

I suspected that the flag would be in /flag since we had solved other challenges where the flag was in /flag. Luckily I was right, and upon upload I was presented with the first few characters of the flag. Unfortunately I didn’t realize there was a hidden field being sent to determine the output size of the icon, so I wasted a lot of time coming up with this solution.

Solution

I uploaded the read_file.mvg file a total of 5 times, modifying the image over line each time in order to shift what I was able to view and move along the string. In order to do this, I had to set the first value (immediately after ‘over’) to -64, -128, -192, -256, and -320. This allowed me to read each section of the flag inside the tiny 64x48 viewport, instead of just modifying the hidden field to produce a bigger image.

Flag

BSidesPDX{alw4ys_ch3ck_f0r_1day_b4_y0u_l00k_f0r_0day}

Oct 21, 2017 - BSidesPDX CTF : SeaQuell

Author: dade

Publish Date: 2017-10-21

Category: Web

Points: 200

Description:

Our competitors at SeaQuell have uploaded their latest proprietary data to their employee area. We have already compromised their web developer and obtained the source code to their site, here: seaquell.py

Host: a32fcd6eab2d811e784db0a6f99bb55a-829124630.eu-central-1.elb.amazonaws.com

Port: 1589

Seaquell.py

Note

The BSidesPDX organizers have made the source code for all of their challenges freely available so that you can run them at home and follow along. You can find more information here.

Investigation

At the beginning of the challenge you are given the source for the website, and you know ou have to attempt to login to the employees-only area. Since we’ve got the source, we can see how the SQL queries are created for the login and craft an attack against that query.

seaquell.py:31: cur.execute('SELECT password FROM employees WHERE username == "'+user+'"')

By injecting " or 1=1 -- into the username field and supplying a random password, we got a result in one of the HTTP headers that gave us a descriptive error. Invalid user: "" or 1=1 --" (got [(u'pirat3',), (u'drillBabyDrill',)])

Now we’ve got passwords, since the SQL query was selecting passwords where a username matched and we inserted a 1=1 which always evaluates true. Next we need to get the usernames associated with these passwords. Nothing a little union select can’t handle. User " union select username from employees-- with a random password returns us a list of passwords in the same HTTP header error message. Invalid user: "" union select username from employees--" (got [(u'sparrowj',), (u'tillersonr',)])

Once we’ve got the username password pairs, we login and there’s a link to the flag. Yes! We’ve got it!

<h1>403</h1>Not Authorized

I guess not. Let’s take another look at the source and see what’s causing this.

        if ('..' in self.path or 
           not (self.path.endswith('.html') or
                self.path.endswith('/') or
                self.path.endswith('.jpg'))):
           self.send_response(403)
           self.end_headers()
           self.wfile.write('<h1>403</h1>Not Authorized')

So it looks like if we try to do any directory traversals we’ll get a 403, and if we don’t end with .html, /, or .jpg we’ll also get a 403. Luckily this is not how you properly evaluate the extension of a file in a URL, so we can abuse it to get the flag.

Solution

Send your get request but append ?.html to the end of the flag url so that it looks like /employees-only/flag?.html. Now you’ll receive the flag because self.path.endswith('.html') evaluates to True

Flag

BSidesPDX{7h3_se4w33d_i5_alw4s_gr33n3r_wh3n_y0u_hav3_cr3ds}

Oct 21, 2017 - BSidesPDX CTF : DoNotTrek

Author: dade

Publish Date: 2017-10-21

Category: Web

Points: 100

Description:

To boldly go where trackers may or may not track you. Also have you seen my pet snake?

host: a9a4a876db2d711e7887102abc71843c-387472393.eu-central-1.elb.amazonaws.com

Note

The BSidesPDX organizers have made the source code for all of their challenges freely available so that you can run them at home and follow along. You can find more information here.

Investigation

Upon loading the host, we see a flying spaceship Enterprise, with some marqueeing text that says “Do not track is 0!” Since Do Not Track is a common HTTP header you can send websites to ask not to be tracked, we know the web app must be reflecting our value back to us in some regard. The first step I took was to see if I could evaluate math in the DNT header. I fired up burp and set it to intercept requests, then reloaded the page.

When the intercept came up, I changed DNT: 0 to DNT: 1+1. Lo and behold, the page reflected Do not track is 2! Next I tried to inject some other stuff and see what else was allowed. By modifying the DNT header to read DNT: globals() I was able to confirm that python was getting evaluated in the header.

From here I decided to have a look at the filesystem so I intercepted another request and set it to DNT: __builtins__.__import__('subprocess').check_output(["ls", "-la"]) which yielded the contents of the current directory into the page. From here I could see that there was a file named flag.

Solution

Create or intercept an http request to the challenge host and set the DNT flag to: DNT: __builtins__.__import__('subprocess').check_output(["cat", "flag"])

Flag

BSidesPDX{d0_tr4ckers_3ven_EVAL_th1s_he4d3r}