Rootme No software breakpoints Cracking Challenge

Warning: Undefined array key 1 in /var/www/wptbox/wp-content/plugins/coblocks/src/blocks/gist/index.php on line 27

Warning: Undefined array key 1 in /var/www/wptbox/wp-content/plugins/coblocks/src/blocks/gist/index.php on line 27

Here is another very interesting challenge from Rootme. The title says ELF – no software breakpoints.

View post on

Let’s run the file command and see.

% file ch20.bin
ch20.bin: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped

The executable seemed to be striped.
Next I examined the sections in file and the .text section starts at 0x08048080

View post on

This is the disassembly of the text section. I spent some time trying to understand the logic. Well let’s see what this is 🙂

ch20.bin: file format elf32-i386
Disassembly of section .text:
08048080 <.text>:
8048080: b8 04 00 00 00 mov eax,0x4
8048085: bb 01 00 00 00 mov ebx,0x1
804808a: b9 a1 91 04 08 mov ecx,0x80491a1
804808f: ba 26 00 00 00 mov edx,0x26
8048094: cd 80 int 0x80
8048096: b8 03 00 00 00 mov eax,0x3
804809b: 31 db xor ebx,ebx
804809d: b9 88 91 04 08 mov ecx,0x8049188
80480a2: ba 33 00 00 00 mov edx,0x33
80480a7: cd 80 int 0x80
80480a9: 31 c9 xor ecx,ecx
80480ab: b8 80 80 04 08 mov eax,0x8048080
80480b0: bb 23 81 04 08 mov ebx,0x8048123
80480b5: e8 5b 00 00 00 call 0x8048115
80480ba: 89 ca mov edx,ecx
80480bc: b9 19 00 00 00 mov ecx,0x19
80480c1: b8 55 91 04 08 mov eax,0x8049155
80480c6: bb 88 91 04 08 mov ebx,0x8049188
80480cb: d1 ca ror edx,1
80480cd: 8a 44 08 ff mov al,BYTE PTR [eax+ecx*1-0x1]
80480d1: 8a 5c 0b ff mov bl,BYTE PTR [ebx+ecx*1-0x1]
80480d5: 30 d8 xor al,bl
80480d7: 30 d0 xor al,dl
80480d9: 75 1b jne 0x80480f6
80480db: 49 dec ecx
80480dc: 75 e3 jne 0x80480c1
80480de: b8 04 00 00 00 mov eax,0x4
80480e3: bb 01 00 00 00 mov ebx,0x1
80480e8: b9 24 91 04 08 mov ecx,0x8049124
80480ed: ba 26 00 00 00 mov edx,0x26
80480f2: cd 80 int 0x80
80480f4: eb 16 jmp 0x804810c
80480f6: b8 04 00 00 00 mov eax,0x4
80480fb: bb 01 00 00 00 mov ebx,0x1
8048100: b9 4a 91 04 08 mov ecx,0x804914a
8048105: ba 0b 00 00 00 mov edx,0xb
804810a: cd 80 int 0x80
804810c: b8 01 00 00 00 mov eax,0x1
8048111: 31 db xor ebx,ebx
8048113: cd 80 int 0x80
8048115: 29 c3 sub ebx,eax
8048117: 31 c9 xor ecx,ecx
8048119: 02 08 add cl,BYTE PTR [eax]
804811b: c1 c1 03 rol ecx,0x3
804811e: 40 inc eax
804811f: 4b dec ebx
8048120: 75 f7 jne 0x8048119
8048122: c3 ret

Let’s open in gdb and start debugging.

View post on

   0x8048080:	mov    eax,0x4
   0x8048085:	mov    ebx,0x1
   0x804808a:	mov    ecx,0x80491a1
   0x804808f:	mov    edx,0x26
   0x8048094:	int    0x80

It will first print the text “Welcome to Root-Me Challenges\r\nPass: ” using the write system call.

   0x8048096:	mov    eax,0x3
   0x804809b:	xor    ebx,ebx
   0x804809d:	mov    ecx,0x8049188
   0x80480a2:	mov    edx,0x33
   0x80480a7:	int    0x80

Next it will store the input in 0x8049188 using the read system call and store in ecx.

   0x80480a9:	xor    ecx,ecx
   0x80480ab:	mov    eax,0x8048080
   0x80480b0:	mov    ebx,0x8048123
   0x80480b5:	call   0x8048115

Next it will store 0x8048080 which means the starting address of the text section in eax and the ending section 0x8048123 of the text section in ebx. Next it calls 0x8048115

   0x8048115:	sub    ebx,eax
   0x8048117:	xor    ecx,ecx
   0x8048119:	add    cl,BYTE PTR [eax]
   0x804811b:	rol    ecx,0x3
   0x804811e:	inc    eax
   0x804811f:	dec    ebx
   0x8048120:	jne    0x8048119
   0x8048122:	ret

Next it subtracts ebx by eax which results in the size of the text section which is 163. Zero outs the ecx register. Add each opcode of the program’s text section into the cl register. Rotate left ecx by 3 bits and store in ecx. Next increment to the next opcode in eax and decrement the counter. If ebx not equal to zero keep looping. As you can clearly see this is a loop which will rotate left each opcode of the text section and sum in the cl register. This seems to be calculating a checksum for the serial routine.

This is known anti debugging technique in which can’t place any software breakpoints in the application itself. Because when we hit a breakpoint in a user mode applications a 0xCC (INT 3) will be placed in the code, hence the calculation will be wrong and will generate a wrong checksum. So, while debugging even we enter the correct password we won’t be validated because the checksum will be wrong.
The problem arises in calculating the checksum. What I did was I extracted the opcodes of the text section like we extract shellcode 😉 Then we can calculate the checksum like in the program.

View post on

extern printf
extern exit
global main
section .text
lea esi, [shellcode] ; load offset of shellcode
mov ebx, shellcode_len ; mov the len of shellcode
xor ecx, ecx ; Zero out ecx
add cl, [esi] ; add opcode to cl
rol ecx, 0x3 ; Rotate left ecx by 3
inc esi ; incremenet esi
dec ebx ; decrement ebx
jnz _loop ; if ebx != 0 loop
push ecx ; push the result to stack
push fmt_checksum ; push the format string
call printf ; print it
mov ebx, [esp+4] ; mov the result from stack to ebx
add esp, 0x8 ; Clear the stack
push 1
call exit
section .data
fmt: db "Checksum: %x",0xa,0
db 0xb8,0x04,0x00,0x00,0x00,0xbb,0x01,0x00,0x00,0x00
db 0xb9,0xa1,0x91,0x04,0x08,0xba,0x26,0x00,0x00,0x00
db 0xcd,0x80,0xb8,0x03,0x00,0x00,0x00,0x31,0xdb,0xb9
db 0x88,0x91,0x04,0x08,0xba,0x33,0x00,0x00,0x00,0xcd
db 0x80,0x31,0xc9,0xb8,0x80,0x80,0x04,0x08,0xbb,0x23
db 0x81,0x04,0x08,0xe8,0x5b,0x00,0x00,0x00,0x89,0xca
db 0xb9,0x19,0x00,0x00,0x00,0xb8,0x55,0x91,0x04,0x08
db 0xbb,0x88,0x91,0x04,0x08,0xd1,0xca,0x8a,0x44,0x08
db 0xff,0x8a,0x5c,0x0b,0xff,0x30,0xd8,0x30,0xd0,0x75
db 0x1b,0x49,0x75,0xe3,0xb8,0x04,0x00,0x00,0x00,0xbb
db 0x01,0x00,0x00,0x00,0xb9,0x24,0x91,0x04,0x08,0xba
db 0x26,0x00,0x00,0x00,0xcd,0x80,0xeb,0x16,0xb8,0x04
db 0x00,0x00,0x00,0xbb,0x01,0x00,0x00,0x00,0xb9,0x4a
db 0x91,0x04,0x08,0xba,0x0b,0x00,0x00,0x00,0xcd,0x80
db 0xb8,0x01,0x00,0x00,0x00,0x31,0xdb,0xcd,0x80,0x29
db 0xc3,0x31,0xc9,0x02,0x08,0xc1,0xc1,0x03,0x40,0x4b
db 0x75,0xf7,0xc3
shellcode_len equ $-shellcode

View post on

The checksum is “ac77e166”

Let’s proceed and see knowing we will get a wrong checksum while inside the debugger.

   0x80480ba:	mov    edx,ecx
   0x80480bc:	mov    ecx,0x19
   0x80480c1:	mov    eax,0x8049155
   0x80480c6:	mov    ebx,0x8049188
   0x80480cb:	ror    edx,1
   0x80480cd:	mov    al,BYTE PTR [eax+ecx*1-0x1]
   0x80480d1:	mov    bl,BYTE PTR [ebx+ecx*1-0x1]
   0x80480d5:	xor    al,bl
   0x80480d7:	xor    al,dl
   0x80480d9:	jne    0x80480f6
   0x80480db:     dec    ecx
   0x80480dc:	jne    0x80480c1
   0x80480de:	mov    eax,0x4
   0x80480e3:	mov    ebx,0x1
   0x80480e8:	mov    ecx,0x8049124
   0x80480ed:	mov    edx,0x26
   0x80480f2:	int    0x80

Next we have the serial routine which is a loop that. The checksum will be moved to edx and ecx will contain 25 which is the length of our password. We see that eax contains 0x8049155 which is 25 bytes of the key.

View post on

The user entered password will be stored in ebx. The checksum edx will be rotated to right by 1 and stored in edx. Mov al, [eax+ecx*1-0x1] means the starting address of the key bytes + 25 which will point to the 25th byte of the key 0xe0. Likewise this will place the each byte starting from the last byte in descending order basically and place in the al register.
Every last byte of our entered password will be store in the bl register like the above. Next the key byte will XORed by the entered password byte. Next the result will be XORed by the checksum byte. If the result is not equal to zero we will jump to bad boy which is 0x80480f6. If not we keep on looping. If loop went successfully it will print the message 0x8049124 “Well done man, use this pass to flag!\n”
The program basically check like this:

Password ^ Key byte ^ Checksum == 0

To get the password basically we just have to XOR the checksum with the key byte.

Checksum ^ Key byte = Password

After looking at the application logic since we calculated the checksum before it was easy to apply the serial routine and get the password like in the program, Simple XOR logic 😉
I wrote the keygen using NASM. It’s self-explanatory.

View post on

Well, here’s the high level version of the keygen written in C. I have written in a way that it would compile under both the GNU C compiler and the Microsoft’s Visual C compiler. This is due to the way both compilers handle inline assembly in two different formats.

View post on

I hope this challenge was fun and interesting 🙂

4 thoughts on “Rootme No software breakpoints Cracking Challenge

Leave a Reply