Sunday, May 24, 2015

ASIS Quals CTF 2015 "Selfie" - practice session write-up

Hi folks!

This is the first of (hopefully!) many posts I like to call "practice write-ups". Wat's dat? Well... while taking pleasure in playing CTF's ans solving challenges, I often find that I don't get to try out every CTF challenge and if I do, I usually just try to solve it as quickly and painlessly as possible to get the flag. So, in an attempt to improve my skills and play around with fun CTF challenges, I decided to start writing these blog posts to share what I learned, and possibly get feedback from others on how to improve.

All good? Excellent!
And now... to the fun part :)




The file can be downloaded from: http://tasks.asis-ctf.ir/selfie_5867d7cda31739aa81dec7b4355b2fab

The only thing we are told on the download site is: 
"Find the flag in this file." :)

..so, not much help there.


First, lets see what we find out about the app without running it!


# file selfie
selfie: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x5bd0390c80a9727d604eda8d4bddd7af86eff94e, not stripped

# ldd selfie 
 linux-vdso.so.1 =>  (0x00007fff58cee000)
 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f92257f0000)
 /lib64/ld-linux-x86-64.so.2 (0x00007f9225b97000)

Obviously, we are dealing with a 64-bit ELF which uses shared libs (that actually makes things a lot easier since library code will not be integrated in the binary, and thus easier to read through!).

Another great thing is its not stripped! This means that function names will be preserved (must be Christmas!). ldd gives us the libs that are dynamically loaded - nothing rely of note here (ld needed for dynamic linking, good old libc, and vdso which is another system lib injected into every process by the kernel).

So far so good! Let's take a look at the function list!

# nm selfie 
0000000000600d70 d _DYNAMIC
0000000000600f48 d _GLOBAL_OFFSET_TABLE_
0000000000400be0 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
0000000000400d50 r __FRAME_END__
0000000000600d68 d __JCR_END__
0000000000600d68 d __JCR_LIST__
0000000000600fe0 D __TMC_END__
0000000000600fe0 B __bss_start
0000000000600fd0 D __data_start
00000000004007e0 t __do_global_dtors_aux
0000000000600d60 t __do_global_dtors_aux_fini_array_entry
0000000000600fd8 D __dso_handle
0000000000600d58 t __frame_dummy_init_array_entry
                 w __gmon_start__
0000000000600d60 t __init_array_end
0000000000600d58 t __init_array_start
0000000000400bd0 T __libc_csu_fini
0000000000400b60 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
0000000000600fe0 D _edata
0000000000600fe8 B _end
0000000000400bd4 T _fini
0000000000400618 T _init
0000000000400730 T _start
0000000000600fe0 b completed.6661
0000000000600fd0 W data_start
0000000000400760 t deregister_tm_clones
                 U fclose@@GLIBC_2.2.5
                 U fopen@@GLIBC_2.2.5
0000000000400800 t frame_dummy
                 U fread@@GLIBC_2.2.5
                 U fseeko@@GLIBC_2.2.5
                 U ftello@@GLIBC_2.2.5
0000000000400826 T loading
00000000004008a0 T main
                 U malloc@@GLIBC_2.2.5
                 U printf@@GLIBC_2.2.5
                 U putchar@@GLIBC_2.2.5
                 U puts@@GLIBC_2.2.5
00000000004007a0 t register_tm_clones
                 U rewind@@GLIBC_2.2.5
                 U strlen@@GLIBC_2.2.5
                 U usleep@@GLIBC_2.2.5
 

Judging from the blue highlighted functions, the binary is probably going to do some file reading. This made me double check if I didn't miss downloading an additional file from the CTF (turns out I didn't). Interestingly, there seems to be no file writing, just reading! But what is being read?!?! Guess I'll have to disassemble this bad boy to find that one out...the red functions will probably be our targets (notice how the names are nicely preserved).
Note to self: although the frame_dummy function looks suspicious, it actually is not! Its actually a function in every ELF and it is used in the process of loading a program under linux systems. More on the matter can be found on this page.
First, let's start by getting the strings to see if there is anything interesting.

# strings selfie
/lib64/ld-linux-x86-64.so.2
libc.so.6
fopen
puts
putchar
printf
rewind
strlen
fclose
malloc
ftello
usleep
fread
__libc_start_main
fseeko
__gmon_start__
GLIBC_2.2.5
fffff.
-\|/
ASIS{4a2H
cdaf7d77H
165eb3fdH
b70 : i H
am the fH
irst parH
t of flaH
        H
    f
<TuU
<ru>
<yu'
[]A\A]A^A_
[1A%s%c
[1A%s 
%d[%c]
;*3$"

Aha! The flag at last!!1! ..or so it seems. It seems a part of the flag is actually embedded in plaintext somewhere in the binary. Running the binary actually gives us this part of the flag upfront ...


# ./selfie
ASIS{4a2cdaf7d77165eb3fdb70 : i am the first part of flag        

Try harder :)

Hmm... that's odd - I didn't see the "Try harder string" at all in the strings output. Let's try searching the entire file for the "Try harder" string.


# strings -a selfie | grep Try
Try harder :)

Ok... so obviously its somewhere in the binary, just not in the initialized and loaded sections of object files. Lets finally go and see what this bad boy does under the hood!

(In retrospect, at this point I had actually made a mistake in not researching the location of the "Try harder" string a bit more because it led me on a wild goose chase - as you will see below)

Using your favorite debugger/disassembler, its easy enough to get the source code of main and loading functions. You can even do a sweet one-liner with GDB:
# gdb -batch -ex 'file selfie' -ex 'disassemble main'

After quite a lot of tinkering and reversing, this is a rough sketch of what the main function looks like:


int main(...usual main stuff...)
{
  argv_pointer = argv;
  ptr_to_alloc_space = 0LL;
  
  size_of_self = 0;
  offset_to_try_harder = 13848;
  
  strcpy(flag_buffer, "ASIS{4a2cdaf7d77165eb3fdb70 : i am the first part of flag\t");
  length_of_flagg_buffer = strlen(flag_buffer);
  
  index = 0;
  putchar(10);
  while ( index < length_of_flagg_buffer )
  {
    current_character = (unsigned __int8)flag_buffer[index];
    a_temp_buffer[index] = current_character;
    a_temp_buffer[index + 1] = 0;
    loading((__int64)a_temp_buffer, (__int64)argv, current_character, probably_dash);
    ++index;
  }
  
  putchar(10);
  
  // gets size of self
  stream_to_self = fopen(*argv, "r");
  fseeko(stream_to_self, 0LL, 2);
  size_of_self = ftello(stream_to_self);
  rewind(stream_to_self);
    
  ptr_to_alloc_space = malloc((signed int)(size_of_self + 1));
  
  count_of_elements_read = fread(ptr_to_alloc_space, 1uLL, (signed int)size_of_self, stream_to_self);
  *((char *)ptr_to_alloc_space + (signed int)size_of_self) = 0;
  
  strcpy(str_14_spaces, "              ");
  str_14_len = strlen(str_14_spaces);
  
  // only invoked when 2 arguments are provided !
  if ( argc == 3 )                              
  {
    for ( i = 0; (signed int)i < (signed int)size_of_self; ++i )
    {
      if ( *((char *)ptr_to_alloc_space + (signed int)i) == 84  // T
        && *((char *)ptr_to_alloc_space + (signed int)i + 1) == 114 // r
        && *((char *)ptr_to_alloc_space + (signed int)i + 2) == 121) // y
        printf("%d[%c]\n", i, *((char *)ptr_to_alloc_space + (signed int)i), argv_pointer);
    }
  }
  
  for ( j = 0; j < str_14_len; ++j )
    str_14_spaces[j] = *((char *)ptr_to_alloc_space + offset_to_try_harder + j);
  
  puts(str_14_spaces);
  
  fclose(stream_to_self);
  return 0;
}

As can be seem, the ELF clearly makes a reference to the "Try harder" string in itself at offset 13848 (0x3618).
It then appears to iterate over the array holding the first part of the flag and calling a the loading function. It the opens a stream to itself and starts reading its own image from the disk (hece the name "selfie" I assume). The reading seems to only be used so that we can get its size on disk.
Another array is initialized with 14 spaces and then iterated over starting from the offset of the "Try harder" string. The only strange thing here is that it does not enter into a conditional IF statement if we did not supply at least two parameters. Running the ELF with two parameters just prints the offset of the "Try harder" string and its first letter. The parameters themselves do not seem to be used at all, and thus irrelevant.

When I first started to analyze this ELF I assumed it would end in having to modify some part of the binary so that it could be correctly decoded and thus show the second part of the flag. I though maybe providing a meaningful set of parameters was the trick. However, after looking at the main function, it really does not hold any sort of encoding/decoding routine, just a bunch of iterating over initialized arrays.

All is not lost! We still have the loading function - this is where true magic obviously begins!!1!

int loading(a_temp_buffer, argv, current_character, probably_dash)
{
  for ( i = 0; i <= 7; ++i )  // just the irritating prints loader thingy...
  {
    int some_huge_num = 796679213;
    printf("\x1B[1A%s%c\n",
      a_temp_buffer,
      *((char *)&some_huge_num
      + (signed int)(((((unsigned int)((unsigned __int64)i >> 32) >> 30) + (char)i) & 3)
                   - ((unsigned int)((unsigned __int64)i >> 32) >> 30))));
    usleep(0x124F8u); // sleep for 75000 microseconds
  }
  return printf("\x1B[1A%s \n", a_temp_buffer, current_character, probably_dash);
}

The red part certainly looks like some decoding routine... however, after a bit of debugging, it becomes obvious that this is just a routine that makes the "loader" thingy rotate. If you started the ELF, you noticed it takes a while for it to "load". The obvious function to blame for this is usleep! Searching for the value 0x124F8 in your favorite hex editor (watch out for endian-stuff!) makes it easy to make the delay a bit shorter by changing it to something smaller.

Still... it does not really bring us closer to the second part of the flag! :(
At this point I started looked closer at the location where the "Try  harder" string was in the ELF and noticed it was surround with more "stuff".


The "GCC: Debian..." stuff seems to be legitimate "ELF stuff" (I'm not one of those guys that know the ELF format by heart, but I remember seeing it in other challenges). After searching the "GCC Debian" string, it seems to appear twice (the first time near the begging of the ELF)! Now that does in fact look strange - why does this sequence repeat, and why is it also near the header?

Scrolling a bit further up from the "Try harder" string there seems to be more header specific stuff, and (at last the smoking gun!) something that appears to be the start of an ELF... but wait, we are nowhere near the beginning of the ELF (at 0x2300 to be precise), why is there another header here???


Obviously, this is an embedded ELF! I quickly extracted the ELF and began searching for additional embedded ELF's (fool me once ...). After a few tries, it would appear as though this was the only one in there. In retrospect... I should have noticed the location of the "Try harder" string sooner. Also, the size of the selfie ELF is a bit to large for such a simple app (around 19KB).

Running file, strings, ldd, nm on the new ELF nothing special other than the fact that it is retrieving the current time (via time function) and that it has a main function and a function named sitoor. I started with the good-old main function.


int main(..the usual...)
{
  counter_190 = 0xBE;
  pointer_to_buffer = initialized_buffer;

  while ( counter_190 )
  {
    *(_QWORD *)pointer_to_buffer = *(_QWORD *)pointer_to_some_buffer;
    pointer_to_some_buffer += 8LL;
    pointer_to_buffer += 8;
    --counter_190;
  }

  *(_WORD *)pointer_to_buffer = *(_WORD *)pointer_to_some_buffer;
  current_timestamp = (unsigned int)time(0LL);

  sitoor(current_timestamp);

  printf("%lu %lu\n ", g_r, current_timestamp - g_r * g_r);

  time_gr_sqare = current_timestamp - g_r * g_r;
  some_calculation_result = (unsigned __int64)((g_r - ((signed int)current_timestamp - (signed int)g_r * (signed int)g_r)) / 2) - 49;
  printf("%d\n", some_calculation_result);

  if ( 3013 * g_r == 3286 * time_gr_sqare + 5 )
  {
    for ( i = 0; (signed int)i < (signed int)some_calculation_result; ++i )
    {
      if ( !(unsigned int)sitoor((signed int)i) )
        putchar(initialized_buffer[i + 1]);
    }
  }
  else
  {
    dest = 0LL;
    dest = (char *)malloc(1394uLL);
    strcpy(dest, hidden);
  }

  return 0;
}

Finally, some nice math!  :)
It seems the ELF is getting the current time and doing a bunch of calculations and printing (or not printing) a series of characters from an initialized buffer. As can be seen from the line bellow, the buffer is located at offset 0x980 within the binary.


0000000000400705    mov     edx, 0x0000000000400980


Looking at the blue while loop in main, it seems that the buffer is located from 0x980 to 0x5F0 (0xBE times 8). Using a hex editor, I just extracted that buffer and began looking for signs of a flag. Unfortunately, the buffer seems to be jumbled up quite a bit, so I couldn't really see anything flag-like.

At that point I started looking at the last remaining thing there is - the sitoor function. It appears to take the timestamp and do some wild math operations to calculate the offset within the buffer.
Excelent! That look like the decoding function I was looking for!!1! :)
I opened up my editor and started experimenting with the buffer and the sitoor function. After a bit of trial and error, it becomes apparent that the purple code in main does not actually do anything, so i discarded it. What remained can be seen bellow.


#include "stdafx.h"
#include "string.h"

signed long g_r; 

long sitoor(signed long curr_timestamp)
{
  long result; 
  signed int i; 
  long double tmp_var; 

  if ( curr_timestamp * curr_timestamp == curr_timestamp )
  {
    result = 0LL;
  }
  else
  {
    tmp_var = (long double)(curr_timestamp / 2);
    for ( i = 0; i < 1000; ++i )
      tmp_var = (tmp_var * tmp_var + (long double)curr_timestamp) / (tmp_var + tmp_var);
    g_r = (signed long)tmp_var;
    result = 0.0 != tmp_var - (long double)(signed long)tmp_var;
  }
  return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
 long i;
 const char buff[] = "\x93\x74\x68\xb2\x47\x65\x64\x00\xd9\xee\x20\xb5\x9a\x55\xe4\x62\x75\x73\xec\x1e\xa5\xfa\x8d\x2d\x9c\x96\x65\x68\x26\x3d\x81\x59\x10\x0f\x91\xaa\x95\x63\x86\xc3\xc0\x3c\xc7\x11\x57\xd9\x92\xad\x9b\x73\x6f\xf6\xff\xf4\x7b\x57\x1b\xfe\x5a\x18\xa6\xc2\xfb\x7e\x17\x64\xd3\x4e\xbe\x39\x2a\x0d\xe9\x1d\x35\xda\xc4\x03\xab\xa6\x58\x08\x6e\x1d\x73\xa1\xd4\xb0\xe7\x7a\x0b\xf0\x2c\xa7\x57\x56\x35\xec\xcb\xad\xe8\x20\x97\x8e\xf3\xf1\x28\x60\x42\x5c\x13\xfc\x3e\x5e\x89\x1d\x72\x14\xc7\xb8\xc0\x4a\x70\xf1\x2b\x50\x8f\x14\x3a\xfe\xb3\x42\xfc\x37\x3c\x66\x81\xf0\x74\xbf\x65\x63\xd3\xdf\xea\x61\x6d\xe9\x37\xaf\xd1\x35\x31\x51\x52\xd7\x9c\x26\x7e\xc5\xb3\x64\x40\xbe\x11\xb4\x14\xe9\x8a\x3e\x72\x50\x2b\x57\x83\xda\x8a\xe2\xc4\x9f\x46\xc4\x2b\xb6\xaa\x22\xbd\x7f\xc3\x89\x07\xe4\xd0\x79\xef\xc4\x3e\x74\xbf\x4c\xd3\x78\x93\x61\x93\x6b\xd3\x90\xd5\x6a\xad\x81\x80\xd4\x8d\xdd\xc2\x09\xf9\x64\xe8\x3a\xba\x6e\x12\xda\x20\x53\xcf\x78\xac\x94\xf4\xdb\x00\xdf\x33\x10\x25\xb0\x9c\x05\xdd\x63\x72\x7a\x99\x8f\x4b\xac\xee\x56\x18\x98\xc2\x12\xd2\x6f\x87\x7a\x7b\xdd\xb3\xff\x76\x77\x0c\x64\x30\x4c\x3d\x10\x6e\xa3\xac\x8c\x4f\x5e\xa6\x01\x4d\x42\x6f\x98\xb7\xad\x96\xee\xc0\x8b\x66\xd9\xf0\xf9\xf0\x5e\x29\x96\xac\x8f\x91\xa3\x3a\xf7\x0b\xac\x03\x4c\x74\x67\x71\xf5\x4c\x48\x3f\x8d\x2f\xc1\xc3\xcc\x81\xa7\xb6\x7c\xe3\x20\x48\x7b\xc4\x44\xda\x76\xf3\xcf\xfb\x9e\x57\x71\x81\x8b\x97\x2d\x49\xef\xcf\xb0\xf4\x2a\x09\x69\x7d\x31\x9b\x08\x9d\x2f\x3c\x9e\x68\x47\x2a\x60\x66\xd0\x91\xb0\x55\x5f\x9f\x4c\x8d\x84\xf0\x71\x4c\x7a\x27\x6e\x16\xe1\x56\x30\x11\x8f\x16\x94\x92\x83\x42\x98\x6d\x18\x4c\x3a\x1a\xd5\x8b\x50\x6d\x9c\x0c\x6c\xb2\x8a\x85\x9b\x50\x0c\x60\x78\x3e\xcb\xca\xd8\x88\x9c\xa5\x1d\x9f\x4a\x83\xff\x9e\xac\x37\xc2\x84\xb9\xff\xaa\x0c\x45\x18\xb5\xc9\x0a\x8b\x9e\x69\x07\x53\x39\x61\x9b\x91\x5d\x29\x5c\xfe\x76\x7e\x57\x20\xfd\x2c\xc6\x56\xd0\xd7\x00\x55\xf3\xf6\x22\x4e\x37\x36\x6f\x44\x95\x0f\xa0\x9a\x46\x18\xe3\x50\x9a\x21\x01\xa6\xb1\x1f\x0e\xab\x67\xba\x2d\x6a\xa4\x24\x1c\x9f\xfe\xe4\x6b\x6b\x24\x7f\x6d\xa2\x31\xea\x12\xd5\xa6\x2c\x08\x00\x05\x94\x45\xd9\xe0\x96\x55\x37\xfe\xb0\xf7\x99\xfa\xd1\xed\xdd\xc3\xd8\xc5\xaf\xc4\x20\x47\x8c\x37\xaf\x06\x12\xd1\x64\xab\x1b\x8b\x86\xeb\x47\x07\xdf\xb5\x94\xb2\x0e\x0e\xc1\x5a\xf9\xe0\x11\x26\x34\x8c\x52\x75\x43\xff\xd9\x7c\x1f\xdf\x48\x60\xe8\xf7\x38\x35\xc7\xbc\x72\x69\xbe\x5d\x89\xab\x3b\x1e\x01\x25\x22\x60\x5f\x73\xfa\xc8\x96\x41\xd9\x6b\x11\x53\xa2\x27\x66\x27\x98\x38\xa8\xf7\xce\x28\x41\x7f\x3b\x37\x3c\xc5\x85\xb5\xe8\xaf\x4e\x56\x0a\x62\x8a\xb9\xbb\xec\x73\xe8\x3c\x7a\x7a\x72\x6e\x30\xa8\x01\x44\x0e\x06\x14\x71\x46\xc2\x27\x7e\x13\xa2\x0d\xd3\xa9\x4a\x01\xb8\x22\xe3\x40\x14\xc4\x93\xca\x70\x11\xb0\xdd\x42\xef\x01\x5e\x97\x97\x9b\x4a\xd0\xba\xd1\xd1\x1f\x3a\x47\xe8\x40\x4d\xc1\x17\x28\x85\x53\x48\x34\x47\xe8\x9f\xc3\x9b\x71\x48\x81\x3f\x95\x4b\x0d\x13\x16\xfb\xb6\xc1\x01\x0c\x18\xbd\xdc\x7f\x70\x37\x9a\x16\x8e\xe6\x3e\xcc\x50\x86\x32\x69\x84\xef\xd1\xe4\x44\x69\x20\x43\x43\x3b\xfb\x40\x34\xf4\xdb\x2d\x8a\x0f\xd0\x3e\xf1\x32\x2b\xfa\xd4\x4f\x37\xd8\xd9\x49\x9e\xfd\x03\xff\x45\x41\x30\x92\x9a\x38\xb4\x20\x15\x57\x81\x9b\xca\xff\xe2\x81\x42\x7e\x0f\xee\xb1\x1b\x79\xfa\xe8\xc1\xae\x39\x9a\xac\x45\x0e\xa4\xe4\x3f\x0c\x2d\xaa\x75\x75\xd2\x02\x84\x90\xfc\xe3\x22\x30\x15\xf7\x04\x32\xa3\x0e\x3c\x60\xfe\x1d\xac\x92\xe4\x5b\x7f\x1f\xa4\x6b\xdd\x2b\x1d\xa2\x77\x7e\x76\xad\x18\x2e\xff\x1e\x2e\x7e\xb4\xca\x55\x3a\x33\x56\x8b\x36\x9b\x68\xc1\xa0\xcc\x92\xbc\x1a\x0f\x80\x86\x8d\xda\x8f\x5f\x36\x04\xdb\x78\x9f\x0b\xd4\x15\xca\xb3\x33\x45\x9d\xe2\xde\x75\x05\x2b\x71\xa3\x7c\x06\x2f\x19\xb5\xa2\x14\x0a\x5c\x71\x2a\x7e\x3a\x3c\xb2\x54\x7f\x98\x67\xe6\x61\xaf\x1f\xb4\xc3\xb1\x61\x6b\x86\xd8\xe0\x67\xcc\x91\xb7\xad\xaa\x23\x26\xd8\xa7\x5d\x67\x0e\x16\x98\x0a\x05\xfd\xbb\xbc\x25\x08\x57\x72\x4d\x26\x5f\x42\x2f\x87\xb7\xd0\x29\xbe\xb2\x0f\x8c\xac\xf6\xa0\x78\x6f\xd0\xe7\x98\xb4\x0d\x22\x28\x45\x36\x7e\xc3\x8a\x0c\x62\xfa\xb7\xfb\x1e\x2b\xd5\x06\x78\x3d\x4b\x8e\x49\x35\x8c\x09\x69\x51\x7d\xb4\x42\x61\x16\xc2\xea\x7f\xab\x14\x8b\x2c\x40\x16\xd0\x0e\xaa\xa6\x57\xae\xa3\x68\x4f\xa1\x66\xa0\xde\x44\x42\xfa\xcc\xb4\x94\x4c\xc0\xd1\x3f\x0b\x03\x05\x34\xf0\xc5\xe4\x05\x40\x37\x00\x57\x1a\x05\x27\x34\x70\x19\x75\x96\xb1\xf6\xcb\x01\x87\xf3\xf8\x77\xb9\x78\x13\x18\xda\xeb\x37\x95\xcd\x19\xe7\x53\x7e\xe1\xa4\xe0\x70\xe2\x54\xfc\x72\x82\xe0\xdb\x0c\x3e\x38\x05\x91\x91\xb1\x87\xa4\x3e\xf3\x67\x79\xf0\xce\x67\x31\x8f\x39\x73\xaa\x84\x46\x7b\xcc\xd9\xe4\x4f\xd0\xa4\x1e\xfa\xdc\x53\xc7\x3a\x04\x51\xf7\xf8\x99\xea\x6e\x41\x86\x2c\xc7\x66\x51\x04\xb3\x51\xe2\x45\x9d\xd9\x4a\x15\xf1\xfc\x06\x3f\x40\x5c\xde\x7d\xe4\xb9\x5e\x01\x74\x91\x6d\x76\x7e\xa9\x68\x67\x5c\xcc\x91\xe3\x20\x61\xeb\x79\x53\x1c\x19\x33\xbd\xca\x52\xa0\x81\x76\x6d\x1e\xd5\xe8\x47\xa0\x4d\x60\xdf\xab\x11\xe1\x28\xfe\x22\xd0\xfb\x43\xe5\x45\x66\xa0\xda\xb0\x49\x50\xf1\xa6\x81\x24\xe7\x78\x87\x98\x7c\x83\x18\xd3\xea\xc7\x8c\xea\x5a\xf6\xaa\x4f\xce\xed\xdd\x6c\xc3\x36\x07\x28\xb1\xd9\x39\x21\xed\x04\x15\xfd\x3c\x0c\xac\x13\x1f\x8d\xc1\xf2\xdf\x5e\xac\x59\x39\x71\x8c\x66\xbe\x2e\x5a\x8b\x96\xcf\x59\x62\x93\x7b\xaf\xbd\xcb\x6c\x0b\x5f\x03\x06\x01\x89\xc2\x8b\xfc\xda\xa7\xcc\xfa\x50\xb3\x11\x79\x1a\x7d\xab\x8a\x7f\x0a\x6f\x45\x63\xa7\x85\x98\x76\xdf\x3f\x6e\xb1\x02\x39\x53\x2e\xe7\xe3\x1e\x73\xe8\x55\x10\x8b\x97\xe1\x58\x8b\x77\xa9\xde\x5c\xa8\x74\x82\x5f\x19\xfd\xdf\x51\xb8\xd9\x48\x52\x4d\xa7\x75\x7e\x38\x77\xf8\xd5\x74\x22\x20\x98\xb7\x5e\xcb\x63\xe9\x00\x89\x13\x15\xb7\x24\x6c\xf9\x33\xd8\x0d\x07\x69\x05\xc9\x02\xa9\x25\x00\xe8\x65\xc6\xa3\x82\x25\x61\x6f\x7b\x5a\xaa\x17\x6d\xd9\x2f\xb3\xd5\x5f\xff\xdb\x48\x79\xf1\x0d\xa0\xdd\x57\x24\xb2\xf5\x6d\x8c\x03\xe0\xa0\x69\x77\xb3\xb9\x85\xc6\x3d\xe7\x14\x76\x71\x80\x39\x82\xf7\x94\x6d\x32\xe0\xf0\x99\x21\x0d\x78\xb0\x28\x3a\x74\x80\xd5\xc9\x1e\x44\x3c\x39\x5c\x04\x24\xdb\x9b\x5d\x61\x47\x92\xca\x1d\x7d\x6b\x17\x43\xd7\x0f\x56\x1c\x7d\xd7\x2c\x6e\xc0\xe1\x9a\xb8\x47\x6b\x01\x63\x07\x94\x4e\xd6\x41\x3a\x7e\x97\xa9\xe5\x62\xef\xc9\x8a\xb2\x27\xe6\x2d\x21\x99\x42\x82\xcf\x27\x8c\xb0\xb2\x00\xa1\xd5\x38\x3e\xcd\x82\xfb\xc9\x85\x40\xd7\x50\x6a\x37\xf8\xa4\xe4\x6b\x54\x20\x03\xcc\xde\x6d\xd4\xd4\x06\x76";
 
 g_r = 0;
 for(i = 0; i< 2720713; i++){
  if ( !(unsigned int)sitoor((signed int)i) ){
   printf("%c", buff[i + 1]);
  }
 }
}

As you can see I tried to brute force my way into finding the right timestamp that would decode the buffer correctly (and have thus set the value for i a bit high). Luckily, the correct values are right at the beginning, so by running the above one is presented with the glorious goodness which is the second part of the flag.


the secodn part of flag is: 93a641a99a}

P.S. To be fair, I did not realize that the purple code in main is actually preventing us from getting to the correct values and decoding the buffer. In my first try I embedded  3013 * g_r == 3286 * time_gr_sqare + 5  check before the call to sitoor, which yielded the following (unsuccessful results):


2720713 => the s
67592379 => the secodn par¦
132421600 => the secodn par¦    ?q
218846413 => the secodn par¦    ?q
326866818 => the secodn par¦

Still, it showed me that I was on the right track, and with a bit of trial end error I removed the purple check, which resulted in the flag being reviled.

This was fun!  :)

P.S.S. Here's a cool trick to quickly find out if there is an embedded ELF. As you can see, the standard ELF entry point functions are found twice!


# strings -a selfie | sort | uniq -c | grep main
      2 __libc_start_main
      2 __libc_start_main@@GLIBC_2.2.5
      2 main


No comments:

Post a Comment