Код переполнения на основе стека из Hacking: The Art of Exploitation

Это может быть связано с этим , но я не уверен, что они в одной лодке.

Итак, я перечитал Hacking: The Art of Exploitation, и у меня есть вопрос о некоторых частях кода C в книге, который мне не совсем понятен:

Давайте просто предположим, что мы вернулись примерно в 2000 год, и у нас на самом деле нет файлов cookie стека и ASLR (может быть, они есть, но они не реализованы или не получили широкого распространения) или любого другого типа защиты, который у нас есть сейчас. дней.

Он показывает нам этот фрагмент кода для использования простого переполнения на основе стека:

#include <stdlib.h>

char shellcode[] = "..." // omitted

unsigned long sp(void) 
{ __asm__("movl %esp, %eax); }

int main(int argc, char *argv[]) {
int i, offset;
long esp, ret, *addr_ptr;
char *buffer, *ptr;

offset = 0;
esp = sp();
ret = esp - offset;

// bunch of printfs here...

buffer = malloc(600);

ptr = buffer;
addr_ptr = (long *) ptr;
for(i = 0; i < 600; i+=4)
{ *(addr_ptr++) = ret; }

for(i = 0; i < 200; i++)
{ buffer[i] = '\x90'; }

ptr = buffer + 200;
for(i = 0; i < strlen(shellcode); i++)
{ *(ptr++) = shellcode[i]; }

buffer[600-1] = 0;

execl("./vuln", "vuln", buffer, 0);

free(buffer);

return 0;
}

Итак, что он хочет сделать, так это взять адрес ESP и перезаписать сохраненный EIP этим адресом, чтобы процессор перешел к своей NOP-цепочке в памяти и выполнил шелл-код в стеке.

Чего я не понимаю, так это того, как он может использовать это конкретное значение ESP, которое он получает от sp() в текущий момент времени, когда он его вызывает.

Насколько я понимаю, стек выглядит примерно так:

...
saved ebp <-- execl
saved eip
"./vuln"
"vuln"
buffer
0
*ptr <-- sp() returns this address?
*buffer
*addr_ptr
ret
esp
offset
i
saved ebp <-- main
saved eip
argc
argv
...

Поскольку он вызывает (я знаю, что это указатель на функцию, так что, думаю, это не совсем точная формулировка?) sp() так рано в эксплойте, разве это не должно дать ему неверный адрес ESP? Даже если на то пошло, я не понимаю, как он вообще может использовать эту технику здесь, потому что он никогда не получит ESP, который указывает на верхнюю часть буфера внутри его vuln программы.

Спасибо.


person Volatile    schedule 17.07.2013    source источник


Ответы (3)


Я не понимаю, как он может использовать эту технику здесь, потому что он никогда не получит ESP, который указывает на верхнюю часть буфера внутри его vuln программы.

Я не читал большую часть книги, но я думаю, что понял это. Вот как выглядит *buffer:

NOP sled | shellcode | Address of buffer in the exploit's stack frame

Когда vuln выполняет strcpy() на buffer в свой собственный стек, он не может проверить границы и перезаписывает свой собственный EIP адресом начала буфера во фрейме стека эксплойта или, по крайней мере, чем-то близким к это (отсюда и сани NOP). След NOP и шелл-код, скопированные в кадр стека vuln, являются случайными; это не то, откуда они запускаются. Крайне важно, чтобы салазки и шеллкод были меньше, чем vuln ожидает buffer, иначе сохраненный EIP будет перезаписан. по шеллкоду, а не по адресу buffer.

Затем, когда какая-либо часть vuln, которая использует strcpy() на buffer, возвращается, она переходит к салазкам NOP и выполняет шелл-код.

Важным моментом является то, что buffer читается дважды в двух разных местах.

Редактировать: Не обращайте на это внимания, я сам запутался (хотя спасибо за согласие!). Надеюсь, я вас тоже не запутаю, поэтому и пишу эту правку. Уязвимая программа находится в совершенно пространстве виртуальной памяти, поскольку она запускается операционной системой в отдельном процессе (или в том же процессе с новым образом? Как угодно). Таким образом, vuln не сможет получить доступ к стеку эксплойта или куче.

Хитрость ESP должна каким-то образом угадывать, где NOP-цепочка в скопированном буфере заканчивается в стеке vuln. Лично я ожидал бы гораздо большего смещения, чем 0, поскольку стек эксплойта довольно мал по сравнению со стеком vuln.

Тем не менее, я почти уверен, что в vuln все еще есть две копии шеллкода (иначе, откуда он мог бы strcpy()?). Со смещением 0, возможно, он запускает шелл-код, хранящийся в argv[]...?!? В этом случае у вас все еще будет ситуация, когда адрес в одном буфере указывает на салазки NOP в другом буфере, как в моем исходном ответе. Я ошибался раньше, так что дайте мне знать, если это не имеет смысла.

person Vanessa Phipps    schedule 17.07.2013
comment
По сути, vuln вернется в шелл-код, содержащийся в стеке эксплойта, а не в своем собственном стеке. Имеет смысл, спасибо. - person Volatile; 17.07.2013
comment
Спасибо, что приняли! Я на самом деле не уверен, что это правильно, теперь, когда я думаю об этом. Я думаю, что для этого buffer[] нужно было бы объявить как автоматическую переменную, а не malloc()'d...? Я также не совсем понимаю, что мешает ему просто заполнить конец buffer[] своим собственным начальным адресом, вместо того, чтобы возиться с ESP. - person Vanessa Phipps; 17.07.2013

Многое будет зависеть от того, для какой конкретной ОС предназначен код. Не зная этого, любое обсуждение должно быть несколько общим [и догадкой с моей стороны].

Одна из возможностей состоит в том, что в "кучке printfs", которую вы упустили, было что-то важное...

Если там действительно не происходит ничего умного, я бы предположил, что уязвимость, которую он пытается использовать, находится в вызове execl(..) и/или в ОС, когда эффективно передается длинный (600 байт) параметр командной строки. Где-то там [я предполагаю] подпрограмма будет настраивать среду для нового процесса и попутно будет копировать 600-байтовую строку, переданную в качестве параметра (buffer), в то, что вполне может быть небольшим( ish) буфер фиксированного размера в стеке нового процесса и [предположительно] перезаписывает адрес возврата этой функции «настройки» множеством копий указателя стека из исходного вызова. Когда «функция копирования из командной строки» вернется, она, таким образом, вернется к тщательно подготовленному buffer из исходной копии и выполнит шелл-код.

(Если пропущенный shellcode содержит нулевой байт ...\x00..., то это не может быть тем, что происходит, так как это будет означать конец копируемой строки при настройке буфера командной строки).

person TripeHound    schedule 17.07.2013

:) Я был в этом в течение нескольких дней, пытаясь выяснить, что на самом деле происходит. В процессе я также обнаружил этот пост. Теперь, когда у меня есть представление о том, что происходит, я подумал, что должен поделиться тем, что понял, чтобы другие, такие как «я», также нашли это полезным.

unsigned long getesp()
{
__asm__("movl %esp, %eax");
}

Эта функция фактически используется для угадывания обратного адреса. Он возвращает значение ESP нашей программы внедрения шелл-кода, а НЕ значение ESP уязвимой программы. Но поскольку стек начинается почти с одного и того же адреса (для систем без включенного ASLR) и, как упоминает aleph one в своей статье, «Большинство программ не помещают в стек более нескольких сотен или нескольких тысяч байтов за раз. Следовательно, зная, где начинается стек, мы можем попытаться угадать, где будет находиться буфер, который мы пытаемся переполнить», мы можем получить представление о том, где должен быть наш шелл-код. Позволь мне объяснить.

Предположим, что для нашей тестовой программы стек начинается с 1000. Этот адрес фактически возвращается приведенным выше кодом, когда мы его выполняем. Теперь рассмотрим нашу уязвимую программу и предположим, что буфер, в который мы пытаемся внедрить, находится по адресу 970, а адрес возврата хранится по адресу 1040.

[БУФЕР 970][RETURN_ADDRESS 1070]

Ok? Теперь буфер заполняется с NOPS до первой половины, потом с шеллкодом и потом с адресом возврата прямо..

[NOP SLED][SHELL_CODE][RETURN_ADDRESS]

давай заполним вот так

NOPS [970-1010] SHELLCODE[ 1010-1050 ] RETURN_ADDRESS[1050-1070]

Значение, возвращаемое getesp(), дает представление о том, где будет находиться стек. поэтому, если мы перепишем адрес возврата на 1000, который был возвращен getesp(), мы увидим, что эксплойт все еще будет работать, потому что адрес 1000 указан с nops. экзекция соскользнет к шеллкоду!

person Ray    schedule 18.06.2014