PWN college. Part 1: Assembler + GDB
Я прошёл два курса в pwn.college в pwn.college. Один был короткий, второй – более продолжительный. Оба курса дали практический опыт, который стоит получить.
Отмечу классное решений в pwn.college — автоматизация лабораторных заданий. На каждую лабораторную работу создаётся виртуальная машина, к которой можно подключиться по SSH и выполнить задание.
Практика охватывает множество тем: проблемы с памятью, гонки, ядро, реверс-инжиниринг.
Курс по консоли linux: Linux Luminarium
Этот курс посвящен на работе с Linux-консолью. Подчерпнул новую информацию из темы про каналы:
- Перенаправление stderr в stdout:
2>&1
- Создание именованного канала:
>()
- Дублирование каналов с помощью:
tee
В остальном я уже был подкован, но качество курса это не умоляет. Отточил навыки работы с bash.
Курс по ассемблеру и GDB: Computing 101
Курс плавно вводит тебя в ассемблер. Даже учат собирать программу:
as -o server.o server.s && ld -o server server.o
После прохождения базы на мини-лабах дают курсовое задание – написать простой web-сервер, который на каждый accept создаёт дочерний процесс для обработки HTTP-запросов. Спасибо авторам курса, что не нужно обрабатывать ошибочные пути системных вызовов и некорректные http запросы, только happy-path. Даже в такой реализации программа занимает около 230 строк кода.
Для себя сделал вывод, как хорошо, что у нас есть C/C++/Python и другие языки, которые позволяют от абстрагироваться.
Пример кода с системным вызовом, очень уж мне понравилось писать их на ассмеблере:
.intel_syntax noprefix
.global _start
SYS_WRITE=1
SYS_EXIT=60
STDOUT=0
MSG_LEN=13
.section .text
_start:
mov rdi, STDOUT # accepted socket
lea rsi, [hello_msg]
mov rdx, MSG_LEN
mov rax, SYS_WRITE
syscall # write to socket
mov rax, SYS_EXIT
mov rdi, 23
syscall
.section .data
hello_msg:
.asciz "Hello_world\n"
GDB
В курсе выделен блок “отладка с помощью GDB”.
Для работы с ассемблером советуют установить intel синтаксис:
cat ~/.gdbinit
set disassembly-flavor intel
Читается такой ассемблер приятно, но вот для архитектур отличных от x86 не подойдет, так что нужно подумать, прежде чем переключаться на него не стоит.
Для упрощения жизни рассматривается плагин GEF.
В ходе лабораторных даются задания по анализу внутренностей бинарника. Приведу краткую выжимку по командам gdb, которую использовал в ходе работы:
display/16i $rip-0x10 - Показывает 16 инструкций вокруг $rip при каждом шаге исполнения
display/10gx $rsp - Выводит 10 hex quad word из содержимого стека ($rsp)
x/gx $rbp-0x10 - Показывает данные в формате hex quad word по адресу ($rbp - 0x10)
x/a $rsp - Выводит значение по адресу $rsp в виде адреса (dereferenced)
x/20i main+560 - Выводит 20 инструкций от main со смещением 560
set $rip = *main+762 - Устанавливает указатель инструкций на (main + 762)
set $local_variable = \*(unsigned long long*)($rbp-0x100) - Записывает значение из памяти по адресу ($rbp - 0x100) в переменную
print $local_variable - Распечатывает значение переменной
printf "Current value: %llx\n", $local_variable - Выводит значение переменной в шестнадцатеричном формате
set \*(unsigned long long*)($rbp-0x200) = $local_variable - Изменяет значение в памяти по адресу ($rbp - 0x200) на $local_variable
run - Запускает программу
b *main+757 - Устанавливает точку останова по адресу (main + 757)
del b NUMBER - Удаляет точку останова с номером NUMBER
info break - Показывает список всех точек останова
info reg - Выводит состояние всех регистров
disassemble main - Показывает дизассемблированный код функции main
c - Продолжает выполнение программы
si - Выполняет следующий шаг с заходом в вызовы (step in)
ni - Выполняет следующий шаг без захода в вызовы (next instruction)
Стоит отличать команды print и x (examine).
Команда print просто выводит значение переменной, а команда x разименовывает и показывает содержимое по адресу, хранящемуся в переменной или регистре.
Курсы pwn.college дают реальный практический опыт с автоматизированной проверкой заданий. Если вы хотите развить свои навыки, рекомендую попробовать эти курсы.