Exploit a buffer overflow

前端 未结 1 1963
渐次进展
渐次进展 2021-02-19 18:52

For my studies I try to create a payload so that it overflows the buffer and calls a \"secret\" function called \"target\"

This is the code I use for testing on an i686<

相关标签:
1条回答
  • 2021-02-19 19:13

    You need enough data to fill the reserved memory for the stack where 'buffer' is located, then more to overwrite the stack frame pointer, then overwrite the return address with the address of target() and then one more address within target() but not at the very beginning of the function - enter it so the old stack frame pointer is not pushed on the stack. That will cause you to run target instead of returning properly from vulnerable() and then run target() again so you return from target() to main() and so exit without a segmentation fault.

    When we enter vulnerable() for the first time and are about to put data into the 'buffer' variable the stack looks like this:

    -----------
    |  24-bytes of local storage - 'buffer' lives here 
    -----------
    |  old stack frame pointer (from main) <-- EBP points here
    -----------
    |  old EIP (address in main)
    -----------
    |  'input' argument for 'vulnerable'
    -----------
    |  top of stack for main
    -----------
    |  ... more stack here ...
    

    So starting at the address of 'buffer' we need to put in 24-bytes of junk to get past the local storage reserved on the stack, then 4-more bytes to get past the old stack frame pointer stored on the stack, then we are at the location where the old EIP is stored. That's the instruction pointer that the CPU follows blindly. We like him. He's going to help us crush this program. We overwrite the value of the old EIP in the stack which currently points to an address in main() with the start address of target() which is found via the gdb disassemble command:

    (gdb) disas target
    Dump of assembler code for function target:
       0x08048424 <+0>:     push   %ebp
       0x08048425 <+1>:     mov    %esp,%ebp
       0x08048427 <+3>:     sub    $0x18,%esp
       0x0804842a <+6>:     movl   $0x8048554,(%esp)
       0x08048431 <+13>:    call   0x8048354 <puts@plt>
       0x08048436 <+18>:    leave
       0x08048437 <+19>:    ret
    End of assembler dump.
    

    The address of the target() function is 0x08048424. Since the (my system at least) system is little endian we enter those values with the LSB first so x24, x84, x04, and x08.

    But that leaves us with a problem because as vulnerable() returns it pops all the junk that we put in the stack off the stack and we are left with a stack that looks like this when we are just about to process in target() for the first time:

    -----------
    |  'input' argument for 'vulnerable'
    -----------
    |  top of stack for main
    -----------
    | ... more stack here ...
    

    So when target() wants to return it will not find the return address on the top of its stack as expected and so will have a segmentation fault.

    So we want to force a new return value onto the top of the stack before we start processing in target(). But what value to choose? We don't want to push the EBP because it contains garbage. Remember? We shoved garbage into it when we overwrote 'buffer'. So instead push the target() instruction just after the

    push %ebp

    ( in this case address 0x08048425 ).

    This means that the stack will look like this when target() is ready to return for the first time:

    -----------
    |  address of mov %esp, %ebp instruction in target()
    -----------
    |  top of stack for main
    -----------
    |  ... more stack here ...
    

    So upon return from target() the first time , the EIP will now point at the second instruction in target(), which means that the second time we process through target() it has the same stack that main() had when it processed. The top of the stack is the same top of the stack for main(). Now the stack looks like:

    -----------
    |  top of stack for main
    -----------
    |  ... more stack here ...
    

    So when target() returns the second time it has a good stack to return with since it is using the same stack that main() used and so the program exits normally.

    So to sum it up that is 28-bytes followed by the address of the first instruction in target() followed by the address of the second instruction in target().

    sys1:/usr2/home> ./buggy AAAAAAAAAABBBBBBBBBBCCCCCCCC$'\x24\x84\x04\x08'$'\x25\x84\x04\x08'
    target
    target
    sys1:/usr2/home>
    
    0 讨论(0)
提交回复
热议问题