01 Feb 2016 @ 7:53 PM 

Yet another x64 ELF, this time also obfuscated.
RE4-obfMoar while loops!

We have option to select one of 3 cells. Then we have to provide paths. Each step is accepted as a character. By following scanf() and jumping though the decompiled code, it was evident that there are 7 possible letters = “asdqwez”. When we provide the path, it is verified by a function(sub_400960()) and decided whether program will continue or not. If the path is accepted, it is fed to MD5. At the final state (‘e’), the hash is calculated and compared to these values “6dff819e14ce1bfc112d1817e69cff1f”, “6a9e23f57e9f5590b0c168a781bf07c7”, “05aeebcadfe7f05a7e778d904d6d297e”. We can guess that each one of the hash is for one of the cell.

Now the check function (sub_400960()) is small and can be decompiled to pretty easily. Rest of the code also can be reconstructed by looking around decompiled code and eliminating loops. The final code should look something like this.

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

int CheckFunc(unsigned int *a1, unsigned int *a2)
{
	if (a1[0] < a1[1])
	{
		if (a2[0] == a2[1])
		{
			a2[(a2[0] - 1) + 2] = a1[a1[0] + 2];
			a1[0] = a1[0] + 1;
			a2[0] = a2[0] - 1;
			return 0;
		}
		else
		{
			if (a1[a1[0] + 2] < a2[a2[0] + 2])
			{
				a2[(a2[0] - 1) + 2] = a1[a1[0] + 2]; 
				a1[0] = a1[0] + 1;
				a2[0] = a2[0] - 1;
				return 0;
			}
			else
			{
				return 1;
			}
		}
	}
	return 1;
}
int main()
{
	unsigned int DF1[14] = { 0 }, DF2[14] = { 0 }, DF3[14] = { 0 };
	int cell, count, ret;
	char c = 0;
	//MD5_CTX ctx;
	printf("Select your cell (1-3): ");
	scanf("%d", &cell);
	switch (cell)
	{
	case 1:
		count = 12;
		break;
	case 2:
		count = 10;
		break;
	case 3:
		count = 11;
		break;
	}
	DF1[0] = count;
	DF1[1] = count;

	DF2[0] = count;
	DF2[1] = count;

	DF3[0] = count;
	DF3[1] = count;

	while (DF3[0])
	{
		DF3[(DF3[0] - 1) + 2] = DF3[0];
		DF3[0] = DF3[0] - 1;
	}
	//MD5_Init(&ctx);
	while (c != 'e')
	{
		printf("Enter your path: ");
		scanf("%c", &c);
		switch (c)
		{
		case 'a':
			ret = CheckFunc(DF3, DF1);			
			break;
		case 's':
			ret = CheckFunc(DF1, DF3);
			break;
		case 'd':
			ret = CheckFunc(DF3, DF2);
			break;
		case 'q':
			ret = CheckFunc(DF2, DF1);
			break;
		case 'w':
			ret = CheckFunc(DF1, DF2);
			break;
		case 'z':
			ret = CheckFunc(DF2, DF3);
			break;
		}
		
		if (ret == 1)
		{
			printf("Bad boy!");
			exit(0);
		}
		//MD5_Update(&ctx, &c, 1);
	}
	if (DF2[0] == 0 && DF1[0] == DF1[1] && DF3[0] == DF3[1])
	{
		//MD5_Final(&ctx);
		//get md5 string

		//6dff819e14ce1bfc112d1817e69cff1f
		//6a9e23f57e9f5590b0c168a781bf07c7
		//05aeebcadfe7f05a7e778d904d6d297e

		//see if string is of any of this
	}
	
	return 0;
}

Now we have 3 arrays and it is doing some operation on that. First thing in mind is the hash cracking – key space is small (asdqwz) and we may get lucky. I ran Hashcat till 16 chars without any luck. Mean while I was trying to figure out what exactly was the operation that is happening here. By the prison and path, it was clear that it is some kind of puzzle, but which puzzle will have 6 types of moves and these weird conditions. It didn’t make any sense. Finally drawn the array in a notebook to figure out if that makes any sense. Suddenly it all became clear – this is Tower of Hanoi!

The cells are number of disks (10, 11, 12 – not in order) and 3 arrays are poles. The CheckFunction makes sure that the move is valid.

Solution for this is to solve Tower of Hanoi and provide the solution in this format (asdqwz). A recursive solver was written and final solution was provided to challenge.

import sys
import subprocess
import time

solution = 'adwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwazqazwszqadwazqazwszwadwszqazwszqadwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwszqazwszqadwazqazwszwadwszqazwszwadwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwazqazwszqadwazqazwszwadwszqazwszqadwazqadwszwadwazqazwszqadwazqazwszwadwszqazwszwadwazqadwszwadwszqazwszqadwazqazwszwadwszqazwszqadwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwazqazwszqadwazqazwszwadwszqazwszqadwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwszqazwszqadwazqazwszwadwszqazwszwadwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwszqazwszqadwazqazwszwadwszqazwszqadwazqadwszwadwazqazwszqadwazqazwszwadwszqazwszwadwazqadwszwadwszqazwszqadwazqazwszwadwszqazwszwadwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwazqazwszqadwazqazwszwadwszqazwszqadwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwszqazwszqadwazqazwszwadwszqazwszwadwazqadwszwadwazqazwszqadwazqadwszwadwszqazwszwadwazqadwszwadwe'


p = subprocess.Popen("./jail_break_bin", stdin=subprocess.PIPE)
p.stdin.write(str(2) + '\n')
p.stdin.write(str(2) + '\n')
for c in solution:
	p.stdin.write(c + '\n')
p.stdin.close()
ret = p.wait()


dan@ubuntu:~/nullc$ python jail.py
Welcome to the Mini-Prison (not secure, but hard to escape)!!
You should select a cell and find a path to escape to the flag.
You will not be disappointed!!
Select your cell (1-3):
Go on enter your path:You Found The Path.
The flag is nullcon{t00_34sy_t0_br34k_th15_pr1510n_by_d0nf05}

Posted By: Dan
Last Edit: 01 Feb 2016 @ 07:57 PM

EmailPermalinkComments (0)
Tags
Categories: CTF, HackIM2016
 01 Feb 2016 @ 7:46 PM 

x64 ELF, probably obfuscated with LLVM Obfuscator. Hexrays will decompile it to a nested while-loop.

RE3-obfI spent sometime understanding how exactly it works. Basic idea about this obfuscation is to transform pieces of code into different loops, set a variable to identify which loop and condition to execute. Even though it looked confusing initially, with a bit of splicing decompiled code, it made better sense.

Essentially code reads 16 numbers, and calls a function (sub_400780())to see if that value is correct or not. If it is correct, the next number is checked. If the numbers are correct, it is used in some operation to finally calculate the flag string.

To solve this I decompiled sub_400780() and bruteforced it. Initially I thought there will be only 1 correct solution and I have figured all the checks, only to see that there are few other checks (like total length should be 26).

unsigned int cpow(int val, int pow)
{
	unsigned int pp = 1;
	while (pow)
	{
		pp *= val;
		pow--;
	}
	return pp;
}

int Brute(unsigned int loc)
{
	unsigned int HCArr[] = { 0xE2246054, 0x1DDB9FAF, 0x0E224604C, 0x1DDB9FA9, 0x0EB48CD5A, 0x0EB48CD66, 0x0EB48CD68, 0x14B732AC, 0x0E9682E7A, 0x0E9682E3A, 0x0E9682E37, 0x1697D1DA, 0x9E32D9, 0x0FF61CD00, 0x0FF61CD1F, 0x9E32FE, 0x3FDD8C9D, 0x0C0227348, 0x0C0227355, 0x3FDD8CAB, 0x108AE52C, 0x0EF751AFB, 0x0EF751AFA, 0x108AE52C, 0x0FED8F192, 0x1270E7E, 0x0FED8F1BE, 0x1270E73, 0x3D51216D, 0x3D51214B, 0x0C2AEDEBA, 0x3D512142, 0x0D63C4BCE, 0x29C3B40C, 0x29C3B42E, 0x29C3B42F, 0x0C93E69E2, 0x0C93E69AD, 0x36C19603, 0x36C19641, 0x1149F143, 0x0EEB60ED5, 0x0EEB60E9E, 0x1149F173, 0x0CB68709A, 0x0CB6870DE, 0x0CB6870B5, 0x34978F66, 0x0C163D0A7, 0x3E9C2F09, 0x3E9C2F02, 0x3E9C2F5F, 0x0D2CB22ED, 0x2D34DD3E, 0x0D2CB22F3, 0x2D34DD1B, 0x0F6BA6729, 0x0F6BA6721, 0x0F6BA6769, 0x94598CD, 0x0D302FAE3, 0x0D302FA82, 0x2CFD057C, 0x2CFD0554 };

	unsigned int val = 0;
	unsigned int res = 0;
	unsigned int eax, edx, ebx, ecx, esi, edi, r8d, r9d, r10d;

	while (val < 0xFFFFFFFF)
	{
		res = cpow(val, 3);
		eax = cpow(val, 2);
		edx = HCArr[loc * 4];
		ecx = HCArr[(loc * 4) + 3];

		esi = (~edx) & 0x6EFBE94D;
		edx = edx & 0x910416B2;
		edi = (~ecx) & 0x6EFBE94D;
		ecx = ecx & 0x910416B2;

		edx = edx | esi;
		ecx = ecx | edi;
		ecx = ecx ^ edx;
		ecx = ecx * eax;
		ecx = -ecx;
		ecx -= res;
		ecx = -ecx;
		res = ecx;

		eax = cpow(val, 2);
		edx = HCArr[(loc * 4) + 1];
		ecx = HCArr[(loc * 4) + 3];
		esi = (~edx) & ecx;
		ecx = (~ecx) & edx;
		ecx |= esi;
		ecx *= eax;
		res += ecx;

		eax = cpow(val, 2);
		edx = HCArr[(loc * 4) + 2];
		ecx = HCArr[(loc * 4) + 3];
		esi = (~edx) & 0x43B37B1;
		edx &= 0x0FBC4C84E;
		edi = (~ecx) & 0x43B37B1;
		ecx &= 0x0FBC4C84E;
		edx |= esi;
		ecx |= edi;
		ecx ^= edx;
		ecx *= eax;
		ecx = -ecx;
		res -= ecx;

		esi = HCArr[(loc * 4)];
		edi = (~esi) & 0x59C0DD4B;
		esi &= 0x0A63F22B4;

		ebx = HCArr[(loc * 4) + 3];
		ecx = (~ebx) & 0x59C0DD4B;
		eax = ebx & 0x0A63F22B4;
		esi |= edi;
		eax |= ecx;
		eax ^= esi;

		ecx = HCArr[(loc * 4) + 1];
		edx = (~ecx) & 0x0BA0892CF;
		ecx &= 0x45F76D30;
		ebx = (~HCArr[(loc * 4) + 3]) & 0x0BA0892CF;
		r8d = HCArr[(loc * 4) + 3] & 0x45F76D30;
		ecx |= edx;
		r8d |= ebx;
		r8d ^= ecx;
		r8d *= eax;
		r8d *= val;
		res += r8d;

		ecx = HCArr[(loc * 4) + 2];
		esi = (~ecx) & 0x0EFD60EC8;
		ecx &= 0x1029F137;
		eax = HCArr[(loc * 4) + 3];
		edi = ~eax;
		ebx = (edi)& 0x0EFD60EC8;
		edx = eax & 0x1029F137;
		ecx |= esi;
		edx |= ebx;
		edx ^= ecx;
		ecx = HCArr[(loc * 4) + 1];
		esi = (~ecx) & 0x6F5BEF81;
		ecx &= 0x90A4107E;
		edi &= 0x6F5BEF81;
		eax &= 0x90A4107E;
		ecx |= esi;
		eax |= edi;
		eax ^= ecx;
		eax *= edx;
		eax *= val;
		res += eax;

		ecx = HCArr[(loc * 4)];
		edx = (~ecx) & 0x50C0D70D;
		ecx &= 0x0AF3F28F2;
		eax = HCArr[(loc * 4) + 3];
		edi = ~eax;
		ebx = edi & 0x50C0D70D;
		esi = eax & 0x0AF3F28F2;
		ecx |= edx;
		esi |= ebx;
		esi ^= ecx;

		ecx = HCArr[(loc * 4) + 2];
		edx = ecx;
		edx = (~edx) & eax;
		edi &= ecx;
		edi |= edx;
		edi *= esi;
		edi *= val;
		res += edi;

		r10d = HCArr[(loc * 4)];
		ecx = ~r10d;
		eax = HCArr[(loc * 4) + 3];
		ecx &= eax;
		esi = ~eax;
		r10d &= esi;
		r10d |= ecx;

		ecx = HCArr[(loc * 4) + 1];
		ebx = (~ecx) & 0x73E6034A;
		ecx &= 0x8C19FCB5;
		edx = esi & 0x73E6034A;
		edi = eax & 0x8C19FCB5;
		ecx |= ebx;
		edi |= edx;
		edi ^= ecx;
		edi *= r10d;

		ecx = HCArr[(loc * 4) + 2];
		edx = (~ecx) & 0x0AC23EFC0;
		ecx &= 0x53DC103F;
		esi &= 0x0AC23EFC0;
		eax &= 0x53DC103F;
		ecx |= edx;
		eax |= esi;
		eax ^= ecx;
		eax *= edi;
		res += eax;

		if (res == 0x0)
		{
			printf("%x-", val);
			//return val;
		}
		val++;
	}
	return 0;
}

int main()
{
	printf("%d\n", Brute(11));
	printf("%d\n", Brute(12));
	printf("%d\n", Brute(6));
	printf("%d\n", Brute(7));

	printf("%d\n", Brute(4));
	printf("%d\n", Brute(0xd));
	printf("%d\n", Brute(5));
	printf("%d\n", Brute(0));

	printf("%d\n", Brute(1));
	printf("%d\n", Brute(0xf));
	printf("%d\n", Brute(8));
	printf("%d\n", Brute(0xe));

	printf("%d\n", Brute(0xa));
	printf("%d\n", Brute(2));
	printf("%d\n", Brute(9));
	printf("%d\n", Brute(3));
	return 0;
}

Now I had a list of solutions for each of 16 numbers, and I needed to make a combination of them and  bruteforce the binary directly. I removed large numbers as it won’t fit the 26 length criteria.
import sys
import subprocess
import itertools

a = [[4, 45, 72], [8], [31, 51], [8], [2, 29], [10, 24], [0, 41, 42], [3, 27], [10, 53, 60], [42, 73], [31], [20, 28, 92], [19, 90], [19, 32, 96], [20, 93], [2, 31]]

vals = list(itertools.product(*a))
count = 0;
while count < len(vals):
	p = subprocess.Popen("./donfos_reversing", stdin=subprocess.PIPE)
	p.stdin.write(str(vals[count][0]) + '\n')
	p.stdin.write(str(vals[count][1]) + '\n')
	p.stdin.write(str(vals[count][2]) + '\n')
	p.stdin.write(str(vals[count][3]) + '\n')
	p.stdin.write(str(vals[count][4]) + '\n')
	p.stdin.write(str(vals[count][5]) + '\n')
	p.stdin.write(str(vals[count][6]) + '\n')
	p.stdin.write(str(vals[count][7]) + '\n')
	p.stdin.write(str(vals[count][8]) + '\n')
	p.stdin.write(str(vals[count][9]) + '\n')
	p.stdin.write(str(vals[count][10]) + '\n')
	p.stdin.write(str(vals[count][11]) + '\n')
	p.stdin.write(str(vals[count][12]) + '\n')
	p.stdin.write(str(vals[count][13]) + '\n')	
	p.stdin.write(str(vals[count][14]) + '\n')
	p.stdin.write(str(vals[count][15]) + '\n')
	p.stdin.close()
	ret = p.wait()
	count = count+1

Runnin it for sometime gave possible flags:

Good Job!!
flag=nullcon{d0n_f05ijg[65\5rt_t0_n8?qo1}
Good Job!!
flag=nullcon{d0n_f05ing_15_4rt_t0_l34rn}
Good Job!!
flag=nullcon{d0h_f0=kna]22Z6uw^u3Vd:?tn02}
Good Job!!
flag=nullcon{g:e]o:6hje^74[1rv\v1_m;?{o31}
Good Job!!
flag=nullcon{g:e]o:6hja^33[2sv\v1_m94pl2}

nullcon{d0n_f05ing_15_4rt_t0_l34rn} it is!

Posted By: Dan
Last Edit: 01 Feb 2016 @ 07:46 PM

EmailPermalinkComments (0)
Tags
Categories: CTF, HackIM2016
 01 Feb 2016 @ 7:37 PM 

Again x64 ELF. This one was the last RE challenge I solved in HackIM, because I didn’t see the srand in .ctor 🙁 initially.
The code is pretty clear, there were few obfuscation though (v18 = v19 + v18 – 409176519 + 409176519;)

decSeed is fixed, which will produce consistent random numbers.
There are 3 interesting functions in the code, two of them generates a number as output and the other one is a check. Once the check is successful, the user entered number is MD5ed and compared to a hardcoded hash value “15b74b4db57d0afdfe98eb5dbc3b542b”

Again we are back to bruteforcing. (Actually we don’t need to bruteforce, the Gen1()/Func() will spit out the correct code)

int Func(int a)
{
	int temp = 1;
	int result = 0;
	while (temp)
	{
		if (a & (~temp ^ a))
		{
			result = ~(~temp | ~a);
		}
		temp *= 2;
		if (temp > a)
			break;
	}
	return result;
}

int Func2(int a)
{
	int result = 0;
	while (a)
	{
		a = ~(~(a - 1) | ~a);
		result++;
	}
	return result;
}
int Func3(int a1, int a2)
{
	if (a1&&a2)
	{
		int v4 = a1 & (Func(a1) ^ a1);
		int v5 = Func(a1);
		int v8 = (2 * v5 ^ v4 | 2 * v5 & v4) == a2 + a1;
		return v8;
	}
	return 0;
}
int Brute()
{
	int rnum;
	int inp, size, temp, count;
	char str[128] = { 0 };
	MD5 md;
	rnum = 0x327B23C6;
	int end = 0x0;
	count = 0;
	temp = Func(rnum);
	size = (1 << Func2(rnum)) - 1;
	md.Init();

	inp = 1;
	while (inp < 0x7fffffff && count != rnum)
	{
		if (Func3(size, inp))		
		{
			sprintf(str, "%d", inp);
			printf("%s\n", str);
			//printf("==>%d\n", Func(size) == inp);
			size += inp;
			md.Update((unsigned char*)str, strlen(str));
			while (~(~temp | ~size))
			{
				count = temp ^ count | temp & count;
				size &= temp ^ size;
				temp = Func(rnum & (count ^ rnum));
			}
			inp = 0;
		}
		inp++;
	}
	md.Final();
	if (strcmp(md.digestChars, "15b74b4db57d0afdfe98eb5dbc3b542b") == 0)
	{
		printf("\nSuccess: %d\n\n", rnum);
	}

	return 0;
}

Code will spit up valid inputs, which will give us the flag. Input is too long to type into console, so wrote a bit of python to automate. You should have also seen that there are two sleep() calls which we need to patch/LD_PRELOAD. I patched out those sleeps.
import sys
import subprocess

arr = [32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 64, 128, 256, 512, 1024, 2048, 4096, 32, 64, 128, 256, 16, 32, 64, 128, 8, 16, 32, 64, 4, 8, 16, 32, 2, 1]


p = subprocess.Popen("./patched", stdin=subprocess.PIPE)
for i in arr:
	p.stdin.write(str(i) + '\n')
p.stdin.close()
ret = p.wait()


dan@ubuntu:~/nullc$ python ./pssolve.py
I will generate some random numbers.
If you can give me those numbers, you will be $$rewarded$$
hmm..thinking...OK. I am Ready. Enter Numbers.
Good Job!!
Wait till I fetch your reward...OK. Here it is
The flag is:nullcon{50_5tup1d_ch4113ng3_f0r_e1i73er_71k3-y0u}

Posted By: Dan
Last Edit: 01 Feb 2016 @ 07:37 PM

EmailPermalinkComments (0)
Tags
Categories: CTF, HackIM2016
 01 Feb 2016 @ 7:29 PM 

Given file is x64 ELF binary. Opened it up in IDA and code looks pretty straight forward.
If you have HexRays 64, things are pretty easy.
decompiledCode accepts couple of numbers as input, XORs them together, initiates srand() with the final value and creates 30 rand() values. Rand values are converted into strings and calculates MD5 of them and compares with a hardcoded hash value “5eba99aff105c9ff6a1a913e343fec67”.

Now this is a pretty straight forward bruteforce.

#include <openssl/md5.h>
#include <stdio.h>

int main()
{
	MD5_CTX ctx;
	unsigned char out[MD5_DIGEST_LENGTH];
	int n=0;
	char hash[128] = {0};
	int i = 1;
	int sum = 0;
	int temp;
	int seed;
	int count;
	int rnd;
	char ssra[128] = {0};
	while (1)
	{		
		if (i > 0xffff)
			break;
		i++;
		temp = i;
		sum = 0;
		while (temp)
		{
			sum++;
			temp &= (temp - 1);
		}

		if (sum == 10)
		{
			seed = i;
			srand(seed);
			MD5_Init(&ctx);
			for(count=0;count<30;count++)
			{
				rnd = rand() % 1000;
				sprintf(ssra, "%d", (unsigned int)rnd);
				rnd = strlen(ssra);
				MD5_Update(&ctx, ssra, rnd);
			}

			MD5_Final(out, &ctx);
			for(n=0; n<MD5_DIGEST_LENGTH; n++)
			{
				sprintf(&(hash[2*n]), "%02x", out[n]);
			}
			if ( strcmp(hash, "5eba99aff105c9ff6a1a913e343fec67") == 0 )
			{
				printf("Got: %d\n", i);
			}
		}
	}
	
	return 0;
}


dan@ubuntu:~/nullc$ ./zorro_bin
Welcome to Pub Zorro!!
Straight to the point. How many drinks you want?1
OK. I need details of all the drinks. Give me 1 drink ids:59306

You choose right mix and here is your reward: The flag is nullcon{nu11c0n_s4yz_x0r1n6_1s_4m4z1ng}

Posted By: Dan
Last Edit: 01 Feb 2016 @ 07:29 PM

EmailPermalinkComments (0)
Tags
Categories: CTF, HackIM2016

 Last 50 Posts
Change Theme...
  • Users » 1
  • Posts/Pages » 19
  • Comments » 41
Change Theme...
  • VoidVoid « Default
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LightLight

About



    No Child Pages.