Difference between revisions of "W4505 Capture the Flag V"

From Coder Merlin
(added stacktastic writeup)
(added decompile trial writeup)
Line 89: Line 89:


This code seems to define some constants that represent letters of the alphabet. These constants are later pushed on and popped off the stack using the push and pop instructions. The ecx after the pop instructions refers to the ecx register of where to store popped data. We can manually figure out what the stack will look like after this code runs by typing whatever characters are pushed in a text file, and clicking backspace upon a pop. We get "stacks_r_cool". We can wrap this in the flag wrapper to get '''ahsCTF{stacks_r_cool}'''.
This code seems to define some constants that represent letters of the alphabet. These constants are later pushed on and popped off the stack using the push and pop instructions. The ecx after the pop instructions refers to the ecx register of where to store popped data. We can manually figure out what the stack will look like after this code runs by typing whatever characters are pushed in a text file, and clicking backspace upon a pop. We get "stacks_r_cool". We can wrap this in the flag wrapper to get '''ahsCTF{stacks_r_cool}'''.
=== Decompile Trial ===
<pre>
[125 Points] I stole this file off the server, but need to figure out how it works!!! Can you figure out the correct input and get me the flag?
</pre>
The challenge also provides the executable file decompileTrial.
Let's import this file into Ghidra in order to see the source code. Here's what Ghidra decompiled from the main() function:
<syntaxhighlight highlight="" lang="c" line>
void main(void)
{
  long lVar1;
  uint uVar2;
  long in_FS_OFFSET;
  uint input;
  int i;
  uint encodedFlag [38];
 
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  encodedFlag[0] = 0x62;
  encodedFlag[1] = 0x69;
  encodedFlag[2] = 0x74;
  encodedFlag[3] = 0x44;
  encodedFlag[4] = 0x55;
  encodedFlag[5] = 0x47;
  encodedFlag[6] = 0x7c;
  encodedFlag[7] = 0x65;
  encodedFlag[8] = 0x31;
  encodedFlag[9] = 0x6f;
  encodedFlag[10] = 0x55;
  encodedFlag[11] = 0x60;
  encodedFlag[12] = 0x67;
  encodedFlag[13] = 0x34;
  encodedFlag[14] = 0x41;
  encodedFlag[15] = 0x73;
  encodedFlag[16] = 0x60;
  encodedFlag[17] = 0x75;
  encodedFlag[18] = 0x69;
  encodedFlag[19] = 0x34;
  encodedFlag[20] = 0x60;
  encodedFlag[21] = 0x53;
  encodedFlag[22] = 0x66;
  encodedFlag[23] = 0x77;
  encodedFlag[24] = 0x34;
  encodedFlag[25] = 0x73;
  encodedFlag[26] = 0x25;
  encodedFlag[27] = 0x66;
  encodedFlag[28] = 0x60;
  encodedFlag[29] = 0x66;
  encodedFlag[30] = 0x4f;
  encodedFlag[31] = 0x68;
  encodedFlag[32] = 0x6a;
  encodedFlag[33] = 0x6f;
  encodedFlag[34] = 0x34;
  encodedFlag[35] = 0x34;
  encodedFlag[36] = 0x73;
  encodedFlag[37] = 0x7e;
  i = 0;
  while (i < 0x26) {
    puts("Enter your input! Correct input will be one character of the flag in hex!");
    __isoc99_scanf(&DAT_00102052,&input);
    uVar2 = f(input);
    if (uVar2 == encodedFlag[i]) {
      puts("Correct character!");
    }
    else {
      puts("Incorrect character.");
    }
    i = i + 1;
  }
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
</syntaxhighlight>
The code seems to create an array called encodedFlag and assign values to its indexes. The program then scans user input, runs it through a function called f(), and compares it to the current index of the array. If the values are equal, the program tells us our input is the hex representation of a character in the flag. The program will use a loop to repeat this process for every element in encodedFlag. It seems that we will input one character of the flag at a time (in hex), and the program will tell us if out character was correct. Instead of manually trying every character, we can decode the encodedFlag array. To do this, let's look at how f() encoded our input. Here is the decompiled code for f():
<syntaxhighlight lang="c" line>
uint f(uint num)
{
  return num + 1;
}
</syntaxhighlight>
The f() function seems to add 0x1 to whatever character we input. That means that the values in encodedFlag will be 0x1 higher than the actual hex values of the flag. We can subtract 0x1 from every element in encodedFlag to get the actual character of the flag. After doing that, the characters of the flag in hex seem to be:
<pre>
0x61,0x68,0x73,0x43,0x54,0x46,0x7b,0x64,0x30,0x6e,0x54,0x5f,0x66,0x33,0x40,0x72,0x5f,0x74,0x68,0x33,0x5f,0x52,0x65,0x76,0x33,0x72,0x24,0x65,0x5f,0x65,0x4e,0x67,0x69,0x6e,0x33,0x33,0x72,0x7d
</pre>
We can covert these hex values to their ASCII representation using online tools. We get '''ahsCTF{d0nT_f3@r_th3_Rev3r$e_eNgin33r}'''.

Revision as of 13:33, 3 March 2021

Within these castle walls be forged Mavens of Computer Science ...
— Merlin, The Coder
ComingSoonIcon.png
Coming Soon
This page will serve as a writup for the CTF V competition problems.

Reverse Engineering[edit]

Stacktastic[edit]

[100 Points] Wth do push and pop mean??? Could you help me out and tell me what the stack will look like (from bottom to top) after this runs.
Hint: The flag is the elements on the stack from bottom to top, wrapped in ahsCTF{}

The challenge also provides the file stacktastic.asm.

When opening stacktastic.asm in a text editor, we see the following assembly code:

section	.text
	global _start
_start:
	push s
	pop ecx
	push s
	push t
	push h
	push i
	pop ecx
	pop ecx
	push a
	push a
	pop ecx
	push c
	push k
	pop ecx
	push u
	pop ecx
	push k
	push s
	push _
	push _
	pop ecx
	push r
	push r
	pop ecx
	push _
	push c
	push o
	push o
	push _
	pop ecx
	pop ecx
	push o
	push l
	
	;;; printing stack
	; code used to print stack has been redacted
	
	;;; exit program
	mov	eax, 1
	int	0x80

;;; constants
section .data
a db 'a'
b db 'b'
c db 'c'
d db 'd'
e db 'e'
f db 'f'
g db 'g'
h db 'h'
i db 'i'
j db 'j'
k db 'k'
l db 'l'
m db 'm'
n db 'n'
o db 'o'
p db 'p'
q db 'q'
r db 'r'
s db 's'
t db 't'
u db 'u'
v db 'v'
w db 'w'
x db 'x'
y db 'y'
z db 'z'
_ db '_'

Prerequisate: https://en.wikipedia.org/wiki/Stack_(abstract_data_type)

This code seems to define some constants that represent letters of the alphabet. These constants are later pushed on and popped off the stack using the push and pop instructions. The ecx after the pop instructions refers to the ecx register of where to store popped data. We can manually figure out what the stack will look like after this code runs by typing whatever characters are pushed in a text file, and clicking backspace upon a pop. We get "stacks_r_cool". We can wrap this in the flag wrapper to get ahsCTF{stacks_r_cool}.

Decompile Trial[edit]

[125 Points] I stole this file off the server, but need to figure out how it works!!! Can you figure out the correct input and get me the flag?

The challenge also provides the executable file decompileTrial.

Let's import this file into Ghidra in order to see the source code. Here's what Ghidra decompiled from the main() function:

void main(void)

{
  long lVar1;
  uint uVar2;
  long in_FS_OFFSET;
  uint input;
  int i;
  uint encodedFlag [38];
  
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  encodedFlag[0] = 0x62;
  encodedFlag[1] = 0x69;
  encodedFlag[2] = 0x74;
  encodedFlag[3] = 0x44;
  encodedFlag[4] = 0x55;
  encodedFlag[5] = 0x47;
  encodedFlag[6] = 0x7c;
  encodedFlag[7] = 0x65;
  encodedFlag[8] = 0x31;
  encodedFlag[9] = 0x6f;
  encodedFlag[10] = 0x55;
  encodedFlag[11] = 0x60;
  encodedFlag[12] = 0x67;
  encodedFlag[13] = 0x34;
  encodedFlag[14] = 0x41;
  encodedFlag[15] = 0x73;
  encodedFlag[16] = 0x60;
  encodedFlag[17] = 0x75;
  encodedFlag[18] = 0x69;
  encodedFlag[19] = 0x34;
  encodedFlag[20] = 0x60;
  encodedFlag[21] = 0x53;
  encodedFlag[22] = 0x66;
  encodedFlag[23] = 0x77;
  encodedFlag[24] = 0x34;
  encodedFlag[25] = 0x73;
  encodedFlag[26] = 0x25;
  encodedFlag[27] = 0x66;
  encodedFlag[28] = 0x60;
  encodedFlag[29] = 0x66;
  encodedFlag[30] = 0x4f;
  encodedFlag[31] = 0x68;
  encodedFlag[32] = 0x6a;
  encodedFlag[33] = 0x6f;
  encodedFlag[34] = 0x34;
  encodedFlag[35] = 0x34;
  encodedFlag[36] = 0x73;
  encodedFlag[37] = 0x7e;
  i = 0;
  while (i < 0x26) {
    puts("Enter your input! Correct input will be one character of the flag in hex!");
    __isoc99_scanf(&DAT_00102052,&input);
    uVar2 = f(input);
    if (uVar2 == encodedFlag[i]) {
      puts("Correct character!");
    }
    else {
      puts("Incorrect character.");
    }
    i = i + 1;
  }
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

The code seems to create an array called encodedFlag and assign values to its indexes. The program then scans user input, runs it through a function called f(), and compares it to the current index of the array. If the values are equal, the program tells us our input is the hex representation of a character in the flag. The program will use a loop to repeat this process for every element in encodedFlag. It seems that we will input one character of the flag at a time (in hex), and the program will tell us if out character was correct. Instead of manually trying every character, we can decode the encodedFlag array. To do this, let's look at how f() encoded our input. Here is the decompiled code for f():

uint f(uint num)

{
  return num + 1;
}

The f() function seems to add 0x1 to whatever character we input. That means that the values in encodedFlag will be 0x1 higher than the actual hex values of the flag. We can subtract 0x1 from every element in encodedFlag to get the actual character of the flag. After doing that, the characters of the flag in hex seem to be:

0x61,0x68,0x73,0x43,0x54,0x46,0x7b,0x64,0x30,0x6e,0x54,0x5f,0x66,0x33,0x40,0x72,0x5f,0x74,0x68,0x33,0x5f,0x52,0x65,0x76,0x33,0x72,0x24,0x65,0x5f,0x65,0x4e,0x67,0x69,0x6e,0x33,0x33,0x72,0x7d

We can covert these hex values to their ASCII representation using online tools. We get ahsCTF{d0nT_f3@r_th3_Rev3r$e_eNgin33r}.