Edited: The code below works, and the changes are commented. As noted, with python3 one must prefix the string literals with a "b" to produce an instance of the byte type instead of a Unicode str type.
I'm trying to use msfrpc (written in Python 2) in Python 3, and I'm encountering authentication errors. The code I'm using is below; see the comments in the code for the changes I made.
The program runs successfully in python2 (when using httplib rather than http.client), with what appears to be the same authentication exchange as seen when using python3.
import msgpack
import http.client #Changed from httplib
class Msfrpc:
class MsfError(Exception):
def __init__(self,msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
class MsfAuthError(MsfError):
def __init__(self,msg):
self.msg = msg
def __init__(self,opts=[]):
self.host = opts.get('host') or "127.0.0.1"
self.port = opts.get('port') or 55552
self.uri = opts.get('uri') or "/api/"
self.ssl = opts.get('ssl') or False
self.authenticated = False
self.token = False
self.headers = {"Content-type" : "binary/message-pack" }
if self.ssl:
self.client = http.client.HTTPSConnection(self.host,self.port) #Changed httplib -> http.client
else:
self.client = http.client.HTTPConnection(self.host,self.port) #Changed httplib -> http.client
def encode(self,data):
return msgpack.packb(data)
def decode(self,data):
return msgpack.unpackb(data)
def call(self,meth,opts = []):
if meth != "auth.login":
if not self.authenticated:
raise self.MsfAuthError("MsfRPC: Not Authenticated")
if meth != "auth.login":
opts.insert(0,self.token)
opts.insert(0,meth)
params = self.encode(opts)
self.client.request("POST",self.uri,params,self.headers)
resp = self.client.getresponse()
return self.decode(resp.read())
def login(self,user,password):
ret = self.call('auth.login',[user,password])
if ret.get(b'result') == b'success': #Added b
self.authenticated = True
self.token = ret.get(b'token') #Added b
return True
else:
raise self.MsfAuthError("MsfRPC: Authentication failed")
if __name__ == '__main__':
# Create a new instance of the Msfrpc client with the default options
client = Msfrpc({})
# Login to the msfmsg server using the password "abc123"
client.login('msf','abc123')
# Get a list of the exploits from the server
mod = client.call('module.exploits')
# Grab the first item from the modules value of the returned dict
print ("Compatible payloads for : %s\n" % mod[b'modules'][0]) #Added () #Added b
# Get the list of compatible payloads for the first option
ret = client.call('module.compatible_payloads',[mod[b'modules'][0]]) #Added b
for i in (ret.get(b'payloads')): #Added b
print ("\t%s" % i) #Added ()
When running the program, the result is:
root@kali:~/Dropbox/PythonStuff/python-nmap-test# python3 test3.py
Traceback (most recent call last):
File "test3.py", line 20, in <module>
client.login('msf','abc123')
File "/usr/local/lib/python3.7/dist-packages/msfrpc.py", line 64, in login
raise self.MsfAuthError("MsfRPC: Authentication failed")
msfrpc.MsfAuthError: 'MsfRPC: Authentication failed'
Curiously, running tcpdump while the program is executing shows a successful authentication and a token being granted:
When the program executes successfully with python2 the authentication exchange appears identical, but if someone feels posting the packet capture of the program (running in python2) completing successfully would help to answer the question I can easily add it.