Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeXTF2 committed Aug 14, 2022
0 parents commit 8e77d48
Show file tree
Hide file tree
Showing 8 changed files with 514 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/__pycache__
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Burp2Malleable
This is a quick python utility I wrote to turn HTTP requests from burp suite into Cobalt Strike Malleable C2 profiles.
As of now, it currently does not perform custom mangling such as prepend, append and encodings, but rather generates the rough profile with a default encoding of mask+base64. You are expected to add your own prepends, appends and encoding if you want to make it more convincing. I am working on ways to automate this as well.

## Installation
```
pip install -r requirements.txt
```
## Usage
```
python burp2malleable.py request.txt response.txt
```

Work in progress, will be updated if I think of ideas. Feel free to submit issues/PRs/suggestions.

## TODO
- Detect base64 strings in original request and response and automatically use those to store beacon data
259 changes: 259 additions & 0 deletions burp2malleable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
import burpee
import sys
import os
from malleablec2 import Profile
from malleablec2.components import *
from termcolor import colored

toolbanner = """
█▄▄ █░█ █▀█ █▀█  ▀█ █▀▄▀█ ▄▀█ █░░ █░░ █▀▀ ▄▀█ █▄▄ █░░ █▀▀
█▄█ █▄█ █▀▄ █▀▀  █▄ █░▀░█ █▀█ █▄▄ █▄▄ ██▄ █▀█ █▄█ █▄▄ ██▄
https://github.com/CodeXTF2/Burp2Malleable
"""
print(colored(toolbanner,"cyan"))

#print functions
def printsuccess(msg):
print(colored(colored("[+] ","green") + msg,attrs=["bold"]))

def printfail(msg):
global errors
print(colored("[!] ","red",attrs=['bold']) + colored(msg,"yellow",attrs=['bold']))

def printbold(msg):
print(colored(msg,attrs=['bold']))

def printmsg(msg):
print(colored("[*] ","cyan",attrs=["bold"]) + msg)


def storelocation(item):
print(colored(toolbanner,"cyan"))
location = input(f"Where do you want to store {item}?\n\t1. Header\n\t2. Body\n\t3. URI-Param\n>")
if location == "1":
headername = input("Header name: ")
return ['header',headername]
elif location == "3":
paramname = input("Param name: ")
return ['uriparam',paramname]
else:
return ['body','']

#is the req body used already


# fix the files
reqfilename = sys.argv[1]
resfilename = sys.argv[2]

reqfile = open(reqfilename,"r",errors='ignore').read()
resfile = open(resfilename,"r",errors='ignore').read()

with open("tempreq","w+",errors='ignore') as f:
f.write(reqfile.replace("\"","\'").replace("\\","\\\\"))

with open("tempres","w+",errors='ignore') as f:
f.write(resfile.replace("\"","\'").replace("\\","\\\\"))

reqfile = open("tempreq").read()
resfile = open("tempres").read()
requri = reqfile.split("\n")[0].split(" ")[1].split("?")[0]

try:
reqparams = reqfile.split("\n")[0].split(" ")[1].split("?")[1]
except:
reqparams= ""
reqmethod = reqfile.split("\n")[0].split(" ")[0]

reqheaders, reqdata = burpee.parse_request("tempreq")
resheaders, resdata = burpee.parse_request("tempres")
os.remove("tempreq")
os.remove("tempres")
reqfile_commented = ""
for x in reqfile.split("\n"):
reqfile_commented += "# " + x + "\n"

resfile_commented = ""
for x in resfile.split("\n"):
resfile_commented += "# " + x + "\n"



original = "# Original HTTP request\n#\n" + reqfile_commented + "\n#"
original += "\n# Original HTTP response\n#\n" + resfile_commented + "\n#"
original += "#\n#\n"





uri_used = False
body_used = False
beaconmeta = storelocation("Beacon metadata")
while beaconmeta [0] == "body" and reqmethod != "POST":
printfail(f"Request body may only be used in POST requests. This is a {reqmethod} request.")
beaconmeta = storelocation("Beacon metadata")


beaconid = storelocation("Beacon ID")
while beaconid[0] == "body" and reqmethod != "POST":
printfail(f"Request body may only be used in POST requests. This is a {reqmethod} request.")
beaconid = storelocation("Beacon ID")
while beaconid[0] == "body" and body_used:
printfail(f"Request body already in use")
beaconid = storelocation("Beacon ID")
if beaconid[0] == "body":
body_used = True



beaconresponse = storelocation("Beacon response")
while beaconresponse[0] == "body" and reqmethod != "POST":
printfail(f"Request body may only be used in POST requests. This is a {reqmethod} request.")
beaconresponse = storelocation("Beacon response")
while beaconresponse[0] == "body" and body_used:
printfail(f"Request body already in use")
beaconresponse = storelocation("Beacon ID")
if beaconid[0] == "body":
body_used = True


profilebanner = """
############################################################################
# Generated by Burp2Malleable - https://github.com/CodeXTF2/Burp2Malleable #
# By: CodeX #
############################################################################
"""


#create our profile
profile = Profile.from_scratch()



#http.get block
http_get = HttpGetBlock()
http_get.set_option("verb", reqmethod)
http_get.set_option("uri", requri.lower())

client_get = ClientBlock()
metadata = MetadataBlock()
for x in reqheaders.items():
client_get.add_statement("header", x[0], x[1])

metadata.add_statement("mask")
metadata.add_statement("base64url")

#metadata
if beaconmeta[0] == "body":
metadata.add_statement("print")
printmsg(f"Storing beacon metadata in request body")
elif beaconmeta[0] == "uriparam":
metadata.add_statement("parameter",beaconmeta[1])
printmsg(f"Storing beacon metadata in the URI parameter {beaconmeta[1]}")
else:
metadata.add_statement("header",beaconmeta[1])
printmsg(f"Storing beacon metadata in request header {beaconmeta[1]}")

client_get.add_code_block(metadata)
server_get = ServerBlock()
output_get = OutputBlock()
output_get.add_statement("mask")
output_get.add_statement("base64url")
#beacon tasking
output_get.add_statement("print")



server_get.add_code_block(output_get)
for x in resheaders.items():
server_get.add_statement("header", x[0], x[1])

http_get.add_code_block(client_get)
http_get.add_code_block(server_get)




#http.post block
http_post = HttpPostBlock()
http_post.set_option("verb", reqmethod)
if requri == "/":
requri += "/"
http_post.set_option("uri", requri.upper())


#http.post.client
client_post = ClientBlock()

#add the output_post block for the client
output_post = OutputBlock()
output_post.add_statement("mask")
output_post.add_statement("base64url")

#beaconupload
if beaconresponse[0] == "body":
output_post.add_statement("print")
printmsg(f"Storing beacon response in request body")
elif beaconresponse[0] == "uriparam":
output_post.add_statement("parameter",beaconresponse[1])
printmsg(f"Storing beacon response in the URI parameter {beaconresponse[1]}")
else:
output_post.add_statement("header",beaconresponse[1])
printmsg(f"Storing beacon response in request header {beaconresponse[1]}")


post_id = IdBlock()
post_id.add_statement("mask")
post_id.add_statement("base64url")
#beaconid
if beaconid[0] == "body":
post_id.add_statement("print")
printmsg(f"Storing beacon ID in request body")
elif beaconid[0] == "uriparam":
post_id.add_statement("parameter",beaconid[1])
printmsg(f"Storing beacon ID in the URI Parameter {beaconid[1]}")
else:
post_id.add_statement("header",beaconid[1])
printmsg(f"Storing beacon ID in request header {beaconid[1]}")


for x in reqheaders.items():
client_post.add_statement("header", x[0], x[1])

client_post.add_code_block(post_id)
client_post.add_code_block(output_post)



#http.post.server
server_post = ServerBlock()

#add the output_post block for the server
output_post = OutputBlock()
output_post.add_statement("mask")
output_post.add_statement("base64url")
output_post.add_statement("print")
server_post.add_code_block(output_post)








for x in resheaders.items():
server_post.add_statement("header", x[0], x[1])

http_post.add_code_block(client_post)
http_post.add_code_block(server_post)


#build the profile
profile.add_code_block(http_get)
profile.add_code_block(http_post)

with open("generated.profile","w+") as f:
f.write(profilebanner + str(profile))
printsuccess("Profile saved in generated.profile. Remember to run ./c2lint!")
74 changes: 74 additions & 0 deletions burpee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# https://github.com/xscorp/Burpee
import requests

debug = False

def print_debug(*msg):
if debug == True:
for info in msg:
print(info , end = "")

def parse_request(file_name):
line = ""
headers = {}
post_data = ""
header_collection_done = False
file_object = open(file_name , "r")
file_object.seek(0)
file_object.readline()
for line in file_object.readlines():
if header_collection_done is False:
if line.startswith("\n"):
header_collection_done = True
else:
headers.update({
line[0:line.find(":")].strip() : line[line.find(":")+1 :].strip()
})
else:
post_data = post_data + line
file_object.close()
return (headers , post_data)

def dump_headers(file_name):
headers , post_data = parse_request(file_name)
for header , value in headers.items():
print(header , ": " , value , sep = "")

def dump_data(file_name):
headers , post_data = parse_request(file_name)
print(post_data)

def get_method_and_resource(file_name):
file_object = open(file_name , "r")
request_line = file_object.readline()
file_object.close()
request_line = request_line.split(" ")
method_name = request_line[0]
if request_line[1].startswith("/"):
resource_name = request_line[1]
else:
resource_name = request_line[1][request_line[1].find("/"):]
return method_name , resource_name

def request(file_name , https = False , proxies = None):
headers , post_data = parse_request(file_name)
method_name , resource_name = get_method_and_resource(file_name)
protocol = "https" if (https is True) else "http"
url = protocol + "://" + headers["Host"] + resource_name

#debug information
print_debug("DEBUG INFORMATION")
print_debug("\n==========================================")
print_debug("\nProtocol : " , protocol)
print_debug("\n\nMethod name : " , method_name)
print_debug("\n\nResource requested : " , resource_name)
print_debug("\n\nPost data : " , post_data)
print_debug("\n\nHeaders : " , headers)
print_debug("\n\nProxies : " , proxies)
print_debug("\n==========================================\n\n")

if method_name.lower() == "get":
response = requests.get(url = url , headers = headers , proxies = proxies , verify = False)
elif method_name.lower() == "post":
response = requests.post(url = url , headers = headers , data = post_data , proxies = proxies , verify = False)
return response
Loading

0 comments on commit 8e77d48

Please sign in to comment.