From 6b8f4a55b23cb6ec68ce05723c4a947363e81f2a Mon Sep 17 00:00:00 2001 From: Consultant Date: Tue, 21 Feb 2023 15:41:29 +0000 Subject: [PATCH] Added support for HijackLibs --- README.md | 39 ++++++++++- gtfoblookup.1 | 166 ++++++++++++++++++++++++++++---------------- gtfoblookup.py | 185 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 307 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 57afece..6e20837 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # GTFOBLookup -Offline command line lookup utility for [GTFOBins](https://gtfobins.github.io/), [LOLBAS](https://lolbas-project.github.io/), and [WADComs](https://wadcoms.github.io). +Offline command line lookup utility for [GTFOBins](https://gtfobins.github.io/), [LOLBAS](https://lolbas-project.github.io/), [WADComs](https://wadcoms.github.io), and [HijackLibs](https://hijacklibs.net/). ## Files - **.gitignore**: Gitignore file @@ -26,7 +26,7 @@ To install GTFOBLookup, git clone the repository to your machine and run `gtfobl ## Usage On Linux, navigate to the GTFOBLookup directory and run `man ./gtfoblookup.1` or see below:
-gtfoblookup.py [-h] {update,purge,gtfobins,lolbas,wadcoms} ...
+gtfoblookup.py [-h] {update,purge,gtfobins,lolbas,wadcoms,hijacklibs} ...
 
 OPTIONS
    Sub-commands
@@ -45,6 +45,9 @@ OPTIONS
        gtfoblookup.py wadcoms
               search the local copy of WADComs
 
+       gtfoblookup.py hijacklibs
+              search the local copy of HijackLibs
+
 OPTIONS 'gtfoblookup.py update'
        usage: gtfoblookup.py update [-h] [-r repo]
 
@@ -155,4 +158,36 @@ OPTIONS 'gtfoblookup.py wadcoms search'
 
        -f, --file
               use a file containing a list of executables (one per line) instead of a single executable
+
+OPTIONS 'gtfoblookup.py hijacklibs'
+       usage: gtfoblookup.py hijacklibs [-h] {list,search} ...
+
+  Sub-commands 'gtfoblookup.py hijacklibs'
+       gtfoblookup.py hijacklibs list
+              list all types/categories/executables/prerequisites/services/attack types/OSs featured in the local copy of HijackLibs
+
+       gtfoblookup.py hijacklibs search
+              searchthe HijackLibs repository
+
+OPTIONS 'gtfoblookup.py hijacklibs list'
+       usage: gtfoblookup.py hijacklibs list [-h] attribute
+
+       attribute
+              the attribute to list
+
+  Sub-commands 'gtfoblookup.py hijacklibs search'
+       usage: gtfoblookup.py hijacklibs search [-h] [-a attack_types] [-v vendors] [-f] executable
+
+       executable
+              the executable to search for (use "all" to show results for all executables)
+
+OPTIONS 'gtfoblookup.py hijacklibs search'
+       -a attack_types, --attacktype attack_types
+              search for executables that can be used for aspecific type or types (comma separated) of attacks
+
+       -v vendors, --vendor vendors
+              search for executables from a specific vendor or vendors (comma separated)
+
+       -f, --file
+              use a file containing a list of executables (one per line) instead of a single executable
 
diff --git a/gtfoblookup.1 b/gtfoblookup.1 index 8a50061..b3e871b 100755 --- a/gtfoblookup.1 +++ b/gtfoblookup.1 @@ -1,16 +1,14 @@ -.TH gtfoblookup.py "1" Manual +.TH GTFOBLOOKUP.PY "1" "2023\-02\-21" "GTFOBLookup" "Generated Python Manual" .SH NAME gtfoblookup.py .SH SYNOPSIS .B gtfoblookup.py -[-h] {update,purge,gtfobins,lolbas,wadcoms} ... +[-h] {update,purge,gtfobins,lolbas,wadcoms,hijacklibs} ... .SH DESCRIPTION -Offline command line lookup utility for GTFOBins -(https://gtfobins.github.io/), LOLBAS(https://lolbas\-project.github.io/), and -WADComs (https://wadcoms.github.io) -.SH OPTIONS -.SS -\fBSub-commands\fR +Offline command line lookup utility for GTFOBins (https://gtfobins.github.io/), LOLBAS(https://lolbas\-project.github.io/), WADComs (https://wadcoms.github.io), HijackLibs (https://hijacklibs.net/) + +.SH +POSITIONAL ARGUMENTS .TP \fBgtfoblookup.py\fR \fI\,update\/\fR update local copies of repositories @@ -26,50 +24,55 @@ search the local copy of LOLBAS .TP \fBgtfoblookup.py\fR \fI\,wadcoms\/\fR search the local copy of WADComs -.SH OPTIONS 'gtfoblookup.py update' -usage: gtfoblookup.py update [-h] [-r repo] +.TP +\fBgtfoblookup.py\fR \fI\,hijacklibs\/\fR +search the local copy of HijackLibs +.SH COMMAND \fI\,'gtfoblookup.py update'\/\fR +usage: gtfoblookup.py update [\-h] [\-r repo] +.SH OPTIONS \fI\,'gtfoblookup.py update'\/\fR .TP -\fB\-r\fR repo, \fB\-\-repo\fR repo +\fB\-r\fR \fI\,repo\/\fR, \fB\-\-repo\fR \fI\,repo\/\fR Only update the specified repository -.SH OPTIONS 'gtfoblookup.py purge' -usage: gtfoblookup.py purge [-h] [-r repo] - +.SH COMMAND \fI\,'gtfoblookup.py purge'\/\fR +usage: gtfoblookup.py purge [\-h] [\-r repo] +.SH OPTIONS \fI\,'gtfoblookup.py purge'\/\fR .TP -\fB\-r\fR repo, \fB\-\-repo\fR repo +\fB\-r\fR \fI\,repo\/\fR, \fB\-\-repo\fR \fI\,repo\/\fR Only delete the specified repository -.SH OPTIONS 'gtfoblookup.py gtfobins' -usage: gtfoblookup.py gtfobins [-h] {list,search} ... +.SH COMMAND \fI\,'gtfoblookup.py gtfobins'\/\fR +usage: gtfoblookup.py gtfobins [\-h] {list,search} ... -.SS -\fBSub-commands\fR +.SH +POSITIONAL ARGUMENTS \fI\,'gtfoblookup.py gtfobins'\/\fR .TP \fBgtfoblookup.py gtfobins\fR \fI\,list\/\fR list all types/categories/executables/prerequisites/services/attack types/OSs featured in the local copy of GTFOBins .TP \fBgtfoblookup.py gtfobins\fR \fI\,search\/\fR searchthe GTFOBins repository -.SH OPTIONS 'gtfoblookup.py gtfobins list' -usage: gtfoblookup.py gtfobins list [-h] attribute + +.SH COMMAND \fI\,'gtfoblookup.py gtfobins list'\/\fR +usage: gtfoblookup.py gtfobins list [\-h] attribute .TP \fBattribute\fR the attribute to list - -.SH OPTIONS 'gtfoblookup.py gtfobins search' -usage: gtfoblookup.py gtfobins search [-h] [-c categories] [-f] executable +.SH COMMAND \fI\,'gtfoblookup.py gtfobins search'\/\fR +usage: gtfoblookup.py gtfobins search [\-h] [\-c categories] [\-f] executable .TP \fBexecutable\fR -the executable to search for +the executable to search for (use "all" to show results for all executables) +.SH OPTIONS \fI\,'gtfoblookup.py gtfobins search'\/\fR .TP -\fB\-c\fR categories, \fB\-\-category\fR categories +\fB\-c\fR \fI\,categories\/\fR, \fB\-\-category\fR \fI\,categories\/\fR category or categories (comma separated) to search in .TP @@ -77,40 +80,40 @@ category or categories (comma separated) to search in use a file containing a list of executables (one per line) instead of a single executable +.SH COMMAND \fI\,'gtfoblookup.py lolbas'\/\fR +usage: gtfoblookup.py lolbas [\-h] {list,search} ... -.SH OPTIONS 'gtfoblookup.py lolbas' -usage: gtfoblookup.py lolbas [-h] {list,search} ... - -.SS -\fBSub-commands\fR +.SH +POSITIONAL ARGUMENTS \fI\,'gtfoblookup.py lolbas'\/\fR .TP \fBgtfoblookup.py lolbas\fR \fI\,list\/\fR list all types/categories/executables/prerequisites/services/attack types/OSs featured in the local copy of LOLBAS .TP \fBgtfoblookup.py lolbas\fR \fI\,search\/\fR searchthe LOLBAS repository -.SH OPTIONS 'gtfoblookup.py lolbas list' -usage: gtfoblookup.py lolbas list [-h] attribute + +.SH COMMAND \fI\,'gtfoblookup.py lolbas list'\/\fR +usage: gtfoblookup.py lolbas list [\-h] attribute .TP \fBattribute\fR the attribute to list - -.SH OPTIONS 'gtfoblookup.py lolbas search' -usage: gtfoblookup.py lolbas search [-h] [-c categories] [-t types] [-f] - executable +.SH COMMAND \fI\,'gtfoblookup.py lolbas search'\/\fR +usage: gtfoblookup.py lolbas search [\-h] [\-c categories] [\-t types] [\-f] + executable .TP \fBexecutable\fR -the executable to search for +the executable to search for (use "all" to show results for all executables) +.SH OPTIONS \fI\,'gtfoblookup.py lolbas search'\/\fR .TP -\fB\-c\fR categories, \fB\-\-category\fR categories +\fB\-c\fR \fI\,categories\/\fR, \fB\-\-category\fR \fI\,categories\/\fR category or categories (comma separated) to search in .TP -\fB\-t\fR types, \fB\-\-type\fR types +\fB\-t\fR \fI\,types\/\fR, \fB\-\-type\fR \fI\,types\/\fR type or types (comma separated)of executable to search for .TP @@ -118,52 +121,52 @@ type or types (comma separated)of executable to search for use a file containing a list of executables (one per line) instead of a single executable +.SH COMMAND \fI\,'gtfoblookup.py wadcoms'\/\fR +usage: gtfoblookup.py wadcoms [\-h] {list,search} ... -.SH OPTIONS 'gtfoblookup.py wadcoms' -usage: gtfoblookup.py wadcoms [-h] {list,search} ... - -.SS -\fBSub-commands\fR +.SH +POSITIONAL ARGUMENTS \fI\,'gtfoblookup.py wadcoms'\/\fR .TP \fBgtfoblookup.py wadcoms\fR \fI\,list\/\fR list all types/categories/executables/prerequisites/services/attack types/OSs featured in the local copy of WADComs .TP \fBgtfoblookup.py wadcoms\fR \fI\,search\/\fR searchthe WADComs repository -.SH OPTIONS 'gtfoblookup.py wadcoms list' -usage: gtfoblookup.py wadcoms list [-h] attribute + +.SH COMMAND \fI\,'gtfoblookup.py wadcoms list'\/\fR +usage: gtfoblookup.py wadcoms list [\-h] attribute .TP \fBattribute\fR the attribute to list - -.SH OPTIONS 'gtfoblookup.py wadcoms search' -usage: gtfoblookup.py wadcoms search [-h] [-p prerequisites] [-s services] - [-a attack_types] [-o OSs] [-f] - executable +.SH COMMAND \fI\,'gtfoblookup.py wadcoms search'\/\fR +usage: gtfoblookup.py wadcoms search [\-h] [\-p prerequisites] [\-s services] + [\-a attack_types] [\-o OSs] [\-f] + executable .TP \fBexecutable\fR -the executable to search for +the executable to search for (use "all" to show results for all executables) +.SH OPTIONS \fI\,'gtfoblookup.py wadcoms search'\/\fR .TP -\fB\-p\fR prerequisites, \fB\-\-prereq\fR prerequisites +\fB\-p\fR \fI\,prerequisites\/\fR, \fB\-\-prereq\fR \fI\,prerequisites\/\fR search for executables with a specific prerequisite or prerequisites (comma separated) .TP -\fB\-s\fR services, \fB\-\-service\fR services +\fB\-s\fR \fI\,services\/\fR, \fB\-\-service\fR \fI\,services\/\fR search for executables that interract with aspecific service or services(comma separated) .TP -\fB\-a\fR attack_types, \fB\-\-attacktype\fR attack_types +\fB\-a\fR \fI\,attack_types\/\fR, \fB\-\-attacktype\fR \fI\,attack_types\/\fR search for executables that can be used for aspecific type or types (comma separated) of attacks .TP -\fB\-o\fR OSs, \fB\-\-os\fR OSs +\fB\-o\fR \fI\,OSs\/\fR, \fB\-\-os\fR \fI\,OSs\/\fR search for executables that can be run on a specific operating system oroperating systems (comma separated) @@ -172,9 +175,54 @@ oroperating systems (comma separated) use a file containing a list of executables (one per line) instead of a single executable +.SH COMMAND \fI\,'gtfoblookup.py hijacklibs'\/\fR +usage: gtfoblookup.py hijacklibs [\-h] {list,search} ... + +.SH +POSITIONAL ARGUMENTS \fI\,'gtfoblookup.py hijacklibs'\/\fR +.TP +\fBgtfoblookup.py hijacklibs\fR \fI\,list\/\fR +list all types/categories/executables/prerequisites/services/attack types/OSs featured in the local copy of HijackLibs +.TP +\fBgtfoblookup.py hijacklibs\fR \fI\,search\/\fR +searchthe HijackLibs repository + +.SH COMMAND \fI\,'gtfoblookup.py hijacklibs list'\/\fR +usage: gtfoblookup.py hijacklibs list [\-h] attribute + +.TP +\fBattribute\fR +the attribute to list + +.SH COMMAND \fI\,'gtfoblookup.py hijacklibs search'\/\fR +usage: gtfoblookup.py hijacklibs search [\-h] [\-a attack_types] [\-v vendors] + [\-f] + executable + +.TP +\fBexecutable\fR +the executable to search for (use "all" to show results for all executables) + +.SH OPTIONS \fI\,'gtfoblookup.py hijacklibs search'\/\fR +.TP +\fB\-a\fR \fI\,attack_types\/\fR, \fB\-\-attacktype\fR \fI\,attack_types\/\fR +search for executables that can be used for aspecific type or types (comma +separated) of attacks + +.TP +\fB\-v\fR \fI\,vendors\/\fR, \fB\-\-vendor\fR \fI\,vendors\/\fR +search for executables from a specific vendor or vendors (comma separated) + +.TP +\fB\-f\fR, \fB\-\-file\fR +use a file containing a list of executables (one per line) instead of a single +executable + .SH AUTHORS -.B GTFOBLookup -was written by James Conlan . +.nf +James Conlan - James.Conlan@nccgroup.com +.fi + .SH DISTRIBUTION The latest version of GTFOBLookup may be downloaded from .UR https://github.com/nccgroup/GTFOBLookup diff --git a/gtfoblookup.py b/gtfoblookup.py index 77e3e17..d5eab62 100755 --- a/gtfoblookup.py +++ b/gtfoblookup.py @@ -16,6 +16,7 @@ from appdirs import user_cache_dir import colorama from git import Repo +from glob import glob import os import re import shutil @@ -53,6 +54,7 @@ "services": {}, "attacktypes": {}, "os": {}, + "vendors": False, "searchFunc": "gtfobSearch" }, "LOLBAS": {"url": "https://github.com/LOLBAS-Project/LOLBAS.git", @@ -86,6 +88,7 @@ "services": {}, "attacktypes": {}, "os": {}, + "vendors": False, "searchFunc": "lolbasSearch" }, "WADComs": {"url": "https://github.com/WADComs/WADComs.github.io.git", @@ -120,8 +123,28 @@ "linux": "Linux", "all": "all" }, + "vendors": False, "searchFunc": "wadcomsSearch" - } + }, + "HijackLibs": {"url": "https://github.com/wietze/HijackLibs.git", + "dir": os.path.join(repodir, "HijackLibs"), + "exeDirs": ["yml/3rd_party/*", "yml/microsoft/built-in", + "yml/microsoft/external"], + "exeFileExt": ".yml", + "categories": {}, + "types": {}, + "prereqs": {}, + "services": {}, + "attacktypes": {"sideloading": "Sideloading", + "variable": "Environment Variable", + "phantom": "Phantom", + "order": "Search Order", + "all": "all" + }, + "os": {}, + "vendors": True, + "searchFunc": "hijackSearch" + } } #Text formatting @@ -138,7 +161,8 @@ def genParser(): " utility for GTFOBins " + "(https://gtfobins.github.io/), LOLBAS" + "(https://lolbas-project.github.io/), " + - "and WADComs (https://wadcoms.github.io)") + "WADComs (https://wadcoms.github.io), " + + "HijackLibs (https://hijacklibs.net/)") parser.set_defaults(func=printUsage, parser=parser) subparsers = parser.add_subparsers() #Update @@ -173,6 +197,12 @@ def genParser(): parserWadcoms.set_defaults(func=printUsage, parser=parserWadcoms, repo="WADComs") wadcomsSubparsers = parserWadcoms.add_subparsers() + #HijackLibs + parserHijacklibs = subparsers.add_parser('hijacklibs', help="search the " + + "local copy of HijackLibs") + parserHijacklibs.set_defaults(func=printUsage, parser=parserHijacklibs, + repo="HijackLibs") + hijacklibsSubparsers = parserHijacklibs.add_subparsers() #Common options for repo in repos: parentParser = "parser{0}".format(repo.lower().capitalize()) @@ -237,6 +267,14 @@ def genParser(): "operating systems (comma separated)", action='store', dest='os', metavar='OSs') parserSearch.set_defaults(os="all") + #Vendors + if repos[repo]['vendors']: + parserSearch.add_argument('-v', '--vendor', help="search for " + + "executables from a specific vendor or " + + "vendors (comma separated)", + action='store', dest='vendors', + metavar='vendors') + parserSearch.set_defaults(vendors="all") #File parserSearch.add_argument('-f', '--file', help="use a file " + "containing a list of executables (one per " + @@ -246,7 +284,7 @@ def genParser(): #Executable parserSearch.add_argument('executable', help="the executable to " + "search for (use \"all\" to show results " + - "for all executables") + "for all executables)") return parser def printUsage(args): @@ -333,16 +371,17 @@ def listExes(args): """Lists the executables featured in the local copy of a repo""" exes = [] for folder in repos[args.repo]['exeDirs']: - for file in os.listdir(os.path.join(repos[args.repo]['dir'], folder)): - if file.endswith(repos[args.repo]['exeFileExt']): - if repos[args.repo]['exeFileExt'] == ".md": - exes.append(file[:-3]) - elif repos[args.repo]['exeFileExt'] == ".yml": - ymlParsed = parseYaml(os.path.join(repos[args.repo]['dir'], - folder, file)) - for data in ymlParsed: - if data is not None: - exes.append(data['Name']) + folder = os.path.join(repos[args.repo]['dir'], folder) + for folder in glob(folder): + for file in os.listdir(folder): + if file.endswith(repos[args.repo]['exeFileExt']): + if repos[args.repo]['exeFileExt'] == ".md": + exes.append(file[:-3]) + elif repos[args.repo]['exeFileExt'] == ".yml": + ymlParsed = parseYaml(os.path.join(folder, file)) + for data in ymlParsed: + if data is not None: + exes.append(data['Name']) exes.sort(key=str.lower) maxLen = len(max(exes, key=len)) cols = 5 @@ -542,6 +581,72 @@ def extractMdWadcoms(paths, attrs): subsequent_indent=subIndent)) print(reset) +def extractYmlHijack(paths, attrs): + """Extracts details of a specified executable with specified attributes from + the local copy of HijackLibs + """ + ymls = [] + for path in paths: + yml = (parseYaml(path)) + if yml is not None: + ymls.append(yml) + vendors = [x.lower() for x in attrs['vendors']] + matches = [] + for yml in ymls: + for data in yml: + if vendors: + if data['Vendor'].lower() not in vendors: + continue + for exe in data['VulnerableExecutables']: + if exe['Type'] in attrs['attacktypes']: + matches.append(data) + break + if matches: + indent = " " + for match in matches: + print("{0}{1}Author{2}: {3}\n".format(indent, bold, reset, + match['Author'])) + print("{0}{1}Created{2}: {3}\n".format(indent, bold, reset, + match['Created'])) + print("{0}{1}Vendor{2}: {3}\n".format(indent, bold, reset, + match['Vendor'])) + print("{0}{1}Expected Locations{2}:\n".format(indent, bold, reset)) + if "ExpectedLocations" in match.keys(): + for loc in match['ExpectedLocations']: + print("{0}{0}{1}{2}{3}\n".format(indent, dim, loc, reset)) + else: + print("{0}{0}None\n".format(indent)) + print("{0}{1}Vulnerable Executables{2}:\n".format(indent, bold, + reset)) + if "Vulnerable Executables" in match.keys(): + for exe in match['VulnerableExecutables']: + print("{0}{0}{1}{2}{3} ({4})\n".format(indent, dim, + exe['Path'], + reset, exe['Type'])) + else: + print("{0}{0}None\n".format(indent)) + print("{0}{1}Resources{2}:\n".format(indent, bold, reset)) + if "Resources" in match.keys(): + for res in match['Resources']: + print("{0}{0}{1}\n".format(indent, res)) + else: + print("{0}{0}None\n".format(indent)) + print("{0}{1}Acknowledgements{2}:\n".format(indent, bold, reset)) + if "Acknowledgements" in match.keys(): + for ack in match['Acknowledgements']: + if ack['Twitter']: + print("{0}{0}{1} ({2})\n".format(indent, ack['Name'], + ack['Twitter'])) + else: + print("{0}{0}{1}\n".format(indent, ack['Name'])) + else: + print("{0}{0}None\n".format(indent)) + + + else: + errorNoCatResults() + + def extract(args, paths, extractFunc): """Uses a specified extraction function to extract data on a specified executable with specified attributes from a specified repo @@ -567,18 +672,26 @@ def extract(args, paths, extractFunc): attrs['os'] = args.os.lower().split(",") except: attrs['os'] = [] + try: + attrs['vendors'] = args.vendors.lower().split(",") + except: + attrs['vendors'] = [] for attr in attrs: if "all" in attrs[attr]: - attrs[attr] = list(repos[args.repo][attr].values()) - attrs[attr].remove("all") + if attr != "vendors": + attrs[attr] = list(repos[args.repo][attr].values()) + attrs[attr].remove("all") + else: + attrs[attr] = [] else: - newVals = [] - for val in attrs[attr]: - try: - newVals.append(repos[args.repo][attr][val]) - except: - pass - attrs[attr] = newVals + if attr != "vendors": + newVals = [] + for val in attrs[attr]: + try: + newVals.append(repos[args.repo][attr][val]) + except: + pass + attrs[attr] = newVals extractFunc(paths, attrs) def errorExeNotFound(args): @@ -710,6 +823,34 @@ def wadcomsSearch(args): else: errorExeNotFound(args) +def hijackSearch(args): + """Searches local copy of HighjackLibs for a specified executable with + specified attributes + """ + repCheck(args.repo) + exe = args.executable.lower() + exeSplit = exe.split(".") + if len(exeSplit) > 1: + exe = ".".join(exeSplit[:-1]) + paths = [] + for folder in repos[args.repo]['exeDirs']: + folder = os.path.join(repos[args.repo]['dir'], folder) + for folder in glob(folder): + for file in os.listdir(folder): + path = os.path.join(folder, file) + if exe == "all": + paths.append(path) + elif file == "{0}{1}".format(exe, + repos[args.repo]['exeFileExt']): + paths.append(path) + if paths: + for path in paths: + print(green + bold + path.split("/")[-1].split(".")[0] + ".dll" + + reset + green + ":\n" + reset) + extract(args, [path], extractYmlHijack) + else: + errorExeNotFound(args) + def search(args): """Searches local copy of specified repo for a specified executable of a specified type in a specified category