Friday 7 November 2014

Reversing a bonus challenge binary which appeared in coursera malware class.

The challenge is to crack the challenge by answering it right.

seed@seed-desktop:~/projects/2$ ./bonus_reverse-challenge
Are you feeling lucky today? 1
^C
[2]+  Stopped                 ./bonus_reverse-challenge

seed@seed-desktop:~/projects/2$ file ./bonus_reverse-challenge
./bonus_reverse-challenge: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, stripped

This is a stripped binary so cannot find main in objdump output. So the guess is since "Are you feeling lucky today?" is printed by
a call to printf with the string as an argument in the program. we need to find where the string is and where is getting loaded to stack
just before a call to printf, then we know that we are somewhere in code section and check what happens after that to our input.

(gdb) p/x 'A'
$1 = 0x41
(gdb) p/x 'r'
$2 = 0x72
(gdb)

"Are you feeling lucky today?" starts with 'A' and 'r' so we try to find 41 and 72 in objdump.

seed@seed-desktop:~/projects/2$ objdump -D ./bonus_reverse-challenge > obj
seed@seed-desktop:~/projects/2$ grep -n "41 72" obj
1018: 8048bfa:    00 41 72                 add    %al,0x72(%ecx)
(gdb) x/s 0x8048bfb
0x8048bfb:     "Are you feeling lucky today? "
searching 8048bfb to figuring who is loading it to stack in objdump gives.
 8048997:       b8 fb 8b 04 08          mov    $0x8048bfb,%eax
 804899c:       89 04 24                mov    %eax,(%esp)
 804899f:       e8 0c fb ff ff          call   80484b0 <printf@plt>
 80489a4:       a1 60 a0 04 08          mov    0x804a060,%eax
 80489a9:       89 04 24                mov    %eax,(%esp)
 80489ac:       e8 0f fb ff ff          call   80484c0 <fflush@plt>
 80489b1:       c7 44 24 08 ff 01 00    movl   $0x1ff,0x8(%esp)
 80489b8:       00
 80489b9:       8d 44 24 20             lea    0x20(%esp),%eax
 80489bd:       89 44 24 04             mov    %eax,0x4(%esp)
 80489c1:       c7 04 24 00 00 00 00    movl   $0x0,(%esp)
 80489c8:       e8 d3 fa ff ff          call   80484a0 <read@plt>
 80489cd:       8d 44 24 20             lea    0x20(%esp),%eax
 80489d1:       c7 44 24 1c ff ff ff    movl   $0xffffffff,0x1c(%esp)
 80489d8:       ff
 80489d9:       89 c2                   mov    %eax,%edx
 80489db:       b8 00 00 00 00          mov    $0x0,%eax
 80489e0:       8b 4c 24 1c             mov    0x1c(%esp),%ecx
 80489e4:       89 d7                   mov    %edx,%edi
 80489e6:       f2 ae                   repnz scas %es:(%edi),%al
 80489e8:       89 c8                   mov    %ecx,%eax
 80489ea:       f7 d0                   not    %eax
 80489ec:       83 e8 01                sub    $0x1,%eax
 80489ef:       89 84 24 28 02 00 00    mov    %eax,0x228(%esp)
 80489f6:       8b 84 24 28 02 00 00    mov    0x228(%esp),%eax
 80489fd:       83 e8 01                sub    $0x1,%eax
 8048a00:       0f b6 44 04 20          movzbl 0x20(%esp,%eax,1),%eax
 8048a05:       3c 0a                   cmp    $0xa,%al
 8048a07:       75 0f                   jne    8048a18 <close@plt+0x498>
 8048a09:       8b 84 24 28 02 00 00    mov    0x228(%esp),%eax
 8048a10:       83 e8 01                sub    $0x1,%eax
 8048a13:       c6 44 04 20 00          movb   $0x0,0x20(%esp,%eax,1)
 8048a18:       0f b6 44 24 20          movzbl 0x20(%esp),%eax
 8048a1d:       0f be c0                movsbl %al,%eax
 8048a20:       83 f8 42                cmp    $0x42,%eax
 8048a23:       74 17                   je     8048a3c <close@plt+0x4bc>
 8048a25:       83 f8 43                cmp    $0x43,%eax
 8048a28:       74 1f                   je     8048a49 <close@plt+0x4c9>
 8048a2a:       83 f8 41                cmp    $0x41,%eax
 8048a2d:       75 27                   jne    8048a56 <close@plt+0x4d6>
 8048a2f:       c7 84 24 2c 02 00 00    movl   $0x804872b,0x22c(%esp)
 8048a36:       2b 87 04 08
 8048a3a:       eb 1c                   jmp    8048a58 <close@plt+0x4d8>
 8048a3c:       c7 84 24 2c 02 00 00    movl   $0x8048644,0x22c(%esp)
 8048a43:       44 86 04 08
 8048a47:       eb 0f                   jmp    8048a58 <close@plt+0x4d8>
 8048a49:       c7 84 24 2c 02 00 00    movl   $0x80486ca,0x22c(%esp)
 8048a50:       ca 86 04 08
 8048a54:       eb 02                   jmp    8048a58 <close@plt+0x4d8>
 8048a56:       eb fe                   jmp    8048a56 <close@plt+0x4d6>
 8048a58:       0f b6 44 24 20          movzbl 0x20(%esp),%eax
 8048a5d:       0f be c0                movsbl %al,%eax
 8048a60:       83 e8 42                sub    $0x42,%eax
 8048a63:       89 84 24 24 02 00 00    mov    %eax,0x224(%esp)
 8048a6a:       8b 84 24 24 02 00 00    mov    0x224(%esp),%eax
 8048a71:       89 44 24 04             mov    %eax,0x4(%esp)
 8048a75:       8d 44 24 20             lea    0x20(%esp),%eax
 8048a79:       83 c0 01                add    $0x1,%eax
 8048a7c:       89 04 24                mov    %eax,(%esp)
 8048a7f:       8b 84 24 2c 02 00 00    mov    0x22c(%esp),%eax
 8048a86:       ff d0                   call   *%eax
 8048a88:       89 84 24 20 02 00 00    mov    %eax,0x220(%esp)
 8048a8f:       83 bc 24 20 02 00 00    cmpl   $0x0,0x220(%esp)
 8048a96:       00
 8048a97:       74 1a                   je     8048ab3 <close@plt+0x533>
 8048a99:       b8 19 8c 04 08          mov    $0x8048c19,%eax
 8048a9e:       8d 54 24 20             lea    0x20(%esp),%edx
 8048aa2:       83 c2 01                add    $0x1,%edx
 8048aa5:       89 54 24 04             mov    %edx,0x4(%esp)
 8048aa9:       89 04 24                mov    %eax,(%esp)
 8048aac:       e8 ff f9 ff ff          call   80484b0 <printf@plt>
 8048ab1:       eb 23                   jmp    8048ad6 <close@plt+0x556>
 8048ab3:       0f b6 44 24 20          movzbl 0x20(%esp),%eax
 8048ab8:       3c 42                   cmp    $0x42,%al

As you can see this is similar to reverse-ex:
printf("Are you feeling lucky today?");
fflush()
read(0,buf,511)
if (buf[n
n = strlen(buf);
if(buf[n-1] = '\n')
    buf[n-1] = 0;
   
switch[buf[0])   
    case 0x42:
        calls 0x8048644
        break;
    case 0x43:
        calls $0x80486ca
        break;
    case 0x41:
        calls 0x804872b
        break;
    default:
        loop
       
Let's test above analysis.

seed@seed-desktop:~/projects/2$ ./bonus_reverse-challenge
Are you feeling lucky today? A
[~] Maybe.
seed@seed-desktop:~/projects/2$ ./bonus_reverse-challenge
Are you feeling lucky today? B
[-] Nope.
seed@seed-desktop:~/projects/2$ ./bonus_reverse-challenge
Are you feeling lucky today? C
[~] Maybe.
seed@seed-desktop:~/projects/2$ ./bonus_reverse-challenge
Are you feeling lucky today? D
^C
[4]+  Stopped                 ./bonus_reverse-challenge

looks like some progress. Let's choose B route since it is different. Other's will lead to dead-end
but interesting stuff.
So jumping to 0x8048644 the 'B' related answer. This function gets called with two arguments (buf + 1) and (buf[0] - 0x42 = 0).

 8048644:       55                      push   %ebp
 8048645:       89 e5                   mov    %esp,%ebp
 8048647:       57                      push   %edi
 8048648:       56                      push   %esi
 8048649:       83 ec 10                sub    $0x10,%esp
 804864c:       8b 45 08                mov    0x8(%ebp),%eax
 804864f:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048652:       8b 55 0c                mov    0xc(%ebp),%edx
 8048655:       50                      push   %eax
 8048656:       31 c0                   xor    %eax,%eax
 8048658:       68 64 86 04 08          push   $0x8048664
 804865d:       58                      pop    %eax
 804865e:       01 d0                   add    %edx,%eax
 8048660:       50                      push   %eax
 8048661:       c3                      ret

Here ret is popping 0x8048664 and jumping to it, Now instruction pointer is at 0x8048664.
 8048662:       b8 01 c7 45 f0          mov    $0xf045c701,%eax
 8048667:       fa                      cli
 8048668:       00 00                   add    %al,(%eax)
 804866a:       00 58 eb                add    %bl,-0x15(%eax)
 804866d:       17                      pop    %ss
 804866e:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048671:       0f b6 00                movzbl (%eax),%eax
...
As you can 0x8048664 is middle of instruction at  0x8048662, so this means objdump disassembly for this piece of
code is bad, let's fix it to find the right instructions which get executed.

code jumps to 8048664 which is the middle of disassembled instruction at 8048662.
So we need to find to what extent the disassembly is bad and of-course the real
opcodes that will be executed.
So implemented a simple C code which converts hex to binary for the opcodes in hex
from address 8048664 for some bytes till the new disassembly (got from feeding the
binary output to objdump) matches the original disassembly.

seed@seed-desktop:~/projects/2$ cat x.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


unsigned char a[64] = {0xc7,0x45,0xf0,0xfa,0x00,0x00,0x00,0x58,
              0xeb,0x17,0x8b,0x45,0xf4,0x0f,0xb6,0x00,
              0x8b,0x55,0xf0,0x83,0xe2,0x2b,0x31,0xc2,
              0x8b,0x45,0xf4,0x88,0x10,0x83,0x45,0xf4,
              0x01,0x8b,0x45,0xf4,0x0f,0xb6,0x00,0x84,
              0xc0,0x75,0xdf,0x8b,0x45,0x08,0x89,0xc2,
              0xb8,0xc0,0x8b,0x04,0x08,0xb9,0x0f,0x00,
              0x00,0x00,0x89,0xd6,0x89,0xc7,0xf3,0xa6};
main()
{
int fd;
int ret;

fd = open("c", O_CREAT|O_WRONLY);
if (fd > 0) {
ret = write(fd,a, 64);
}
printf("%d %d\n", fd, ret);
}

seed@seed-desktop:~/projects/2$ gcc x.c
seed@seed-desktop:~/projects/2$ ./a.out
3 64
seed@seed-desktop:~/projects/2$ objdump -D -b binary -mi386 c

c:     file format binary


Disassembly of section .data:

00000000 <.data>:
   0:    c7 45 f0 fa 00 00 00     movl   $0xfa,-0x10(%ebp)
   7:    58                       pop    %eax
   8:    eb 17                    jmp    0x21
   a:    8b 45 f4                 mov    -0xc(%ebp),%eax
   d:    0f b6 00                 movzbl (%eax),%eax
  10:    8b 55 f0                 mov    -0x10(%ebp),%edx
  13:    83 e2 2b                 and    $0x2b,%edx
  16:    31 c2                    xor    %eax,%edx
  18:    8b 45 f4                 mov    -0xc(%ebp),%eax
  1b:    88 10                    mov    %dl,(%eax)
  1d:    83 45 f4 01              addl   $0x1,-0xc(%ebp)
  21:    8b 45 f4                 mov    -0xc(%ebp),%eax
  24:    0f b6 00                 movzbl (%eax),%eax
  27:    84 c0                    test   %al,%al
  29:    75 df                    jne    0xa
  2b:    8b 45 08                 mov    0x8(%ebp),%eax
  2e:    89 c2                    mov    %eax,%edx
  30:    b8 c0 8b 04 08           mov    $0x8048bc0,%eax
  35:    b9 0f 00 00 00           mov    $0xf,%ecx
  3a:    89 d6                    mov    %edx,%esi
  3c:    89 c7                    mov    %eax,%edi
  3e:    f3 a6                    repz cmpsb %es:(%edi),%ds:(%esi)

So only the hex bytes (\xc7\x45\xf0\x00\x00\x00\x58\xeb\x17) are the bad disassembled codes
otherwise everything remains the same.
 8048662:       b8 01 c7 45 f0          mov    $0xf045c701,%eax
 8048667:       fa                      cli
 8048668:       00 00                   add    %al,(%eax)
 804866a:       00 58 eb                add    %bl,-0x15(%eax)
 804866d:       17                      pop    %ss

 is equivalent to

    0:    c7 45 f0 fa 00 00 00     movl   $0xfa,-0x10(%ebp)
   7:    58                       pop    %eax
   8:    eb 17                    jmp    0x21

 The following remaining disassembled instructions are valid.
 804866e:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048671:       0f b6 00                movzbl (%eax),%eax
 8048674:       8b 55 f0                mov    -0x10(%ebp),%edx <== 0xfa gets loaded here.
 8048677:       83 e2 2b                and    $0x2b,%edx
 804867a:       31 c2                   xor    %eax,%edx
 804867c:       8b 45 f4                mov    -0xc(%ebp),%eax
 804867f:       88 10                   mov    %dl,(%eax)
 8048681:       83 45 f4 01             addl   $0x1,-0xc(%ebp)
 8048685:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048688:       0f b6 00                movzbl (%eax),%eax
 804868b:       84 c0                   test   %al,%al
 804868d:       75 df                   jne    804866e <close@plt+0xee>
...
So it jumps to 804868d which jumps back to 804866e. As you can see this piece of code
is xoring 0x2b with (buf contents bitwise AND with 0xFA) and storing it to buf contents till buf[blah] string reaches a 0 (NULL character).

 804868f:       8b 45 08                mov    0x8(%ebp),%eax
 8048692:       89 c2                   mov    %eax,%edx
 8048694:       b8 c0 8b 04 08          mov    $0x8048bc0,%eax
 8048699:       b9 0f 00 00 00          mov    $0xf,%ecx
 804869e:       89 d6                   mov    %edx,%esi
 80486a0:       89 c7                   mov    %eax,%edi
 80486a2:       f3 a6                   repz cmpsb %es:(%edi),%ds:(%esi)
 80486a4:       0f 97 c2                seta   %dl
 80486a7:       0f 92 c0                setb   %al
 80486aa:       89 d1                   mov    %edx,%ecx
 80486ac:       28 c1                   sub    %al,%cl
 80486ae:       89 c8                   mov    %ecx,%eax
 80486b0:       0f be c0                movsbl %al,%eax
 80486b3:       85 c0                   test   %eax,%eax
 80486b5:       75 07                   jne    80486be <close@plt+0x13e>
 80486b7:       b8 01 00 00 00          mov    $0x1,%eax            <== Success
 80486bc:       eb 05                   jmp    80486c3 <close@plt+0x143>
 80486be:       b8 00 00 00 00          mov    $0x0,%eax
 80486c3:       83 c4 10                add    $0x10,%esp
 80486c6:       5e                      pop    %esi
 80486c7:       5f                      pop    %edi
 80486c8:       5d                      pop    %ebp
 80486c9:       c3                      ret

 so modified input = (input ^ (0xfa & 0x2b)) = input ^ 0x2a.
(gdb) p/x 0xfa & 0x2b
$5 = 0x2a

The above code strcmp(modified input, $0x8048bc0)
(gdb) x/s  0x8048bc0
0x8048bc0:     "xKZl_^_XCY^CIE"

input ^ 0x2a =  "xKZl_^_XCY^CIE"
input ^ 0x2a ^ 0x2a = "xKZl_^_XCY^CIE" ^ 0x2a (xoring for all characters).
input = "xKZl_^_XCY^CIE" ^ 0x2a (xoring for all characters).

$ python -c 'print "".join([chr(ord(c)^0x2a) for c in "xKZl_^_XCY^CIE"])'
RapFuturistico

So the input is "BRapFuturistico".

seed@seed-desktop:~/projects/2$ ./bonus_reverse-challenge
Are you feeling lucky today? BRapFuturistico
[+] WooT!: xKZl_^_XCY^CIE

DONE...

[NOTE:]
Actual disassembly of the function for option 'B':
 8048644:       55                      push   %ebp
 8048645:       89 e5                   mov    %esp,%ebp
 8048647:       57                      push   %edi
 8048648:       56                      push   %esi
 8048649:       83 ec 10                sub    $0x10,%esp
 804864c:       8b 45 08                mov    0x8(%ebp),%eax
 804864f:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048652:       8b 55 0c                mov    0xc(%ebp),%edx
 8048655:       50                      push   %eax
 8048656:       31 c0                   xor    %eax,%eax
 8048658:       68 64 86 04 08          push   $0x8048664
 804865d:       58                      pop    %eax
 804865e:       01 d0                   add    %edx,%eax
 8048660:       50                      push   %eax
 8048661:       c3                      ret

Replace following from
 8048662:       b8 01 c7 45 f0          mov    $0xf045c701,%eax
 8048667:       fa                      cli
 8048668:       00 00                   add    %al,(%eax)
 804866a:       00 58 eb                add    %bl,-0x15(%eax)
 804866d:       17                      pop    %ss
to
   0:    c7 45 f0 fa 00 00 00     movl   $0xfa,-0x10(%ebp)
   7:    58                       pop    %eax
   8:    eb 17                    jmp    0x21 (0x 8048685)

 804866e:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048671:       0f b6 00                movzbl (%eax),%eax
 8048674:       8b 55 f0                mov    -0x10(%ebp),%edx
 8048677:       83 e2 2b                and    $0x2b,%edx
 804867a:       31 c2                   xor    %eax,%edx
 804867c:       8b 45 f4                mov    -0xc(%ebp),%eax
 804867f:       88 10                   mov    %dl,(%eax)
 8048681:       83 45 f4 01             addl   $0x1,-0xc(%ebp)
 8048685:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048688:       0f b6 00                movzbl (%eax),%eax
 804868b:       84 c0                   test   %al,%al
 804868d:       75 df                   jne    804866e <close@plt+0xee>
 804868f:       8b 45 08                mov    0x8(%ebp),%eax
 8048692:       89 c2                   mov    %eax,%edx
 8048694:       b8 c0 8b 04 08          mov    $0x8048bc0,%eax
 8048699:       b9 0f 00 00 00          mov    $0xf,%ecx
 804869e:       89 d6                   mov    %edx,%esi
 80486a0:       89 c7                   mov    %eax,%edi
 80486a2:       f3 a6                   repz cmpsb %es:(%edi),%ds:(%esi)
 80486a4:       0f 97 c2                seta   %dl
 80486a7:       0f 92 c0                setb   %al
 80486aa:       89 d1                   mov    %edx,%ecx
 80486ac:       28 c1                   sub    %al,%cl
 80486ae:       89 c8                   mov    %ecx,%eax
 80486b0:       0f be c0                movsbl %al,%eax
 80486b3:       85 c0                   test   %eax,%eax
 80486b5:       75 07                   jne    80486be <close@plt+0x13e>
 80486b7:       b8 01 00 00 00          mov    $0x1,%eax
 80486bc:       eb 05                   jmp    80486c3 <close@plt+0x143>
 80486be:       b8 00 00 00 00          mov    $0x0,%eax
 80486c3:       83 c4 10                add    $0x10,%esp
 80486c6:       5e                      pop    %esi
 80486c7:       5f                      pop    %edi
 80486c8:       5d                      pop    %ebp
 80486c9:       c3                      ret

  

No comments:

Post a Comment