Kill My Linux

March 28 2017

# #

So I have another reverse question. This one should be easy, all you have to do is to let this binary run, and it will eventually print the correct answer. :)

  • Hint : The binary is dynamically linked.
  • Hint : How is the executable crashing the system? Can you prevent the executable from doing random BC on your system?

  • Flag Format : /flag{[a-z]+}/

Provided kill-my-linux

Solution

So we start off with the basic tests.

$ file kill-my-linux
kill-my-linux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=98869d89b9397811a12119d5e71002c02b0a4797, not stripped

Hmm, seems to be a ELF file, which is dynamically linked and also not stripped. That is quite interesting, because that enables us to view exactly what functions are being called here.

$ gdb kill-my-linux
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from kill-my-linux...(no debugging symbols found)...done.
(gdb) info functions
All defined functions:

Non-debugging symbols:
0x0000000000400788  _init
0x00000000004007c0  free@plt
0x00000000004007d0  putchar@plt
0x00000000004007e0  omp_get_thread_num@plt
0x00000000004007f0  memset@plt
0x0000000000400800  __libc_start_main@plt
0x0000000000400810  calloc@plt
0x0000000000400820  omp_get_num_threads@plt
0x0000000000400830  fflush@plt
0x0000000000400840  GOMP_parallel@plt
0x0000000000400850  execlp@plt
0x0000000000400860  sleep@plt
0x0000000000400870  fork@plt
0x0000000000400880  usleep@plt
0x00000000004008a0  _start
0x00000000004008d0  deregister_tm_clones
0x0000000000400910  register_tm_clones
0x0000000000400950  __do_global_dtors_aux
0x0000000000400970  frame_dummy
0x0000000000400996  main
0x0000000000410e75  main._omp_fn
...
0x0000000000451e77  main._omp_fn
0x0000000000451f10  __libc_csu_init
0x0000000000451f80  __libc_csu_fini
0x0000000000451f84  _fini
(gdb)

This is quite an interesting output.

We see a whole lot of functions called main._omp_fn. We also see some other omp related functions like GOMP_parallel@plt

This means that the file was compiled with OpenMP, a library to do multi-processing in C.

We decompile the main function to see what exactly is being parallelized.

$ objdump -S kill-my-linux
...
0000000000400996 <main>:
400996:	55                   	push   %rbp
400997:	48 89 e5             	mov    %rsp,%rbp
40099a:	48 83 ec 20          	sub    $0x20,%rsp
40099e:	89 7d ec             	mov    %edi,-0x14(%rbp)
4009a1:	48 89 75 e0          	mov    %rsi,-0x20(%rbp)
4009a5:	be 01 00 00 00       	mov    $0x1,%esi
4009aa:	bf 30 75 00 00       	mov    $0x7530,%edi
4009af:	e8 5c fe ff ff       	callq  400810 <calloc@plt>
4009b4:	48 89 45 f0          	mov    %rax,-0x10(%rbp)
4009b8:	bf 88 13 00 00       	mov    $0x1388,%edi
4009bd:	e8 be fe ff ff       	callq  400880 <usleep@plt>
4009c2:	b9 00 00 00 00       	mov    $0x0,%ecx
4009c7:	ba 00 00 00 00       	mov    $0x0,%edx
4009cc:	be 00 00 00 00       	mov    $0x0,%esi
4009d1:	bf 75 0e 41 00       	mov    $0x410e75,%edi
4009d6:	e8 65 fe ff ff       	callq  400840 <GOMP_parallel@plt>
4009db:	b9 00 00 00 00       	mov    $0x0,%ecx
4009e0:	ba 00 00 00 00       	mov    $0x0,%edx
4009e5:	be 00 00 00 00       	mov    $0x0,%esi
4009ea:	bf 08 0f 41 00       	mov    $0x410f08,%edi
4009ef:	e8 4c fe ff ff       	callq  400840 <GOMP_parallel@plt>
4009f4:	b9 00 00 00 00       	mov    $0x0,%ecx
4009f9:	ba 00 00 00 00       	mov    $0x0,%edx
4009fe:	be 00 00 00 00       	mov    $0x0,%esi
400a03:	bf 9b 0f 41 00       	mov    $0x410f9b,%edi
400a08:	e8 33 fe ff ff       	callq  400840 <GOMP_parallel@plt>
400a0d:	bf 88 13 00 00       	mov    $0x1388,%edi
400a12:	e8 69 fe ff ff       	callq  400880 <usleep@plt>
...

So, here I see a call to usleep for 1ms, then GOMP_parallel, and then another call to usleep.

Looking across the output, I see that the entire binary is filled with the calls to GOMP_parallel followed by usleep.

Looking into the function being called…

410ed0:       89 c3                   mov    %eax,%ebx
410ed2:       c7 45 ec 00 00 00 00    movl   $0x0,-0x14(%rbp)
410ed9:       8b 45 ec                mov    -0x14(%rbp),%eax
410edc:       3b 45 e8                cmp    -0x18(%rbp),%eax
410edf:       7c 0b                   jl     410eec <main._omp_fn.0+0x77>
410ee1:       83 6d e8 01             subl   $0x1,-0x18(%rbp)
410ee5:       39 5d e8                cmp    %ebx,-0x18(%rbp)
410ee8:       7f e8                   jg     410ed2 <main._omp_fn.0+0x5d>
410eea:       eb 15                   jmp    410f01 <main._omp_fn.0+0x8c>
410eec:       e8 7f f9 fe ff          callq  400870 <fork@plt>
410ef1:       83 45 ec 01             addl   $0x1,-0x14(%rbp)
410ef5:       eb e2                   jmp    410ed9 <main._omp_fn.0+0x64>
410ef7:       b8 00 00 00 00          mov    $0x0,%eax
410efc:       83 c1 01                add    $0x1,%ecx
410eff:       eb ae                   jmp    410eaf <main._omp_fn.0+0x3a>
410f01:       48 83 c4 28             add    $0x28,%rsp
410f05:       5b                      pop    %rbx
410f06:       5d                      pop    %rbp
410f07:       c3                      retq

Huh!

So it does a parallel call of the fork().

I also find another interesting function call.

406381:       ba 00 00 00 00          mov    $0x0,%edx
406386:       be 94 1f 45 00          mov    $0x451f94,%esi
40638b:       bf 94 1f 45 00          mov    $0x451f94,%edi
406390:       b8 00 00 00 00          mov    $0x0,%eax
406395:       e8 b6 a4 ff ff          callq  400850 <execlp@plt>

That is the pointer to where /sbin/reboot string is.

So we have this program doing parallelized fork, along with parallelized reboots, along with a bunch of usleep function calls in the middle.

I see in the above info functions that there is a call to putchar, memset, and sleep. Of which sleep seems more interesting. ( Since we came into a ton of usleep calls.)

40a1b4:       bf 80 01 66 09          mov    $0x9660180,%edi
40a1b9:       e8 a2 66 ff ff          callq  400860 <sleep@plt>
40a1be:       48 8b 45 f0             mov    -0x10(%rbp),%rax

Oh dear. It also does a long sleep of 0x9660190 seconds or 157680000 seconds. Which makes it exactly 5 years.

Guessing by the nature of the question, and the hints, I suppose we can try to skip all the function calls that we don't want to. And since it is a dynamically linked, and non-stripped binary, that should be easy enough to do.

We make a block.c

int fork() {
  return 0;
}

int usleep() {
  return 0;
}

int sleep() {
  return 0;
}

int execlp(char * file, char * arg, ...) {
  return 0;
}

Then we do the following.

$ gcc -c block.c
$ gcc block.o -shared -o libtest.so

This makes a libtest.so file, which contains a dummy declaration of all the functions that we want to override.

Now comes the magic.

$ LD_PRELOAD=./libtest.so ./kill-my-linux

What LD_PRELOAD does is that it tells the dynamic linker that the file provided should be preloaded. Which means that the functions from the library are going to get overridden.

Since I am the creator of the question, I know for a fact that skipping the OpenMP function is safe by itself too. But even without skipping that part, we get to the solution in a minute.

The binary completes the multiprocessing and spits out the following.

$ LD_PRELOAD=./libtest.so ./kill-my-linux
I see you shiver with antici ...... pation. flag{tweettweet}

Flag

flag{tweettweet}

Additional Notes

This is a nod to the account of Frank Furter, who made a two tweet legendary joke that was spaced exactly 5 years apart.

The binary itself is computing a 3-D matrix addition problem in parallel, while running a transliterated brainfuck program to print the above string.

The completed C code without the garbage fork, usleep, and sleep is,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[]) {
  unsigned char *cell = calloc(30000, 1);
  unsigned char *cells = cell;
  --*cell;
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  putchar(*cell);
  fflush(stdout);
  putchar(*cell);
  fflush(stdout);
  memset(cells, 0, 30000);
  ++*cell;
  ++*cell;
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  putchar(*cell);
  fflush(stdout);
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    ++cell;
    ++*cell;
    ++*cell;
    ++*cell;
    --cell;
  }
  ++cell;
  putchar(*cell);
  fflush(stdout);
  putchar(*cell);
  fflush(stdout);
  while (*cell) {
    --*cell;
    --*cell;
    --*cell;
    ++cell;
    ++*cell;
    --cell;
  }
  ++cell;
  --*cell;
  --*cell;
  --*cell;
  putchar(*cell);
  fflush(stdout);
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  ++*cell;
  putchar(*cell);
  fflush(stdout);
  free(cells);
  return 0;
}

Which makes it quite difficult for a person to read.


Recommended Reading

Timing Attack

# # # #

Once upon a time, there was a programmer. His name was Anshul. He did not know how to work with passwords. His friend Animesh took this opportunity to do jugaad and guess the passwords so that he is able to order a lot of free shirts from MustCapture...

...

Recommended Reading

Boring Assignment

# # # #

There was once a guy, who hadn't anything to do. So he made haiku.

CTF question, related to cryptography, he presents to you.

Solve you can or not, you must at least try or else, you disappoint him.

  • Flag Format : /FLAG[A-Z]+/

Provided boring...

...