Я экспериментирую с шеллкодом и наткнулся на технику nop-slide. Я написал небольшой инструмент, который принимает размер буфера в качестве параметра и создает буфер следующим образом: [NOP | SC | RET], при этом NOP забирает половину буфера, затем шелл-код, а остальные заполняются (предположительно) адресом возврата. Он очень похож на инструмент aleph1, описанный в его знаменитой статье.
Мое уязвимое тестовое приложение такое же, как в его статье:
int main(int argc, char **argv) {
char little_array[512];
if(argc>1)
strcpy(little_array,argv[1]);
return 0;
}
Я проверил и хорошо, он работает:
jth@insecure:~/no_nx_no_aslr$ ./victim $(./exploit 604 0)
$ exit
Но, честно говоря, я понятия не имею, почему. Хорошо, сохраненный eip был перезаписан как положено, но вместо того, чтобы прыгнуть куда-нибудь в буфер, я думаю, что он переместился в argv.
gdb обнаружил следующие адреса до вызова strcpy ():
(gdb) i f
Stack level 0, frame at 0xbffff1f0:
eip = 0x80483ed in main (victim.c:7); saved eip 0x154b56
source language c.
Arglist at 0xbffff1e8, args: argc=2, argv=0xbffff294
Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
Saved registers:
ebp at 0xbffff1e8, eip at 0xbffff1ec
Адрес little_array:
(gdb) print &little_array[0]
$1 = 0xbfffefe8 "\020"
После strcpy ():
(gdb) i f
Stack level 0, frame at 0xbffff1f0:
eip = 0x804840d in main (victim.c:10); saved eip 0xbffff458
source language c.
Arglist at 0xbffff1e8, args: argc=-1073744808, argv=0xbffff458
Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
Saved registers:
ebp at 0xbffff1e8, eip at 0xbffff1ec
Итак, что здесь произошло? Я использовал 604-байтовый буфер для переполнения little_array, поэтому он, безусловно, перезаписал сохраненные ebp, сохраненные eip и argc, а также argv с предполагаемым адресом 0xbffff458.
Затем, после возврата, EIP указал на 0xbffff458. Но little_buffer находится в 0xbfffefe8, это разница в 1136 байт, поэтому он, конечно, не выполняет little_array. Я следил за выполнением с помощью команды stepi и, ну 0xbffff458 и далее, он выполняет NOP и достигает шелл-кода.
Я не совсем уверен, почему это происходит. Прежде всего, я прав, что он выполняет мой шелл-код в argv, а не little_array? И где загрузчик (?) Помещает argv в стек? Я думал, что это следует сразу после argc, но между argc и 0xbffff458 существует разрыв в 620 байт. Как это возможно, что он успешно «приземлился» в NOP-Pad по адресу 0xbffff458, что намного выше сохраненного eip в 0xbffff1ec?
Может кто-нибудь уточнить это? Я действительно понятия не имею, почему это работает. Мой тестовый компьютер - 32-разрядный компьютер Ubuntu 9.10 без ASLR. У жертвы есть исполняемый стек, установленный с помощью execstack -s.
Заранее спасибо.