CTF competitions

CTF competitions are fun activities to test your self. However sometimes due to nature of CTF or the vague answers this leads to complete chaos. Yesterday I tried to have some fun with some reversing tasks in https://www.dkhoctf.com I firstly tried first mobile question. I use iOS but binary was in android. My only chance was emulators and static analysis and found out that program gets user input reverse the text and use this text as a key and to decrypt “encrypted” file in raw folder. Upon decryption if the file is correctly decrypted, image is shown. CTF picture was showing a scene from a movie name G.O.R.A When you check that scene you will see that name of the ship “KA-FA 1500”. However, we need to enter it backwards for program to accept. I you enter 0051 AF-AK, program accepts the input and shows us a picture.

decrypted

It was clearly saying Flag{Uf0_GOr3n_M4sum_K0ylu}. Yay we did it. Did we?

I entered all text, with the flag without the flag, with or without l33t text I even tried name of the actor, the name that appears on that scene, KA-FA 1500 and 0051 AF-AK. Nope it doesn’t accept. There is only one password to unlock the picture program accepts it, gives me the flag. But web site doesn’t accept it. I don’t know I guess there are still some questions to answer but couldn’t find. I thought maybe there is extra stuff hidden in the file and I wrote a decryptor to check the file.

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.spec.AlgorithmParameterSpec;
import java.security.MessageDigest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

class Decryptor {
	public static byte[] reverse(byte[] bArr, byte[] bArr2, byte[] bArr3) {
		try {
			AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(bArr);
			Key secretKeySpec = new SecretKeySpec(bArr2, "AES");
			Cipher instance = Cipher.getInstance("AES/CBC/PKCS5Padding");
			instance.init(2, secretKeySpec, ivParameterSpec);
			return instance.doFinal(bArr3);
		}
		catch (Exception e){
			System.out.println(e);
		}
		return null;
	}

	public static byte[] getBytesFromFile(File file)  {
		FileInputStream fileInputStream = null;
		byte[] bFile = new byte[(int) file.length()];
		try {
			fileInputStream = new FileInputStream(file);
			fileInputStream.read(bFile);
			fileInputStream.close();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		return bFile;
	}

	public static void main(String[] args) {
		String str = "KA-FA 1500";
		File file = new File("encrypted");
		byte[] sourceImg = getBytesFromFile(file);
		byte[] iv = new byte[]{(byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0};
		try {
			byte[] result = reverse(iv,MessageDigest.getInstance("MD5").digest(str.getBytes()),sourceImg);
			File outputFile = new File("decrypted.bmp");
			FileOutputStream outputStream = new FileOutputStream(outputFile);
			outputStream.write(result);
		}  catch (Exception e) {
			e.printStackTrace();
		}
	}
}

It is a basic bitmap file and there was not much inside. No matter what I did, web site didn’t accept the flag. I lost. Strike 1

OK. I thought maybe I was not good enough to solve this one. Next reversing task is #17 Roots. File is packed. No problem unpack and decompile with ILSpy. Here is the important parts of code

public static byte[] StringToByteArray(string hex) {
return (from x in Enumerable.Range(0, hex.Length) where x % 2 == 0 select Convert.ToByte(hex.Substring(x, 2), 16)).ToArray < byte > ();
}

private static bool run1(byte input) {
return Convert.ToBoolean((int)(input * input) - 374 * (int) input + 34969);
}

public static bool run(byte[] input) {
bool flag = Form1.run1(input[0]);
bool flag2 = Form1.run2(input[1]);
bool flag3 = Form1.run3(input[2]);
bool flag4 = Form1.run4(input[3]);
bool flag5 = Form1.run5(input[4]);
bool flag6 = Form1.run6(input[5]);
bool flag7 = Form1.run7(input[6]);
bool flag8 = Form1.run8(input[7]);
bool flag9 = Form1.run9(input[8]);
bool flag10 = Form1.run10(input[9]);
bool flag11 = Form1.run11(input[10]);
bool flag12 = Form1.run12(input[11]);
bool flag13 = Form1.run13(input[12]);
bool flag14 = Form1.run14(input[13]);
bool flag15 = Form1.run15(input[14]);
bool flag16 = Form1.run16(input[15]);
return !flag && !flag2 && !flag3 && !flag4 && !flag5 && !flag6 && !flag7 && !flag8 && !flag9 && !flag10 && !flag11 && !flag12 && !flag13 && !flag14 && !flag15 && !flag16;
}

private static bool run4(byte input) {
return Convert.ToBoolean((int)(input * input - 242 * input) + 14641);
}

private static bool run2(byte input) {
return Convert.ToBoolean((int)(input * input - 56 * input) + 784);
}

private static bool run3(byte input) {
return Convert.ToBoolean((int)(input * input) - 358 * (int) input + 32041);
}

private static bool run5(byte input) {
return Convert.ToBoolean((int)(input * input - 172 * input) + 7396);
}

private static bool run6(byte input) {
return Convert.ToBoolean((int)(input * input) - 312 * (int) input + 24336);
}

private static bool run7(byte input) {
return Convert.ToBoolean((int)(input * input - 228 * input) + 12996);
}

private static bool run8(byte input) {
return Convert.ToBoolean((int)(input * input) - 324 * (int) input + 26244);
}

private static bool run9(byte input) {
return Convert.ToBoolean((int)(input * input) - 470 * (int) input + 55225);
}

private static bool run10(byte input) {
return Convert.ToBoolean((int)(input * input - 156 * input) + 6084);
}

private static bool run11(byte input) {
return Convert.ToBoolean((int)(input * input - 202 * input) + 10201);
}

private static bool run12(byte input) {
return Convert.ToBoolean((int)(input * input) - 368 * (int) input + 33856);
}

private static bool run13(byte input) {
return Convert.ToBoolean((int)(input * input) - 434 * (int) input + 47089);
}

private static bool run14(byte input) {
return Convert.ToBoolean((int)(input * input) - 418 * (int) input + 43681);
}

private static bool run15(byte input) {
return Convert.ToBoolean((int)(input * input) - 500 * (int) input + 62500);
}

private static bool run16(byte input) {
return Convert.ToBoolean((int)(input * input - 174 * input) + 7569);
}
private void button1_Click(object sender, EventArgs e) {
string text = this.textBox1.Text;
if (text.Length != 32 || text.Length % 2 != 0) {
Environment.Exit(0);
}
byte[] input = Form1.StringToByteArray(text);
if (Form1.run(input)) {
this.textBox1.Text = "Tebrikler";
}
}

User input is checked for 32 chars and then it is converted to hex which makes 16 byes. Each byte is run against a function and result is returned. Result of each function must be false so that their combined result makes it true. When you check functions you will realize that it is basic (x-y)^2 = 0 when you solve those functions and combine you will get BB1CB379569C72A2EB4E65B8D9D1FA57. I entered this text to program. It accepted it. I put this answer to CTF web site. Nope it doesn’t accept. Maybe lower case? Nope it doesn’t accept. I really don’t understand why someone checks the length for 32 chars and then checks whether length is divisible by 2. Isn’t 32 divisible by 2? I don’t know maybe it is part of the question. I failed again. Strike 2

I realized that maybe I am not good enough and tried to test something that lots of people solved. It is #11 which was basic barcode. I decoded the barcode got 8690624303612 as number. I searched with google. Result was Çerezza Tv Süt Mısiri Aroma Çeşnili Mısır Çerezi 65 gr. I tried different combinations with small caps just brand, brand with name, with or without Turkish letters. Nope I couldn’t make it. I was just tired of solving stupid google captchas. Strike 3. I am out.

I lost three times and realized that I am not good enough to solve any question in this CTF. Anyway, it was a good lesson for me that I should never waste my time in CTFs which doesn’t have clear answers.

EDIT:
Finally I was able solve them Here are the mistakes
1. In the image it was showing as Flag{Uf0_GOr3n_M4sum_K0ylu}
it was not Flag but flag. Why? No idea
2.Even though picture clearly shows O letter in GOr3en it should be number 0. Why? No freaking idea again.

After I correctly put the answers, I decided to go for another spin and tried to solve couple of RCE stuff. I half solved couple of them missed Base32 decoding one lol. Anyway, I liked solving WhatsApp encrypted chat and,iOS RCE. However my favorite was iOS. Since I am quite familiar with iOS, when I read the question it made sense to me. We know that audit is made before the login of actual user. So by checking what is recorded for previous user, we can find the algorithm and extract the information. When you download the zip file, you have following files.

keychaindump.txt
Dump from iOS keychain. Nothing much inside but we find following information

Generic Password
—————-
Service: com.ohkd.ftc
Account: keychainValue
Entitlement Group: 5A564.com.ohkd.ftc
Label: (null)
Generic Field: (null)
Keychain Data: g4r4v3lust4

/Documents/com.ohkd.ftc.plist
LJ/T+9cC6sJjKD5KMXB94+Yy02QxXaDomZwiv4rxAU9eK8cpYNw/hFSsbUy0b3StoIPNaqGHnzxvHU8uuwWVFw==
Hex: 2C9FD3FBD702EAC263283E4A31707DE3E632D364315DA0E8999C22BF8AF1014F5E2BC72960DC3F8454AC6D4CB46F74ADA083CD6AA1879F3C6F1D4F2EBB059517

/Library/
introspy-com.ohkd.ftc.db SQLite Database for pentest result

CC_SHA256

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>arguments</key>
	<dict>
		<key>data</key>
		<data>
		azBtdXQ0bmwwZzRy
		</data>
		<key>md</key>
		<data>
		YmE0NGE0ZTBjYzIzNjFlNjE5Y2QwMTNmZDRiMzk0M2QyM2E5ZTRiNGU4OGQwMDgxMTkxMjU2ZTJkYTRhMWI4Nw==
		</data>
	</dict>
	<key>returnValue</key>
	<integer>71104280</integer>
</dict>
</plist>

Base64Decode(azBtdXQ0bmwwZzRy) = k0mut4nl0g4r
Base64Decode(YmE0NGE0ZTBjYzIzNjFlNjE5Y2QwMTNmZDRiMzk0M2QyM2E5ZTRiNGU4OGQwMDgxMTkxMjU2ZTJkYTRhMWI4Nw==) = ba44a4e0cc2361e619cd013fd4b3943d23a9e4b4e88d0081191256e2da4a1b87 = sha-256(k0mut4nl0g4r)

This log shows that SHA256 of key is taken

CCCrypt

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>arguments</key>
	<dict>
		<key>alg</key>
		<integer>0</integer>
		<key>dataIn</key>
		<data>
		ZfQ8h4alDhIdBii3WYZnVVmlf3LzOSOZsmQGx4AhDcs=
		</data>
		<key>dataOut</key>
		<data>
		QXJpZkNla3UyMDA0
		</data>
		<key>iv</key>
		<data>
		AAAAAAAAAAAAAAAAAAAAAA==
		</data>
		<key>key</key>
		<data>
		YmE0NGE0ZTBjYzIzNjFlNg==
		</data>
		<key>op</key>
		<integer>1</integer>
		<key>options</key>
		<integer>1</integer>
	</dict>
	<key>returnValue</key>
	<integer>0</integer>
</dict>
</plist>

dataIn: Encrypted blob
Base64Decode(dataOut): ArifCeku2004
Base64Decode(key) : ba44a4e0cc2361e6
Base64Decode(iv) : Hex(000000000000000)

As you can see it clearly, SHA-256 hash of key is used for the key. Since CCCrypt is a wrapper function for many cryptography functions, we need to find the algorithm, and other options used inside.

If you check CCCrypt function signature you will find below header

CCCryptorStatus CCCrypt(
    CCOperation op,         /* kCCEncrypt, etc. */
    CCAlgorithm alg,        /* kCCAlgorithmAES128, etc. */
    CCOptions options,      /* kCCOptionPKCS7Padding, etc. */
    const void *key,
    size_t keyLength,
    const void *iv,         /* optional initialization vector */
    const void *dataIn,     /* optional per op and alg */
    size_t dataInLength,
    void *dataOut,          /* data RETURNED here */
    size_t dataOutAvailable,
    size_t *dataOutMoved)
    __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0);
 

alg 0 –> kCCAlgorithmAES
op 1 –> kCCDecrypt
options 1 –> kCCOptionPKCS7Padding (CBC Mode)

Let’s prepare our data for this function.

SHA-256(g4r4v3lust4) = 844ea03c23622f5bd6be95a369b336781f9f322aa7e33afa8ef1485f712d89b8 so;
key: 844ea03c23622f5b
iv: 00000000000000000000000000000000
dataIn:2C9FD3FBD702EAC263283E4A31707DE3E632D364315DA0E8999C22BF8AF1014F5E2BC72960DC3F8454AC6D4CB46F74ADA083CD6AA1879F3C6F1D4F2EBB059517

According to this information, data is decrypted. If you don’t have any tools to test, you may test this code via following web site

http://aes.online-domain-tools.com/

Input Text: 2C9FD3FBD702EAC263283E4A31707DE3E632D364315DA0E8999C22BF8AF1014F5E2BC72960DC3F8454AC6D4CB46F74ADA083CD6AA1879F3C6F1D4F2EBB059517
Tick Hex
Function: AES
Mode: CBC
Key: 844ea03c23622f5b
Tick Plain
IV: 00000000000000000000000000000000

Hit Decrypt button
You will get RmxhZ3twZmYuLiAzdjNuIEZCSSBjNG4gZjFuZCB0aDFzfQ== when you Base64 decode it finally we get the flag
Flag{pff.. 3v3n FBI c4n f1nd th1s}

Since I failed in the first challenge all went down the hill because I really didn’t know what was wrong.I wish I could spend much time on challenges instead of wasting my time on single one. Is it too much to ask to check your questions before you post? Smh.

2 thoughts on “CTF competitions

  1. looks like you need to answer the questions with “flag{xx}”, where xx is the answer. I have done one and got my points. Found it on twitter and not on the site of the CTF. A bit bad of the not explaining the way they want to have the answers

    • Problem was in picture. It clearly shows as O instead of 0(zero). After I contacted them they said change O letter to 0 number and add flag then it worked. However it could be all prevented a) if they said add flag{} instead of Flag{} as it appears on image b) spelling the zero correctly. Once I failed I wasted my time to find another solutions.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s