Tuesday, April 1, 2014

Crackme Bin by Basse write-up

After cracking the Magic Numbers crackme, I've chosen to crack (from the crackmes collection mentioned in Magic Numbers) one more. This time it's crackme "Bin" by Basse.
Goal: Find the correct key.
We have a GetDlgItemInt command call at 0040105E. 
0040105E | E8 31010000    | CALL
This function translates the text of a specified control into an integer value. So the key is integer value. And the key after this function call is stored at EAX.
After calling GetDlgItemInt the offset of ASCII data (located at offset 00403000) is copying to ESI register. 
Then after checks 4 bytes of ESI data for 0 (null terminator - end of data):
00401068 | 833E 00     | CMP DWORD PTR DS:[ESI],0
we're jumping to 00401071 if not end of ASCII data:
0040106B | 75 04       | JNE SHORT Bin.00401071
otherwise we're jumping to 0040107D if the end of ASCII data:
0040106D | EB 0E       | JMP SHORT Bin.0040107D

The important comparison is performed here:
0040107D | 3D BF96287A | CMP EAX,7A2896BF
the result of function is compared to the hex value 0x7A2896BF (2049480383),
and if the result is equal to this value - the "Congratulation, you found the right key" message is shown:
00401084 | 6A 40       | PUSH 40
00401086 | 68 30354000 | PUSH OFFSET Bin.00403530 ; ASCII "In the Bin"
0040108B | 68 3B354000 | PUSH OFFSET Bin.0040353B ; ASCII "Congratulation, you found the right key"
00401090 | FF75 08     | PUSH DWORD PTR SS:[EBP+8]
00401093 | E8 02010000 | CALL

After jumping to 00401071 we moving current 4 bytes of ASCII data to EBX register.
00401071 | 8B1E        | MOV EBX,DWORD PTR DS:[ESI]
Then an important function at 0040110F is called:
00401073 | E8 97000000 | CALL Bin.0040110F
After that the ASCII data pointer at ESI by 4 (dword) increased:
00401078 | 83C6 04     | ADD ESI,4
And we jump back to 00401068:
0040107B | EB EB       | JMP SHORT Bin.00401068

Now lets look into the this important function:
We have 4 bytes of ASCII data at EBX register, and the key value at EAX.
Here is the code of this function with comments.
Address  | Hex dump    | Command     ; Comments
0040110F | 51          | PUSH ECX    ; push ECX onto stack
00401110 | 52          | PUSH EDX    ; push EDX onto stack
00401111 | 8BD3        | MOV EDX,EBX ; copy 4 bytes of data
00401113 | 8BC8        | MOV ECX,EAX ; copy key
00401115 | 40          | INC EAX     ; key = key + 1
00401116 | F7D0        | NOT EAX     ; key = ~(key)
00401118 | 43          | INC EBX     ; data = data + 1
00401119 | F7D3        | NOT EBX     ; data = ~(data)
0040111B | 40          | INC EAX     ; key = key + 1
0040111C | 43          | INC EBX     ; data = data + 1
0040111D | 23C2        | AND EAX,EDX ; key = key & copy of data 
0040111F | 23D9        | AND EBX,ECX ; data = data & copy of key
00401121 | 03C3        | ADD EAX,EBX ; result = key + data
00401123 | 5A          | POP EDX     ; restore EDX
00401124 | 59          | POP ECX     ; restore ECX
00401125 | C3          | RETN        ; return result 
So this function is could be written this way:
result = (value & (~(key + 1) + 1)) + (key & (~(value + 1) + 1))
If simplify this function it will be:
result = key ^ value, — just exclusive or (xor) operation.
so knowing the final result 0x7A2896BF (2049480383) it's easy to find the key.
Here is my python code, to find the key:
import struct

data = 'Oqiqb4EhM/4jISMjlzQf6kpGQwLrG+GEIY4bPc0JL/jWBfNLejmbme3garIrG4ngbXtWQY3Y2VdbvRxleHU9aGxFRLXkh5BDGVbm5gAAhGeBMBl65XKmZ9sbNn4xxi3cbD7M02MpwZ3BpN4lG3xyFPsofbhXbMu8Z/1rlqfdul/KLaGmkllOYRj9Mhnumqw1f464dK948rgz5JxpeSQHN45GlMNjb717x6IeCCMa6gN+YX73M/LrkH1xZEhpjZ4YLugpHGquVl9m5Kq7AvcapkVEUsZt29JWB/dzq//bFG15ykd53wpP/8gddTTwV6i2vmLXLjDrfwO4NCLolYyD78vmdPsZRvlI4B0bslHerN7buJ938iWcaKg6NjrHMfZhO6BrvbLRbhSUQSKfgyXsAhaT/O1p1fM6KoFlWbHri9HfIwKocjXQkUDsT2u7U2+82oYHVvhthhCOlxlQyiUKr11Cj9Pzbqz11sulpr0D0rfChHOO81Ht3ax1ynL/nTQmNWCj4U4C0T9cjmUNU47gdGMEa0+tyv2s75/Xvo+qTrywdVqLDEviE+3Gxy3U+vX5MRrJipxK2OnUu/g/uanoLok7CA4LKQe7+ho6Vrb91/K/scyEdIvUlZ5A3LfP3DRWsE4LbKkYcwUy6ea7aEqdaEqd6ea7cwUybKkYsE4L3DRW3LfPlZ5AdIvUscyE1/K/Vrb9+ho6KQe7CA4LLok7uanou/g/2OnUipxKMRrJ+vX5xy3UE+3GDEvidVqLTrywvo+q75/Xyv2sa0+tdGMEU47gjmUN0T9c4U4CNWCjnTQmynL/3ax181HthHOO0rfCpr0D1sulbqz1j9Pzr11CyiUKlxlQhhCOVvht2oYHU2+8T2u7kUDscjXQIwKoi9HfWbHrKoFl1fM6/O1pAhaTgyXsQSKfbhSUvbLRO6BrMfZhNjrHaKg68iWcuJ93rN7bslHe4B0bRvlIdPsZ78vmlYyDNCLofwO4LjDrvmLXV6i2dTTw/8gd3wpPykd5FG15q//bB/dz29JWUsZtpkVEAvca5Kq7Vl9mHGquLugpjZ4YZEhpkH1xM/LrYX736gN+CCMax6Ieb717lMNjN45GeSQH5Jxp8rgzdK94f464mqw1MhnuYRj9kllOLaGmul/KlqfdZ/1rbMu8fbhXFPsoG3xypN4lwZ3B02MpbD7Mxi3cNn4xZ9sb5XKmMBl6hGeB5gAAGVbmh5BDRLXkaGxFeHU9vRxl2VdbQY3YbXtWG4ngarIrme3gejmbBfNLL/jWPc0JIY4bG+GEQwLr6kpGlzQfISMjM/4jb4EhOqiq'

def invert(x):
 return ~x & 0xffffffff

def decode_func(key, value):
 return (value & (invert(key + 1) + 1)) + (key & (invert(value + 1) + 1))

def checker(key):
 result = key
 for i in xrange(0, len(data), 4):
  value = struct.unpack('I', data[i:i+4])[0]
  result = decode_func(result, value)
 return result

key = checker(0x7a2896bf)
print 'The key is: %s' % key
So the key is: 0x7a2896bf (2049480383). The same as the final result.

Sunday, March 30, 2014

RuCTF Quals 2014 - Stegano 400 writeup

We have an one hour pixel video with 10800 frames (3 frame per second). Each frame contain a 8x8 grid of colored squares.
I didn't solved this task during the game, and today after a huge number of unsuccessful attempts, I finally solved it. No LSB, MSB as I thought.
I've even found that squares with indexes [0,0], [4,0], [0,4] and [4,4] are filled with more solid color, but alas...
The solution of this task is to stare at video and notice that some of the squares with white background sometimes contain some text and images.
So you can see, that the flag is: V1de0_mast3r.
Here is an assembled flag frame:

Saturday, March 22, 2014

Spring has come

Spring has come. It's time to dig out the umbrellas.
Весна пришла - самое время откапывать зонтики

Friday, March 21, 2014

A version of team name

Today I invented a variant of a name for Kazakh CTF team: hackorda (kz: hack horde), ak (kz: ақ) = white, reference to white hats :)
A variant of writing (using the letter қ from Kazakh alphabet).
Logos of the hack0rda team.

Sunday, March 16, 2014

Magic Numbers crackme solution

I've decided to solve some crackme and randomly selected a crackme named magic. I've downloaded this one from a good crackmes collection here. This is my first solution write up for crackme, so don't judge strictly :)
In this crackme needed to find a correct combination of 16 "magic numbers" (serial). So firstly it's needed to understand checking algorithm.
Checking algorithm is the next:
1) The serial must contain all numbers in the range [0..F] and these numbers must be unique.
2) Numbers must satisfy the following conditions:
x1 + x2 + x3 + x4 = x5 + x6 + x7 + x8 = x9 + x10 + x11 + x12 = x13 + x14 + x15 + x16 =
x1 + x5 + x9 + x13 = x2 + x6 + x10 + x14 = x3 + x7 + x11 + x15 = x4 + x8 + x12 + x16 =
x1 + x6 + x11 + x16 =
x4 + x7 + x10 + x13
After understanding the magic numbers checking algorithm, I've coded a program to find some appropriate combinations.
Success!
By the way "About" button doing nothing until you have created a file "Info.txt" with the some about data.
Here is about dialog with my info:
That's all.

Friday, February 28, 2014

The Art of Software Testing

Review: Good classic book about basic principles of software testing. Most of the principles and testing approaches from the book were already known to me. But it's a classic book, so, I'm highly recommend it to the newcomers to software testing.

Sunday, February 16, 2014

Olympic CTF 2014 - Find da key writeup

I didn't solved this task during the competition, and today I've finally solved it. Since I haven't found a write-up for it, I decided to write my own solution.

Freestyle 200 - Find da Key
Author: vos
Task is very unusual: find the key. stego.txt

We have a file with base64 encoded lines. After decoding of all of them we get the text about Steganography from wikipedia.
First encoded line: U3RlZ2Fub2dyYXBoeSBpcyB0aGUgYXJ0IGFuZCBzY2llbmNlIG9m
Decoded text: Steganography is the art and science of
After trying to encode to base64 just decoded lines it's possible to discover that the last bytes are sometimes changing. For example for a line:
IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmV=
Decoded text: " writing hidden messages in such a way that no one"
And again encoded to base64:
IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmU=
The last byte (before pad character "=") changed from V to U. Then to solve this task, we need to know base64 encoding and decoding algorithm. I've used the description from RFC 4648.
So after reading and understanding the algorithm (especially pads adding ), its possible to make an assumption: if one pad (=)  is at the end of encoded data then two bits are available for hiding data, if two pads (==) then four bits are available for hiding, and if no pad then no bits are available.
Here is a solution source code in Python:
def get_base64_diff_value(s1, s2):
 base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
 res = 0
 for i in xrange(len(s1)):
  if s1[i] != s2[i]:
   return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
 return res

def solve_stego():
 with open('stego.txt', 'rb') as f:
  file_lines = f.readlines()

 bin_str = ''
 for line in file_lines:
  steg_line = line.replace('\n', '')
  norm_line = line.replace('\n', '').decode('base64').encode('base64').replace('\n', '')

  diff = get_base64_diff_value(steg_line, norm_line)
  pads_num = steg_line.count('=')
  if diff:
   bin_str += bin(diff)[2:].zfill(pads_num * 2)
  else:
   bin_str += '0' * pads_num * 2

 res_str = ''
 for i in xrange(0, len(bin_str), 8):
  res_str += chr(int(bin_str[i:i+8], 2))
 print res_str

solve_stego()
The flag is: Base_sixty_four_point_five
P.S. The task is truly unusual, and it is the first time I met a method of hiding data in Base64.