Как написать эксплуат буфера в GCC, Windows XP, x86?
-
23-09-2019 - |
Вопрос
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;
ret = buffer1 + 12;
(*ret) += 8;//why is it 8??
}
void main() {
int x;
x = 0;
function(1,2,3);
x = 1;
printf("%d\n",x);
}
Вышеуказанная демонстрация отсюда:
http://insecure.org/stf/smashstack.html
Но здесь это не работает:
D:\test>gcc -Wall -Wextra hw.cpp && a.exe
hw.cpp: In function `void function(int, int, int)':
hw.cpp:6: warning: unused variable 'buffer2'
hw.cpp: At global scope:
hw.cpp:4: warning: unused parameter 'a'
hw.cpp:4: warning: unused parameter 'b'
hw.cpp:4: warning: unused parameter 'c'
1
И я не понимаю, почему это 8, хотя автор думает:
Небольшая математика говорит нам, что расстояние составляет 8 байтов.
Мой свалку GDB, как называется:
Dump of assembler code for function main:
0x004012ee <main+0>: push %ebp
0x004012ef <main+1>: mov %esp,%ebp
0x004012f1 <main+3>: sub $0x18,%esp
0x004012f4 <main+6>: and $0xfffffff0,%esp
0x004012f7 <main+9>: mov $0x0,%eax
0x004012fc <main+14>: add $0xf,%eax
0x004012ff <main+17>: add $0xf,%eax
0x00401302 <main+20>: shr $0x4,%eax
0x00401305 <main+23>: shl $0x4,%eax
0x00401308 <main+26>: mov %eax,0xfffffff8(%ebp)
0x0040130b <main+29>: mov 0xfffffff8(%ebp),%eax
0x0040130e <main+32>: call 0x401b00 <_alloca>
0x00401313 <main+37>: call 0x4017b0 <__main>
0x00401318 <main+42>: movl $0x0,0xfffffffc(%ebp)
0x0040131f <main+49>: movl $0x3,0x8(%esp)
0x00401327 <main+57>: movl $0x2,0x4(%esp)
0x0040132f <main+65>: movl $0x1,(%esp)
0x00401336 <main+72>: call 0x4012d0 <function>
0x0040133b <main+77>: movl $0x1,0xfffffffc(%ebp)
0x00401342 <main+84>: mov 0xfffffffc(%ebp),%eax
0x00401345 <main+87>: mov %eax,0x4(%esp)
0x00401349 <main+91>: movl $0x403000,(%esp)
0x00401350 <main+98>: call 0x401b60 <printf>
0x00401355 <main+103>: leave
0x00401356 <main+104>: ret
0x00401357 <main+105>: nop
0x00401358 <main+106>: add %al,(%eax)
0x0040135a <main+108>: add %al,(%eax)
0x0040135c <main+110>: add %al,(%eax)
0x0040135e <main+112>: add %al,(%eax)
End of assembler dump.
Dump of assembler code for function function:
0x004012d0 <function+0>: push %ebp
0x004012d1 <function+1>: mov %esp,%ebp
0x004012d3 <function+3>: sub $0x38,%esp
0x004012d6 <function+6>: lea 0xffffffe8(%ebp),%eax
0x004012d9 <function+9>: add $0xc,%eax
0x004012dc <function+12>: mov %eax,0xffffffd4(%ebp)
0x004012df <function+15>: mov 0xffffffd4(%ebp),%edx
0x004012e2 <function+18>: mov 0xffffffd4(%ebp),%eax
0x004012e5 <function+21>: movzbl (%eax),%eax
0x004012e8 <function+24>: add $0x5,%al
0x004012ea <function+26>: mov %al,(%edx)
0x004012ec <function+28>: leave
0x004012ed <function+29>: ret
В моем случае расстояние должно быть - = 5, верно? Но кажется, что он не работает ..
Почему function
потребности 56 байты для локальных переменных? ( sub $0x38,%esp
)
Решение
В качестве Джоуха указал, значение EIP, сохраненное в стеке (обратный адрес) call
инструкция должна быть увеличена на 7 байты (0x00401342
- 0x0040133b
= 7), чтобы пропустить x = 1;
инструкция (movl $0x1,0xfffffffc(%ebp)
).
Вы правы, что 56 байтов зарезервированы для локальных переменных (sub $0x38,%esp
), поэтому недостающая часть - сколько байтов прошлого buffer1
На стеке сохраненный EIP.
Немного тестового кода и встроенной сборки сообщают мне, что магическое значение 28 для моего теста. Я не могу дать окончательный ответ о том, почему это 28, но я бы предположил, что компилятор добавляет прокладку и/или Канарские острова.
Следующий код был составлен с использованием GCC 3.4.5 (Mingw) и протестирован на Windows XP SP3 (x86).
unsigned long get_ebp() {
__asm__("pop %ebp\n\t"
"movl %ebp,%eax\n\t"
"push %ebp\n\t");
}
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;
/* distance in bytes from buffer1 to return address on the stack */
printf("test %d\n", ((get_ebp() + 4) - (unsigned long)&buffer1));
ret = (int *)(buffer1 + 28);
(*ret) += 7;
}
void main() {
int x;
x = 0;
function(1,2,3);
x = 1;
printf("%d\n",x);
}
Я мог бы так же легко использовать GDB, чтобы определить это значение.
(Скомпилировано с/ -g
включить символы отладки)
(gdb) break function
...
(gdb) run
...
(gdb) p $ebp
$1 = (void *) 0x22ff28
(gdb) p &buffer1
$2 = (char (*)[5]) 0x22ff10
(gdb) quit
(0x22ff28
+ 4) - 0x22ff10
= 28
(Значение EBP + размер слова) - Адрес Buffer1 = Количество байтов
В дополнение к Разбить стек для удовольствия и прибыли, Я бы посоветовал прочитать некоторые из статей, которые я упомянул мой ответ на ваш предыдущий вопрос и/или другой материал по предмету. Хорошее понимание того, как именно работает этот тип эксплойта, должно помочь вам Напишите более безопасный код.
Другие советы
Трудно предсказать что buffer1 + 12
Действительно указывает на. Ваш компилятор может положить buffer1
а также buffer2
В любом месте в стеке, в котором он желает, даже не сэкономив место для buffer2
вообще. Единственный способ узнать, где buffer1
GOS - это посмотреть на вывод сборка вашего компилятора, и есть большая вероятность, что он будет прыгать с различными настройками оптимизации или разными версиями одного и того же компилятора.
Я еще не проверяю код на своей собственной машине, но вы приняли во внимание выравнивание памяти? Попробуйте разобрать код с GCC. Я думаю, что код сборки может дать вам дальнейшее понимание кода. :-)
Этот код печатает 1, а также на OpenBSD и FreeBSD и дает ошибку сегментации на Linux.
Этот вид эксплуатации сильно зависит как от набора инструкций конкретной машины, так и от призывных соглашений компилятора и операционной системы. Все в макете стека определяется реализацией, а не языком C. В статье предполагается Linux на x86, но похоже, что вы используете Windows, и ваша система может быть 64-битной, хотя вы можете переключить GCC на 32-битный -m32
.
Параметры, которые вам придется настроить, составляют 12, что является смещением от кончика стека на адрес возврата, и 8, а это сколько байтов main
Вы хотите перепрыгнуть. Как говорится в статье, вы можете использовать GDB, чтобы осмотреть разборку функции, чтобы увидеть (а) как далеко настанет стек, когда вы звоните function
, и (b) байтовые смещения инструкций в main
.
Проверьте, есть ли анонимный доступ к <сильным> шаблонам формы библиотека.Все шаблоны формы InfoPath находятся в этой библиотеке, поэтому вы можете проверить, может ли анонимный доступ к вашему конкретному InfoPath тоже
Вы собираете программу C с компилятором C ++. Переименовать hw.cpp до hw.c, и вы обнаружите, что он будет компилировать.