Writeup: Redpwn 2019 - Generic Crackme Redux

Information

  • category: reverse
  • points: 50

Description

Note: Enclose the flag with flag{}

1 file: generic_crackme_redux.bin

Writeup

Execute the program:

1
2
3
$ ./generic_crackme_redux.bin 
Enter access code: 1111
Bzzzzrrrppp

Ltrace the program:

1
2
3
4
5
6
7
8
ltrace ./generic_crackme_redux.bin

printf("Enter access code: ") = 19
__isoc99_scanf(0x557444018018, 0x7ffd67e4bb14, 0, 0Enter access code: 11
) = 1
puts("Bzzzzrrrppp"Bzzzzrrrppp
) = 12
+++ exited (status 0) +++

Well, we need to dig deeper using radare2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$ r2 -d generic_crackme_redux.bin
[0x7ffb5769d100]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[Warning: Invalid range. Use different search.in=? or anal.in=dbg.maps.x
Warning: Invalid range. Use different search.in=? or anal.in=dbg.maps.x
[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] Use -AA or aaaa to perform additional experimental analysis.
[0x7ffb5769d100]> afl
0x55b310500070 1 46 entry0
0x55b310502fe0 1 4124 reloc.__libc_start_main
0x55b310500030 1 6 sym.imp.puts
0x55b310500040 1 6 sym.imp.__stack_chk_fail
0x55b310500050 1 6 sym.imp.printf
0x55b3104ff000 3 209 -> 202 loc.imp._ITM_deregisterTMCloneTable
0x55b310500060 1 6 sym.imp.__isoc99_scanf
0x55b310500186 6 131 main
0x55b310500160 5 153 -> 60 entry.init0
0x55b310500110 5 65 -> 55 entry.fini0
0x55b310502ff8 1 4100 reloc.__cxa_finalize
0x55b3105000a0 4 41 -> 34 fcn.55b3105000a0
[0x7ffb5769d100]> s main
[0x55b310500186]> pdf
/ (fcn) main 131
| int main (int argc, char **argv, char **envp);
| ; var int32_t var_ch @ rbp-0xc
| ; var int32_t var_8h @ rbp-0x8
| ; DATA XREF from entry0 @ 0x55b310500091
| 0x55b310500186 55 push rbp
| 0x55b310500187 4889e5 mov rbp, rsp
| 0x55b31050018a 4883ec10 sub rsp, 0x10
| 0x55b31050018e 64488b042528. mov rax, qword fs:[0x28] ; [0x28:8]=-1 ; '(' ; 40
| 0x55b310500197 488945f8 mov qword [var_8h], rax
| 0x55b31050019b 31c0 xor eax, eax
| 0x55b31050019d 488d3d600e00. lea rdi, str.Enter_access_code: ; 0x55b310501004 ; "Enter access code: "
| 0x55b3105001a4 b800000000 mov eax, 0
| 0x55b3105001a9 e8a2feffff call sym.imp.printf ; int printf(const char *format)
| 0x55b3105001ae 488d45f4 lea rax, [var_ch]
| 0x55b3105001b2 4889c6 mov rsi, rax
| 0x55b3105001b5 488d3d5c0e00. lea rdi, [0x55b310501018] ; "%d"
| 0x55b3105001bc b800000000 mov eax, 0
| 0x55b3105001c1 e89afeffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
| 0x55b3105001c6 8b45f4 mov eax, dword [var_ch]
| 0x55b3105001c9 89c7 mov edi, eax
| 0x55b3105001cb e899ffffff call 0x55b310500169
| 0x55b3105001d0 84c0 test al, al
| ,=< 0x55b3105001d2 740e je 0x55b3105001e2
| | 0x55b3105001d4 488d3d400e00. lea rdi, str.Access_granted ; 0x55b31050101b ; "Access granted"
| | 0x55b3105001db e850feffff call sym.imp.puts ; int puts(const char *s)
| ,==< 0x55b3105001e0 eb0c jmp 0x55b3105001ee
| |`-> 0x55b3105001e2 488d3d410e00. lea rdi, str.Bzzzzrrrppp ; 0x55b31050102a ; "Bzzzzrrrppp"
| | 0x55b3105001e9 e842feffff call sym.imp.puts ; int puts(const char *s)
| | ; CODE XREF from main @ 0x55b3105001e0
| `--> 0x55b3105001ee b800000000 mov eax, 0
| 0x55b3105001f3 488b55f8 mov rdx, qword [var_8h]
| 0x55b3105001f7 644833142528. xor rdx, qword fs:[0x28]
| ,=< 0x55b310500200 7405 je 0x55b310500207
| | 0x55b310500202 e839feffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
| `-> 0x55b310500207 c9 leave
\ 0x55b310500208 c3 ret
[0x55b310500186]>

Visualize the main:

Our scope is to print "Access granted".

Pseudocode main:

1
2
3
4
5
6
7
8
9
10
11
int main()
{
int x;
scanf("%d", &x);
if(flag(x) == 0) // flag() = 0x55b310500169,
puts("Bzzzzrrrppp"); // '\0' because return is in al (8 bit)
else
puts("Access granted");

return 0;
}

Let’s see what the function flag() = 0x55b310500169 does:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[0x55b310500186]> s 0x55b310500169
[0x55b310500169]> pd
; CALL XREF from main @ 0x55b3105001cb
0x55b310500169 55 push rbp
0x55b31050016a 4889e5 mov rbp, rsp
0x55b31050016d 897dfc mov dword [rbp - 4], edi
0x55b310500170 8b55fc mov edx, dword [rbp - 4]
0x55b310500173 89d0 mov eax, edx
0x55b310500175 c1e002 shl eax, 2
0x55b310500178 01d0 add eax, edx
0x55b31050017a 01c0 add eax, eax
0x55b31050017c 3d92c20a00 cmp eax, 0xac292
0x55b310500181 0f94c0 sete al
0x55b310500184 5d pop rbp
0x55b310500185 c3 ret

Pseudocode:

1
2
3
4
5
6
7
8
9
10
11
char flag(int x)
{
int a = x;
a = a * 4; // shl eax, 2 (4x)
a = a + x; // add eax, edx (5x)
a = a + a; // add eax,eax (5x + 5x) = 10x
if (a == 0xac292) // cmp eax, 0xac292
return 1; // sete al, return 1 if ZF = 1
else
return 0;
}

To print "Access granted" we need that the flag function returns 0x1. To do so we just need to solve (10 * x) = 0xac292 –> x = 0xac292 / 10 –> x = 70517.

1
2
3
$ ./generic_crackme_redux.bin
Enter access code: 70517
Access granted

Flag

flag{70517}