Skip to content

Instantly share code, notes, and snippets.

@dtouch3d
Last active August 29, 2015 14:21
Show Gist options
  • Save dtouch3d/4e74017ee484d398a85d to your computer and use it in GitHub Desktop.
Save dtouch3d/4e74017ee484d398a85d to your computer and use it in GitHub Desktop.

Binary Exploitation Course Part 1

Okay, so I decided to follow this binary exploitation course from RPI and do the challenges. It is interesting that it is run by students passionate about security and generally looks quite a promising introduction in binary exploitation, so you may want to check out the slides.

On to the challenges.

1. Basic RE

For crackme0x00a and crackme0x00b the slides pretty much give it away. I have decided to use radare2 so

$ r2 0xcrackme0x00a
> aa
> pdf @ main

...
|          0x0804851b    8d442413       lea eax, [esp + 0x13]           ; 0x13 
|          0x0804851f    89442404       mov dword [esp + 4], eax        ; [0x4:4]=0x10101 
|          0x08048523    c7042424a004.  mov dword [esp], sym.pass.1685  ; [0x804a024:4]=0x64303067  ; "g00dJ0B!" @ 0x804a024
|          0x0804852a    e891feffff     call sym.imp.strcmp             ; fcn.080483bc+0x4
|             fcn.080483bc() ; sym.imp.strcmp
|          0x0804852f    85c0           test eax, eax
|      ,=< 0x08048531    7521           jne 0x8048554                 
|      |   0x08048533    c70424548604.  mov dword [esp], str.Congrats_  ; [0x8048654:4]=0x676e6f43  ; "Congrats!" @ 0x8048654
|      |   0x0804853a    e8b1feffff     call sym.imp.puts

So radare quite helpfully fetches the string contents of the password. Crackme is the same with a very small catch left as excersice for the reader.

For crackme0x01 we can use objdump

$ objdump -d crackme0x01 | less
 ...
 8048418:       8d 45 fc                lea    -0x4(%ebp),%eax
 804841b:       89 44 24 04             mov    %eax,0x4(%esp)
 804841f:       c7 04 24 4c 85 04 08    movl   $0x804854c,(%esp)
 8048426:       e8 e1 fe ff ff          call   804830c <scanf@plt>
 804842b:       81 7d fc 9a 14 00 00    cmpl   $0x149a,-0x4(%ebp)
 8048432:       74 0e                   je     8048442 <main+0x5e>
 8048434:       c7 04 24 4f 85 04 08    movl   $0x804854f,(%esp)
 804843b:       e8 dc fe ff ff          call   804831c <printf@plt>
 8048440:       eb 0c                   jmp    804844e <main+0x6a>
 8048442:       c7 04 24 62 85 04 08    movl   $0x8048562,(%esp)
 8048449:       e8 ce fe ff ff          call   804831c <printf@plt>
 804844e:       b8 00 00 00 00          mov    $0x0,%eax
 8048453:       c9                      leave  
 8048454:       c3                      ret

So we can clearly (?) see that it uses the value at -0x4(%ebp) as the second parameter to scanf at 804841b and then it checks the same memory address with 0x149a at line 804842b. If you have trouble understanding this, remember that the function parameters are passed from last to first on the stack and read the lecture slides, page 17.

Defeating crackme0x02 is just a tad trickier. We could use objdump for this but radare2 make our life a bit easier.

$ radare2 crackme0x02
> aa
> pdf @ main
|          ; arg int arg_22_2     @ ebp+0x5a
|          ; arg int arg_123      @ ebp+0x1ec
|          ; var int local_1      @ ebp-0x4
|          ; var int local_2      @ ebp-0x8
|          ; var int local_3      @ ebp-0xc
.
.
.
|          0x08048418    8d45fc         lea eax, [ebp-local_1]
|          0x0804841b    89442404       mov dword [esp + 4], eax        ; [0x4:4]=0x10101 
|          0x0804841f    c704246c8504.  mov dword [esp], 0x804856c      ; [0x804856c:4]=0x50006425  ; "%d" @ 0x804856c
|          0x08048426    e8e1feffff     call sym.imp.scanf
|             sym.imp.scanf()
|          0x0804842b    c745f85a0000.  mov dword [ebp-local_2], 0x5a   ; [0x5a:4]=0x81540000  ; 'Z'
|          0x08048432    c745f4ec0100.  mov dword [ebp-local_3], 0x1ec  ; [0x1ec:4]=0
|          0x08048439    8b55f4         mov edx, dword [ebp-local_3]
|          0x0804843c    8d45f8         lea eax, [ebp-local_2]
|          0x0804843f    0110           add dword [eax], edx
|          0x08048441    8b45f8         mov eax, dword [ebp-local_2]
|          0x08048444    0faf45f8       imul eax, dword [ebp-local_2]
|          0x08048448    8945f4         mov dword [ebp-local_3], eax
|          0x0804844b    8b45fc         mov eax, dword [ebp-local_1]
|          0x0804844e    3b45f4         cmp eax, dword [ebp-local_3]
|      ,=< 0x08048451    750e           jne 0x8048461                 
|      |   0x08048453    c704246f8504.  mov dword [esp], str.Password_OK_:__n  ; [0x804856f:4]=0x73736150  ; "Password OK :)." @ 0x804856f
|      |   0x0804845a    e8bdfeffff     call sym.imp.printf
|      |      sym.imp.printf()
|     ,==< 0x0804845f    eb0c           jmp 0x804846d                 
|     ||   ; JMP XREF from 0x08048451 (sym.main)
|     |`-> 0x08048461    c704247f8504.  mov dword [esp], str.Invalid_Password__n  ; [0x804857f:4]=0x61766e49  ; "Invalid Password!." @ 0x804857f
|     |    0x08048468    e8affeffff     call sym.imp.printf
|     |       sym.imp.printf()
|     |    ; JMP XREF from 0x0804845f (sym.main)
|     `--> 0x0804846d    b800000000     mov eax, 0
|          0x08048472    c9             leave
\          0x08048473    c3             ret

As a general rule when you don't know how to proceed just break it down.

The scanf is responsible for saving our input in local_1. Every reference to local variables is made through the ebp register via an offset as stated in the beginning. Remember the stack layout from the previous link. After a bunch of instructions, the program compares our input with local_3. The instructions are quite simple. The program adds two values and then squares the result. If the result matches our input it prints "Password OK :)". Notice the reading difficulty of the operation compared to a high level programming language.

Until next time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment