├── NetworkMiner_logo_313x313.png ├── README.md ├── arkime_geoipupdater.sh ├── dga_example.py ├── distro_prep.sh ├── fix-network.sh ├── for572-aliases.sh ├── for572-evidence_load.sh ├── pcap_iterator.sh ├── uridecode.py └── uriencode.py /NetworkMiner_logo_313x313.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philhagen/for572-scripts/8c68f65f3dec98ecdff380229e905af17938f95e/NetworkMiner_logo_313x313.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # for572-scripts 2 | 3 | A completely unsupported set of scripts used in SANS FOR572, Advanced Network Forensics and Analysis 4 | 5 | Note to any past/current/future FOR572 students who see this repository: These scripts are already incorporated into your SIFT Workstation VM. They should not be run manually or outside the class workbook or other guidance. I only have them in GitHub for convenience and ease-of-updates! :) 6 | -------------------------------------------------------------------------------- /arkime_geoipupdater.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script is used to perform an in-place update of the geoipupdate utility. 4 | # The new version is needed for new-format hashed API keys 5 | 6 | # perform version check and quit if not the specific old version 7 | 8 | if [ $(rpm -q geoipupdate --queryformat %{VERSION}) != "2.5.0" ]; then 9 | # already updated - exit cleanly 10 | exit 11 | fi 12 | 13 | if [[ $EUID -ne 0 ]]; then 14 | echo "This script must be run as root. Exiting." 15 | exit 1 16 | fi 17 | 18 | yum -q -y install https://github.com/maxmind/geoipupdate/releases/download/v4.10.0/geoipupdate_4.10.0_linux_386.rpm > /dev/null 19 | 20 | rm -f /etc/GeoIP.conf 21 | 22 | if [ -f /etc/GeoIP.conf.rpmsave ]; then 23 | mv /etc/GeoIP.conf.rpmsave /etc/GeoIP.conf.old_version 24 | echo "Your exisitng GeoIP update configuration has been renamed" 25 | echo " \"/etc/GeoIP.conf.old_version\". It will no longer work and you must" 26 | echo " generate a NEW version of a GeoIP key, then run" 27 | echo " \"sudo geoip_bootstrap.sh\" again, supplying the new key." 28 | fi 29 | 30 | curl -s -L -o /etc/GeoIP.conf.dist https://for572.com/arkime-geoip-default 31 | -------------------------------------------------------------------------------- /dga_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import fileinput 4 | 5 | def generate_domain(year, month, day): 6 | """Generates a domain by the current date""" 7 | domain = "" 8 | for i in range(16): 9 | year = ((year ^ 8 * year) >> 11) ^ ((year & 0xFFFFFFF0) << 17) 10 | month = ((month ^ 4 * month) >> 25) ^ 16 * (month & 0xFFFFFFF8) 11 | day = ((day ^ (day << 13)) >> 19) ^ ((day & 0xFFFFFFFE) << 12) 12 | domain += chr(((year ^ month ^ day) % 25) + 97) 13 | return domain 14 | 15 | for line in fileinput.input(): 16 | (y, m, d) = line.split('-') 17 | print(generate_domain(int(y), int(m), int(d))) 18 | -------------------------------------------------------------------------------- /distro_prep.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DISKSHRINK=1 4 | CASERELOAD=1 5 | 6 | labs='demo-01 lab-1.2 lab-2.1 lab-2.2 lab-3.2 lab-3.3 lab-4.1 lab-4.2 lab-5.1 lab-5.2 lab-5.3' 7 | placeholder_labs='capstone lab-1.1 lab-2.3 lab-3.1 lab-4.3' 8 | 9 | # parse any command line arguments 10 | if [ $# -gt 0 ]; then 11 | while true; do 12 | if [ "$1" ]; then 13 | if [ "$1" == '-nodisk' ]; then 14 | DISKSHRINK=0 15 | elif [ "$1" == '-nocases' ]; then 16 | CASERELOAD=0 17 | fi 18 | shift 19 | else 20 | break 21 | fi 22 | done 23 | fi 24 | 25 | if [ ! -z $SSH_CONN ]; then 26 | echo "ERROR! This script must be run locally, not via ssh." 27 | echo "quitting." 28 | exit 2 29 | fi 30 | 31 | if [ ! $UID == 0 ]; then 32 | echo "ERROR! This script must be run as root." 33 | echo "quitting." 34 | exit 2 35 | fi 36 | 37 | echo "looking for specific pre-distribution notes/instructions" 38 | if [ -s ~/distro_prep.txt ]; then 39 | echo "~/distro_prep.txt still contains instructions - Exiting." 40 | echo 41 | cat ~/distro_prep.txt 42 | exit 2 43 | fi 44 | echo 45 | 46 | echo "Please confirm the ~sansforensics/.ssh/* files are correct and free of detritus." 47 | echo "Press return if you've completed this." 48 | read 49 | echo 50 | 51 | if [ $CASERELOAD -eq 1 ]; then 52 | if [ ! -d /mnt/hgfs/sample_pcaps/ -o ! -d /mnt/hgfs/lab_data/ ]; then 53 | echo "ERROR: Required source directories in /mnt/hgfs/ are not availalble - exiting." 54 | exit 2 55 | fi 56 | fi 57 | 58 | echo "updating for572-scripts git clone" 59 | cd /usr/local/for572/src/for572-scripts 60 | su - sansforensics -c "git pull" 61 | 62 | echo "updating for572 workbook" 63 | su - sansforensics -c "bash /var/www/html/workbook/resources/workbook-update.sh" 64 | 65 | echo "clearing sansforensics and root users' preference files" 66 | sudo -u sansforensics bleachbit -c firefox.* chromium.* bash.history gnome.* system.cache system.recent_documents system.trash 67 | bleachbit -c apt.* bash.history system.rotated_logs 68 | rm -rf ~sansforensics/Downloads/* 69 | rm -rf ~sansforensics/.mono/ 70 | rm -f ~sansforensics/.mysql_history 71 | rm -f ~sansforensics/.scapy_history 72 | rm -f ~sansforensics/.lesshst 73 | rm -f ~sansforensics/.viminfo 74 | rm -f ~sansforensics/.wget-hsts 75 | rm -rf ~sansforensics/.local/share/Trash/* 76 | rm -rf ~sansforensics/.local/share/ijq/ 77 | rm -rf /cases/.Trash* 78 | rm -f ~root/.mysql_history 79 | rm -f ~root/.scapy_history 80 | rm -f ~root/.lesshst 81 | rm -f ~root/.viminfo 82 | rm -rf ~root/.cache/ 83 | rm -f ~root/.wget-hsts 84 | rm -rf /usr/local/for572/NetworkMiner_*/AssembledFiles/* 85 | rm -f /etc/GeoIP.conf 86 | rm -f /var/spool/mail/* 87 | mkdir -m 1777 /usr/local/for572/NetworkMiner/AssembledFiles/cache/ 88 | 89 | echo "resetting Wireshark profiles" 90 | #for ws_profile in no_desegment_tcp; do 91 | # rm -rf ~sansforensics/.config/wireshark/profiles/${ws_profile} 92 | # cp -a ~sansforensics/.config/wireshark/profiles/${ws_profile}.DIST ~sansforensics/.config/wireshark/profiles/${ws_profile} 93 | #done 94 | for rmfile in rsa_keys recent recent_common preferences enabled_protos maxmind_db_paths ssl_keys; do 95 | rm -f ~sansforensics/.config/wireshark/${rmfile} 96 | if [ -f ~sansforensics/.config/wireshark/${rmfile}.DIST ]; then 97 | cp -a ~sansforensics/.config/wireshark/${rmfile}.DIST ~sansforensics/.config/wireshark/${rmfile} 98 | fi 99 | done 100 | 101 | echo "Resetting GeoIP data" 102 | for GEOIPDB in ASN City Country; do 103 | rm -f /usr/local/for572/share/GeoIP/GeoLite2-${GEOIPDB}.mmdb 104 | curl -s -L -o /usr/local/for572/share/GeoIP/GeoLite2-${GEOIPDB}.mmdb https://lewestech.com/dist/GeoLite2-${GEOIPDB}.mmdb 105 | chmod 644 /usr/local/for572/share/GeoIP/GeoLite2-${GEOIPDB}.mmdb 106 | done 107 | rm -f /etc/cron.d/geoipupdate 108 | 109 | /sbin/ifconfig ens33 down 110 | 111 | if [ $CASERELOAD -eq 1 ]; then 112 | echo "ensure /cases/for572/ only contains what is required from original evidence files" 113 | echo "will do this automatically, but need to ensure source data is available at /mnt/hgfs/lab_data/ before proceeding" 114 | read 115 | rm -rf /cases/for572/* 116 | 117 | mkdir /cases/for572/sample_pcaps/ 118 | cd /cases/for572/sample_pcaps/ 119 | cp -a /mnt/hgfs/sample_pcaps/* ./ 120 | 121 | for lab in $labs; do 122 | cd /cases/for572/ 123 | mkdir $lab 124 | cd /cases/for572/$lab/ 125 | unzip /mnt/hgfs/lab_data/${lab}_source_evidence.zip 126 | done 127 | 128 | for placeholder in $placeholder_labs; do 129 | cd /cases/for572/ 130 | mkdir $placeholder 131 | cd /cases/for572/$placeholder/ 132 | cp -a /mnt/hgfs/lab_data/placeholders/${placeholder}_readme.txt ./ 133 | done 134 | 135 | cd /cases/for572/ 136 | chown -R sansforensics:sansforensics /cases/for572/* 137 | fi 138 | 139 | echo "clearing logs" 140 | service rsyslog stop 141 | find /var/log -type f -exec rm -f {} \; 142 | 143 | echo "ACTION REQUIRED!" 144 | echo "remove any shared folders, touch up/re-version VM metadata/info, etc" 145 | if df 2> /dev/null | grep -q hgfs; then 146 | echo "- YOU CURRENTLY HAVE SHARED FOLDERS ACTIVE!!!" 147 | fi 148 | read 149 | 150 | if [ $DISKSHRINK -eq 1 ]; then 151 | echo "ACTION REQUIRED!" 152 | echo "remove any snapshots that already exist and press Return" 153 | read 154 | 155 | echo "zeroize swap:" 156 | for swappart in $( swapon --show --noheadings | awk '{print $1}' ); do 157 | swapuuid=$( swaplabel ${swappart} | awk '{print $2}' ) 158 | echo "- zeroize $swappart (swap)" 159 | swapoff -U ${swapuuid} 160 | shred -n 0 -z -v ${swappart} 161 | mkswap ${swappart} -U ${swapuuid} 162 | done 163 | 164 | echo "zeroize disks:" 165 | for diskpart in $( mount | grep -e "xfs\|ext[234]" | awk '{print $3}' | grep -v ^\/var\/lib\/docker\/aufs$ ); do 166 | echo "- zeroize ${diskpart}" 167 | dd if=/dev/zero of=${diskpart}/ddfile 168 | rm -f ${diskpart}/ddfile 169 | done 170 | 171 | echo "shrink all drives:" 172 | for shrinkpart in $( vmware-toolbox-cmd disk list ); do 173 | vmware-toolbox-cmd disk shrink ${shrinkpart} 174 | done 175 | fi 176 | -------------------------------------------------------------------------------- /fix-network.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo systemctl restart NetworkManager 3 | -------------------------------------------------------------------------------- /for572-aliases.sh: -------------------------------------------------------------------------------- 1 | alias NetworkMiner="mono /usr/local/for572/NetworkMiner/NetworkMiner.exe" 2 | alias squidtime="awk '{\$1=strftime(\"%F %T\", \$1, 1); print \$0}'" 3 | alias workbook-update="/bin/bash /var/www/html/workbook/resources/workbook-update.sh" 4 | alias wsreset="cp -a enabled_protos.DIST enabled_protos ; cp -a maxmind_db_paths.DIST maxmind_db_paths ; cp -a preferences.DIST preferences ; cp -a recent.DIST recent ; cp -a recent_common.DIST recent_common" 5 | -------------------------------------------------------------------------------- /for572-evidence_load.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DEMO_LIST="01" 4 | LAB_LIST="1.1 1.2 2.1 2.2 2.3 3.1 3.2 3.3 4.1 4.2 4.3 5.1 5.2 5.3" 5 | for i in $DEMO_LIST; do 6 | echo "Creating working directory for Demo ${i}" 7 | mkdir /cases/for572/demo-${i} 8 | if [ -f /mnt/hgfs/lab_data/Demo-${i}_source_evidence.zip ]; then 9 | echo " - Extracting source evidence for Demo ${i}" 10 | unzip -q -d /cases/for572/demo-${i} /mnt/hgfs/lab_data/Demo-${i}_source_evidence.zip 11 | fi 12 | echo 13 | done 14 | 15 | for i in $LAB_LIST; do 16 | echo "Creating working directory for Lab ${i}" 17 | mkdir /cases/for572/lab-${i} 18 | if [ -f /mnt/hgfs/lab_data/lab-${i}_source_evidence.zip ]; then 19 | echo " - Extracting source evidence for Lab ${i}" 20 | unzip -q -d /cases/for572/lab-${i} /mnt/hgfs/lab_data/lab-${i}_source_evidence.zip 21 | fi 22 | echo 23 | done 24 | -------------------------------------------------------------------------------- /pcap_iterator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # (C)2025 Lewes Technology Consulting, LLC 3 | 4 | # This script traverses a directory tree full of pcap files and runs a series 5 | # of commands against each pcap file. 6 | # As distributed, it's designed to handle the capstone data in FOR572, but you 7 | # can adjust it as needed for other situations. 8 | 9 | # Set these two variables as needed. Be mindful of the space available in 10 | # $DEST_DIR_ROOT, as the commands below may require a LOT of disk space. 11 | SOURCE_PCAPS="/path/to/source/pcaps/" 12 | DEST_DIR_ROOT="/cases/for572/capstone/" 13 | 14 | # Expand and normalize the two paths defined above. Do not modify the following 15 | # two lines 16 | SOURCE_PCAPS=$( eval echo ${SOURCE_PCAPS} ) 17 | DEST_DIR_ROOT=$( eval echo ${DEST_DIR_ROOT} ) 18 | # End expand/normalize handling 19 | 20 | if [ $UID == 0 ]; then 21 | echo "WARNING! You're running this script as root (directly or with sudo)." 22 | echo " This may not be intended - since most evidence access should be done" 23 | echo " with user-level permissions." 24 | echo " Press Ctrl-C to terminate if you don't really NEED to run this as root" 25 | echo " or press Return to continue if you truly know what you're doing." 26 | echo 27 | echo " Hint: For all uses in FOR572 courseware, you DO NOT need to run this as root!" 28 | read 29 | fi 30 | 31 | # Uncomment one or more of the annotated sections below, then run the script 32 | for src_file in $( find -L ${SOURCE_PCAPS} -type f ); do 33 | echo "- processing ${src_file}" 34 | 35 | directory=$( dirname ${src_file#${SOURCE_PCAPS}} ) 36 | filename=$( basename $src_file ) 37 | if [ ! -d ${DEST_DIR_ROOT}/${directory} ]; then 38 | mkdir -p ${DEST_DIR_ROOT}/${directory} 2> /dev/null 39 | if [ ! -d ${DEST_DIR_ROOT}/${directory} ]; then 40 | echo "ERROR: Could not create destination subdirectory ${DEST_DIR_ROOT}/${directory}." 41 | echo "Exiting." 42 | exit 2 43 | fi 44 | elif [ ! -w ${DEST_DIR_ROOT}/${directory} ]; then 45 | echo "ERROR: Destination subdirectory ${DEST_DIR_ROOT}/${directory} exists but is not writable." 46 | echo "Exiting." 47 | exit 2 48 | fi 49 | 50 | ###### TCPDUMP ###### 51 | # Uncomment the following four commands. 52 | # Change the following two variable assignments to reflect the pcap 53 | # reduction you require 54 | # $TRAFFIC_TYPE is a cosmetic label that will be prepended to the output 55 | # filenames 56 | # $BPF is the filter to apply. Be careful, as this could result in a LOT 57 | # of space. 58 | # After running this sequence, you will likely want to use mergecap or 59 | # something similar to unify the resulting files. 60 | #TRAFFIC_TYPE=NFURY_MYSQL 61 | #BPF='host 172.16.7.15 and tcp and port 3306' 62 | #mkdir -p ${DEST_DIR_ROOT}/$directory/tcpdump_reduced 63 | #tcpdump -n -s 0 -r ${src_file} -w ${DEST_DIR_ROOT}/${directory}/tcpdump_reduced/${TRAFFIC_TYPE}_${filename} ${BPF} 64 | 65 | ###### TRIMPCAP ###### 66 | # Uncomment the following two commands. 67 | # $TRIM_LENGTH is an integer for the maximum number of bytes per flow that will be retained 68 | # WARNING WARNING WARNING: The trimpcap.py command OVERWRITES the source file so be sure you don't need the original data 69 | # THERE IS NO UNDO BUTTON HERE!!!!! 70 | #$TRIM_LENGTH=30280 71 | #trimpcap.py $TRIM_LENGTH ${src_file} 72 | 73 | ###### ZEEK ###### 74 | # Uncomment the following two commands to create an output directory for 75 | # each input pcap file, as required for Zeek processing 76 | #mkdir -p ${DEST_DIR_ROOT}/${directory}/zeek_output/${filename} 77 | #cd ${DEST_DIR_ROOT}/${directory}/zeek_output/${filename} 78 | 79 | # Uncomment this command to process with Zeek, using the for572 policy 80 | #zeek for572 -D -r ${src_file} 2> /dev/null 81 | 82 | # Uncomment this command to process with Zeek, using the for572-allfiles 83 | # policy 84 | # This will take a LONG time and require a LOT of disk space! You probably 85 | # DO NOT want to do this to ALL the capstone pcaps!! 86 | #zeek for572-allfiles -D -r ${src_file} 2> /dev/null 87 | 88 | # compress the log files just created before moving on 89 | #gzip -f *.log 90 | 91 | ###### PASSIVEDNS ###### 92 | # Uncomment this one command to process with passivedns 93 | # This is a pretty manageable process 94 | #passivedns -r ${src_file} -l ${DEST_DIR_ROOT}/${directory}/passivedns.txt -L ${DEST_DIR_ROOT}/${directory}/passivedns_nxdomain.txt 95 | 96 | ###### NFCAPD ###### 97 | # Uncomment these two commands to process with nfpcapd 98 | # This is not needed for the FOR572 capstone, as you’ve been provided with 99 | # NetFlow that covers well beyond the pcap data, but the command is here 100 | # for your reference and future use as needed 101 | #mkdir -p ${DEST_DIR_ROOT}/${directory}/netflow/${filename} 102 | #nfpcapd -r ${src_file} -S 1 -z -l ${DEST_DIR_ROOT}/${directory}/netflow/${filename} 103 | 104 | done 105 | -------------------------------------------------------------------------------- /uridecode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import urllib.parse 3 | import sys 4 | 5 | for line in sys.stdin: 6 | sys.stdout.write(urllib.parse.unquote(line)) 7 | -------------------------------------------------------------------------------- /uriencode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import urllib.parse 3 | import sys 4 | 5 | for line in sys.stdin: 6 | sys.stdout.write(urllib.parse.quote(line)) 7 | --------------------------------------------------------------------------------