Мастерская бравого хакера Крис Касперски Хакер, номер #091, стр. 091-116-5 Доработка напильником Shell-код имеет сложную структуру и обычно состоит из нескольких частей. Например, exploit milw0rm.com/exploits/1075, приложенный в файле 1075.с, использует целых 6 «иероглифических» массивов: dce_rpc_header1, tag_private, dce_rpc_header2, dce_rpc_header3, offsets, bind_shellcode. Первые пять — это служебные структуры, атакующие жертву, срывающие буферу крышу и передающие управление на bind_shellcode. Последний представляет собой «чистый» shell-код, который может быть беспрепятственно заменен любым другим. На самом деле, тут все не так просто, и произвола хоть отбавляй. Как минимум, необходимо убедиться, что мы используем shell-код, совместимый с атакуемой системой, и точки входа у них совпадают. Часто (но не всегда) точка входа расположена в самом начале shell-кода, реже — в его конце или середине. Гораздо хуже, если exploit написан «пионером», и все блоки идут одним большим кусом, внутри которого присутствует и shell-код. Чтобы определить положение дел, необходимо преобразовать «иероглифический» текст в двоичный файл и дизассемблировать его. Разыскивать соответствующий конвертор совершенно необязательно. Проще переложить эту задачу на плечи компилятору Си, написав простенькую программку из нескольких строк. Простейший конвертор для преобразования строковых констант в двоичный код #include <stdio.h> int main(void) { FILE *f; if (f = fopen("shellcode", "wb")) fwrite(shellcode, sizeof(shellcode), 1, f); exit(0); } Сам shell-код должен быть размещен в массиве, объявленном как «char shellcode[]» (см. прилагаемый файл hex2bin.c) и приведенным к синтаксису Си (то есть, если shell-код выдернут из perl'а, необходимо удалить точки в конце строковых констант). Компилируем наш импровизированный конвертор, запускаем его на выполнение — и тут же на диске образуется файл «shellcode», который можно загрузить в HTE, IDA Pro или любой другой дизассемблер по вкусу, не забывая, конечно, переключить его в 32-битный режим. В данном случае мы получим следующий код: Первые 16-байт shell-кода содержат осмысленный код расшифровщика 00000000: 29C9 sub ecx,ecx 00000002: 83E9B0 sub ecx,-050 ;"P" 00000005: D9EE fldz 00000007: D97424F4 fstenv [esp][-000C] 0000000B: 5B pop ebx 0000000C: 81731319F50437 xor d,[ebx][00013],03704F519 ; "7?o?" 00000013: 83EBFC sub ebx,-004 ; "?" 00000016: E2F4 loop 00000000C (1) Ага! Вполне типичный расшифровщик. Значит, точка входа в shell-код действительно находится в начале массива, и он может быть беспрепятственно заменен любым таким же. Если же вместо осмысленного кода нас встречает мусор, то нужно последовательно отступать на один байт до тех пор, пока мы не получим что-то удобоваримое. Естественно, для этого необходимо знать ассемблер и хотя бы в общих чертах представлять себе устройство операционной системы. |