[TUCTF 2017] Reverse – Mainframe (300 points)

Mainframe

Files: mainframehacker.exe decompile_c.txt decompile_pseudo.txt
 

OK… so we are messing with an elf64 binary which was C source code, which was created by cobc (gnu-cobol), which had as input some COBOL source code. RIGHT!

That was really tricky challenge as it wasn’t easy at all, to find variable addresses and function parameters and understand what the heck it was doing. Running the binary was like that :-

$ ./mainframehacker.exe
Mainframe Hacking Tool v2.1
Important Note: Never, ever leave this tool behind
Enter Login Name: user
Welcome back, user
Enter Secure Login Code: 1234
INVALID CREDENTIALS

It simply asks for login and password and if they are valid we will get the flag. Time for reversing…

The only important function that we have to decompile is the NON__MALICIOUS__SOFTWARE_ which does the validation for the input credentials.

The gnu-cobol (libcob) firstly does a module initialization, which loads all the variables before starting executing COBOL code line by line with cob_set_location.

Let’s see the interesting variables initialized (see also attached decompile_c.txt) :-

Initialize module test.cbl
	login[60]=null
	password[90]=null
	password2[33]=null
	password_reversed[33]=null
	flag_bytes[33]=[
			b_15_7199 = 13618;
			byte_560AF9A5F2A2 = 48;
			b_16_7200 = 13872;
			byte_560AF9A5F2B2 = 54;
			b_17_7201 = 13872;
			...
			]

	invalid_char=false
	cur_char=null

First thing that we noticed, was the actual flag size, which is 33 bytes. The second thing was that there is another mess with the decompilation but probably that’s not IDA’s fault. Gnu-cobol seems to work with integers in a very weird way, this is probably for better compatibility with COBOL types(?).
So b_15_7199 = 13618 = 0×3532 = little-endian ( chr(0×35) + chr(0×32) ) = 25 and then byte_560AF9A5F2A2 = 48 = chr(48) = 0 gives us the first byte for the flag_bytes array which is 250.

Rather, than working in this way to find out the encrypted flag_bytes we reviewed the test.cbl modules initiliaztion dynamically :-

flag_bytes in memory
000055734ECF92A0  32 35 30 00 00 00 00 00  00 00 00 00 00 00 00 00  250.............
000055734ECF92B0  30 36 36 00 00 00 00 00  00 00 00 00 00 00 00 00  066.............
000055734ECF92C0  30 36 36 00 00 00 00 00  00 00 00 00 00 00 00 00  066.............
000055734ECF92D0  31 35 32 00 00 00 00 00  00 00 00 00 00 00 00 00  152.............
000055734ECF92E0  30 39 36 00 00 00 00 00  00 00 00 00 00 00 00 00  096.............
000055734ECF92F0  31 33 32 00 00 00 00 00  00 00 00 00 00 00 00 00  132.............
000055734ECF9300  30 39 36 00 00 00 00 00  00 00 00 00 00 00 00 00  096.............
000055734ECF9310  31 33 34 00 00 00 00 00  00 00 00 00 00 00 00 00  134.............
000055734ECF9320  31 39 30 00 00 00 00 00  00 00 00 00 00 00 00 00  190.............
000055734ECF9330  30 39 34 00 00 00 00 00  00 00 00 00 00 00 00 00  094.............
000055734ECF9340  32 33 38 00 00 00 00 00  00 00 00 00 00 00 00 00  238.............
000055734ECF9350  31 39 30 00 00 00 00 00  00 00 00 00 00 00 00 00  190.............
000055734ECF9360  32 32 30 00 00 00 00 00  00 00 00 00 00 00 00 00  220.............
000055734ECF9370  30 39 36 00 00 00 00 00  00 00 00 00 00 00 00 00  096.............
000055734ECF9380  32 33 30 00 00 00 00 00  00 00 00 00 00 00 00 00  230.............
000055734ECF9390  31 39 36 00 00 00 00 00  00 00 00 00 00 00 00 00  196.............
000055734ECF93A0  30 39 38 00 00 00 00 00  00 00 00 00 00 00 00 00  098.............
000055734ECF93B0  31 34 32 00 00 00 00 00  00 00 00 00 00 00 00 00  142.............
000055734ECF93C0  31 39 30 00 00 00 00 00  00 00 00 00 00 00 00 00  190.............
000055734ECF93D0  31 30 32 00 00 00 00 00  00 00 00 00 00 00 00 00  102.............
000055734ECF93E0  32 30 38 00 00 00 00 00  00 00 00 00 00 00 00 00  208.............
000055734ECF93F0  31 36 38 00 00 00 00 00  00 00 00 00 00 00 00 00  168.............
000055734ECF9400  31 39 30 00 00 00 00 00  00 00 00 00 00 00 00 00  190.............
000055734ECF9410  32 31 34 00 00 00 00 00  00 00 00 00 00 00 00 00  214.............
000055734ECF9420  31 33 34 00 00 00 00 00  00 00 00 00 00 00 00 00  134.............
000055734ECF9430  31 30 34 00 00 00 00 00  00 00 00 00 00 00 00 00  104.............
000055734ECF9440  31 34 34 00 00 00 00 00  00 00 00 00 00 00 00 00  144.............
000055734ECF9450  32 34 36 00 00 00 00 00  00 00 00 00 00 00 00 00  246.............
000055734ECF9460  31 34 30 00 00 00 00 00  00 00 00 00 00 00 00 00  140.............
000055734ECF9470  31 36 38 00 00 00 00 00  00 00 00 00 00 00 00 00  168.............
000055734ECF9480  31 33 34 00 00 00 00 00  00 00 00 00 00 00 00 00  134.............
000055734ECF9490  31 37 30 00 00 00 00 00  00 00 00 00 00 00 00 00  170.............
000055734ECF94A0  31 36 38 00 00 00 00 00  00 00 00 00 00 00 00 00  168.............

We continue to decompiling careful with the same way the rest of the code and the following pseudo code was constructed :-

Initialize module test.cbl
	login[60]=null
	password[90]=null
	password2[33]=null
	password_reversed[33]=null
	flag_bytes[33]=[.....]
	invalid_char=false
	cur_char=null

MAIN-PROCEDURE:DISPLAY
	Mainframe Hacking Tool v2.1
	Important Note: Never, ever leave this tool behind
	Enter Login Name:

LOGIN-PROCUDURE:ACCEPT
	login

LOGIN-PROCUDURE:DISPLAY
	Welcome back, 
	Enter Secure Login Code:

LOGIN-PROCUDURE:ACCEPT
	password

LOGIN-PROCUDURE:MOVE
	password -> password2

LOGIN-PROCUDURE:MOVE
	reverse(password2)-> password_reverse

LOGIN-PROCUDURE:PERFORM
	for ( iter_i = 0; iter_i < 34; iter_i++ ) {
		STRMOD:COMPUTE
			cur_char=ord(password_reverse[i]) * 2

		STRMOD:IF
			if ( cur_char != flag_bytes[i] )
				STRMOD:MOVE
					invalid_char = true
	}
	if ( invalid_char == true )
		DISPLAY
			INVALID CREDENTIALS
	else
		DISPLAY
			Nice Try Hackeman!
			You got the flag but I have escaped!

As our pseudo code looks much more readable from the gnu-cobol one... we can finally see that it just reverses our input and multiplies each char by 2 and then compares it with the flag_bytes.
So we just need to divide the numbers that we found in memory by 2 and then reverse them to get the flag.

#!/usr/bin/python
flag_bytes=[250,66,66,152,96,132,96,134,190,94,238,190,220,96,230,196,98,142,190,102,208,168,190,214,134,104,144,246,140,168,134,170,168]
print "".join([chr(x/2) for x in flag_bytes])[::-1]

# TUCTF{H4Ck_Th3_G1bs0n_w/_C0B0L!!}

PS: That was the only flag that we didn't capture as we solved this just after the CTF was finished. But flags are still flags without points :)

Share

Leave a Reply

Photo

root

November 29th


CTF


line

© 2017 SuRGeoNix | Security Blog