Как написать вирус на linux

Обновлено: 07.07.2024

Нет, я не собираюсь рассказывать, как написать своего шифровальщика-вымогателя, майнера или эксплуатировать супер-новую уязвимость, как вы могли подумать. И тем более я не горю желанием поднимать холивар «Linux безопаснее Windows?(да)». Моей целью было написание простого вируса для linux, некого, так сказать, «Just for Fun», единственной функцией которого является распространение своей копии. О том, что у меня получилось, я расскажу в этой статье. В конце я приведу ссылку на GitHub с исходниками.

image


Дисклеймер

Данная статья написана в ознакомительных целях. Автор ни в коем случае не призывает читателей к нарушению законодательства РФ. Пожалуйста, не повторяйте действия, описанные в данной статье, предварительно не ознакомившись с главой 28 УК РФ.

И что мы, собственно, будем делать?

Самым простым в реализации механизмом распространения вируса для меня показалось распространение через модифицированные deb/rpm пакеты. Пакеты формата deb и rpm сейчас являются наиболее популярным средством распространения по для Linux. Я остановил свой выбор на формате deb, так как количество пользователей Debian-based дистрибутивов преобладает над пользователями Red Hat и ее «последователей».

Еще необходимо, чтобы вирус автоматически запускался, и через каждый определенный период времени сканировал компьютер в поисках deb-пакетов. Для удобства отладки я выбрал период равный 10 минутам.

Что такое deb-пакет?

Deb-пакет представляет из себя архив формата .ar, который не использует сжатие. Внутри архива еще три файла: debian-bynary, control.tar и data.tar

debian.binary — текстовый файл, содержащий версию формата deb-пакета, на данный момент там всегда пишут «2.0».

control.tar — архив с файлами, содержащими информацию о пакете (например — обязательный файл control) и пакеты, необходимые для установки пакета (например — скрипты preinst, postinst, prerm и postrm, запускаемые до/после установки/удаления пакета). Может быть сжат с помощью gzip или xz, в таком случае к имени архива добавляется расширение .gz или .xz соответственно.

data.tar — архив с директориями, содержащими устанавливаемые файлы. Директории представлены деревом, в виде которого они должны извлечься в корень файловой системы. Может быть сжат с помощью gzip, bzip2, lzma, xz.

Нам необходимо обратить внимание на файл control из архива control.tar. Этот файл содержит информацию о пакете, такую как автор, описание, версию, приоритет пакета в системе и т. д. Меня интересует поле depends, в котором указаны зависимости (пакеты, без которых по из данного пакета не может работать). В это поле наш вирус будет дописывать fakeroot и dpkg — утилиты, которые понадобятся при модификации других пакетов на зараженном компьютере.

Для сборки deb-пакета создается корневая директория пакета. В нее кладутся директории с устанавливаемыми файлами и директория DEBIAN, содержащую служебные файлы, среди которых control и скрипты для установки/удаления. Затем выполняется команда fakeroot dpkg-deb --build ./path.

Сначала был демон

На момент написания вируса я еще плохо представлял, что такое Cron, и поэтому пошел путем написания собственного демона для systemd. Я создал файл trojan_penguin.service, который будет помещаться в директорию /lib/systemd/system, и добавил в нее следующее:


ExecStart=/usr/bin/trojan_penguin.sh — тут я указал путь к файлу (к будущему вирусу), который должен запускаться при старте системы.

Type=fork — это строка показывает, что процесс должен ответвиться от родительского процесса.
Я не видел необходимости в PID-файле, по этому я не стал его добавлять.

В мануалах по написанию своего демона фалы .service предлагается размещать в директориях /usr/lib/systemd/system/ или /etc/systemd/system/. Но я в своей убунте нашел директорию /lib/systemd/system. (у меня туда попал apache2.service). Может быть кто-нибудь в комментариях напишет, для чего нужна эта директория, и чем она отличается от двух других.

Файл /usr/bin/trojan_penguin.sh у меня получился таким:


Мы ищем deb-пакеты в разделе /home (а где их еще искать то?), пути к найденным файлам записываем в переменную list. Потом просто перебираем все строки из line и для каждого файла запускаем скрипт tp_infect.sh, который заразит этот файл. Когда я писал вирус, скрипты находились в отдельной директории, и для удобства я создал переменную debug, в которой я прописал путь к этой папке.

Демон готов, осталось научиться его запускать при старте системы. Для этого я написал скрипт postinstall. Он будет запускаться сразу после установки зараженного пакета и указывать, чтобы наш вирус запускался вместе с системой. Разместил я его в директории "/usr/bin/", чтобы от туда копировать его в заражаемые пакеты.

Модифицируем deb-пакет

Как я писал выше, архивы, содержащиеся в deb-пакете могут иметь разные разрешения. Я не стал заморачиваться, и рассмотрел только тот случай, когда архивы сжаты с помощью .xz. Файл /usr/bin/tp_infect.sh, отвечающий за модификацию, получил такое содержимое:

Проблемы с postinstall

Все бы хорошо, но теперь у нас проблема. А что если в пакете уже есть postinstal? Оригинальный postinstal может быть написан на разных языках (python, bash. ), может это даже бинарник. Это не позволят нам просто взять и дописать свой postinstall в него. Я решил эту проблему следующим образом:

Добавил в скрипт tp_infect.sh такую вещь:


А в postinstal вот это:


Одну проблему я решил, но появилась другая. Наш вирус будет модифицировать пакет, даже если он уже заражен. При модификации вирус увидит, что в пакете есть postinstal (который на самом деле наш), переместит его в /usr/bin/, тем самым перезаписав оригинал. Чтобы этого избежать, я добавил проверку в «tp_infect.sh», модифицировали мы этот файл или нет:

Собираем воедино

Вирус готов. Вот ссылка на GitHub, как и обещал. Этот вирус можно собрать в отдельный deb-пакет (запустите makedeb.sh) из репозитория. Чтобы внедрить вирус в какой-либо пакет, достаточно выполнить команду:


В репозитории есть две копии скрипта postinst

DEBIAN/postinst — эта копия выполняется только при установке пустого пакета с вирусом. Я его закомментировал, чтобы вирус не запускался после установки, а модивиццировал пакеты только по команде.

usr/bin/postinst — это копия вставляется в заражаемые пакеты.

А вывод очевиден и без этой статьи: не стоит скачивать и запускать программы из непроверенных источников.

Ради любопытства, я отправил deb-пакет с вирусом на VirusTotal для анализа. На момент написания статьи ни один антивирус не задетектировал его. Вот ссылка на отчет. Интересно, сколько должно пройти времени, и сколько хостов нужно заразить этим вирусом, чтобы антивирусы обратили на него внимание?

Нет, я не собираюсь рассказывать, как написать своего шифровальщика-вымогателя, майнера или эксплуатировать супер-новую уязвимость, как вы могли подумать. И тем более я не горю желанием поднимать холивар «Linux безопаснее Windows?(да)». Моей целью было написание простого вируса для linux, некого, так сказать, «Just for Fun», единственной функцией которого является распространение своей копии. О том, что у меня получилось, я расскажу в этой статье. В конце я приведу ссылку на GitHub с исходниками.

image


Дисклеймер

Данная статья написана в ознакомительных целях. Автор ни в коем случае не призывает читателей к нарушению законодательства РФ. Пожалуйста, не повторяйте действия, описанные в данной статье, предварительно не ознакомившись с главой 28 УК РФ.

И что мы, собственно, будем делать?

Самым простым в реализации механизмом распространения вируса для меня показалось распространение через модифицированные deb/rpm пакеты. Пакеты формата deb и rpm сейчас являются наиболее популярным средством распространения по для Linux. Я остановил свой выбор на формате deb, так как количество пользователей Debian-based дистрибутивов преобладает над пользователями Red Hat и ее «последователей».

Еще необходимо, чтобы вирус автоматически запускался, и через каждый определенный период времени сканировал компьютер в поисках deb-пакетов. Для удобства отладки я выбрал период равный 10 минутам.

Что такое deb-пакет?

Deb-пакет представляет из себя архив формата .ar, который не использует сжатие. Внутри архива еще три файла: debian-bynary, control.tar и data.tar

debian.binary — текстовый файл, содержащий версию формата deb-пакета, на данный момент там всегда пишут «2.0».

control.tar — архив с файлами, содержащими информацию о пакете (например — обязательный файл control) и пакеты, необходимые для установки пакета (например — скрипты preinst, postinst, prerm и postrm, запускаемые до/после установки/удаления пакета). Может быть сжат с помощью gzip или xz, в таком случае к имени архива добавляется расширение .gz или .xz соответственно.

data.tar — архив с директориями, содержащими устанавливаемые файлы. Директории представлены деревом, в виде которого они должны извлечься в корень файловой системы. Может быть сжат с помощью gzip, bzip2, lzma, xz.

Нам необходимо обратить внимание на файл control из архива control.tar. Этот файл содержит информацию о пакете, такую как автор, описание, версию, приоритет пакета в системе и т. д. Меня интересует поле depends, в котором указаны зависимости (пакеты, без которых по из данного пакета не может работать). В это поле наш вирус будет дописывать fakeroot и dpkg — утилиты, которые понадобятся при модификации других пакетов на зараженном компьютере.

Для сборки deb-пакета создается корневая директория пакета. В нее кладутся директории с устанавливаемыми файлами и директория DEBIAN, содержащую служебные файлы, среди которых control и скрипты для установки/удаления. Затем выполняется команда fakeroot dpkg-deb --build ./path.

Сначала был демон

На момент написания вируса я еще плохо представлял, что такое Cron, и поэтому пошел путем написания собственного демона для systemd. Я создал файл trojan_penguin.service, который будет помещаться в директорию /lib/systemd/system, и добавил в нее следующее:


ExecStart=/usr/bin/trojan_penguin.sh — тут я указал путь к файлу (к будущему вирусу), который должен запускаться при старте системы.

Type=fork — это строка показывает, что процесс должен ответвиться от родительского процесса.
Я не видел необходимости в PID-файле, по этому я не стал его добавлять.

В мануалах по написанию своего демона фалы .service предлагается размещать в директориях /usr/lib/systemd/system/ или /etc/systemd/system/. Но я в своей убунте нашел директорию /lib/systemd/system. (у меня туда попал apache2.service). Может быть кто-нибудь в комментариях напишет, для чего нужна эта директория, и чем она отличается от двух других.

Файл /usr/bin/trojan_penguin.sh у меня получился таким:


Мы ищем deb-пакеты в разделе /home (а где их еще искать то?), пути к найденным файлам записываем в переменную list. Потом просто перебираем все строки из line и для каждого файла запускаем скрипт tp_infect.sh, который заразит этот файл. Когда я писал вирус, скрипты находились в отдельной директории, и для удобства я создал переменную debug, в которой я прописал путь к этой папке.

Демон готов, осталось научиться его запускать при старте системы. Для этого я написал скрипт postinstall. Он будет запускаться сразу после установки зараженного пакета и указывать, чтобы наш вирус запускался вместе с системой. Разместил я его в директории "/usr/bin/", чтобы от туда копировать его в заражаемые пакеты.

Модифицируем deb-пакет

Как я писал выше, архивы, содержащиеся в deb-пакете могут иметь разные разрешения. Я не стал заморачиваться, и рассмотрел только тот случай, когда архивы сжаты с помощью .xz. Файл /usr/bin/tp_infect.sh, отвечающий за модификацию, получил такое содержимое:

Проблемы с postinstall

Все бы хорошо, но теперь у нас проблема. А что если в пакете уже есть postinstal? Оригинальный postinstal может быть написан на разных языках (python, bash. ), может это даже бинарник. Это не позволят нам просто взять и дописать свой postinstall в него. Я решил эту проблему следующим образом:

Добавил в скрипт tp_infect.sh такую вещь:


А в postinstal вот это:


Одну проблему я решил, но появилась другая. Наш вирус будет модифицировать пакет, даже если он уже заражен. При модификации вирус увидит, что в пакете есть postinstal (который на самом деле наш), переместит его в /usr/bin/, тем самым перезаписав оригинал. Чтобы этого избежать, я добавил проверку в «tp_infect.sh», модифицировали мы этот файл или нет:

Собираем воедино

Вирус готов. Вот ссылка на GitHub, как и обещал. Этот вирус можно собрать в отдельный deb-пакет (запустите makedeb.sh) из репозитория. Чтобы внедрить вирус в какой-либо пакет, достаточно выполнить команду:


В репозитории есть две копии скрипта postinst

DEBIAN/postinst — эта копия выполняется только при установке пустого пакета с вирусом. Я его закомментировал, чтобы вирус не запускался после установки, а модивиццировал пакеты только по команде.

usr/bin/postinst — это копия вставляется в заражаемые пакеты.

А вывод очевиден и без этой статьи: не стоит скачивать и запускать программы из непроверенных источников.

Ради любопытства, я отправил deb-пакет с вирусом на VirusTotal для анализа. На момент написания статьи ни один антивирус не задетектировал его. Вот ссылка на отчет. Интересно, сколько должно пройти времени, и сколько хостов нужно заразить этим вирусом, чтобы антивирусы обратили на него внимание?

Трояны в линуксе

Хоть я и рискую получить такую же славу, как Евгений Воганыч Кошмарский, который недавно отрапортовал на многих известных ресурсах о том, что для линукса написали ужасный и кошмарный вирус, сносящий всё и вся, всё же я приступлю к сути вопроса, побудившего написать эту статью.

Примерно месяц назад мне позвонил человек, которому дали рекомендации обратиться ко мне по одному вопросу.
Мы договорились с ним встретиться в офисе их компании, где он мне и изложил его суть.
Их фирме необходим был чудо-диск, который бы в течении 15 секунд мог снести все данные с жёсткого диска компьютера, а затем, если будет ещё время, то ещё пару раз раскатать поверхность жёстокого диска так, чтобы уже было невозможно восстановить данные даже в лаборатории.
При этом от диска требовалось, чтобы он сделал всё сам без какого-либо участия со стороны человека, максимум, что должен был бы сделать человек, это вставить этот диск в привод.
Ну и ещё одно условие, это чтобы всё это чудо было сделано на основе линукс, т.к. в фирме также был один ПК, использующийся как хранилище всей информации фирмы, работающий под управлением OpenSUSE и им не хотелось связываться с лицензированием и прочими вещами.
Кроме того, в фирме был также свой сисадмин, который подготовил техническое задание, а затем и проверил как оно реализовано.

Задача на первый взгляд мне показалась сложной.
Но потом я вспомнил об автозагрузке, чудо-папках в линукс и скриптах, с помощью которых всё это можно реализовать.
Думаю, что хоть с тем, что такое состряпать не сложно, вы не будете спорить?

Ну так вот. Диск был сделан, предоставлен заказчику и все разошлись довольные.

К чему вся эта предистория?

Но вот я вам только что подсказал, как можно создать дистрибутив, который вынесет за малое количество времени всё содержимое вашего ПК, какая бы ОС на нём ни стояла.

Возможно вы скажете, что существование подобного дистрибутива в сети невозможно, т.к. обычно все пользователи линукс качают дистрибутивы с их оф.сайтов.
Но всё более увеличивающееся количество офисного планктона и школоты, а также нубов этого не делают и качают откуда дотянутся, и они как раз могут попасть на такой чудо-дистр.

Если взять в пример рядового виндузятника, то он качает софт для своей системы с различных варезников, каталогов программ, файловых хранилищ и прочих мест.

Им привычно это делать, поэтому, пользуясь линукс, они будут делать тоже самое.

За рубежом, где пользователей линукс достаточно много, уже существуют аналогичные виндузятским каталоги файлов, исходных кодов и программ, где вы можете качать программы, собранные другими людьми, или код, пропатченный неизвестными программистами.
То, что ещё никто не начал туда впихивать вирусы, это просто потому, что линукс нафиг никому не нужен, а на компах его юзеров ничего ценнее пары гигов порнухи и аниме нет

Да здравствует открытый код!

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

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

Действительно. Совершенно спокойно я мог внедрить в свои дистрибутивы, скажем, скрипт ботнета, скрипт бы мониторил вызов от меня, а ПК, имеющие один и тот же пароль, который я знаю, стали бы отличными зомби-машинами, и с помощью ПК своих пользователей я мог бы осуществлять DDOS атаки или заваливать спамом почтовые ящики.

При учёте того, что количество людей, скачивающих мои дистрибутивы, растёт с каждым выходом новой версии, то получилась бы достаточно мощная ботнет сеть

Ещё они упускают и такую вещь, что в дистрибутив можно встроить и программу, которая сохранит пароль администратора, который введёте вы при установке системы и пришлёт его мне на почтовый ящик, поэтому совершенно не важно, ввели ли вы пароль сами или он уже был до вас.

В общем, остаётся вам только надеяться на мою честность и что ничего я не воткнул в свой дистрибутив, проверить-то нечем

Чтож, немного отвлечёмся и давайте обратимся к истории.

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

Вот почему красноглазикам везде мерещится заговор, ботнеты, вирусы, злоумышленники и шпионы И единственное чему они доверяют, это репозитарию своего дистрибутива.

Так при чём тут репозитарий?

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

Следовательно изначальная методика сборки дистрибутива и репозитария для него со временем отомрёт и что же мы получим в итоге?
А в итоге мы получим Линукс развивающийся по модели Windows.

Почему чтобы поставить программу в Windows, мне достаточно просто скачать эту программу и установить её, а чтобы установить эту же программу в линукс, мне нужно скачать её, а затем вытянуть километр зависимостей из репозитария?
Привязанность к репозитарию и к интернету, которые, кстати, если кто не в курсе, бывают недоступны неделями покажет многие недостатки такого метода сборки дистрибутивов, если вдруг количество их пользователей выростет хотя бы раза в два (тогда сервера дистрибутивов просто не смогу держать нагрузку от тысяч скачивающих компьютеров и будут постоянно в отключке, как это бывает в первые недели выхода нового дистрибутива GNU/Linux, когда и зеркала, и официальные репозитарии просто падают от нагрузок).

Тут-то и придёт время файловых хранилищ и сторонних сайтов с пакетами. А за ними подтянутся и вирусы

Также известен случай, когда вирус был обнаружен в официальном репозитарии программы Sendmail.
В ноябре 2003 года были взломаны репозитарии Debian. Кому интересно может найти материалы об этом на самом сайте данного дистрибутива.

вся совокупность пользователей ОС GNU/Linux не составляет более 0,7% от всех пользователей персональных компьютеров

IoT — самый настоящий тренд последнего времени. Почти везде в нем используется ядро Linux. Однако статей по вирусописательству и шелл-кодингу под эту платформу сравнительно мало. Думаешь, писать шелл-код под Linux — только для избранных? Давай выясним как написать вирус для Linux!

Картинки по запросу linux iot virus

БАЗА ДЛЯ НАПИСАНИЯ ВИРУСА ДЛЯ LINUX

Что нужно для работы?

Для компиляции шелл-кода нам понадобится компилятор и линковщик. Мы будем использовать nasm и ld. Для проверки работы шелл-кода мы напишем небольшую программку на С. Для ее компиляции нам понадобится gcc. Для некоторых проверок будет нужен rasm2 (часть фреймворка radare2). Для написания вспомогательных функций мы будем использовать Python.

Что нового в x64?

x64 является расширением архитектуры IA-32. Основная отличительная ее особенность — поддержка 64-битных регистров общего назначения, 64-битных арифметических и логических операций над целыми числами и 64-битных виртуальных адресов.

Если говорить более конкретно, то все 32-битные регистры общего назначения сохраняются, добавляются их расширенные версии (rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp) и несколько новых регистров общего назначения (r8, r9, r10, r11, r12, r13, r14, r15).

Появляется новое соглашение о вызовах (в отличие от архитектуры x86, оно только одно). Согласно ему, при вызове функции каждый регистр используется для определенных целей, а именно:

  • первые четыре целочисленных аргумента функции передаются через регистры rcx, rdx, r8 и r9 и через регистры xmm0 — xmm3 для типов с плавающей точкой;
  • остальные параметры передаются через стек;
  • для параметров, передаваемых через регистры, все равно резервируется место в стеке;
  • результат работы функции возвращается через регистр rax для целочисленных типов или через регистр xmm0 для типов с плавающей точкой;
  • rbp содержит указатель на базу стека, то есть место (адрес), где начинается стек;
  • rsp содержит указатель на вершину стека, то есть на место (адрес), куда будет помещено новое значение;
  • rsi, rdi используются в syscall.

Немного о стеке: так как адреса теперь 64-битные, значения в стеке могут иметь размер 8 байт.

Syscall. Что? Как? Зачем?

Syscall — это способ, посредством которого user-mode взаимодействует с ядром в Linux. Он используется для различных задач: операции ввода-вывода, запись и чтение файлов, открытие и закрытие программ, работа с памятью и сетью и так далее. Для того чтобы выполнить syscall, необходимо:

• загрузить соответствующий номер функции в регистр rax;
• загрузить входные параметры в остальные регистры;
• вызвать прерывание под номером 0x80 (начиная с версии ядра 2.6 это делается через вызов syscall).

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

Номера нужных syscall-функций можно найти, например, здесь.

Если мы посмотрим на готовые шелл-коды, то многие из них используют функцию execve().

execve() имеет следующий прототип:


argv[] является указателем на массив, по сути, это тот самый argv[], который мы видим, например, в C или Python.

envp[] — указатель на массив, описывающий окружение. В нашем случае не используется, будет иметь значение null.

Основные требования к шелл-коду

Существует такое понятие, как position-independent code. Это код, который будет выполняться независимо от того, по какому адресу он загружен. Чтобы наш шелл-код мог выполняться в любом месте программы, он должен быть позиционно-независимым.

Чаще всего шелл-код загружается функциями вроде strcpy(). Подобные функции используют байты 0x00, 0x0A, 0x0D как разделители (зависит от платформы и функции). Поэтому лучше такие значения не использовать. В противном случае функция может скопировать шелл-код не полностью. Рассмотрим следующий пример:

Как видно, код push 0x00 скомпилируется в следующие байты 6a 00. Если бы мы использовали такой код, наш шелл-код бы не сработал. Функция скопировала бы все, что находится до байта со значением 0x00.

В шелл-коде нельзя использовать «захардкоженные» адреса, потому что мы заранее эти самые адреса не знаем. По этой причине все строки в шелл-коде получаются динамически и хранятся в стеке.

Вот вроде бы и все.

JUST DO IT!

Если ты дочитал до этого места, то уже должна сложиться картина, как будет работать наш шелл-код.

Первым делом необходимо подготовить параметры для функции execve() и затем правильно расположить их на стеке. Функция будет выглядеть следующим образом:



Второй параметр представляет собой массив argv[]. Первый элемент этого массива содержит путь к исполняемому файлу.

Третий параметр представляет собой информацию об окружении, нам он не нужен, поэтому будет иметь значение null.

Сначала получим нулевой байт. Мы не можем использовать структуру вида mov eax, 0x00, поскольку это приведет к появлению null-байтов в коде, так что мы будем использовать следующую инструкцию:

xor rdx, rdx

Оставим это значение в регистре rdx — оно еще понадобится в качестве символа конца строки и значения третьего параметра (которое будет null).

Так как стек растет от старших адресов к младшим, а функция execve() будет читать входные параметры от младших к старшим (то есть стек работает с памятью в обратном порядке), то на стек мы будем класть перевернутые значения.

Для того чтобы перевернуть строку и перевести ее в hex, можно использовать следующую функцию на Python:



Вызовем эту функцию для /bin/sh: >>> rev.rev_str(«/bin/sh»)

Получили строку длиной 7 байт. Теперь рассмотрим, что произойдет, если мы попробуем положить ее в стек:

Мы получили нулевой байт (второй байт с конца), который сломает наш шеллкод. Чтобы этого не произошло, воспользуемся тем, что Linux игнорирует последовательные слеши (то есть /bin/sh и /bin//sh — это одно и то же).

Теперь у нас строка длиной 8 байт. Посмотрим, что будет, если положить ее в стек:

Никаких нулевых байтов!

Затем на сайте ищем информацию о функции execve(). Смотрим номер функции, который положим в rax, — 59. Смотрим, какие регистры используются:
• rdi—хранитадресстроки FILENAME;
• rsi—хранитадресстрокиargv;
• rdx—хранитадресстрокиenvp.

Теперь собираем все воедино.
Кладем в стек символ конца строки (помним, что все делается в обратном порядке):

Кладем в стек строку /bin//sh: mov rax, 0x68732f2f6e69622f
push rax

Получаем адрес строки /bin//sh в стеке и сразу помещаем его в rdi: mov rdi, rsp

В rsi необходимо положить указатель на массив строк. В нашем случае этот массив будет содержать только путь до исполняемого файла, поэтому достаточно положить туда адрес, который ссылается на память, где лежит адрес строки (на языке С указатель на указатель). Адрес строки у нас уже есть, он находится в регистре rdi. Массив argv должен заканчиваться null-байтом, который у нас находится в регистре rdx:

Теперь rsi указывает на адрес в стеке, в котором лежит указатель на строку /bin//sh.

Кладем в rax номер функции execve(): xor rax, rax
mov al, 0x3b

В итоге получили такой файл:


Компилируем и линкуем под x64. Для этого:

Теперь можем использовать objdump -d example для того, чтобы посмотреть получившийся файл:



Чтобы получить шелл-код вида x11x22… из бинарника, можем воспользоваться следующим кодом:


В результате получаем:

Тестируем шелл-код

Для теста используем следующую программу на С (вместо SHELLCODE нужно вставить получившийся шелл-код):


вирус для linux

В результате получаем программу shellcode_test. Запускаем программу и попадаем в интерпретатор sh. Для выхода вводим exit.

ЗАКЛЮЧЕНИЕ

Вот мы и написали свой первый шелл-код под Linux x64. На первый взгляд — ничего сложного, труднее всего сократить размеры шелл-кода. И нельзя забывать, что это лишь «проба пера», наш шелл-код не справится с DEP и ASLR, но полученные навыки пригодятся для написания более сложных вещей.

Читайте также: