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