ZeroNights 2015 HackQuest write-up

Hint: flag is not a frag: once you've got it, you can get one more...

Here goes a small write-up on 2 challenges from ZeroNights hackquest (november 2015).

Task #1 ("Chocolate Factory", Web)


Site with file upload functionality.
At first it was easily solved by uploading JSP-shell in XML format, bypassing white-list. After that all participants were given the source code.
Task again could solved in a "cheating" way, by reading the source code, but I solved it in an intended way.


Open the classes in JD-GUI: screenshot.

We can see the source code of JSP checker, which parses page imports. There're a lot of ways to bypass this silly checker, but we'll try to get flag without reading the file system. Initially the flag was in SecretGrandParentForBigBossesNeeds.class:
public class SecretGrandParentForBigBossesNeeds
  private String TrueSecretChocolateKey()
    return "ZNV:3X@mPl3_k3y_a0a81ab87f74d307b8e51fd85048e714";
On the screenshot on the left you can see a long chain of inherited classes, this clearly tells us, that we should somehow use reflection. If we try to import SecretGrandParentForBigBossesNeeds, we fail, let's try to import Secret.
<%@ page import="java.lang.reflect.*,ZN_Chocolate.CRYPTO.Secret" %>
Secret s = new Secret();
Hm, error 500... In the stack trace we can read, that "method TrueSecretChocolateKey of class SadBigBoss is not visible".
Aha! They changed name of the class after fixing the source code. But anyway, method is not visible, it's private. Let's use reflection to make it accessible:
<%@ page import="java.lang.reflect.*,ZN_Chocolate.CRYPTO.Secret" %>
SadBigBoss s = new SadBigBoss();
Method method = s.getClass().getDeclaredMethod("TrueSecretChocolateKey");
That's it, flag is on the page =)



Site ( with OAuth ( functionality.
During recon one can find and ( subdomains.


There were a lot of unintended bugs, including XSS, SQL injection, RCE, etc... Some of them are described here.

1. Authentication bypass (unintended)
Log in under your vk account through Burp Suite, take a link with auth token (?code=...) and navigate to it in the private tab. You're now logged in as a privileged user, which can upload files.

2. Authentication bypass
Login under your vk account through Burp Suite, take a link with auth token (?code=...), now make a page on your website, which loads 2 images (<img src=...): the first triggers logout CSRF (like /logout), the second is you auth token link. Now send this link to the privileged user, he (the bot) will navigate it, and his account will be connected to your vk profile. Now you can login as a privileged user.

3. Race condition (unintended)
Privileged user can upload avatar. "*.php" is disallowed, but ".jpg.php" is ok =) Where's the shell? Hm, avatars are uploaded to, but they are converted into $hash.jpg. Let's suppose file is first uploaded in the same dir and converted afterwards.
Take BurpSuite, launch 100 threads (GET /avatars/beched.jpg.php, Host: and upload beched.jpg.php. Wow, 200! Shit, plain-text... They disabled PHP execution in this dir, but anyway, this is dangerous bug.

4. SQL injection (unintended)
There was SQL injection in private messaging interface, you could exploit it using multi-INSERT and guessing fields. There was no file_priv and no flag, but there was a link to PoC auth bypass exploit by the author of task. I found a working copy of the task on that server =)

5. Code execution (unintended)
So, we've got author's testing server. Let's log in and check SQL injection there. Wow, there's file_priv=Y! Read the source code, read configs, no flag =(
But there's something else in ZIP upload functionality:
PHP код:
$avatar 'avatars/net-avatara.jpg';
$filename $_FILES['fupload']['name'];
$source $_FILES['fupload']['tmp_name'];    
$target $path_to_90_directory $filename;
move_uploaded_file($source$target);//загрузка оригинала в папку $path_to_90_directory
$command 'python /var/www/ /var/www/'.$filename;
$temp exec($command$output);

So, we can execute code in the filename. But no flag on this test server %)

6. Code execution
Now let's do what they want. Let's upload shell into the docroot of We'll do it with
Create a ZIP archive with path traversal, it we'll be extracted to any directory you want (if it's writable). Now we've got PHP-shell on

7. open_basedir bypass (unintended)
Command execution functions are disabled, but we can browse any directory with DirectoryIterator:
BTW, putenv() and mail() are not disabled, but somehow command execution via library preload and triggering sendmail doesn't work %)

8. Flag
Remember Let's try it from the web-shell: