Forensic - Radare2

https://book.rada.re/debugger/registers.html

https://r2wiki.readthedocs.io/en/latest/home/misc/cheatsheet/

https://book.rada.re/analysis/variables.html

https://scoding.de/uploads/r2_cs.pdf

https://book.rada.re/analysis/code_analysis.html

https://www.radare.org/get/radare.pdf

Reverse engineering

https://rderik.com/blog/understanding-buffer-overflows-using-radare2/

$ cat esp.c
#include <stdio.h>
#include <stdlib.h>

int main(void){
    int a = 121;
    int b = 120;
    char c = 'a';
    printf("%d %p\n", a, &a);
    printf("%d %p\n", b, &b);
    printf("%c %p\n", c, &c);
    return 0;
}
$ gcc -o0 -ggdb esp.c -o esp

Open Radare2 for debugging

$ r2 -d esp
 -- Default scripting languages are NodeJS and Python.
[0x00001080]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.

Get passwd

For this section, we will see how to get the passwd. For doing that, a C program take one argument, it’s the password and the program will compare it with the local password. The local password is stored in a .passwd:

$ printf "myPasswdUnhackable" > .passwd

And the C code:

$ cat main1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 64

void get_passwd(char *passwd){
    int fd;
    int len;
    if ((fd = open(".passwd", O_RDONLY)) < 0){
        exit(-1);
    }

    while ((len = read(fd, passwd, BUF_SIZE)) > 0){
        passwd[len] = '\0';
    }
}
int test_passwd(char *passwd){
    char buf[BUF_SIZE];
    get_passwd(buf);

    if(strcmp(passwd, buf) == 0)
        return 0;
    else
        return 1;
}
int main(int argc, char *argv[]){
    int res = -1;

    if (argc < 2){
        printf("Please, specify a password\n");
        return -1;
    }
    res = test_passwd(argv[1]);

    if(res == 0)
        printf("You are granted\n");
    else
        printf("Password failed");
}
$ gcc -o0 -ggdb main1.c -o main1 && ./main1

Now, we will disassemble it:

$ r2 -d main1
Process with PID 83615 started...
= attach 83615 83615
bin.baddr 0x5632bc6ea000
Using 0x5632bc6ea000
asm.bits 64
Warning: r_bin_file_hash: file exceeds bin.hashlimit
 -- TIRED OF WAITING

First, we analyse the code and to get all functions:

[0x7f0d0114f290]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[TOFIX: aaft can't run in debugger mode.ions (aaft)
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x7f0d0114f290]> afl
0x5632bc6eb120    1 38           entry0
0x5632bc6edfd8    1 4129         reloc.__libc_start_main
0x5632bc6eb150    4 41   -> 34   sym.deregister_tm_clones
0x5632bc6eb180    4 57   -> 51   sym.register_tm_clones
0x5632bc6eb1c0    5 57   -> 54   entry.fini0
0x5632bc6eb0a0    1 11           fcn.5632bc6eb0a0
0x5632bc6eb200    1 9            entry.init0
0x5632bc6eb209    5 111          sym.get_passwd
0x5632bc6eb35c    1 13           sym._fini
0x5632bc6eb2dc    7 126          main
0x5632bc6eb278    6 100          sym.test_passwd
0x5632bc6eb000    3 27           map.home_gbucchino_C_test_r2_main1.r_x
0x5632bc6ea000    3 209  -> 202  sym.imp.__libc_start_main
0x5632bc6eb0b0    1 11           sym.imp.puts
0x5632bc6eb0c0    1 11           sym.imp.__stack_chk_fail
0x5632bc6eb0d0    1 11           sym.imp.printf
0x5632bc6eb0e0    1 11           sym.imp.read
0x5632bc6eb0f0    1 11           sym.imp.strcmp
0x5632bc6eb100    1 11           sym.imp.open
0x5632bc6eb110    1 11           sym.imp.exit

Now, we will analyse the function test_passwd:

[0x7f0d0114f290]> pdf @sym.test_passwd
            ; CALL XREF from main @ 0x5632bc6eb320
┌ 100: sym.test_passwd ();
│           ; var int64_t var_58h @ rbp-0x58
│           ; var int64_t var_50h @ rbp-0x50
│           ; var int64_t var_8h @ rbp-0x8
│           0x5632bc6eb278      f30f1efa       endbr64
│           0x5632bc6eb27c      55             push rbp
│           0x5632bc6eb27d      4889e5         mov rbp, rsp
│           0x5632bc6eb280      4883ec60       sub rsp, 0x60
│           0x5632bc6eb284      48897da8       mov qword [var_58h], rdi
│           0x5632bc6eb288      64488b042528.  mov rax, qword fs:[0x28]
│           0x5632bc6eb291      488945f8       mov qword [var_8h], rax
│           0x5632bc6eb295      31c0           xor eax, eax
│           0x5632bc6eb297      488d45b0       lea rax, [var_50h]
│           0x5632bc6eb29b      4889c7         mov rdi, rax
│           0x5632bc6eb29e      e866ffffff     call sym.get_passwd
│           0x5632bc6eb2a3      488d55b0       lea rdx, [var_50h]
│           0x5632bc6eb2a7      488b45a8       mov rax, qword [var_58h]
│           0x5632bc6eb2ab      4889d6         mov rsi, rdx
│           0x5632bc6eb2ae      4889c7         mov rdi, rax
│           0x5632bc6eb2b1      e83afeffff     call sym.imp.strcmp
│           0x5632bc6eb2b6      85c0           test eax, eax
│       ┌─< 0x5632bc6eb2b8      7507           jne 0x5632bc6eb2c1
│       │   0x5632bc6eb2ba      b800000000     mov eax, 0
│      ┌──< 0x5632bc6eb2bf      eb05           jmp 0x5632bc6eb2c6
│      │└─> 0x5632bc6eb2c1      b801000000     mov eax, 1
│      │    ; CODE XREF from sym.test_passwd @ 0x5632bc6eb2bf
│      └──> 0x5632bc6eb2c6      488b55f8       mov rdx, qword [var_8h]
│           0x5632bc6eb2ca      64482b142528.  sub rdx, qword fs:[0x28]
│       ┌─< 0x5632bc6eb2d3      7405           je 0x5632bc6eb2da
│       │   0x5632bc6eb2d5      e8e6fdffff     call sym.imp.__stack_chk_fail
│       └─> 0x5632bc6eb2da      c9             leave
└           0x5632bc6eb2db      c3             ret

We can see, we do a strcmp at this line:

0x5632bc6eb2b1      e83afeffff     call sym.imp.strcmp

Now, we need to analyse the register RSI, because it’s a pointer to string operations. So, we create a breakpoint and execute the program with an argument:

[0x7fdfd324f290]> db 0x5646826782ae
[0x7fdfd324f290]> ood test
child received signal 9
Process with PID 14546 started...
= attach 14546 14546
File dbg:///home/gbucchino/C/test_r2/main1  test reopened in read-write mode
Unable to find filedescriptor 3
Unable to find filedescriptor 3
14546
[0x7f054669a290]> dc
hit breakpoint at: 556d69e5b2ae

With the dc command, we continue the program until the breakpoint. Now, we can analyse the RSI:

[0x556d69e5b2ae]> px @rdx
- offset -       0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x7ffe33fb5930  6d79 5061 7373 7764 556e 6861 636b 6162  myPasswdUnhackab
0x7ffe33fb5940  6c65 0000 0000 0000 0100 0000 0000 0000  le..............
0x7ffe33fb5950  40a0 e569 6d55 0000 3c98 6946 057f 0000  @..imU..<.iF....

We found our password.

CheatSheet

Common commands

aa -> analyse functions
aaa -> analyse functions + autoname functions (Cf. afna)
afl -> list functions
pd -> disassemble
pdf -> disassemble function
pdf @main -> disass main function
pdf @entry.fini0
iS -> show all sections (.text, .data, .bss, etc...)
px -> hexdump .text section
px @ <address> -> hexdump section at address
dr -> show registers
s 0x1234 -> go to address specified
pxr 10 @rbx + 0x12345 -> print register at rbx + 0x12345 address
afv -> show arguments and variables

Run program

ood -> open in debug mode
db -> list all breakpoints
db @ <address> -> add breakpoint at address specified
dc -> run the program or continue it
db- @ <address> -> remove the breakpoint at the specified address