Как я могу объяснить поведение следующего эксплойта шеллкода? - PullRequest
5 голосов
/ 08 ноября 2010

Это шелл-код для использования уязвимости переполнения буфера.Он устанавливает setuid(0) и порождает оболочку, используя execve().Вот как я это интерпретировал:

xor    %ebx,%ebx       ; Xoring to make ebx value 0
lea    0x17(%ebx),%eax ; adds 23 to 0 and loads effective addr to eax. for setuid()
int    $0x80           ; interrupt
push   %ebx            ; push ebx
push   $0x68732f6e     ; push address // why this address only????
push   $0x69622f2f     ; push address // same question
mov    %esp,%ebx
push   %eax
push   %ebx
mov    %esp,%ecx
cltd                   ; mov execve sys call into al
mov    $0xb,%al
int    $0x80           ; interrupt

Может кто-нибудь объяснить все шаги ясно?

1 Ответ

11 голосов
/ 09 ноября 2010

int - это код операции для запуска программного прерывания.Программные прерывания нумеруются (от 0 до 255) и обрабатываются ядром.В системах Linux прерывание 128 (0x80) является обычной точкой входа для системных вызовов.Ядро ожидает аргументы системного вызова в регистрах;в частности, регистр% eax определяет, о каком системном вызове идет речь.

  1. Установите% ebx равным 0
  2. Вычислите% ebx + 23 и сохраните результат в% eax (код операции - lea как «эффективный адрес загрузки», но не требуется доступ к памяти; это просто хитрый способ сделать дополнение).
  3. Системный вызов.% eax содержит 23, что означает, что системный вызов setuid.Этот системный вызов использует один аргумент (целевой UID), который можно найти в% ebx, который обычно содержит 0 в этой точке (он был задан в первой инструкции).Примечание: по возвращении регистры не изменяются, за исключением% eax, который содержит возвращаемое значение системного вызова, обычно 0 (если вызов был успешным).
  4. Push% ebx в стек (который все еще0).
  5. Вставьте $ 0x68732f6e в стек.
  6. Вставьте $ 0x69622f2f в стек.Поскольку стек растет «вниз» и поскольку процессоры x86 используют кодирование с прямым порядком байтов, эффект от инструкций 4–6 состоит в том, что% esp (указатель стека) теперь указывает на последовательность из двенадцати байтов значений 2f 2f 62 69 6e 2f73 68 00 00 00 00 (в шестнадцатеричном формате).Это кодировка строки "// bin / sh" (с завершающим нулем и тремя дополнительными нулями после него).
  7. Переместить% esp в% ebx.Теперь% ebx содержит указатель на строку "// bin / sh", которая была построена выше.
  8. Push% eax в стеке (% eax равно 0 в этот момент, это возвращаемый статус из setuid).
  9. Вставить% ebx в стек (указатель на "// bin / sh").Инструкции 8 и 9 строят в стеке массив из двух указателей, первый из которых является указателем на «// bin / sh», а второй - указателем NULL.Этот массив - то, что системный вызов execve будет использовать в качестве второго аргумента.
  10. Переместить% esp в% ecx.Теперь% ecx указывает на массив, построенный с инструкциями 8 и 9.
  11. Расширение знака% eax в% edx:% eax.cltd - это синтаксис AT & T для того, что в документации Intel называется cdq.Поскольку% eax в этой точке равен нулю, это также устанавливает% edx в ноль.
  12. Установите% al (наименее значимый байт% eax) равным 11. Поскольку% eax было равно нулю, все значение% eaxсейчас 11.
  13. Системный вызов.Значение% eax (11) идентифицирует системный вызов как execve.execve ожидает три аргумента, в% ebx (указатель на строку с именем исполняемого файла),% ecx (указатель на массив указателей на строки, которые являются аргументами программы, первый из которых является копией имени программы, для использования самой вызываемой программой) и% edx (указатель на массив указателей на строки, которые являются переменными среды; Linux допускает, что это значение равно NULL, для пустой среды), соответственно.

Таким образом, код сначала вызывает setuid(0), а затем вызывает execve("//bin/sh", x, 0), где x указывает на массив из двух указателей, первый из которых является указателем на "// bin / sh", а другой равен NULL.

Этот код довольно запутанный, потому что он хочет избежать нулей: при сборке в двоичные коды операций последовательность команд использует только ненулевые байты.Например, если бы 12-я инструкция была movl $0xb,%eax (установив весь% eax на 11), то двоичное представление этого кода операции содержало бы три байта значения 0. Отсутствие нуля делает эту последовательность пригодной для использования в качестве содержимогостроки с нулем в конце.Разумеется, это предназначено для атаки на ошибочные программы через переполнение буфера.

...