Developers Club geek daily blog

1 year, 9 months ago
We neutralize a bomb with Radare2
Hello, % %username! Today we will go to study uncountable opportunities of a framework for a reverser — radare2. In the form of experimental I took the first got bomb, it appeared from the website of University Carnegie Mellon.

Hashes
Since the binarnik can exchange I will leave just in case heshsumma:
md5sum: 1f38d04188a1d08f95d8c302f5361e9f
sha1sum: 31022a4baa524f6275209f7424c616226bc9814b
sha256sum: 8849e033691d51426c0c91a76eeb0c346eddd37e8fdf21cd93acd16669f1b461

About what in general speech?


Radare2(aka r2)an opensorsny cross-platform framework, for research of binary files (initially, by the way, the hex-editor). The main competitor of it is well-known IDA of Ilfak, but, alas, for the student it is expensive, and the free version is not on friendly terms with x86-64. And still radar it seems as more abruptly.
The binary bomb or just bomb — the performed file for training which receives a certain quantity of lines and if all lines undergo testing, congratulates on it the young analyst. These are so-called levels or phases, at us is their whole 6.

It is a little more about a framework


Radare2 as it was already told, a framework, but not just a disassembler. It includes a heap different tulz like a debagger, the hex-editor, the compiler, search ROPof gadgets and a lot of things another. For not fans of the console it also has two dampish frontends it is WebUI ($ r2 -c "=H" file) and Bokken.
The manual as usual is in man, and also for each command by adding after it "?". For example, "pd?" will issue descriptions of the commands beginning on pd.

It is a little links on a subject:

Here we go!


In addition to the most performed file kindly provided us the file with source codes. However everything that there is — input initialization, a challenge of phases, and amusing comments. Other functions are extended from the corresponding heder whom we do not have.
That file and it is rather big
/***************************************************************************
 * Dr. Evil's Insidious Bomb, Version 1.1
 * Copyright 2011, Dr. Evil Incorporated. All rights reserved.
 *
 * LICENSE:
 *
 * Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the
 * VICTIM) explicit permission to use this bomb (the BOMB).  This is a
 * time limited license, which expires on the death of the VICTIM.
 * The PERPETRATOR takes no responsibility for damage, frustration,
 * insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other
 * harm to the VICTIM.  Unless the PERPETRATOR wants to take credit,
 * that is.  The VICTIM may not distribute this bomb source code to
 * any enemies of the PERPETRATOR.  No VICTIM may debug,
 * reverse-engineer, run "strings" on, decompile, decrypt, or use any
 * other technique to gain knowledge of and defuse the BOMB.  BOMB
 * proof clothing may not be worn when handling this program.  The
 * PERPETRATOR will not apologize for the PERPETRATOR's poor sense of
 * humor.  This license is null and void where the BOMB is prohibited
 * by law.
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "support.h"
#include "phases.h"

/* 
 * Note to self: Remember to erase this file so my victims will have no
 * idea what is going on, and so they will all blow up in a
 * spectaculary fiendish explosion. -- Dr. Evil 
 */

FILE *infile;

int main(int argc, char *argv[])
{
    char *input;

    /* Note to self: remember to port this bomb to Windows and put a 
     * fantastic GUI on it. */

    /* When run with no arguments, the bomb reads its input lines 
     * from standard input. */
    if (argc == 1) {  
    infile = stdin;
    } 

    /* When run with one argument <file>, the bomb reads from <file> 
     * until EOF, and then switches to standard input. Thus, as you 
     * defuse each phase, you can add its defusing string to <file> and
     * avoid having to retype it. */
    else if (argc == 2) {
    if (!(infile = fopen(argv[1], "r"))) {
        printf("%s: Error: Couldn't open %s\n", argv[0], argv[1]);
        exit(8);
    }
    }

    /* You can't call the bomb with more than 1 command line argument. */
    else {
    printf("Usage: %s [<input_file>]\n", argv[0]);
    exit(8);
    }

    /* Do all sorts of secret stuff that makes the bomb harder to defuse. */
    initialize_bomb();

    printf("Welcome to my fiendish little bomb. You have 6 phases with\n");
    printf("which to blow yourself up. Have a nice day!\n");

    /* Hmm...  Six phases must be more secure than one phase! */
    input = read_line();             /* Get input                   */
    phase_1(input);                  /* Run the phase               */
    phase_defused();                 /* Drat!  They figured it out!
                      * Let me know how they did it. */
    printf("Phase 1 defused. How about the next one?\n");

    /* The second phase is harder.  No one will ever figure out
     * how to defuse this... */
    input = read_line();
    phase_2(input);
    phase_defused();
    printf("That's number 2.  Keep going!\n");

    /* I guess this is too easy so far.  Some more complex code will
     * confuse people. */
    input = read_line();
    phase_3(input);
    phase_defused();
    printf("Halfway there!\n");

    /* Oh yeah?  Well, how good is your math?  Try on this saucy problem! */
    input = read_line();
    phase_4(input);
    phase_defused();
    printf("So you got that one.  Try this one.\n");
    
    /* Round and 'round in memory we go, where we stop, the bomb blows! */
    input = read_line();
    phase_5(input);
    phase_defused();
    printf("Good work!  On to the next...\n");

    /* This phase will never be used, since no one will get past the
     * earlier ones.  But just in case, make this one extra hard. */
    input = read_line();
    phase_6(input);
    phase_defused();

    /* Wow, they got it!  But isn't something... missing?  Perhaps
     * something they overlooked?  Mua ha ha ha ha! */
    
    return 0;
}


After start of r2 he meets us by the accidental phrase. Then it puts the current pointer on entry-point and waits for command. The checkbox - And when opening the file at once analyzes it.
Too most it is possible to make the block of the commands beginning on a), for example afl — gets the list of functions from a binarnik. ~ — analog of grep-a (filter). Let's look at it for our functions.
$ r2 -A bomb
 -- In soviet Afghanistan, you debug radare2!
[0x00400c90]> afl~phase
0x00400ee0  28  3  sym.phase_1
0x004015c4  149  8  sym.phase_defused
0x00400efc  71  8  sym.phase_2
0x00400f43  139  8  sym.phase_3
0x0040100c  86  7  sym.phase_4
0x00401062  146  9  sym.phase_5
0x004010f4  272  26  sym.phase_6
0x00401242  81  5  sym.secret_phase

Level 1


Wonderfully, all functions from the source code on site, and at the same time also found a confidential phase. Let's look at contents of the first level at last. It is possible to make it, having displaced the pointer to a certain address of function, and then to output the necessary quantity of opkod for disassembling.
[0x00400c90]> s 0x00400ee0 # В данном случае 's' - не обязательно
[0x00400ee0]> pd 8 # дизассемблировать 8 опкодов от текущего смещения

Since r2 output from a box is just fine, for descriptive reasons for the sake of assembly listings I will post in the form of pictures.
We neutralize a bomb with Radare2
Pay attention that the radar supplied us XREF ами (that from where the control can be transferred) with mnemonik of a jump. Besides, substituted a line to the specified address and the most important — showed in the form of ascii-arrows transitions in the block.
For comparison an output with objdump
0000000000400ee0 <phase_1>:
  400ee0:   48 83 ec 08             sub    rsp,0x8
  400ee4:   be 00 24 40 00          mov    esi,0x402400
  400ee9:   e8 4a 04 00 00          call   401338 <strings_not_equal>
  400eee:   85 c0                   test   eax,eax
  400ef0:   74 05                   je     400ef7 <phase_1+0x17>
  400ef2:   e8 43 05 00 00          call   40143a <explode_bomb>
  400ef7:   48 83 c4 08             add    rsp,0x8
  400efb:   c3                      ret                    retq


Even without penetrating, it becomes clear that the first line necessary for us — "Border relations with Canada have never been better.". And by itself, when feeding to its bomb, it, lets us on the second phase.
$ ./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?

Level 2


The second option of an output of the disassembled function — by means of absolute addressing / tags. On the example of the second phase — it will look so:
[0x00400ee0]> pdf @ 0x00400efc

or, if the address is not known:
[0x00400ee0]> pdf @ sym.phase_2

We neutralize a bomb with Radare2
The ultimate goal at us — not to blow up a bomb, i.e. not to do call sym.explode_bomb challenges so and we will make a start from it. Therefore, at us both jumps of je always have to work.
The first that gets of us in the way — call sym.read_six_numbers challenge. Respectively after this challenge on top of a stack there has to be unit. Let's look what occurs in this function.
We neutralize a bomb with Radare2
Earlier r2 sorted files on function based on ret opkoda that quite often led to an output of several functions (for example, in the presence of system calls of exit ()). In similar cases when the radar incorrectly defines functions it is possible to make it manually.
[0x00400ee0]> s 0x0040149e # двигаем указатель на опкод после конца
[0x0040149e]> af+ sym.read_six_numbers `?vi $$-sym.read_six_numbers` rsn # Определение функции rsn, начинающейся с метки sym.read_six_numbers до текущего указателя.

By the way, in this example other command as argument of the first by means of matching parentheses was used''.
In the function there is nothing interesting, it gets 6 numbers from a read line and writes them one after another in the transferred pointer. Then it is convinced that numbers more than 5.
In Xi it would look approximately so:
void read_six_numbers(char *str, long long *p) {
    if (sscanf(str, "%d %d %d %d %d %d", p, p+1, p+2, p+3, p+4, p+5) <= 5)
        explode_bomb();
}


Let's return to our phase_2 function. The pointer on an array is transferred the pointer to stack top (mov rsi, rsp). Therefore, the first in line has to be — 1.
As you could notice many transitions there. The user of IDA most likely would click a space and looked at a transition graph. You will not believe, but here they are too. vim is similar there is visual-mode (command V) and at it there is that transition graph, on command V too (or at once VV). An output from everyone a mode — q
On an output there will be here such lovely ASCII of columns
We neutralize a bomb with Radare2

It is displayed perfectly, about a minimum of intersections (in comparison with last versions). It is possible to move this miracle shooters, or vim-like 'hjkl'. If you do not like an arrangement of blocks them it is also possible to move Shift+'hjkl' hot keys. At the same time the selected block moves (blue), it is possible to select it Tab/Shift-Tab.
In the first block in rbx the pointer registers in the second, and in rbp — for the end of an array of numbers. And management is thrown on a cycle in which the next numbers are in pairs compared.
mov eax, dword [rbx - 4] ; Положить предыдущее число в eax
add eax, eax             ; Удвоить его
cmp dword [rbx], eax     ; Сравнить с текущим
je 0x400f25              ; Продолжить цикл, если равны
call sym.explode_bomb    ; Взорвать бомбу, если не равны
add rbx, 4               ; Сдвинуть указатель на следующее число
cmp rbx, rbp             ; Проверить, в конце ли мы массива
jne 0x400f17             ; Если нет, то вернутся в начало
jmp 0x400f3c             ; Завершить цикл

It turns out that we need to enter sequence of powers of two from 1 to 32. Perfectly, but after all we will check what is what is necessary.
$ ./bomb
...
Phase 1 defused. How about the next one?
1 2 4 8 16 32
That's number 2.  Keep going!

Level 3


We neutralize a bomb with Radare2
Likely now the person far from the assembler, in epileptic seizures tries to get on a cross on the edge of a window. Actually there is nothing to be afraid here, the most normal switch-case the block just like that looks.
Numbers are read out to similarly previous case, only without function call and only two. They are stored in [rsp+8] and [rsp+0xc] respectively.
Then there are checks that both numbers of a schitana successfully, and also the first argument no more than 7. Then there is that switch transition to the address 0x402470 to the shift (the entered number) *8.
It is not difficult to guess that there addresses of case-tags lie. Not to be unfounded, we will look what there really lies. It is possible to make it by means of groups of the px commands. In this case we are interested in 8-byte words (Quad-word).
[0x0040149e]> pxQ 72 @ 0x402470
0x00402470 0x0000000000400f7c sym.phase_3+57
0x00402478 0x0000000000400fb9 sym.phase_3+118
0x00402480 0x0000000000400f83 sym.phase_3+64
0x00402488 0x0000000000400f8a sym.phase_3+71
0x00402490 0x0000000000400f91 sym.phase_3+78
0x00402498 0x0000000000400f98 sym.phase_3+85
0x004024a0 0x0000000000400f9f sym.phase_3+92
0x004024a8 0x0000000000400fa6 sym.phase_3+99

Actually, as it was expected though it is not absolutely consecutive. There is a check of our second from subjects magic further that was written in eax at a switch. As input in the decimal basis should be converted from hex-and. It is possible to count it by means of rax2 (analog of the calculator) through a shell challenge, and also directly, via the built-in calculator (a hot key —?), without creating new programs. And, not to zhmakat constantly enter can group commands it is direct as in Bachet.
[0x0040149e]> !rax2 0xcf
207
[0x0040149e]> ?vi 0x2c3; ?vi 0x100; ?vi 0x185; ?vi 0xce; ?vi 0x2aa; ?vi 0x147; ?vi 0x137
707
256
389
206
682
327
311

Total possible solutions will be:
  • 0 207
  • 1 311
  • 2 707
  • 3 256
  • 4 389
  • 5 206
  • 6 682
  • 7 327

And once again we will be convinced, on any option that everything works:
$ ./bomb
...
That's number 2.  Keep going!
4 389
Halfway there!

Level 4


sym.phase_4
We neutralize a bomb with Radare2

sym.func4
We neutralize a bomb with Radare2

At this level the recursion appears. In addition to built in by ASCII graphs also there is an opportunity to receive columns in the form of files for utility dot, and then, for example, to perekonvertit in png.
[0x0040149e]> ag sym.func4 > func4.dot
[0x0040149e]> dot -Tpng -o func4.png func4.dot

We neutralize a bomb with Radare2
If to transfer all this to Xi, then will look almost not so terribly.
void phase_4(char *str) {
    int x, y;
    if (sscanf(str, "%d %d", &x;, &y;) != 2 || 
            x > 14 || 
            func4(x, 0, 14) || 
            y != 0)
        explode_bomb();
}

int func4(int x, int y, int z) {
    unsigned diff = (z - y)/2;
    int p = y + diff;

    if (p > x) {
        func4(x, y, p-1);
        return diff * 2;
    } else if (p < x) {
        func4(x, p + 1, z);
        return diff * 2 + 1;
    }

    return 0;
}


The simplest and obvious solution — the func4 function returns 0 when it does not come in else-if. Input of the user manages only x, and p=7 at the first run. Respectively at x=7 function will just return 0, without recurrent challenges. The second variable is strictly set by zero. We will be convinced of it.
$ ./bomb in.tmp 
...
Halfway there!
7 0
So you got that one.  Try this one.

Level 5


We neutralize a bomb with Radare2
With it it will be more difficult, a lot of code is heated up here.
In 0x00401073 the canary registers in a stack. Similar information on a binarnik can be got by means of command i. For example, i ~ will return canary in this case true.
After that the returned value of string_length is compared with 6 and difficult analyzed spaghetti code begins. To deal without debager with it long and difficult therefore there will be a sin him not to use. For this purpose it is necessary to open the file with a flag of a debag or at start:
$ r2 -Ad bomb

or having just rediscovered the file:
[0x0040149e]> ood

The pointer address at the same time will automatically exchange on the first opkod in entry-point which is already loaded in memory. As usual we put breakpoints and we continue execution to them.
[0x7f2960b99d80]> db sym.phase_5 # либо s sym.phase_5; db $$
[0x7f2960b99d80]> dc             # продолжить выполнение до 1 брейкпоинта

There are 2 methods of the analysis further: the first — to use the block of the d/db commands — to be switched by the second in Visual-mode. The first not so visual method therefore we will stop on the second.
As before we pass Visual-mode, and then we select necessary debug-layout for debugging by p/P hot keys.
It is possible to mix up on a code by means of n/N — the following/previous function; j/k — following previous opkod.
And the most interesting: b/F2 — to deliver breykpoint, to s/F7 — a step in 1 opkod, S/F8 — a step in 1 opkod without coming into call, F9 — to continue to a breykpoint.
Here so all this looks
We neutralize a bomb with Radare2

Total poskarmlivav to a debagger several lines, are not difficult to guess that there occurs.
For each character from our line on the module 16 the corresponding character from a line undertakes char *s = "maduiersnfotvbyl" and the received line is compared by "flyers".
Actually our task and to find such characters which indexes in str give a required line.
The line flyers can be received uniquely: { s[0x9], s[0xe], s[0xf], s[0x5], s[0x6], s[0x7] }. I think, ASCII the table stores not everyone in the head, therefore it is possible to ask the utility of rax2 for the help again. With a key - s it converts from hex in string. Since characters undertake on the module 16, for esthetics it is possible to pick up the printed values.
$ rax2 -s 49 4e 4f 45 46 47
IONEFG

$ ./bomb
...
So you got that one.  Try this one.
IONEFG
Good work!  On to the next...

Retreat about a line
I very long thought and still I think that there some intelligent word can turn out. So if suddenly someone will find I will be extremely grateful :)

The Last One


As article appeared I will not be rather big all phases to consider. In particular, I will lower the 6th phase because there is a lot of laborious understanding without direct participation of a framework. Let it will remain homework to the most inquisitive.
It is not so simple to get to a confidential phase, therefore we will simplify to ourselves life propatchiv a binarnik. We should rediscover the file, having issued the rights to record by a checkbox - w, or to rediscover by means of oo + without leaving r2.
$ r2 -Aw bomb
 -- Did you ever ordered a pizza using radare2?
[0x00400c90]> s 0x00400ec6 # call sym.phase_6
[0x00400ec6]> wa call sym.secret_phase # запись нужных опкодов
[0x00400ec6]> pdf @ sym.secret_phase; pdf @ sym.fun7

secret_phase
We neutralize a bomb with Radare2

fun7
We neutralize a bomb with Radare2

Again there is recursive function and this time it is so simple not to bypass it because without recursive calls the necessary value is as simple as was last time, not to receive. ASCII graph can simplify life again.
We neutralize a bomb with Radare2
The analysis gives approximately such analog on Xi:
void secret_phase() {
    long num = strtol(read_line()) - 1;

    if (num > 0x3e8 || 
            fun7((long*)(0x6030f0), num) != 2)
        explode_bomb();

    puts("Wow! You've defused the secret stage!");
    phase_defused();
}

int fun7(long *array, int num) {
    if (array == 0)
        return -1;

    if (*array <= num) {
        if (*array == num)
            return 0;                        // 1
        else {
            return 2 * fun7(array + 1, num); // 2
        }
    } else {
        return 2 * fun7(array + 2, num) + 1; // 3
    }
}

Total, to receive the two on fun7 output, we should cause ret on the 2nd line in the beginning, then on 3 and at last on 1. There is only one riddle — that is stored to the address 0x6030f0.
480 bytes
[0x00401204]> px 480 @ 0x6030f0
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x006030f0  2400 0000 0000 0000 1031 6000 0000 0000  $........1`.....
0x00603100  3031 6000 0000 0000 0000 0000 0000 0000  01`.............
0x00603110  0800 0000 0000 0000 9031 6000 0000 0000  .........1`.....
0x00603120  5031 6000 0000 0000 0000 0000 0000 0000  P1`.............
0x00603130  3200 0000 0000 0000 7031 6000 0000 0000  2.......p1`.....
0x00603140  b031 6000 0000 0000 0000 0000 0000 0000  .1`.............
0x00603150  1600 0000 0000 0000 7032 6000 0000 0000  ........p2`.....
0x00603160  3032 6000 0000 0000 0000 0000 0000 0000  02`.............
0x00603170  2d00 0000 0000 0000 d031 6000 0000 0000  -........1`.....
0x00603180  9032 6000 0000 0000 0000 0000 0000 0000  .2`.............
0x00603190  0600 0000 0000 0000 f031 6000 0000 0000  .........1`.....
0x006031a0  5032 6000 0000 0000 0000 0000 0000 0000  P2`.............
0x006031b0  6b00 0000 0000 0000 1032 6000 0000 0000  k........2`.....
0x006031c0  b032 6000 0000 0000 0000 0000 0000 0000  .2`.............
0x006031d0  2800 0000 0000 0000 0000 0000 0000 0000  (...............
0x006031e0  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x006031f0  0100 0000 0000 0000 0000 0000 0000 0000  ................
0x00603200  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x00603210  6300 0000 0000 0000 0000 0000 0000 0000  c...............
0x00603220  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x00603230  2300 0000 0000 0000 0000 0000 0000 0000  #...............
0x00603240  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x00603250  0700 0000 0000 0000 0000 0000 0000 0000  ................
0x00603260  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x00603270  1400 0000 0000 0000 0000 0000 0000 0000  ................
0x00603280  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x00603290  2f00 0000 0000 0000 0000 0000 0000 0000  /...............
0x006032a0  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x006032b0  e903 0000 0000 0000 0000 0000 0000 0000  ................
0x006032c0  0000 0000 0000 0000 0000 0000 0000 0000  ................


Here 8-byte variables by blocks on 4 are stored. The first is used for comparison with our number; the second and third — pointers on the following characters for comparison; the fourth — just the padding, is not used.
Now it is possible to spread out all conditions and to find a required variable.
  • 2 ret: num <0x24
  • 3 ret: num> 0x08
  • 1 ret: num == 0x16

$ ./bombSec in.tmp 
...
Good work!  On to the next...
22
Wow! You've defused the secret stage!
Congratulations! You've defused the bomb!


To Ekh, we made it! The mankind can quietly live. In spite of the fact that article appeared is a little rather big, many features of a framework were not lit so the interested still can open much for themselves. Also, I will be glad to listen to ideas for possible continuation.

This article is a translation of the original post at habrahabr.ru/post/274617/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus