AH19CTF WriteUps: Command Parser

What’s provided:

  • Server access to a directory containing an executable and a flag file.

You cannot just cat flag because r--r----- 1 commandparserctf-pwn root ... flag and of course, your whoami profile is not in the sudoers list.

  • A link to download the executable file.

This is good. You can dissassemble it later.

Let’s get cracking :D

Your first step is to run the executable and have a clue of what it does. Notice the file permissions on the commandparser file above -rwsr-xr-x: the setuid flag s. This means that the file runs with escalated priviledge, in this case, the root(owner of the file). The program asks for an input that is a command to execute. You put in /bin/cat flag; perhaps being run in UID root, this might spit back the flag. You get a input not allowed error instead and the program exits.

You run ltrace. It will help in debugging. You need to monitor library and system calls made by the process as it executes.

Findings:

After this we know the input is checked if it contains a certain string bin by the strstr(const char *haystack, const char *needle)call.

Curious about why the program fails and exits yet the strstr clearly returned a True. :nerd_face: :neckbeard:

You decide to test with another input message and see.

Findings.2:

Interesting!!

  • The call to strstr() is made thrice to check for the specific command words bin, cat and flag. Execution continues on fail of these three.
  • The length of your input string is determined. strlen()

No apparent use for it can be figured from the trace. A note is kept on that though.

  • Your input is being compared if it matches the string /bin/cat flag!! Yet from the strstr observation, it shouldn’t exist in your input.. :confused:
  • We can infer that if the strncmp() passes, the /bin/cat flag gets executed somehow.

On to dissassembly:

You fire up IDA Pro and dissassemble this binary. (Dissassembly can be discussed in detail in a later article :).

These are the functions defined in the program.

The main function is just as you thought:

print "Command to execute: "
fgets() get user input. Save that in var_C dword.
if any of the strstr(var_C, str) functions returns a pointer: 
	print out an error statement then exit.
else:
	print "Almost there" then go to pass var_C and var_10 to subroutine at sub_804858B

at sub_804858B:

arg_0 is our input string. var_14 is the length. var_10 is the counter. arg_4 and var_C are empty strings.

var_14 = strlen(arg_0)

func loc_80485DF: 

	while (var_10 < var_14):
		if (var_10 == 3):
			var_C += get arg_0[var_10] 

The program returns var_C. Sweet!
In simple terms, if
arg_0 = “aaaabaaaiaaan”
then var_C = sub_804858B(arg_0)

var_C = bin :boom:

This string is then sent to strncmp with “/bin/cat flag”. If this passes, a system call is made with the input string. This will spit the flag! :laughing:

Wrapping this up:

You try the string “aaaa/aaabaaaiaaanaaa/aaacaaaaaaataaa aaafaaalaaaaaaag” on the execution. (This time without ltrace)

There is your flag: AH{1 533 Y0U 4r3 c001 w1th 5tr1ng5 !!} :boom:.

The first of many posts.. you hope :)

GDAL on Travis

comments powered by Disqus