Как переполнение буфера используется для взлома компьютеров?
-
19-08-2019 - |
Вопрос
Как переполнение буфера используется для взлома компьютеров?
Как можно выполнить произвольный код, просто вызвав куча или куча переполняется?
Я понимаю, что перезаписываются части памяти программ, которые не должны быть, но я не понимаю, как это приводит к выполнению собственного кода.Кроме того, должен ли сторонний вредоносный код быть написан на языке ассемблера целевого процессора?
Решение
Это наиболее широко известный документ по этому вопросу: Разбиваем стек ради удовольствия и прибыли
Однако «переполнение стека» не имеет ничего общего с переполнением буфера.Переполнение стека, как правило, является просто случаем ошибки в плохом коде, который нельзя использовать ни для чего, кроме сбоя (DoS).
Редактировать:Вы также спросили о переполнении кучи.Это хороший документ по этому вопросу: http://www.w00w00.org/files/articles/heaptut.txt
Другие советы
Стек содержит как данные, так и адрес возврата при переходе в подпрограмму. Если вам удастся поместить конкретный адрес в стек, где находится адрес возврата, вы можете заставить ЦП перейти в определенную область памяти, куда вы положили свой собственный код. Это для переполнения буфера. Переполнение кучи немного отличается и его сложнее использовать.
Переполнение стека - это просто указание на то, что у вас закончилось пространство стека (которое обычно более ограничено, особенно в ядре).
Представьте себе два дома на улице.Один из них — дом вашего друга, а другой — дом его злого соседа-параноика, расположенного через три дома.Злой сосед-параноик никогда не входит и не выходит, и его дом наглухо заперт.
А твой друг такой хороший, доверчивый друг, он разрешает хранить у себя все, что угодно, ставя коробки одну за другой, начиная с одной стены.На самом деле он настолько хороший друг, что будет ставить коробки одну за другой, не проверяя, не ударился ли он о стену, пока они не продолжат лететь в воздухе и, наконец, не пройдут прямо через два других дома на улице и не войдут в дом. Дом злого соседа-параноика.Но ваш друг уверен, что вы не сделаете этого, потому что вы ему нравитесь (и он немного наивен).
Так что у вас есть возможность подложить что-нибудь в дом злобного соседа-параноика, воспользовавшись вашим добрым доверчивым другом.
Замените следующие термины, и вы увидите аналогию с атакой на переполнение буфера:
- "дом твоего друга" --> "часть программы, которая не проверяет переполнение буфера"
- "дом его злого соседа-параноика" --> "еще одна часть программы, которая должна быть безопасной"
- «ящики» -> «аргументы/параметры программы, которая не проверяет переполнение буфера»
Это будет успешным только в том случае, если кто-то выяснит, где находится защищенная область памяти и что нужно будет передать в качестве аргумента рассматриваемой программе, чтобы в конечном итоге оказаться в защищенной области, чтобы получить желаемый эффект.(будь то данные или код, вызывающий выполнение кода эксплуататора)
Практически все современные процессоры при вызове подпрограммы возвращают адрес возврата в ту же область, что и локальные данные (стек). Для подпрограмм, которые не проверяют верхний предел переменной (в частности, функцию strcpy), может произойти перенаправление адреса инструкции (переполнение буфера).
void make(char *me)
{
char sandwich[4]; // local data, this is in stack. the buffer for data is too small
strcpy(sandwich, me);
puts(sandwich);
// implicit "return;" the return instruction(RET on Intel) instructs the processor to implicitly pop an address from stack then resume execution on that address
}
void main()
{
// calling a subroutine (CALL on Intel) implicitly instructs the processor to push the next instruction's address(getchar line) on stack before jumping to make.
make("Love Not War");
getchar();
puts("This will not execute. The address to next instruction(getchar) gets overwritten with Not War");
}
" Кроме того, должен ли злонамеренный код стороннего разработчика быть написан на языке ассемблера целевых процессоров? " <Сильный> Да
Переполнение стека может произойти из нормально работающей программы, например, рекурсивные подпрограммы (вызывающая сама функция) с пропущенным завершающим условием. Область стека будет заполнена множеством локальных переменных в стеке плюс возвращаемые адреса.
Обычный подход заключается в том, что у вас есть где-то в памяти вредоносный код. Затем вы создаете переполнение буфера: волшебство здесь состоит не в том, чтобы просто переполнить его, а в том, что вы уже упоминали, что некоторые части памяти программы перезаписываются. Так как в стеке содержатся не только переменные, но также и когда функция называется адресом возврата, вы пытаетесь перезаписать ее адресом вашего вредоносного кода. Когда функция с переполнением буфера возвращается к своему вызывающему, функция не возвращается к своему исходному вызывающему, а вместо этого к вредоносной подпрограмме. Поскольку теперь исполняемый код обычно имеет привилегии вызывающего кода, каждый пытается найти / создать это переполнение в коде, который имеет более высокое разрешение, чем злой код (иначе вы можете сделать это, напрямую вызвав злую подпрограмму).