• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Обфусцируем и шифруем Bash скрипты в операционной системе Linux

stelthon

RAID-массив
Забанен
Регистрация
29.07.2024
Сообщения
90
Реакции
26
Пожалуйста, обратите внимание, что пользователь заблокирован
Приветствую уважаемые форумчане. Хочу рассказать вам о том, что целью очередной статьи будет являться попытка представить способ зашифровывания цельного файла("тела") скрипта командной оболочки bash в операционных системах Unix в виде сконвертированного, обфусцированного и готового к выполнению исполняемого ELF файла. В статье рассматривается частный случай с ОС Linux. Ведь многие пользователи операционных систем данного семейства не понаслышке знают о том, что одной из неотъемлемых частей пользовательского пространства данного вида систем является программная оболочка, а одним из главных аспектов работы командной/программной оболочки является ее возможность выполнять разнообразные системные и пользовательские задачи с использованием, помимо самих команд терминала, - очень гибкого, мощного и относительно простого инструмента управления задачами-скриптового языка командной оболочки, в данном случае одним из вариантов его реализации. Повторюсь, что основной упор мы сделаем именно на оболочку и одноименный язык bash. И поскольку помимо них так же существуют другие виды командных оболочек, и, соответственно, предоставляемых ими скриптовых языков. Но основная же суть их целевого предназначения остается неизменной - программное и межпрограммное(комплексное) управление и взаимодействие на пользовательском уровне операционной системы, поэтому рассматривать варианты с другими оболочками мы не станем в силу относительной унифицированности способов их применения, а также методов компиляции и шифрования. Известно, что bash скрипты активно вызываются программами и пользователями из командной строки, а так же другими скриптами во время их выполнения, кроме того, специальными системами контроля выполнения задач, таких как cron/incron, и во многих иных вариациях. Комбинаций же их использования, в том числе в виде цепочек и связок вызовов как в рамках процесса выполнения программной оболочки одного скрипта(плоскости листинга скрипта), так и в пределах любого количества уровней вложенности дерева выполнения может быть ограничено разве что ресурсными возможностями операционной и вычислительной систем в части ограничений аппаратных и программных средств, ну и вашим воображением. Но ни общее базовое, ни тем более подробное описание работы с оболочкой и скриптами написанной на языке этой оболочки не является темой статьи. Краткая вводная часть была сделана лишь для раскрытия спектра возможностей тех методов, которые описываются в данной статье. Итак, вернемся в основной фарватер обозначенной тематики, то есть к существующим возможностям зашифровывать скрипт выполнения bash с целью маскировки его содержимого, хранимого в файловой системе в статическом виде.


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

Создаем рабочую директорию для версии, устанавливаемой из исходников:
# mkdir ~/Downloads/shczip && cd ~/Downloads/shczip


Текст самого скрипта, который можно вывести в терминале Linux например командой cat:

# cat > ~/Downloads/shczip/testscript.sh

Вводим текст приведенный ниже. В принципе скрипт вы можете использовать любой, главное чтобы он был именно скриптом bash в системе linux. Данный сценарий после запуска просит пользователя ввести ник и число через запятую, затем выдает число строк соответствующее введенному числу с приветствием по имени и случайным числом. Повторюсь, сценарий большой смысловой нагрузки не несет и взят только для примера:​

Код:
#!/bin/bash

echo "Put your nick and number of strings and random nums separated by commas"
read nickandnum

if [ $? -eq 0 ]; then
    nick=$(echo $nickandnum|cut -d ',' -f 1)
    num=$(echo $nickandnum|cut -d ',' -f 2)

for (( start = 1; start <= $num; start++ ))
do
    echo -e "Hello $nick shell script compiler, your number $RANDOM"
done

else
    echo "Bad return $RANDOM"
fi

Если все получилось, присваиваем биты исполнения:

# chmod +x ~/Downloads/shczip/testscript.sh

Теперь выполним скрипт стандартным методом из командной строки:

# bash -c ~/Downloads/shczip/testscript.sh

Ну или переходим непосредственно в каталог и выполняем там вот таким образом:

# cd ~/Downloads/shczip/testscript.sh

Запускаем наш тестовый скрипт и вводим через запятую запрашиваемые им данные, - имя пользователя и число:

# ./testscript.sh

2.png

Рис.1

Повторим запуск с другими параметрами, а точнее другим числом строк:

# ./testscript.sh

3.png

Рис.2

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


Краткое описание инструмента:

SHC является универсальным компилятором bash скриптов. Shc получает на вход скрипт, указанный в командной строке в качестве аргумента, и, путем преобразования, создает идентичный ему по функционалу исходный код написанный на СИ. Затем, сгенерированный исходный код компилируется и линкуется для создания исполняемого двоичного файла.

Скомпилированный таким образом двоичный файл все равно будет зависимым от оболочки, указанной в первой строке кода оболочки в строке #!/bin/bash, и соответственно при выполнении обращается напрямую к ее функционалу. Поэтому shc не создает полностью независимые двоичные файлы, хоть и является готовой СИ-программой.

Кроме того, сам по себе shc не является компилятором, как cc/gcc, он скорее является оболочкой и дополнительной надстройкой для компилятора, который кодирует и шифрует скрипт оболочки, генерируя исходный код СИ с добавлением различных дополнительных собственных функций, в том числе с возможностью истечения срока выполнения. Затем он использует системный компилятор для компиляции разделенного двоичного файла, который ведет себя точно так же, как исходный скрипт. После выполнения скомпилированный двоичный файл расшифрует и выполнит код с опцией sh -c (bash -c).

С теорией закончили, и пришло время для установки самого инструмента, а так же всего необходимого программного обеспечения, которое пригодится в процессе нашей работы:

# apt update && apt upgrade
# apt install make gcc automake


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

1. Вот вариант с установкой самого последнего релиза исходников с github:

# cd ~/Downloads/shczip
# wget https://github.com/neurobin/shc/archive/release.zip
# unzip release.zip
# ./configure
# make

# make install

Все доcтаточно стандартно. Переходим в рабочую директорию, затем скачиваем, разархивируем, производим процедуру компиляции из исходников. В том случае если make завершится с ошибкой из-за версии automake, следует попробовать запустить ./autogen.sh перед выполнением вышеприведенных команд.

2. Вариант установки из репозитория apt для дистрибутивов Ubuntu:

# add-apt-repository ppa:neurobin/ppa
# apt-get update
# apt-get install shc


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

Вот собственно и все что требовалось сделать для установки средства обфускации bash- скриптов.


Приведем несколько простых примеров, демонстрирующих синтаксис использования shc:

Создаем выполняемый файл из скрипта:

# shc -f script.sh -o binary_script

-f - путь к файлу скрипта.
- выходным файлом в таком случае будет binary_script

Почти то же самое что пример выше, но делаем исполняемый файл нетрассируемым, то есть усложняем возможность его обратной разработки, в том числе путем использования таких инструментов как strace и ltrace:

# shc -U -f script.sh -o binary_script

-U - как раз отвечает за функцию запрета трассировки, включаемую в компилируемый исполняемый бинарный файл.

Еще один небольшой пример:

# shc -r -v -T -f script.sh -o binary_script

-r - возможность запускать на других аппаратных платформах (возможность мультиплатформенности посредством функции кросскомпиляции). Но операционная система должна быть той же, что и та на которой скрипт был скомпилирован как исполняемый бинарник.
-v - подробный вывод состояния процесса во время компиляции.
-T - здесь мы наоборот, разрешаем трассировку скрипта такими программами как strace. Без этой опции можно получить ошибку "(command): Operation not permitted" при запуске не из под рута. Правда имейте ввиду, что некоторые новые версии утилиты могут не содержать данную опцию, где она упразднена.


Выводим более развернутую общую информацию по команде shc которая выдаст перечень большинства применимых параметров и опций данной команды, часть которых мы уже достаточно подробно описали в примерах выше:​


# shc -h

4.png

Рис.3

Нетрудно понять, какие опции за что отвечают, но если представленной в выводе информации по каким-либо причинам покажется мало, то можно изучить более подробную документацию, либо в репозитории github, либо путем чтения man страницы: man shc

Теперь, в качестве демонстрации реальных возможностей данного метода приступим к преобразованию(в данном случае псевдокомпиляции, как было упомянуто в описании shc выше) уже написанного нами ранее bash скрипта в исполняемый ELF файл, предварительно сконвертированный в программу на СИ и с попутной обфускацией его содержимого:


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

# shc -r -f script.sh

Данная команда сгенерирует два новых файла, в дополнении к самому скрипту. Давайте взглянем на них подробнее:

# ls -l script.sh*

5.png

Рис.4


Вот что у нас с вами получилось в итоге. Давайте опишем назначение каждого из получившихся в итоге файлов:

script.sh - это собственно наш оригинальный bash скрипт
script.sh.x - это уже готовый исполняемый бинарник в формате ELF.
script.sh.x.c - это промежуточный исходный файл на языке СИ(о котором уже говорилось ранее), преобразованный из bash скрипта который в дальнейшем автоматически компилируется в запускаемый бинарник script.sh.x. Если интересно изучить его содержимое для исследовательских задач либо с целью простого любопытства, можно это легко сделать, поскольку он имеет обычный текстовый формат.​


# cat /home/XSSIS/Downlooads/shczip/script.sh.x.c

6.png

Рис.5


Если кратко, то зашифрованный код скрипта упаковывается в массивы данных в виде shell-кода внутри промежуточного исходного кода СИ, небольшой фрагмент которого показан выше.​


Посмотрим это на примере вывода стандартной linux-утилиты file:

# file script.sh

7.png

Рис.6

# file script.sh.x


Рис.7

# file script.sh.x.c
9.png

Рис.8

Теперь запустим на выполнение созданный нами скрипт, преобразованный в бинарный исполняемый формат:

# ./script.sh.x

10.png

Рис.9

Не так уж трудно убедиться в том, что наш с вами преобразованный и обернутый в СИ программу, обфусцированный и откомпилированный скрипт делает все то же самое, что и написанный нами в самом начале оригинальный bash скрипт. За исключением разве что чуть более медленного времени исполнения в результате применяемой обфускации и обертывания скрипта в функции СИ, что не всегда является критичным фактором для ряда задач. Тем не менее, всегда стоит это понимать и учитывать в работе. Зато есть и положительная сторона дела, освещение которой и является основной целью данной статьи, - а именно изучить содержание такого скрипта становится гораздо более проблематичной работой, хоть и не сказать что совсем нерешаемой. Так как например остается возможность сделать дамп и попробовать провести обратную разработку с анализом участка данных программы уже загруженного в оперативную память процесса, в том числе штатными средствами ОС Linux, так как при выполнении бинарника происходит его расшифровка в оперативную память. Хотя процесс расшифрования для гораздо более старых версий shc версии и был описан достаточно, однако дамп является более простым способом получения исходного текста скрипта, но при этом все-таки не дает стопроцентной гарантии расшифрования кода и данных программы.

Можно например попытаться сделать так.

Убираем лимит на размер дампа:

# ulimit -c unlimited

Указываем конкретный, нужный нам путь сохранения дампов памяти в системе:

# echo "/tmp/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern

Выполняем скомпилированную программу скрипта с определенной задержкой времени для того чтобы дать возможность системе загрузить данные программы в оперативную память, но при этом не дать этой программе полностью отработать до завершения, и до истечения того момента сделать дамп участка памяти:​

# ./script.sh.x& ( sleep 0.001 && kill -SIGSEGV $! )

11.png

Рис.10

$! — будет содержать PID запущенного процесса
kill -SIGSEGV — вызовет ошибку "Segmentation fault" выгрузку памяти в дамп.

В результате в каталоге /tmp имеем файл дампа памяти: /tmp/core.script.sh.x.19839
Но беглый анализ дампа видимых результатов не дает, ровно как и анализ выполняемого файла, требуется применение методов обратной инженерии. По крайней мере использование подобной утилиты существенно уменьшает риски быстрого раскрытия чувствительных данных и операций над ними.

# cat /tmp/core.script.sh.x.19839

12.png

Рис.11


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

Дата истечения срока запуска указывается в формате dd/mm/yyyy. Если же вы хотите указать свое собственное сообщение об истечении срока действия, используйте параметр -m одновременно с опцией -e:

# shc -e 31/12/2026 -m "Contact me now" -f script.sh

Соответственно по истечении указанного срока, когда кто-то попытается выполнить скрипт, то получит указанное нами сообщение об ошибке:

# ./script.sh.x

13.png

Рис.12

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

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

Спасибо за внимание -)


Автор(stelthon): https://xss.pro/members/376546
Специально для xss.pro
 
Последнее редактирование модератором:
Пожалуйста, обратите внимание, что пользователь заблокирован
Adding a .sh suffix to a bash script is similar to creating a c++ program and adding a .c extension to it. While bash is compatible with sh, they are different shells, and you can write bash scripts without using the .sh extension.
It was represented for better example understanding.
And you can write bash scripts with any extension, because they defined by the line #/bin/bash inside the script.

PS: /bin/sh is a symbolic link to /bin/bash in modern linux systems
 
Последнее редактирование:
It was represented for better example understanding.
And you can write bash scripts with any extension, because they defined by the line #/bin/bash inside the script.
Try to use #!/usr/bin/env bash to make your scripts more portable accross different systems as bash can be installed in different locations, sometimes the bash version in /bin can be older than the version that the system uses, so this approach allows the system to select the appropriate version for you.
PS: /bin/sh is a symbolic link to /bin/bash in modern linux systems
That's not always the case, sometimes you can find sh linked to different shells like dash, zsh, etc.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Try to use #!/usr/bin/env bash to make your scripts more portable accross different systems as bash can be installed in different locations, sometimes the bash version in /bin can be older than the version that the system uses, so this approach allows the system to select the appropriate version for you.

That's not always the case, sometimes you can find sh linked to different shells like dash, zsh, etc.

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

in this case, portability is secondary and has no significance. in most cases these are bash.
for other shells you can choose any other options you need
 
Последнее редактирование:


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх