31 Dec 2014 @ 12:17 AM 

OTP (one time password) challenge gave us a website with username/password/otp as login scheme. A sample login of admin was provided. Since OTP is OTP :P, it won’t work for the second time. We need to understand how exactly OTPs are generated.

Once we create a login in the website, we are provided with an option to download and use OTP generator. Each user gets an option to create a config (token) file, which should be used to feed the OTP generator binary. OTP values contain counters, which will make sure that different OTP gets generated every time.

Reversing OTP binary

Provided binary is ELF x64 C++ binary. Useful symbols were there to help reverse engineer the binary. The config/token files should look like this.

tokenFirst 8 bytes is key-id/random number, second 8 bytes is counter and rest is username. After spending some time with IDA and debugging, we figured the token generating algorithm. It more or less looked like this
1. Username + 7 bytes of key-id is hashed(SHA2) and XORed byte by byte – First 8 bytes of OTP
2. Counter – Next 8 bytes of OTP
3. Counter + 8 bytes of key-id is hashed(SHA2) – last 16 bytes of OTP

Now we know the algorithm, Admin’s OTP and to create the next OTP, we need to know his key-id/token file (8bytes).

Recovering OTP key-id

To attack this scheme, we have to figure out a way to predict the 7 bytes from first part of OTP. An all out brute-force may take ages to complete (even if we precompute values). At this point I consulted dcoder, who pointed me to do meet-in-the-middle.

We are attacking a 7 byte combination. So the idea is to precompute hashes of 3 byte combination, and try to find a match when creating 4 byte hashes. Code should look like this:

uint64 MakeBaseSum()
{
	uint64 base = 0; 
	uint8 data[] ="\x61\x64\x6d\x69\x6e\x00";		//admin\0

	base = SingleHash(0, 0);
	for(int i=0;i<6;i++)
	{
		base ^= SingleHash(data[i], i);
	} 
	return base;
}
void MiTM()
{
	uint64 basesum;
	uint8 target_a[] = "\x9a\xe6\x84\xca\x58\x32\x14\xd3";	//hash
	uint64 p0sum[256];
	uint64 p1sum[256];
	uint64 p2sum[256];
	uint64 p3sum[256];
	uint64 p4sum[256];
	uint64 p5sum[256];
	uint64 p6sum[256];
	uint64 target; 
	memcpy(&target, target_a, sizeof target);

	basesum = MakeBaseSum();
	size_t userLen = 6;		//with '\0'
	for(int i=0;i<256;i++)
	{
		p0sum[i] = SingleHash(i, userLen + 0);
		p1sum[i] = SingleHash(i, userLen + 1);
		p2sum[i] = SingleHash(i, userLen + 2);
		p3sum[i] = SingleHash(i, userLen + 3);
		p4sum[i] = SingleHash(i, userLen + 4);
		p5sum[i] = SingleHash(i, userLen + 5);
		p6sum[i] = SingleHash(i, userLen + 6);
	}
	printf("Tables created.\n");
	unordered_map<uint64, uint32> map;
	map.reserve(1<<24);
	//all 3 byte combination
	for(uint32 i=0; i < (1<<24); i++)
	{
		uint64 temp = basesum ^ p0sum[i&0xFF] ^ p1sum[(i>>8)&0xFF] ^ p2sum[(i>>16)&0xFF];
		map.insert(std::pair<uint64, uint32>(temp, i));
	}
	printf("3 byte done.\n");
	//all 4 byte combination
	for (uint64 i= 0; i < (1LL<<32); i++)
	{
		uint64 temp = p3sum[i&0xFF] ^ p4sum[(i>>8)&0xFF] ^ p5sum[(i>>16)&0xFF] ^ p6sum[(i>>24)&0xFF];
		if(map.count(temp ^ target))
		{
			uint64 full = ((i << 24) + map.at(temp ^ target));
			uint8 bytes[8]; 
			memcpy(bytes, &full, sizeof bytes);
			printf("Found: \n");
			for(size_t j = 0; j < 8; ++j)
				printf("0x%02X,", bytes[j]);
			printf("\n");
			break;
		}
	}					
}

After running this for couple of minutes, we got the 7 bytes of key-id. Missing byte can be brute-forced by comparing with the known OTP value.
Final source code for OTP gen should look like this:
int main( int argc, char *argv[] )
{
	int i;
	sha256_context ctx;
	unsigned char sha256sum[32], basesum[32];
	uint8 data[] ="\x61\x64\x6d\x69\x6e\x00\xC1\x0E\x43\x8C\x99\xBB\x49"; //name+7bytes of key-id
	uint8 base[] ="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; //null byte string to hash first
	sha256_starts( &ctx );
	sha256_update( &ctx, base, 0xd );
	sha256_finish( &ctx, basesum );

	//data is hashed byte by byte and xored
	for(i=0;i<0xd;i++)
	{
		uint8 cont[] ="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
		cont[i] = data[i];
		sha256_starts( &ctx );
		sha256_update( &ctx, cont, 0xd );
		sha256_finish( &ctx, sha256sum );
		XOR(basesum, sha256sum);			//byte array XOR
		//PrintHash(sha256sum);
	} 
	//first 8 bytes of OTP
	for(i=0;i<8;i++)
	{
		printf("%02x", basesum[i] );
	}
	//PrintHash(basesum);
	uint8 count[] = "\x3a\x05\x00\x00\x00\x00\x00\x00\x93\xC1\x0E\x43\x8C\x99\xBB\x49"; //computed key-id
	sha256_starts( &ctx );
	sha256_update( &ctx, count, 0x10 );
	sha256_finish( &ctx, sha256sum );

	//second 8bytes - the counter
	for(i=0;i<8;i++)
	{
		printf("%02x", count[i] );
	}
	//signature
	for(i=0;i<16;i++)
	{
		printf("%02x", sha256sum[i] );
	}
	return 0;
}

Now we can login to the webpage and get our flag ๐Ÿ™‚

Posted By: Dan
Last Edit: 02 Jan 2015 @ 07:02 PM

EmailPermalinkComments (0)
Tags
Tags: , , , ,
Categories: CTF

 30 Dec 2014 @ 6:15 PM 

In this challenge we get AES implemented in a hardware and some kind of SPI interface to access the hardware.

Looking at the code, the FLAG is encrypted by random password every time we access it. Now we need to find a way to get the password or some info about the password which can be useful.
This is how a normal operation looks like.

hwaesThe initial getkey command returns a 16*’0′, which says that the key/password initially set was NULL. We can verify that by encrypting something offline and checking the encrypted value from the service. We can also see that once encryption is done, they getkey command returns a different value – b4ef5bcb3e92e21123e951cf6f8f188e

Searching that value in the net promptly puts us in the AES key expansion, and we know that we have a key/info leak.
Now the question is, can we derive the actual key/password or all roundkeys from the final roundkey?

Well we can!. Before searching much, I just wrote some “ghetto” code to reverse the key expansion.

//final round key
uint8_t s[] = "\xb4\xef\x5b\xcb\x3e\x92\xe2\x11\x23\xe9\x51\xcf\x6f\x8f\x18\x8e";
int round = 40;

Print(s);
for(int i=0; i<10;i++)
{
	Reverse(s, op, round);
	round -= 4;
	for(int j = 0;j<16; j++)
	{
		s[j] = op[j];
	}
} 
void Reverse(uint8_t* inp, uint8_t* op, int round)
{
	uint8_t tempa[4];
	uint8_t k;
	tempa[0] = inp[0];
	tempa[1] = inp[1];
	tempa[2] = inp[2];
	tempa[3] = inp[3];

	for(int i=4; i<16;i++)
	{
		op[i] = inp[i] ^ tempa[i%4];
		tempa[i%4] = inp[i];
	}
	tempa[0] = op[12];
	tempa[1] = op[13];
	tempa[2] = op[14];
	tempa[3] = op[15];

	//rotate
	k = tempa[0];
	tempa[0] = tempa[1];
	tempa[1] = tempa[2];
	tempa[2] = tempa[3];
	tempa[3] = k;

	//substitute
	tempa[0] = getSBoxValue(tempa[0]);
	tempa[1] = getSBoxValue(tempa[1]);
	tempa[2] = getSBoxValue(tempa[2]);
	tempa[3] = getSBoxValue(tempa[3]);

	int i = round;
	tempa[0] =  tempa[0] ^ Rcon[i/Nk];

	op[0] = inp[0] ^ tempa[0];
	op[1] = inp[1] ^ tempa[1];
	op[2] = inp[2] ^ tempa[2];
	op[3] = inp[3] ^ tempa[3];
	Print(op);
}

reverse_keReplace with the getkey value after encrypted flag is obtained, and we will have the key used for encrypting that flag. Decrypt with obtained key and we have our flag.

Posted By: Dan
Last Edit: 30 Dec 2014 @ 06:27 PM

EmailPermalinkComments (0)
Tags
Tags: , , ,
Categories: CTF

 04 Mar 2014 @ 12:56 AM 

Rarverseme is a rar file, and rar has an inbuilt VM which can be programmed(http://blog.cmpxchg8b.com/2012/09/fun-with-constrained-programming.html). Given challenge contains a custom bytecode which will print ๐Ÿ™ every time upon unraring. Our target is to understand the bytecode, reverse it to find the flag.

Idea is to disassemble/debug the rarVM to figure out what exactly is getting executed. After getting unrar source compiled, rest was pretty straight forward.

rarvm
Running a trace resulted in this.

MOVD [010DC294], 0x00002000
MOVD [010FFC30], 0x796f7572 ;your
MOVD [010FFC34], 0x666c6167 ;flag
MOVD [010FFC38], 0x676f6573 ;goes
MOVD [010FFC3C], 0x68657275 ;heru
MOVD [010DC298], 0x00005000
MOVD [01102C30], 0x31337357 ;13sW
MOVD [01102C34], 0x63561227 ;cV.'
MOVD [01102C38], 0x6666654a ;ffeJ
MOVD [01102C3C], 0x78584148 ;xXAH
JMP 0x000000ae
MOVD [010DC290], 0x796f7572 ; flag[i]
AND 0x796f7572, 0x000000ff
MOVD [010DC29C], 0x31337357 ; arr[i]
AND 0x31337357, 0x000000ff
MUL 0x00000072, 0x00000057 ; flag[i] * arr[i]

MOVD [010DC28C], 0x000026be
MOVD [010DC290], 0x796f7572
SHR 0x796f7572, 0x00000008 
AND 0x00796f75, 0x000000ff
MOVD [010DC29C], 0x63561227
AND 0x63561227, 0x000000ff
MUL 0x00000075, 0x00000027
ADDD 0x00003891, 0x000011d3 ; sum the results

MOVD [010DC290], 0x796f7572
SHR 0x796f7572, 0x00000010
AND 0x0000796f, 0x000000ff
MOVD [010DC29C], 0x6666654a
AND 0x6666654a, 0x000000ff
MUL 0x0000006f, 0x0000004a
ADDD 0x000058a7, 0x00002016

MOVD [010DC290], 0x796f7572
SHR 0x796f7572, 0x00000018
AND 0x00000079, 0x000000ff
MOVD [010DC29C], 0x78584148
AND 0x78584148, 0x000000ff
MUL 0x00000079, 0x00000048
ADDD 0x00007aaf, 0x00002208

CMPD 0x00007aaf, 0x0000706f

its doing a multiplication of flag values and a fixed array and comparing to a hardcoded value. If the comparison is wrong, it is jumping to bad_boy. The whole checking code can be dumped by setting CMPD as success. As we have the code figured, rest was simple bruteforcing. Before I started bruteforcing, my friend wrote a z3 code which runs much faster and yielded the flag as: evenmoarvms?rly?

V = [0x706f, 0x7972, 0x89d1, 0x9cc5]
#add rest of hardcoded values

w0, w1, w2, w3 = BitVecs("w0 w1 w2 w3", 16)

solve( w0 * 0x57 + w1 * 0x27 + w2 * 0x4a + w3 * 0x48 == V[0],  
	   w0 * 0x73 + w1 * 0x12 + w2 * 0x65 + w3 * 0x41 == V[1],  
	   w0 * 0x33 + w1 * 0x56 + w2 * 0x66 + w3 * 0x58 == V[2], 
	   w0 * 0x31 + w1 * 0x63 + w2 * 0x66 + w3 * 0x78 == V[3],
	   ULT(w0, 128), ULT(w1, 128))

Posted By: Dan
Last Edit: 04 Mar 2014 @ 12:56 AM

EmailPermalinkComments (2)
Tags
Categories: CTF, Reverse Engineering

 03 Mar 2014 @ 11:09 PM 

Hypercube is a DOL file which points us to gamecube and Dolphin emulator. Once we have the emulator, we can see the output. It clearly states that we are in a gamecube and only hypercube is fast enough to get the flag. This pretty much sounds like Hypercomputer challenge from PlaidCTF. Now its time to do some RE then.

To get disassembly we will need specific loader for DOL files. Hopefully some of those are available and we can directly start our disassembly. We can easily reach interesting function by looking up for strings. Reading Power PC assembly is not in my usual work description, but I can do that too while doing a CTF ๐Ÿ˜‰
init_ida
Next thing I did was to try to debug it in the emulator and see what exactly happens. Once the call at 0x80005c78 was invoked, it just went into full on computation which eventually crashed the emulator. Now the Hyper part was pretty much making sense ๐Ÿ™‚
init_dbg
Upon analyzing there are only 3 functions we have to worry about – 80005B18, 80005A4C and 800059E4.

After converting the PPC to higher language, it was evident that these operations are simple and written in a way that will consume lot of CPU cycles.

We can rename those functions as 80005B18 -Multiply, 80005A4C – Add and 800059E4 – Increment

That reduces our code to minimal and running it yields our flag. (Don’t mind the variable names – happens when you haven’t slept for more than 24 hours ๐Ÿ˜€ )

UInt32 s_8 = 0xadd;
UInt32 s_c = 0x5dd11;
UInt32 s_10 = 0x352463;
UInt32 s_14 = 0x8008135;
UInt32 r0, r11, r3, r9, r4;
for (int i = 0; i <= 31390; i++)
{
	for (int j = 0; j <= 21; j++)
	{
		r9 = s_c * s_10;


		r0 = (UInt32)((((UInt64)r9 * (UInt64)3) & 0xFFFFFFFF00000000) >> 32);
		r11 = r9 - r0;
		r11 = r11 >> 1;
		r0 += r11;
		r11 = r0 >> 30;
		r0 = r11 << 31;
		r0 = r0 - r11;
		r0 = r9 - r0;
		s_8 = r0;
		 

		r3 = s_c;
		r4 = 0x6ddb;
		r9 = r3 * r4;
		
		r0 = (UInt32)((((UInt64)r9 * (UInt64)3)&0xFFFFFFFF00000000)>>32);
		r11 = r9 - r0;
		r11 = r11 >> 1;
		r0 += r11;
		r11 = r0 >> 30;
		r0 = r11 << 31;
		r0 = r0 - r11;
		r0 = r9 - r0;
		s_c = r0;
		

		s_10 = s_c ^ 0x1BA40000 ^ 0x1c3c;
		s_14++;
	}
}
richText.Text = "key{1337" + s_8.ToString() + s_c.ToString() + s_10.ToString() + "h4x" + s_14.ToString() + "}";

Posted By: Dan
Last Edit: 03 Mar 2014 @ 11:22 PM

EmailPermalinkComments (0)
Tags
Categories: CTF, Reverse Engineering

 21 Aug 2013 @ 10:11 PM 

Given challenge is an implementation of ECDSA, where we are given an implementation in python and a list of signed messages for level 0 access. Our aim is to create/forge a signed message with level 1 access. We can see from the source code that, there are 2 users with level 1 access. Cracking those MD5 hashes gives us the username as

Butler : 98c131f9fb31f732b136f87e64ff686a
Kevin : f1cd318e412b5f7226e5f377a9544ff7

Now our main protection comes into picture – ECDSA. As far as the algorithm parameters are concerned, we don’t have any parameters available (not even public params!!). Our first challenge will be to figure out the params.

Looking at the ecdsa.py we can verify that the curve we are dealing with is y^2 = x^3 + ax + b \pmod p. From service.py we can see that 3 points (G, Q and R) are given, which should be points on the curve. From these 3 point values, we can calculate p,a and b of the equation. (a = p - 3)

y^2 = x^3 + ax + b \pmod p

y^2 = x^3 + (p-3)*x + b \pmod p

y^2 = x^3 -3x + b \pmod p

substituting 3 points in the equation and solving:
m = (Qy^2 - (Qx^3 - 3*Qx)) - (Gy^2 - (Gx^3 - 3*Gx))

n = (Qy^2 - (Qx^3 - 3*Qx)) - (Ry^2 - (Rx^3 - 3*Rx))

p = GCD(m, n)

b = Gy^2 - (Gx^3 - 3*Gx)

calculating these equations with actual values will render these results

p = 89953523493328636138979614835438769105803101293517644103178299545319142490503
a = 89953523493328636138979614835438769105803101293517644103178299545319142490500
b = 28285296545714903834902884467158189217354728250629470479032309603102942404639

Now we have to calculate order(cardinality) of the curve, which can be done efficiently by Schoofโ€“Elkiesโ€“Atkin point counting algorithm. Calculating q results in

q = 89953523493328636138979614835438769106005948670998555217484157791369906305783

Now we have all the public parameters.

From checking the implementation and some guess, we can figure out the vulnerability – that is reusing k while signing(PS3 hack ๐Ÿ˜‰ ). ECDSA signature has two parts r and s. r is calculated as r = k * g (x coordinate of point multiplication). So if k is same in different signatures, r will be also same. Now we have to find two instances in given signed messages, where r is same. We can get one pair as

Bushing wNpp5moxL1+Z0I40PJQCC/LegcOQocP+8Y9GV7Mv+5xiKYZxm648bajMuJ9Dy1SyHEpu/MBHkViuCM4P9Fd78Q==
Hotz wNpp5moxL1+Z0I40PJQCC/LegcOQocP+8Y9GV7Mv+5xCxqlIuZkMQDSpRWffZGG4NdkaOvAfttTtQuCaJZonxA==

Now we can calculate sk (secret multiplier) by following the attack specified in wiki (same attack is used in PS3 hack).

s1 - s2 = modinv(k, order) * (hash1 - hash2) % order

k = (hash1 - hash2) * modinv(s1 - s2, order)

sk = (s1*k - hash1) * modinv(r, order)

sk is calculated as

sk = 68503307448214310387573639006216872681840007669594105206515313184282784925849

Now its just the matter of signing a hash. We will just reuse the code from CTF.

import string
import random
import hashlib
import ecdsa
import base64
import os

access = {"f56334fbe02eaa05218c31b01a80f2f6":0, "00b37cb56bb57705348610253b1b82e4":0, 
          "f2131629ea6c08f7f5f326d8bb6eb5fd":0, "6fa95b1427af77b3d769ae9cb853382f":0, 
          "58cd57027cf126fcc9bd93dea9d74c1a":0, "f1cd318e412b5f7226e5f377a9544ff7":1, 
          "98c131f9fb31f732b136f87e64ff686a":1, "6f3249aa304055d63828af3bfab778f6":2}

#our values		  
_p = 89953523493328636138979614835438769105803101293517644103178299545319142490503L
_b = 28285296545714903834902884467158189217354728250629470479032309603102942404639L
_q = 89953523493328636138979614835438769106005948670998555217484157791369906305783L
_sk = 68503307448214310387573639006216872681840007669594105206515313184282784925849L
ec = ecdsa.CurveFp( _p, _p-3, _b )

#some points that really should be on the curve we're going to use
_Gx = 0x337ef2115b4595fbd60e2ffb5ee6409463609e0e5a6611b105443e02cb82edd8L
_Gy = 0x1879b8d7a68a550f58166f0d6b4e86a0873d7b709e28ee318ddadd4ccf505e1aL

_Qx = 0x2a40fd522f73dc9f7c40b2420e39e62c5742ff2f11805a1577ed7f60153a0be1L
_Qy = 0x3085e99246006b71b4211eff47ff3efc0f93103ee7379dc3bcc6decdc46073a3L

_Rx = 0xbd0a442367bdc24cb09c49404e3d307ba99122e7b78e14f0d84870d0df97aa59L
_Ry = 0x22c88612db6b6af6f196cd815fc5f57fe871d3b6588b0c7a59e06cc759d736b2L

#check the curve is loaded ok
if not ec.contains_point(_Gx,_Gy):
        exit()
if not ec.contains_point(_Qx,_Qy):
        exit()
if not ec.contains_point(_Rx,_Ry):
        exit()

g = ecdsa.Point( ec, _Gx, _Gy, _q )
seed = os.urandom(32)

#construct the server key material
server_public_key = ecdsa.Public_key( g, g * _sk)
server_secret_key = ecdsa.Private_key(server_public_key, _sk )

#some extended interfaces to Lis's ecdsa script
def sign(hashed_data, privkey):
        h = int(hashed_data,16)
        k = get_ephemeral_key()
        signature  = privkey.sign( h, k )
        return encode_signature(signature)

def encode_signature(signature):
        rhex = "%064x" % signature.r
        shex = "%064x" % signature.s
        return base64.b64encode(rhex.decode('hex') + shex.decode('hex')) 

def verify(signature, hashed_input, pubkey):
        tmp = signature.replace("\n", "")       
        try:
                tmp = base64.b64decode(tmp).encode('hex')
        except:
                return False
        if len(tmp) != 128:
                return False
        sig = ecdsa.Signature(int(tmp[:64],16),int(tmp[64:],16))
        h = int(hashed_input,16)
        return pubkey.verifies(h, sig)
                
def get_ephemeral_key():
        k = ""
        while len(k) < 32:
                k += hashlib.md5(seed + str(random.randint(0,255))).digest()
        return int(k.encode('hex'),16)

#existing signature	for user level 0
token = 'f56334fbe02eaa05218c31b01a80f2f6'
sec_token = 'wNpp5moxL1+Z0I40PJQCC/LegcOQocP+8Y9GV7Mv+5xCxqlIuZkMQDSpRWffZGG4NdkaOvAfttTtQuCaJZonxA=='

if verify(sec_token, token, server_public_key):
	print "[*]verify good!"
print 
#creating our signature for user level 1
name = 'Kevin'
token = 'f1cd318e412b5f7226e5f377a9544ff7'
sec_token = sign(token, server_secret_key) 
print sec_token
print 
#verifying
if verify(sec_token, token, server_public_key):
	print "[*]verify good!"

Finally we have to bruteforce md5 with a given prefix to get a hash which begins with 0000. Straight forward bruteforce ๐Ÿ™‚

Posted By: Dan
Last Edit: 21 Aug 2013 @ 10:31 PM

EmailPermalinkComments (0)
Tags
Categories: CTF

 08 Aug 2013 @ 8:52 PM 

Cross posted from my team site: http://seg.fault.in

I started looking at cone when I got frustrated with cnot. Initial analysis confirmed that it is a x64 binary, asks for a password when run, and prints whether the password was right or not.

Running through ltrace went fine and there was no trace for anti-dbg (like ptrace call from cnot).

1

Next logical step is to load into IDA and take a look at the disassembly.

No, not this madness again :/ (Both CNOT and CON are obfuscated x64 binaries).

Looking at the disassembly it looked similar to cnot, but expectedly lesser protection/obfuscation. From previous experience from cnot, I started to rename fgetc/fputc/calloc wrapper functions to get a better understanding. In the mean time, lets look at the ltrace logs.

2

There is one calloc just after the password prompt is printed and lot of callocs after the password is read. We can easily assume that lot of allocated memory will be used for password verification.

Now looking back at the disassembly and looking only at function calls we can get the flow ofย  fputc->calloc->fgetc function wrappers. Its time to start debugging as we have figured out where exactly our input is being read. I started debugging by putting breakpoint at the place where it checks for ‘\n’.

.text:0000000000404B0C         mov     qword ptr [rbp-58h], 0
.text:0000000000404B14         mov     dword ptr [rbp-58h], 0Ah
.text:0000000000404B1B         mov     r15d, [rbp-50h]
.text:0000000000404B1F         cmp     r15d, [rbp-58h]
.text:0000000000404B23         jz      short loc_404B36

Then traced down ignoring everything other than function calls (experience from cnot). I stepped into first function call and spent sometime trying to understand what it does, got frustrated and went back into disassembly to see whether the function calls return values is being used/checked at some place. As the check was there, I put BP on the next statement to see the return value. It turned to be 1, and the execution continues. The next function call is interesting one.

3Yes, we have our input in stack and its being referenced in couple of registers(I entered password as “abcd”). Now we can safely assume that call_404f89 does some operation on our password. Stepping into the function and tracing manually was a frustrating experience and decided to do what I previously did –ย  lets check the return value of the function. Return value was 0xa46c74bb and it is saved to stack. Tracing down the function, it ended up in doing a comparison with a hardcoded value.

4

Doing couple of more testing with different passwords verified that the password is split into 4bytes and passed to the function call_404f89, and the return values are compared with different hardcoded values. A total of 9 values are being compared – making our password 36 characters (including ‘\0’ – we will see how we got that later).

So essentially the algo should look like this:

char* szPassword = ReadPassword();
unsigned int hardcoded[] = {0x247BFB03, 0x8C33E4BB, 0xD49D047B,
                            0x7303FC73, 0x8C950303, 0x2304743B,
                            0x64647303, 0xA454949B, 0xD48CB5DB};
for(int i=0; i < 9; i++)
{
 retVals[i] = call_404f89(szPassword + (i * 4));
}
for(int i=0; i < 9; i++)
{
 if(retVals[i] != hardcoded[i])
 {
  //puts("Wrong!");
  //return -1;
 }
}
puts("Correct!");

As we have partially figured out the algo, the next big thing is to understand call_404f89. I tried to single step through the code but resulted in spending more time staring at the disassembly that doesn’t make much sense. Meantime I was also trying out the other challenges and partially solved compression (CRIME attack) and three_eyed_fish (didn’t complete both due to lack of time/resource :/). Revisiting the challenge again, I took a look at the ltrace log – well we havn’t looked at the calloc function calls yet. I put a BP on calloc wrapper function (0x400bc4). We should be worried about breaks only after call_404f89 starts. Once the call_404f89 started, I looked into the allocated memory to see if something interesting gets stored in those places. As the memory got allocated, I looked into the previous allocated space (when 3rd allocation happened, I looked into second allocated heap memory and so on). By the time the processing of call_404f89 got over, I had the full memory dump of all allocated memories. I ran couple of sample inputs and compared the output to make sure that I am not looking at heap headers rather than actual values. Clearly a pattern emerged as shown in the below pic.
5
While debugging at calloc return statement (jmp rdi), we can see that our password (4bytes) are used in somekind of operation and temporary results are stored in heap memory and eventually our calculated value (0xa46c74bb see above) is generated. While debugging after calloc and copy of 4bytes, I stumbled upon a piece of code which actually does an operation on our password values.
6It is a shift-arithmetic-right (sar val,0x15) which produced 0x323, which is present in the memory dump. Yiyeks! we have one operation figured. Looking at the disassembly near by, I figured some kind of pattern and found another operation by address 0x004019bf -> shl val, 0x0b. Now I restarted the debugging session with BP set on to 0x004019bf and 0x00401aea. BP on 0x004019bf hit first, and I can see the value (0x64636261 – “abcd”) is being left shifted with 0x0b resulting 0x1b130800 – which is again present in the memory dump. 2nd BP hit and we got 0x323. Now I looked at the memory dump to see if some info can be retrieved out of it. From the values in memory, I deduced the rest of the operation. Pure intuition and luck works sometime ;). Till now our algo is
value = 0x64636261;

t1 = value << 0x0b; //0x1b130800
t2 = value >> 0x15; //0x323

//next values in memory
//[0x1b130b23] - which is t1 ^ t2
//[0xdeadbeef] 
//[0xc5beb5cc] = 0x1b130b23 ^ 0xdeadbeef
//[0xdeadbeef] 
//[0xa46c74bb] = 0xc5beb5cc + 0xdeadbeef

We can rewrite the function as:
unsigned int call_404f89(char* password)
{
 unsigned int value = (unsigned int *)password;
 return ((((value << 0x0b)^(value >> 0x15))^ 0xdeadbeef)+ 0xdeadbeef);
}

Now we have the checking algo inย  hand. Next is to write small script/program to do brute-forcing.
for (int i = rangeStart; i < rangeEnd; i++)
{
 for (int j = rangeStart; j < rangeEnd; j++)
 {
  for (int k = rangeStart; k < rangeEnd; k++)
  {
   for (int l = rangeStart; l < rangeEnd; l++)
   {
    val = (uint)(i << 0 | j << 8 | k << 16 | l << 24);
    t1 = val << 0x0b;
    t2 = val >> 0x15;
    t2 ^= t1;
    t2 ^= 0xdeadbeef;
    t2 += 0xdeadbeef;
    if (t2 == 0x247BFB03)  //change the hardcoded values to get next 4 chars.
    {
     MessageBox.Show("Got it: " + Convert.ToChar(i) +
                                  Convert.ToChar(j) + 
                                  Convert.ToChar(k) + 
                                  Convert.ToChar(l));
     goto done;
    }
   }
  }
 }
}

The last hadcoded value won’t be found through bruteforcing until you start with rangeStart=0; – the C string delimiter ‘\0’. Anyway last part can be easily guessed ๐Ÿ™‚

Finally the password/flag is: pls_send_help_im_in_a_stack_machine

Posted By: Dan
Last Edit: 08 Aug 2013 @ 08:52 PM

EmailPermalinkComments (0)
Tags
Categories: CTF, Reverse Engineering

 25 Jan 2012 @ 12:54 AM 

HackIM scoreboard

 

Malcon 2011 CTM write up – Malcon-CTM-Writeup

NULLCON 2012 HackIM write up – HackIM – danny

Thanks to many people for constant help and support. I won both the CTFs and hope to participate and learn from the newer ones ๐Ÿ™‚

Posted By: Dan
Last Edit: 25 Jan 2012 @ 12:56 AM

EmailPermalinkComments (0)
Tags
Categories: CTF, Reverse Engineering

 22 Jul 2011 @ 6:34 PM 

One of my friend and colleague was working on automating Microsoft Attack Surface Analyzer (not going to explain what it is or what it does) for some of the projects. There is nothing much to automate other than generating baseline/product cabs and generating reports. For generating cabs, one has to just run the command asa.exe and you have the cabs in position. But for making reports, one has to run “Attack Surface Analyzer.exe”, select the cabs and press “Generate” button. Not quite scriptable is it? Searched for documentation or any online help, but there was none. Well, it is time for a (very) little bit of reverse engineering ๐Ÿ˜€

Microsoft Attack Surface Analyzer

“Attack Surface Analyzer.exe” is a .NET exe. So let us fire up Reflector. Oops, we donโ€™t have free version of Reflector these days (too bad Red Gate). Fortunately we have ILSpy :). Fire up ILSpy and load the exe.
ILSpy

ILSpy have already identified the entry point for us, just click there and we will end up in Main.

Well, game over!

For the sake of completeness, I am posting the command line parameters here.

“Attack Surface Analyzer.exe” /BASELINE “your_baseline.cab” /PRODUCT “your_product.cab” /REPORT “your_report_dir” /USEHTML

Not sure why it was not documented ๐Ÿ˜›

Posted By: Dan
Last Edit: 22 Jul 2011 @ 06:45 PM

EmailPermalinkComments (0)
Tags

 16 Nov 2010 @ 4:05 PM 

[This post has been screwed due to Anti viruses claiming plain text as live exploits. I omitted most of the stuffs I planned to post ๐Ÿ˜ ]

Many people don’t consider PDF files as a possible threat and oh, well I agree to them(!). It is not the PDF files but the rendering softwares we have to be afraid of. If you think I am referring to those Adobe Reader 0-days popping up periodically, hell yeah, you are RIGHT!. We are going to talk about PDF files, few Adobe Reader vulnerabilities, exploits and malwares that comes along with it ๐Ÿ˜‰

You can read about PDF in wiki page. PDF files are binary files with proper formatting and looks like a collection of objects. You can open a PDF file in a text editor or hex editor to view it’s object structure.

pdf file

As you can see PDF files start with a magic header %PDF or %%PDF followed by the spec version number.ย  From next line onwards you can see a pattern emerging, like [obj][data][endobj]. Well, this is the collection of object thing I said earlier. Each object is identified by an ID and a version number. 41 0 obj represents object 41 version 0. You can look into PDF specs for better understanding of the file architecture. You don’t have to understand every details of the spec, but you can specifically look into streams, encodings, java script implementations, acro forms etc… Before going further, I would like to explain a little more about streams. Streams are used to store data(images, text, java scripts etc…) and to make it efficient PDF allows us to use compression and encoding techniques like Flate/LZW/RLE etc. This creates sort of problem for us, we can’t just use text/hex editor for understanding the true content of PDF!. As a programmer I can’t ignore this challenge and I made a tool(PDF Analyzer) to solve this issue. I will use PDF Analyzer throughout this post but you won’t be able to get it as it is still in private build(I will release it…eventually ;)). For now you guys have other options, both commercial and freeware tools are available. I will post some links here.

PDF Dissector by zynamics – commercial

Origami by Sogeti ESEC Labs – freeware

PDF Stream Dumper by Dave – freeware

Various python PDF parsers from Didier Stevens and inREVERSE guys – freeware (search!)

PDF Analyzer is made in C# with only 3 external libraries, zlib(I should have used GZipStream with 2 byte header hack),ย  BeaEngine(Thanks BeatriX) and JSBeautifier(I ported 95% of code from js to C#). I spent around 2 weeks of free time on it. It may not be the fastest PDF parser, but it can handle every ill formatted PDF I have in my repository ;).

pdf analyzerAdobe reader’s top vulnerabilities come from Adobe specific javascript APIs. This gives us a chance to disable javascript and protect us from any of those javascript based exploits. Disabling javascript is crucial but it doesn’t fix vulnerabilities from other parts of Adobe Reader such as embedded image files and flash files.

Now we will look into some of the malware samples which exploits these vulnerabilities. You can find malware sample from many security blogs and I must thank two of my friends who sent a big archive of malware PDFs for analysis and testing :).

pdf analyzer jsThis particular sample splits javascript into three streams and concatenates them using <</Names[(1)6 0 R (2)7 0 R (3)8 0 R]>> which will eventually refer to three objects marked in red. After beautification, it seems it is exploiting one vulnerability existed inย  Adobe Reader namely this.media.newPlayer(null).

media newPlayer

It is essentially spraying heap with NOP sled and shellcode and calling the vulnerable function. The shellcode present here is a dropper/downloader, you can dump it to a file and use IDA to disassemble it.

Another PDF file which exploits util.printf is given below.

util printf
Again you can dump shellcode and disassemble with IDA. Another option is to use PDF Analyzers unescape functionality to directly disassemble the shell code.

disassemblyDisassembly starts with pretty straight forward steps to find base address via delta calculation(call – pop – sub). Then it fetches kernel32 base from PEB(fs[0x30])->Ldr.InInitOrder[0].base_address. This will be used to eventually load other modules and APIs.

Malware writers use multiple techniques to protect their payload. Techniques involves obfuscation, multiple and multi-level usage of encoding/compression schemes.

multiple encodingsIf any of you guys have samples that uses multi-level encoding, please send them to me ๐Ÿ˜‰ , I would like to test those with PDF Analyzer.

I will conclude the exploit samples by posting the latest exploit for the vulnerability printSeps. This code is retrieved from the PDF posted in full disclosure list.

printSeps
Evil actions of PDF malwares varies from regular password stealer to rootkits. Once you have attained arbitrary code execution, rest will be just imagination of malware writer. As malware writers are mainly targeting Adobe Reader, try to shift to other PDF rendering software or at least update to latest version. There are free PDF readers like Sumatra or GhostScript, try those out and always be cautious when opening a PDF file.

Posted By: Dan
Last Edit: 24 Nov 2010 @ 03:23 PM

EmailPermalinkComments (10)
Tags

 06 Nov 2010 @ 6:09 PM 

Well, it seems people are getting crazy about android platform(everyone is trying to buy an android phone!). I don’t have an android cell phone but, lets see if I can get my hands dirty with this Linux+java clean room engineered platform ๐Ÿ˜‰

To begin our journey we need Android SDK, a target to test with and the necessary tools.

You can download the necessary file from these locations:

Android SDK: http://developer.android.com/sdk/index.html

Deurus android crackme 03: http://crackmes.de/users/deurus/android_crackme03/

Smali and baksmali: http://code.google.com/p/smali/

Dex2jar: http://code.google.com/p/dex2jar/

Java decompiler: http://java.decompiler.free.fr/

Download and install android SDK, SDK platform(latest is 2.2 at the time of writing), necessary java packages and rest of the tools. Create a virtual device from SDK menu and start emulation. Within few minutes you can see the emulator booting up and showing the phone screen. Well, thats it! we have our emulator up and running.

Now we need to install the software(crackme, its legal!) to the emulator. For that you may have to get acquainted with android debug bridge(adb).ย  Installing a apk file is pretty simple, all you have to do is to run two commands from android SDK directory/tools.

adb install

After the installation you can see the crackme icon from application menu.

android emulator

Now run the crackme by clicking on it. If everything went as expected you will see the crackme application on the screen.

android crackme

Now we will play with it, pressing check button with no inputs pops a message “Min 4 chars”, and with a proper name it pops up “Bad boy”. We have to remember these strings because we will be using them as our search keys when we dis assemble the apk(actually dex) files. Also note that we have two hardware ids and we need to find out what those exactly means.

As our crackme is up and running in emulator, we now move onto reversing it. If you have read apk file format, you can visualize it as a extended jar file which essentially is a zip file. Now you can change the crackme file name from Crackme03.apk to Crackme03.zip and decompress it to any folder.

apk file

Now the interesting file for us is classes.dex, which contains the compiled vm codes. We are going to disassemble the dex file with baksmali. Commands are pretty simple as you can see from screen shots.

baksmali disassembly

If everything worked fine, we will have a folder structure similar to java packages. Interesting .smali files are located at “\com\example\helloandroid”. Open all the .smali files into your favorite text editor(I use NPP). If you have never done anything related to reverse engineering/esoteric programming/assembly(IL) programming, you will probably think: WTF!. Relax. We have just opened a disassembled dex file. Now, if you are thinking how on earth someone can find the correct location of checking function, I hope you remember those pop up strings I told earlier. Yeah, “Min 4 chars” and “Bad boy”. Now we will use those strings as our search keys. Searching “Min 4 chars” in all the opened .smali files, we will find a hit in HelloAndroid$2.smali line 130.

dex disassembly(I just applied java syntax highlighter as I don’t have dalvik syntax files)

Our aim is to understand the serial checking function and write a keygen for it. For that we have to know all the dalvik opcodes that are used here. You can visit this page to understand the opcodes and after that you can convert disassembled code to much higher language constructs. I will provide a briefย  code snippet which actually implements the algorithm. Two hardware ids used are IMEI and sim serial number.

//Read name from text box
const v23, 0x7f050004
invoke-virtual/range {v22 .. v23}, Lcom/example/helloandroid/HelloAndroid;->findViewById(I)Landroid/view/View;
move-result-object v9

//Read serial from text box
const v23, 0x7f050006
invoke-virtual/range {v22 .. v23}, Lcom/example/helloandroid/HelloAndroid;->findViewById(I)Landroid/view/View;
move-result-object v21

//Checking whether the name is of length greate than 4
const/16 v22, 0x4
move v0, v11
move/from16 v1, v22
if-ge v0, v1, :cond_51

//Popup showing Min 4 chars
const-string v23, "Min 4 chars"
const/16 v24, 0x1
.line 86
invoke-static/range {v22 .. v24}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v13
.line 88
.local v13, notificacionToast:Landroid/widget/Toast;
invoke-virtual {v13}, Landroid/widget/Toast;->show()V

//There is a little exception trick to make integer string from username
//It converts aaaa to 97979797 which is ascii equivalent
invoke-virtual {v10, v5}, Ljava/lang/String;->charAt(I)C
move-result v3

//Getting first 5 chars from ascii converted name
const/16 v22, 0x0
const/16 v23, 0x5
move-object v0, v12
move/from16 v1, v22
move/from16 v2, v23
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->substring(II)Ljava/lang/String;

//Converting it into integer and xoring with 0x6B016   - Serial part 1
invoke-static {v12}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v22
const v23, 0x6b016
xor-int v22, v22, v23

//Getting IMEI from TelephonyManager
//http://developer.android.com/reference/android/telephony/TelephonyManager.html
invoke-virtual {v8}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
move-result-object v6
.line 102
.local v6, imei2:Ljava/lang/String;

//Getting sim serial
invoke-virtual {v8}, Landroid/telephony/TelephonyManager;->getSimSerialNumber()Ljava/lang/String;
move-result-object v16
.line 103
.local v16, simsn:Ljava/lang/String;

//Getting first 6 chars from IMEI, and similarly from sim serial (IMEI.Substring(0,6) will be used as Serial part 3)
const/16 v22, 0x0
const/16 v23, 0x6
move-object v0, v6
move/from16 v1, v22
move/from16 v2, v23
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->substring(II)Ljava/lang/String;

//Converting them to integer and xoring    - Serial part2
invoke-static/range {v19 .. v19}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v22
invoke-static/range {v20 .. v20}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v23
xor-int v22, v22, v23

//Making a new StringBuilder object and formatting the string to part1-part2-part3
new-instance v22, Ljava/lang/StringBuilder;
invoke-static {v12}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v23
invoke-direct/range {v22 .. v23}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
const-string v23, "-"
invoke-virtual/range {v22 .. v23}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v22
invoke-static/range {v17 .. v18}, Ljava/lang/String;->valueOf(J)Ljava/lang/String;
move-result-object v23
invoke-virtual/range {v22 .. v23}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v22
const-string v23, "-"
invoke-virtual/range {v22 .. v23}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v22
move-object/from16 v0, v22
move-object/from16 v1, v19
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v22

//Checking whether user entered serial and program made serials are equal.
invoke-virtual {v14, v15}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

As you can see, the algorithm is pretty straight forward. It is using name and two hardware ids as input and doing some operations on them to make a serial.ย  We can easily recode it in any programming language we prefer to make it as a keygen. Anyway, I am not posting any keygen sources as it will spoil the whole phun!

A demonstrative serial calculation routine is given below:

Name: aaaaa

HW ID1: 0000000000000000

HW ID2: 89014103211118510720

“aaaaa” will be converted to “9797979797”, from which we will take first 5 letters and convert it into integer 97979. This will be xored with 0x6B016(438294 in base to 10) resulting 511661 and this will be first part of serial. For second part, we will take first 6 letters from HW ID1 and HW ID2, convert them to integer and xor, resulting 000000^890141 = 890141. For third part we will use first 6 characters from HW ID1. Formatting with the specified delimiter the serial will become “511661-890141-000000”.

generated serial

Bingo! everything worked as expected. Now, for all those who thinks it is pretty hard to read all those disassembled instructions and manually converting them to higher language constructs, there are other options. As dalvik is based on design of java, it is also susceptible to decompilation. There is no decompiler available at this moment, but there is hope. For now we can use another utility which converts dex files to jar files so that we can use java decompilers to see much more abstracted code. From starting of this blog post you may have noticed the tool dex2jar. Use dex2jar to convert classes.dex to classes.dex.dex2jar.jar. Open it in a java decompiler and you can see much better output than dalvik disassembly. Please note that dex2jar is still in development phase and the output is meaningless at many places. This should be used only to get a quick understanding of all the functions called.

java decompiler

Well, thats it! We have analyzed an android program and defeated its protection. Cheerio!

Posted By: Dan
Last Edit: 14 May 2012 @ 05:54 PM

EmailPermalinkComments (18)
Tags





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

About



    No Child Pages.