Студенты обошли проверку кода в школе, вызвав execve без имени
Calling a function in C without naming it
В школе с автоматической проверкой кода студенты нашли способ выполнить произвольный код, обойдя запрет на использование неразрешённых функций. Они вычислили смещение между printf и mmap, создали исполняемую страницу памяти и вызвали системный вызов execve, не упоминая его имени. Это позволило получить доступ к shell и продемонстрировало уязвимость системы, основанной на анализе AST и ASan.
Мы можем просто сделать плохую процедуру на ассемблере x86, которая позволит нам совершать системные вызовы Linux так, как будто это функция C.
- ashdnazg
В нашем университете были куда менее осторожны и просто запускали наши решения в той же сети, что и всё остальное, правда, от имени пользователя с почти никакими правами.
Однажды, когда автоматические тесты завалили моё решение, я просто использовал `system`, чтобы сдампить тестовый ввод в свою домашнюю директорию. Однако я забыл настроить права доступа, так что на самом деле не смог к нему получить доступ! Ещё пара повторных отправок с дополнительными chmod, каждый раз ломая что-то другое, и мне удалось воспроизвести свой баг, исправить его, отправить заново и подчистить все (или почти все) улики.
- Kevin_Flynn
Поскольку мы знаем, что наш код компилируется с ASan, мы решили утечь смещение между printf — функцией, которая всегда разрешена, — и mmap — функцией, дающей нам выполнение произвольного ассемблерного кода. Так мы можем обойти школьные проверки и вызвать любой системный вызов, в нашем случае execve, чтобы получить доступ к шеллу.
Мы не стали копать глубже и просто сообщили школе о возможной проблеме.
Я не вижу тривиального способа это пропатчить.
Похоже, изъян в системе сдачи работ.
Система сдачи могла бы собирать/перелинковывать ваш код с библиотекой-трамплином, в которой тело каждой запрещённой функции заменено на вывод ошибки и аварийное завершение. В вашем примере она бы перехватила:
char *code =
notmmap.fn(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
и не дала бы вам использовать флаг PROT_EXEC на этапе выполнения проверки сданного решения.
Согласно ИИ, в linux: «... seccomp-BPF фильтр, применяемый к каждому процессу перед запуском программы. Он может проверять аргумент prot у mmap и возвращать EPERM, когда установлен PROT_EXEC».
Кроме того, в linux: «systemd предлагает MemoryDenyWriteExecute=yes для сервисов. Это менее строго, чем запрет всех исполняемых отображений: он нацелен на записываемые+исполняемые отображения и связанные способы сделать память исполняемой».
( ЕСЛИ ... я правильно прочитал статью )
ps. Отправьте предложенные решения заведующему кафедрой или другому начальству, которое может кинуть вам какую-нибудь косточку, чтобы ваша ста […]
- PeterWhittaker
Похоже, школе нужно обернуть всё в denylist для seccomp. Возможно, нетривиально, но потенциально интересно.