RadaRE2 Tuto [Basic] Première approche.

Allez on y va. Voici un petit guide pour mettre le pied à l’étrier et donner sa chance à RadaRE2. C’est affolant de voir qu’il soit si avancé sans avoir plus de doc/tutos que cela. A se demander si ce n’est pas juste utilisé par ses développeurs. Tentons d’y remédier.

On va voir comment reverser avec RadaRE2 un tout petit Chall dont, en plus, on a les sources. On part sur du x64 ELF. Le chall est le suivant :

$ cat crackkids.c 
#include <stdio.h>
#include <string.h>

int main () {
  char password[]="pass!";
  char input[16+1];
  
  printf("Chall easy for Radare dissection\n");
  scanf("%16s", &input);
  if (strcmp(password,input)==0) { 
    printf("You Win\n");
  } else {
    printf("You Failed\n");
  }
        return(0);
}

Compilons ce petit chall et strippons le;

$ gcc crackkids.c -o crackkids && strip crackkids

Bon, on ne va pas faire un «strings crackkids» pour gagner on va voir ce que l’on peut faire avec radaRE2. A partir de maintenant oubliez ce qu’il y a dans ce source, et même ce qu’on a pondu comme exécutable.

Premièrement demandons au Rabin2 ce qu’il pense de ce fichier. Rabin2 est mix de objdump et readelf sous stéroides. Il comprend de base les formats d’exécutables JAVA, ELF et PE (et les MZ).

$ rabin2 -I crackkids
file    /home/thanat0s/code/helloworld/crackkids
type    EXEC (Executable file)
pic     false
canary  false
has_va  true
root    elf
class   ELF64
lang    c
arch    x86
bits    64
machine AMD x86-64 architecture
os      linux
subsys  linux
endian  little
strip   true
static  false
linenum false
lsyms   false
relocs  false
rpath   NONE

Ok… on est devant un ELF 64 bits strippé. Demandons au Rabin les fonctions importées (i) et les strings déclarées (z).

$ rabin2 -iz crackkids
[Imports]
ordinal=001 plt=0x00000480 bind=GLOBAL type=FUNC name=puts
ordinal=002 plt=0x00000490 bind=GLOBAL type=FUNC name=__libc_start_main
ordinal=003 plt=0x000004a0 bind=GLOBAL type=FUNC name=strcmp
ordinal=004 plt=0x00000000 bind=UNKNOWN type=NOTYPE name=__gmon_start__
ordinal=005 plt=0x000004b0 bind=GLOBAL type=FUNC name=__isoc99_scanf

5 imports
addr=0x000006f0 off=0x000006f0 ordinal=000 sz=33 len=33 section=.rodata type=A string=Chall easy for Radare dissection
addr=0x00000711 off=0x00000711 ordinal=001 sz=5 len=5 section=.rodata type=A string=%16s
addr=0x00000716 off=0x00000716 ordinal=002 sz=8 len=8 section=.rodata type=A string=You Win
addr=0x0000071e off=0x0000071e ordinal=003 sz=11 len=11 section=.rodata type=A string=You Failed

Masel Tov Rabin !!!  je vois un STRCMP, et le You Win/You Failed !… Ça a l’air pas mal. Ouvrons ceci dans RadaRE2.

$ radare2 crackkids
 -- This page intentionally left blank.
[0x004004c0]>

Nous voila donc avec un shell à l’entry point. Et c’est là qu’il faut introduire un concept important ; les Flagspaces. L’addresse d’une string, d’une fonction, d’une référence est un “Flag”. Et vu que cela fait beaucoup d’objets, il sont rangés par “FlagSpaces”.  «fs» permet d’afficher ou de sélectionner le Flagspace dans lequel on travaille et «f» affiche les flags.

[0x004004c0]> fs
00   strings
02   symbols
04   relocs
06 * sections
[0x004004c0]> fs strings
[0x004004c0]> f
0x0040071e 11 str.YouFailed
0x00400716 8 str.YouWin
0x00400711 5 str._16s
0x004006f0 33 str.ChalleasyforRadaredissection

Devant nous donc, 4 strings, ce qu’avait trouvé avec le rabin précédemment. On peut afficher les strings avec «ps» (Print String), et plus précisément «psz» pour une stringZ (Zero terminated).

[0x004004c0]> psz@str.YouWin 
You Win

Voir meme en hexa avec px (print hexa) dans ce cas, je précise combien de byte j’en veux et le mode d’affichage.

[0x004007c0]> pxs 16 @str.YouWin 
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x00400716  596f 7520 5769 6e00 596f 7520 4661 696c  You Win.You Fail
[0x004007c0]> pxw 16 @str.YouWin 
0x00400716  0x20756f59 0x006e6957 0x20756f59 0x6c696146  You Win.You Fail

Et il y a bien d’autre print mode hexa. Pour l’aide c’est «?» donc print hexa help c’est «px?». Je vous laisse découvrir tout seul pxe.

[0x004007c0]> px?
|Usage: px[afoswqWqQ][f]
| px     show hexdump
| px/    same as x/ in gdb (help x)
| pxa    show annotated hexdump
| pxe    emoji hexdump! :)
| pxf    show hexdump of current function
| pxo    show octal dump
| pxq    show hexadecimal quad-words dump (64bit)
| pxs    show hexadecimal in sparse mode
| pxQ    same as above, but one per line
| pxw    show hexadecimal words dump (32bit)
| pxW    same as above, but one per line

Bon, avançons, allons voir le FlagSpace avec les fonctions, mais avant cela il faut le populer. Si le code n’a pas été analysé, il n’y a pas de flagspace “fonctions”.

[0x004004c0]> fs  // Pas de flagspace «functions»
00   strings
02   symbols
04   relocs
06 * sections
[0x004004c0]> aa  // On lance l'analyse
[0x004004c0]> fs   // le Flagspace functions est apparu et sélectionné
00   strings
02   symbols
04   relocs
06   sections
08 * functions
[0x004004c0]> f    // quels sont les flags.
0x0040062e 7 loc.0040062e
0x004006e5 13 fcn.004006e5
0x004006d9 12 fcn.004006d9
0x00400635 13 fcn.00400635
0x0040057f 29 fcn.0040057f
0x0040056c 19 fcn.0040056c
0x00400532 7 fcn.00400532
0x004004b6 52 fcn.004004b6
0x004004a6 16 fcn.004004a6
0x00400486 16 fcn.00400486
0x0040047c 10 fcn.0040047c
0x00400470 12 loc.00400470
0x00400496 16 fcn.00400496

Bon maintenant trouvons où est appelé notre STRCMP.  (Analyse Reference Flag)

[0x004004c0]> fs symbols    // os sélectionne le flagspace symbol avec les appel aux libs
[0x004004c0]> f         // Liste les flags
0x004004b0 16 sym.imp.__isoc99_scanf
0x00400000 16 sym.imp.__gmon_start__
0x004004a0 16 sym.imp.strcmp
0x00400490 16 sym.imp.__libc_start_main
0x00400480 16 sym.imp.puts
0x004004c0 256 entry0
0x004005cc 256 main
[0x004004c0]> arf sym.imp.strcmp  // Donne moi les références. 
Finding references of flags matching 'sym.imp.strcmp'...
ar 0x004004a0 0x0040060f
Macro 'findstref' removed.

Et voila STRCMP est appelé en 0x0040060F. Désassemblons désormais la fonction autour de cette adresse. (Print Disassembled Function)

[0x00400bc0]> pdf@0x0040060F
/ (fcn) fcn.0040059c 149
|          0x004005a0    48833d68022. cmp qword [rip+0x200268], 0x0
|      ,=< 0x004005a8    741b         je 0x4005c5
|      |   0x004005aa    b800000000   mov eax, 0x0
|      |   0x004005af    4885c0       test rax, rax
|     ,==< 0x004005b2    7411         je 0x4005c5
|     ||   0x004005b4    55           push rbp
|     ||   0x004005b5    bf10086000   mov edi, 0x600810 ;  0x00600810 
|     ||   0x004005ba    4889e5       mov rbp, rsp
|     ||   0x004005bd    ffd0         call rax
|     ||      0x00000000(unk)
|     ||   0x004005bf    5d           pop rbp
|     ||   0x004005c0    e97bffffff   jmp fcn.00400539
|     ``-> 0x004005c5    e976ffffff   jmp fcn.00400539
|          0x004005ca    90           nop
|          0x004005cb    90           nop
|          ; DATA XREF from 0x004004dd (entry0)
/ (fcn) main 105
|          0x004005cc    55           push rbp
|          0x004005cd    4889e5       mov rbp, rsp
|          0x004005d0    4883ec30     sub rsp, 0x30
|          0x004005d4    c745f070617. mov dword [rbp-0x10], 0x73736170 ;  0x73736170 
|          0x004005db    66c745f42100 mov word [rbp-0xc], 0x21 ;  0x00000021 
|          0x004005e1    bff0064000   mov edi, str.ChalleasyforRadaredissection ;  0x004006f0 
|          ; CODE (CALL) XREF from 0x00400480 (fcn.0040047c)
|          0x004005e6    e895feffff   call sym.imp.puts
|             sym.imp.puts(unk)
|          0x004005eb    488d45d0     lea rax, [rbp-0x30]
|          0x004005ef    4889c6       mov rsi, rax
|          0x004005f2    bf11074000   mov edi, str._16s ;  0x00400711 
|          0x004005f7    b800000000   mov eax, 0x0
|          0x004005fc    e8affeffff   call sym.imp.__isoc99_scanf
|             sym.imp.__isoc99_scanf()
|          0x00400601    488d55d0     lea rdx, [rbp-0x30]
|          0x00400605    488d45f0     lea rax, [rbp-0x10]
|          0x00400609    4889d6       mov rsi, rdx
|          0x0040060c    4889c7       mov rdi, rax
|          0x0040060f    e88cfeffff   call sym.imp.strcmp
|             sym.imp.strcmp()
|          0x00400614    85c0         test eax, eax
|    ,===< 0x00400616    750c         jne 0x400624
|    |     0x00400618    bf16074000   mov edi, str.YouWin ;  0x00400716 
|    |     0x0040061d    e85efeffff   call sym.imp.puts
|    |        sym.imp.puts()
|   ,====< 0x00400622    eb0a         jmp loc.0040062e
|   |`---> 0x00400624    bf1e074000   mov edi, str.YouFailed ;  0x0040071e 
|   |      0x00400629    e852feffff   call sym.imp.puts
|   |         sym.imp.puts()
|   |      ; CODE (CALL) XREF from 0x00400622 (fcn.0040059c)
|- loc.0040062e 7
|   `----> 0x0040062e    b800000000   mov eax, 0x0
|          0x00400633    c9           leave
\          0x00400634    c3           ret
[

C’est un peu large, car il n’a pas détecté la fin inexistante de la fonction fcn.0x0040059c, mais ca passe,  on y est ! On peut constater, comme dans un IDA, les petites flèches d’embranchement qui confirment que le STRCMP est la clef de ce chall. Celui ci compare ce qu’il y aura sur le stack en rbp-0x30 avec ce qu’il y a en rbp-0x10. Le 0x30 sera remplis par un scanf en 0X4005fc. Quand rbp-0x10 il est remplis par deux mov en 0X4005d4 et 0x4005db. Mais comment convertir ceci en string. Et bien on peut utiliser «rax2» un autre tools de la suite RadaRE2 qui convertit tout en tout. Et il est aussi possible de l’apeller directement depuis notre RadaRE2 avec un «!».

[0x00400cc0]> !rax2 -h
Usage: rax2 [options] [expr ...]
  int   ->  hex           ;  rax2 10
  hex   ->  int           ;  rax2 0xa
  -int  ->  hex           ;  rax2 -77
  -hex  ->  int           ;  rax2 0xffffffb3
  int   ->  bin           ;  rax2 b30
  bin   ->  int           ;  rax2 1010d
  float ->  hex           ;  rax2 3.33f
  hex   ->  float         ;  rax2 Fx40551ed8
  oct   ->  hex           ;  rax2 35o
  hex   ->  oct           ;  rax2 Ox12 (O is a letter)
  bin   ->  hex           ;  rax2 1100011b
  hex   ->  bin           ;  rax2 Bx63
  raw   ->  hex           ;  rax2 -S < /binfile
  hex   ->  raw           ;  rax2 -s 414141
  -b    binstr -> bin     ;  rax2 -b 01000101 01110110
  -B    keep base         ;  rax2 -B 33+3 -> 36
  -d    force integer     ;  rax2 -d 3 -> 3 instead of 0x3
  -e    swap endianness   ;  rax2 -e 0x33
  -f    floating point    ;  rax2 -f 6.3+2.1
  -h    help              ;  rax2 -h
  -k    randomart         ;  rax2 -k 0x34 1020304050
  -n    binary number     ;  rax2 -e 0x1234   # 34120000
  -s    hexstr -> raw     ;  rax2 -s 43 4a 50
  -S    raw -> hexstr     ;  rax2 -S < /bin/ls > ls.hex
  -t    tstamp -> str     ;  rax2 -t 1234567890
  -x    hash string       ;  rax2 -x linux osx
  -u    units             ;  rax2 -u 389289238 # 317.0M
  -v    version           ;  rax2 -V
[0x004004c0]> !rax2 -s 0x2173736170  | rev
pass!

Une autre solution capilo-tractée assez violente qui ne servira d’exemple que pour montrer ce que l’on peut faire avec les calculs d’offset de RadaRE2;

[0x00400adb]> 0x4005d4
[0x004005d4]> ps 4 @+$l-4
pass
[0x004005d4]> 0x4005db
[0x004005db]> ps 2 @+$l-2
!\x00

Ok, je traduis. Je me place en 0x4005d4 et j’affiche une string d’une longueur de 4 depuis (l’offset courant + taille de l’opcode – 4). (4 car c’est la longueur du dword).

Et oui la commande permet de faire des opérations de dingue sur les offsets. Et nombre de substitutions sont disponibles.

[0x004005db]> ?$?
|RNum $variables usable in math expressions:
| $$     here (current virtual seek)
| $o     here (current disk io offset)
| $s     file size
| $b     block size
| $w     get word size, 4 if asm.bits=32, 8 if 64, ...
| $c,$r  get width and height of terminal
| $S     section offset
| $SS    section size
| $j     jump address (e.g. jmp 0x10, jz 0x10 => 0x10)
| $f     jump fail address (e.g. jz 0x10 => next instruction)
| $I     number of instructions of current function
| $F     current function size 
| $Jn    get nth jump of function
| $Cn    get nth call of function
| $Dn    get nth data reference in function
| $Xn    get nth xref of function
| $m     opcode memory reference (e.g. mov eax,[0x10] => 0x10)
| $l     opcode length
| $e     1 if end of block, else 0
| ${ev}  get value of eval config variable # TODO: use ?k too
| $?     last comparision value

Voila pour une première approche, et on est loin de loin d’avoir tout vu encore. Je n’ai même pas parlé du mode “Visual”.

Retenons, aa, pdf, psz, f, fs et arf. Cela sera déja très bien.

This entry was posted in Reverse and tagged , . Bookmark the permalink.

7 Responses to RadaRE2 Tuto [Basic] Première approche.

  1. rickroll says:

    Yop!
    Merci pour les tuto! C’est vraiment cool! Ca, c’est pour t’encourager à continuer ton site car c’est une très bonne source d’info.
    Bon, par contre, j’ai pas réussi à tout tout faire dans le tuto et celui d’après… En fait, quand je veux lire le contenu de la mémoire d’un variable, j’ai que du ff ff ff ff.. J’ai testé avec la dernière version de RadaRe (git clone) et dans une VM. C’est peut être pour ça? Du coup, impossible d’écrire… J’ai quand même compris le principe et j’ai bien hâte à la prochaine étape!!
    Tchô, bonne continuation.

  2. romeoandjuliet says:

    Hey merci pour les explications ! J’adore ce tool

  3. zM says:

    Merci Thanat0s pour m’avoir mis le pied à l’étrier. Yaplukapoutrer maintenant !

  4. Pingback: Insomni’Hack 2017 write-up : Internet Of Fail | Le blog du Phil

  5. Pingback: Insomni’Hack 2017 write-up : Internet Of Fail – 400 | Le blog du Phil

  6. Pingback: Insomni’Hack 2017 write-up : Internet Of Fail – 400 – Securimag

Leave a Reply to rickroll Cancel reply

Your email address will not be published. Required fields are marked *

AlphaOmega Captcha Classica  –  Enter Security Code