Restructure repository: organize tools by purpose, create what search tool
- Move single-file tools to tools/ organized by category (security, forensics, data, etc.) - Move multi-file projects to projects/ (go-tools, puzzlebox, timesketch, rust-tools) - Move system scripts to scripts/ (proxy, display, setup, windows) - Organize config files in config/ (shell, visidata, applications) - Move experimental tools to archive/experimental - Create 'what' fuzzy search tool with progressive enhancement (ollama->fzf->grep) - Add initial metadata database for intelligent tool discovery - Preserve git history using 'git mv' commands
This commit is contained in:
113
tools/security/certwipe
Executable file
113
tools/security/certwipe
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
###################Wipe (optional)
|
||||
DEVICE=${1}
|
||||
wipedelay=20
|
||||
|
||||
# Required packages
|
||||
REQUIRED_PACKAGES=("hdparm" "dialog" "dc3dd" "util-linux")
|
||||
|
||||
# Check for missing packages
|
||||
check_missing_packages()
|
||||
{
|
||||
for package in "${REQUIRED_PACKAGES[@]}"; do
|
||||
if ! dpkg -s "${package}" >/dev/null 2>&1; then
|
||||
echo "Wipe script requires the following packages:"
|
||||
for p in "${REQUIRED_PACKAGES[@]}"; do
|
||||
echo " ${p}"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Get device from the user if not specified or invalid
|
||||
get_device()
|
||||
{
|
||||
if [ -z "$DEVICE" ] || [ ! -b "$DEVICE" ]; then
|
||||
# Create a list of available devices
|
||||
W=()
|
||||
while read -r line; do
|
||||
dev=$(echo $line | cut -f1 -d" ")
|
||||
rest=$(echo $line | cut -f2- -d" " | tr -s " ")
|
||||
W+=("/dev/${dev}" "${rest}")
|
||||
done < <(lsblk -l -oname,size,model,type | grep -e disk)
|
||||
|
||||
# Display device selection menu
|
||||
DEVICE=$(dialog --backtitle "CERTBw - SecureErase" --title "Available Devices" --menu "Which disk should be wiped?" 24 80 17 "${W[@]}" 3>&2 2>&1 1>&3)
|
||||
fi
|
||||
}
|
||||
|
||||
# cleanup function to unset the ATA Password if execution gets interrupted
|
||||
cleanup()
|
||||
{
|
||||
echo
|
||||
echo "==WIPE : Removing ATA password due to user interruption..."
|
||||
hdparm --user-master u --security-disable certbw "${DEVICE}"
|
||||
echo "==WIPE : ATA password removed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Display warning and countdown
|
||||
display_warning()
|
||||
{
|
||||
dialog --backtitle "CERTBw - SecureErase" --defaultno --cancel-label "Cancel" --colors --title "\Z1!WARNING!\Zn" --pause "\n\Z1The device ${DEVICE} will be completely erased!\Zn\n\nThe SecureErase process must not be interrupted, as this will lock the device, and it will need to be manually unlocked afterward.\n\n\nThe process will automatically continue after the countdown expires.\n\nTo cancel the DiskWipe, you can:\n \Z4Select \"Cancel\"\n Press \"ESC\"\n Press \"CTRL + C\"\n Turn off the computer\Zn" 24 80 ${wipedelay}
|
||||
if [ "$?" -gt 0 ]; then
|
||||
echo "==WIPE : Wipe was canceled by the user."
|
||||
sleep 1
|
||||
read -p "Press [ENTER] key for Shell..."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Securely erase the device
|
||||
secure_erase()
|
||||
{
|
||||
if hdparm -I "${DEVICE}" | grep supported | grep -q erase; then
|
||||
echo "==WIPE : Secure Erase is supported by ${DEVICE}"
|
||||
if ! (hdparm -I "${DEVICE}" | grep not | grep -q frozen); then
|
||||
echo "==WIPE : The device ${DEVICE} is frozen"
|
||||
echo "==WIPE : The notebook will now be put to sleep for 10 seconds."
|
||||
echo "==WIPE : Do not turn off the notebook."
|
||||
sleep 5
|
||||
rtcwake -s 10 -m mem
|
||||
echo "==WIPE : The notebook has woken up. Checking the status of ${DEVICE}."
|
||||
fi
|
||||
if hdparm -I "${DEVICE}" | grep not | grep -q frozen; then
|
||||
echo "==WIPE : The device ${DEVICE} is 'not frozen'"
|
||||
echo
|
||||
echo "==WIPE : A temporary ATA password (certbw) must be set for SecureErase."
|
||||
echo "==WIPE : If the SecureErase process is interrupted, the disk will be unusable until manually unlocked."
|
||||
echo "==WIPE : Do not turn off the notebook."
|
||||
sleep 5
|
||||
# Set a trap to catch SIGINT and call the cleanup function
|
||||
trap 'cleanup' SIGINT
|
||||
# Set ATA password
|
||||
hdparm --user-master u --security-set-pass certbw "${DEVICE}"
|
||||
# Issue Secure Erase command
|
||||
hdparm --user-master u --security-erase certbw "${DEVICE}"
|
||||
# Remove the trap after the Secure Erase is completed
|
||||
trap - SIGINT
|
||||
else
|
||||
# Normal wipe because unfreeze didn't work
|
||||
echo "==WIPE : The device could not be unfrozen."
|
||||
echo "==WIPE : The device ${DEVICE} will be overwritten."
|
||||
/usr/bin/dc3dd wipe="${DEVICE}"
|
||||
fi
|
||||
else
|
||||
# Normal wipe because Secure Erase is not supported
|
||||
echo "==WIPE : Secure Erase is NOT supported."
|
||||
echo "==WIPE : The device ${DEVICE} will be overwritten."
|
||||
/usr/bin/dc3dd wipe="${DEVICE}"
|
||||
fi
|
||||
}
|
||||
|
||||
check_missing_packages
|
||||
get_device
|
||||
if [ ! -b "${DEVICE}" ]; then
|
||||
echo "==WIPE : Kein gültiges BLOCK-Device ausgewählt."
|
||||
sleep 1
|
||||
read -p "Press [ENTER] key for Shell..."
|
||||
exit 1
|
||||
fi
|
||||
display_warning
|
||||
secure_erase
|
||||
5
tools/security/imphash.py
Executable file
5
tools/security/imphash.py
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
import pefile
|
||||
import sys
|
||||
pe=pefile.PE(sys.argv[1])
|
||||
print(pe.get_imphash())
|
||||
33
tools/security/scan_vt.py
Executable file
33
tools/security/scan_vt.py
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python3
|
||||
import requests
|
||||
import sys
|
||||
import hashlib
|
||||
from os.path import expanduser
|
||||
|
||||
|
||||
out_sep=';'
|
||||
|
||||
with open(expanduser('~/.virustotal_api_key')) as api_f:
|
||||
api_key=api_f.readline().strip()
|
||||
|
||||
with open(sys.argv[1],'rb') as f:
|
||||
hash=hashlib.md5(f.read())
|
||||
|
||||
params = {'apikey': api_key, 'resource': hash.hexdigest()}
|
||||
headers = {
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"User-Agent" : "gzip,python_requests,scan_vt.py"
|
||||
}
|
||||
|
||||
response = requests.get('https://www.virustotal.com/vtapi/v2/file/report', params=params, headers=headers)
|
||||
|
||||
try:
|
||||
json_response = response.json()
|
||||
except:
|
||||
print(response)
|
||||
exit(1)
|
||||
|
||||
if json_response["response_code"]:
|
||||
print("{}{}{}{}{}/{}{}{}".format(sys.argv[1],out_sep,hash.hexdigest(),out_sep,json_response["positives"],json_response["total"],out_sep,json_response["permalink"]))
|
||||
else:
|
||||
print("{}{}{}{}{}".format(sys.argv[1],out_sep,hash.hexdigest(),out_sep,out_sep))
|
||||
47
tools/security/scapy_arp.py
Normal file
47
tools/security/scapy_arp.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from scapy.all import srp, Ether, ARP
|
||||
from threading import Thread
|
||||
from ipaddress import IPv4Network
|
||||
from pprint import pprint
|
||||
from time import sleep, time
|
||||
|
||||
threads = []
|
||||
|
||||
clients = list()
|
||||
class Scanner(Thread):
|
||||
def __init__(self, ip):
|
||||
super().__init__()
|
||||
self.ip = ip
|
||||
|
||||
def run(self):
|
||||
# The below code from https://www.thepythoncode.com/article/building-network-scanner-using-scapy
|
||||
packet = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=self.ip)
|
||||
# this is a tuple, which index 0 is host that answers arp request.
|
||||
# while index 1 is unanswered when no host answers arp request.
|
||||
result = srp(packet, timeout=3, verbose=0)[0]
|
||||
# the result is a tuple with index 0 as sent, and 1 as received.
|
||||
for _, received in result:
|
||||
# psrc is the arp responder's ip address
|
||||
# hwsrc is the arp responder's mac address
|
||||
clients.append(
|
||||
{
|
||||
"ip": received.psrc,
|
||||
"mac": received.hwsrc
|
||||
}
|
||||
)
|
||||
# maintain consistency by forcing this method to sleep for 1 second
|
||||
# before beginning the next host.
|
||||
sleep(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start = time()
|
||||
for ip in IPv4Network('192.168.178.0/24').hosts():
|
||||
t = Scanner(str(ip))
|
||||
threads.append(t)
|
||||
t.start()
|
||||
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
pprint(clients)
|
||||
print(f"Executed in {time() - start} seconds.")
|
||||
30
tools/security/simple_portscan.py
Normal file
30
tools/security/simple_portscan.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import socket as sk
|
||||
import sys
|
||||
print(sys.argv)
|
||||
print(len(sys.argv))
|
||||
print("Host:" , sys.argv[1])
|
||||
default=(21,22,23,80,110,111,135,139,389,443,515,631,3306,3389)
|
||||
|
||||
def usage():
|
||||
print("Usage:",sys.argv[0],"<ip> ( [<start_port> - <end_port] | [<port>] ) ")
|
||||
|
||||
if (len(sys.argv)==5) and sys.argv[3]=='-':
|
||||
try:
|
||||
ports=range(int(sys.argv[2]),int(sys.argv[4]))
|
||||
except:
|
||||
usage()
|
||||
ports=default
|
||||
elif len(sys.argv)>2:
|
||||
ports=sys.arv[2:]
|
||||
else:
|
||||
ports=default
|
||||
|
||||
print("Ports:", ports)
|
||||
for port in ports:
|
||||
try:
|
||||
s=sk.socket(sk.AF_INET,sk.SOCK_STREAM)
|
||||
s.settimeout(1)
|
||||
s.connect((sys.argv[1],port))
|
||||
print('%d:OPEN' % port)
|
||||
s.close
|
||||
except: continue
|
||||
35
tools/security/smtpbanner.py
Normal file
35
tools/security/smtpbanner.py
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# banner.py
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import argparse
|
||||
|
||||
def grab(ip, port):
|
||||
"""Connects to the specified IP and port, retrieves data and returns the decoded response."""
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
|
||||
sock.settimeout(5) # Set a timeout of 5 seconds
|
||||
sock.connect((ip, port))
|
||||
ret = sock.recv(1024)
|
||||
return ret.strip().decode()
|
||||
except socket.error as e:
|
||||
return f"Connection error: {e}"
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Retrieve banner information from the specified IP and port.")
|
||||
parser.add_argument("ip", help="The target IP address")
|
||||
parser.add_argument("-p", "--port", type=int, default=25, help="The target port (default: 25)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
ip = args.ip
|
||||
port = args.port
|
||||
|
||||
print(grab(ip, port))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
26
tools/security/testpw.py
Executable file
26
tools/security/testpw.py
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import hashlib
|
||||
import requests
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: python testpw.py <password>")
|
||||
exit(1)
|
||||
|
||||
url="https://api.pwnedpasswords.com/range/"
|
||||
hash_object = hashlib.sha1(sys.argv[1].encode("UTF-8"))
|
||||
pw_hash=hash_object.hexdigest()
|
||||
first_part=pw_hash[:5]
|
||||
second_part=pw_hash[5:]
|
||||
print(pw_hash)
|
||||
furl="{}{}".format(url,first_part)
|
||||
print("Das gehashte Passwort lautet: {}".format(pw_hash))
|
||||
print("Es werden lediglich die ersten 5 Zeichen des Hashes übertragen ({})".format(first_part))
|
||||
print("Dies lässt keinerlei Rückschlusse auf da Passwort zu.")
|
||||
response=requests.get(furl)
|
||||
for line in response.text.splitlines():
|
||||
if second_part.lower() in line.lower():
|
||||
print("Passwort wurde {} mal im Datenbestand gefunden".format(line.split(":")[1]))
|
||||
exit(0)
|
||||
|
||||
print("Passwort wurde nicht im Datenbestand gefunden")
|
||||
41
tools/security/vt_download.py
Executable file
41
tools/security/vt_download.py
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import pprint
|
||||
import requests
|
||||
import os.path
|
||||
|
||||
|
||||
# os.path.exists(file_path)
|
||||
|
||||
|
||||
out_sep=';'
|
||||
|
||||
with open(os.path.expanduser('~/.virustotal_api_key')) as api_f:
|
||||
api_key=api_f.readline().strip()
|
||||
|
||||
|
||||
hash=sys.argv[1]
|
||||
url = 'https://www.virustotal.com/vtapi/v2/file/download'
|
||||
params = {'apikey': api_key, 'hash':hash }
|
||||
headers = {
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"User-Agent" : "gzip,python_requests,vt_pdns.py"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
response = requests.get(url, params=params, headers=headers)
|
||||
if response.ok:
|
||||
with open(hash, 'wb') as f:
|
||||
f.write(response.content)
|
||||
else:
|
||||
print("NOTFOUND:{}".format(hash))
|
||||
|
||||
|
||||
|
||||
except requests.exceptions.ProxyError as e:
|
||||
print("Proxy Error")
|
||||
print(e)
|
||||
exit(1)
|
||||
56
tools/security/vt_ip.py
Normal file
56
tools/security/vt_ip.py
Normal file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import pprint
|
||||
import requests
|
||||
import os.path
|
||||
|
||||
|
||||
# os.path.exists(file_path)
|
||||
|
||||
|
||||
out_sep=';'
|
||||
|
||||
with open(os.path.expanduser('~/.virustotal_api_key')) as api_f:
|
||||
api_key=api_f.readline().strip()
|
||||
|
||||
if os.path.exists(os.path.expanduser('~/.ipinfo_api_key')):
|
||||
with open(os.path.expanduser('~/.ipinfo_api_key')) as api_g:
|
||||
ipinfo_api_key=api_g.readline().strip()
|
||||
ipinfo_data=requests.get('http://ipinfo.io/{}'.format(sys.argv[1]), params={'token':ipinfo_api_key})
|
||||
print(ipinfo_data.json())
|
||||
|
||||
ip=sys.argv[1]
|
||||
# url='https://www.virustotal.com/vtapi/v2/ip/report'
|
||||
url = 'https://www.virustotal.com/vtapi/v2/ip-address/report'
|
||||
params = {'apikey': api_key, 'ip':ip }
|
||||
headers = {
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"User-Agent" : "gzip,python_requests,vt_pdns.py"
|
||||
}
|
||||
|
||||
|
||||
|
||||
try:
|
||||
response = requests.get(url, params=params, headers=headers)
|
||||
response_data = response.json()
|
||||
except requests.exceptions.ProxyError as e:
|
||||
print("Proxy Error")
|
||||
print(e)
|
||||
exit(1)
|
||||
|
||||
print("=== Short report for : {} ===".format(ip))
|
||||
print(response_data['verbose_msg'])
|
||||
if 'detected_urls' in response_data :
|
||||
print("{} detected URLs found".format(len(response_data['detected_urls'])))
|
||||
if 'detected_downloaded_samples' in response_data :
|
||||
print("{} detected Downloads found".format(len(response_data['detected_downloaded_samples'])))
|
||||
if 'resolutions' in response_data:
|
||||
print("== Resolutions ==")
|
||||
data=sorted(response_data['resolutions'], key=lambda i:i['last_resolved']) if len(response_data['resolutions'])>1 else response_data['resolutions']
|
||||
for r in data:
|
||||
print(" {} : {}".format(r["last_resolved"],r["hostname"]))
|
||||
|
||||
|
||||
for k in response.json():
|
||||
print("=== {} ===".format(k))
|
||||
print(response_data[k])
|
||||
102
tools/security/vt_pdns.py
Executable file
102
tools/security/vt_pdns.py
Executable file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import pprint
|
||||
import requests
|
||||
from os.path import expanduser
|
||||
|
||||
|
||||
out_sep=';'
|
||||
|
||||
with open(expanduser('~/.virustotal_api_key')) as api_f:
|
||||
api_key=api_f.readline().strip()
|
||||
|
||||
domain=sys.argv[1]
|
||||
url='https://www.virustotal.com/vtapi/v2/domain/report'
|
||||
params = {'apikey': api_key, 'domain':domain }
|
||||
headers = {
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"User-Agent" : "gzip,python_requests,vt_pdns.py"
|
||||
}
|
||||
|
||||
|
||||
cat_fields=["Alexa category",
|
||||
"categories",
|
||||
"BitDefender category",
|
||||
"TrendMicro category",
|
||||
"Forcepoint ThreatSeeker category"]
|
||||
#
|
||||
# "whois",
|
||||
# "WOT domain info",
|
||||
# "Webutation domain info",
|
||||
# "BitDefender domain info",
|
||||
# "Alexa domain info",
|
||||
# BitDefender category
|
||||
# WOT domain info
|
||||
# Webutation domain info
|
||||
# Alexa category
|
||||
# Opera domain info
|
||||
# TrendMicro category
|
||||
# categories
|
||||
# domain_siblings
|
||||
# BitDefender domain info
|
||||
# whois
|
||||
# Alexa domain info
|
||||
# Forcepoint ThreatSeeker category
|
||||
# Alexa rank
|
||||
#
|
||||
# detected_downloaded_samples
|
||||
# detected_urls
|
||||
#
|
||||
# detected_communicating_samples
|
||||
# detected_referrer_samples
|
||||
# undetected_downloaded_samples
|
||||
# undetected_referrer_samples
|
||||
# undetected_urls
|
||||
# undetected_communicating_samples
|
||||
# resolutions
|
||||
# response_code
|
||||
# verbose_msg
|
||||
# pcaps
|
||||
#
|
||||
try:
|
||||
response = requests.get(url, params=params, headers=headers)
|
||||
response_data = response.json()
|
||||
except requests.exceptions.ProxyError as e:
|
||||
print("Proxy Error")
|
||||
print(e)
|
||||
exit(1)
|
||||
|
||||
# resolutions=[r for r in response.json()['resolutions']]
|
||||
|
||||
|
||||
def get(key,dict):
|
||||
split_key=key.split(sep=" ")
|
||||
if len(split_key)>1:
|
||||
prefix="{}: ".format(split_key[0])
|
||||
else:
|
||||
prefix="VT: "
|
||||
if key in dict:
|
||||
print("{}{}".format(prefix,dict[key]))
|
||||
|
||||
# # detected_downloaded_samples=[d for d in response.json()['detected_downloaded_samples']]
|
||||
# # detected_url=[d for d in response.json()['detected_url']]
|
||||
|
||||
print("=== Short report for : {} ===".format(domain))
|
||||
print(response_data['verbose_msg'])
|
||||
if 'detected_urls' in response_data :
|
||||
print("{} detected URLs found".format(len(response_data['detected_urls'])))
|
||||
if 'detected_downloaded_samples' in response_data :
|
||||
print("{} detected Downloads found".format(len(response_data['detected_downloaded_samples'])))
|
||||
if any([True for x in cat_fields if x in response_data]):
|
||||
print("== Categories ==")
|
||||
for cat in cat_fields:
|
||||
get(cat,response_data)
|
||||
if 'resolutions' in response_data:
|
||||
print("== Resolutions ==")
|
||||
data=sorted(response_data['resolutions'], key=lambda i:i['last_resolved']) if len(response_data['resolutions'])>1 else response_data['resolutions']
|
||||
for r in data:
|
||||
print(" {} : {}".format(r["last_resolved"],r["ip_address"]))
|
||||
|
||||
# print('--------------------------infos')
|
||||
# for k in response.json():
|
||||
# print(k)
|
||||
Reference in New Issue
Block a user