#!/bin/bash # # Copyright Emeric Nasi # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=- # swap_digger is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # swap_digger is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Thylacine If not, see . # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=- # # http://blog.sevagas.com # https://github.com/sevagas/swap_digger declare -r working_path="/tmp/swap_dig" declare -r swap_dump_path="${working_path}/swap_dump.txt" declare -r swap_wordlist_path="${working_path}/swap_wordlist.txt" declare -r keepass_wordlist_path="${working_path}/keepass_wordlist.txt" declare -a passwordList=() declare -a guessedPasswordList=() declare -a emailList=() LOG_FILE="" TARGET_ROOT_DIR="/" # Output functions out () { echo "$1" [ $LOG ] && { echo "$1" >> "$LOG_FILE"; } } note () { echo -e "\033[40m\033[01;36m Note:\033[0m $1" [ $LOG ] && { echo "Note: $1" >> "$LOG_FILE"; } } warning () { echo -e "\033[40m\033[01;33m Warning:\033[0m $1" >&2 [ $LOG ] && { echo "Warning: $1" >> "$LOG_FILE"; } } error () { echo -e "\033[40m\033[1;31m [!] Error: $1\033[0m " >&2 [ $LOG ] && { echo " [!] Error: $1" >> "$LOG_FILE"; } } blue () { echo -e "\033[40m\033[01;36m $1 \033[0m" [ $LOG ] && { echo " $1 " >> "$LOG_FILE"; } } # usage : ask "QUESTION" # NOTE : Ask for confirmations (y/Y -> return 0, else 1) ask () { echo -n " $@" '[y/n] ' [ $LOG ] && { echo -n " $@" '[y/n] ' >> "$LOG_FILE"; } local ans read ans case "$ans" in y*|Y*) return 0 ;; *) return 1 ;; esac } function init () { #User must be root if [ `/usr/bin/id -u` -ne 0 ] then echo -e "\033[40m\033[1;31m [!] Sorry, this script needs root access -> abort! $1\033[0m " >&2 exit 1 fi # Create test folder mkdir -p "$working_path" # Next 3 lines are for security chown root:root "$working_path" chmod 700 "$working_path" cd "$working_path" || { echo -e "\033[40m\033[1;31m [!] Init error -> abort! $1\033[0m " >&2; exit 1; } [ $LOG ] && { now=`date +%Y-%m-%d.%H:%M:%S` LOG_FILE="$working_path/output_${now}.log" } out blue "- SWAP Digger -" [ $LOG ] && note "Logging all outputs in $LOG_FILE" out # Check param values [ $SWAP_PATH ] && ! [ -e "$SWAP_PATH" ] && { error "Invalid path for swap file!"; exit 1; } ! [ -d "$TARGET_ROOT_DIR" ] && { error "Invalid path for root directory!"; exit 1; } # Check, that an action was specified (search, passwd retrieval or application data mining) [ -z $SWAP_SEARCH ] && [ -z $PASSWD ] && [ -z $APPLICATION_DATA ] && { error "Specify one or more options such as:" echo -e " -S search for swap devices!" echo -e " -a mine for application data " echo -e " -p mine for system passwds " >&2 echo -e " -h view all options " >&2 exit 1 } } function end () { out blue "SWAP Digger end, byebye! " out cd - [ $CLEAN ] && rm "$working_path" -rf exit 0 } function dig_unix_passwd () { # Looking for linux account passwords (ubuntu)wc -l out out blue " ==== Linux system accounts ===" out [ $VERBOSE ] && out " [+] Using shadow file: ${TARGET_ROOT_DIR}etc/shadow..." [ -f "${TARGET_ROOT_DIR}etc/shadow" ] || { error "${TARGET_ROOT_DIR}etc/shadow: No such file."; return 1; } out " [+] Digging linux accounts credentials... (pattern attack)" SHADOWHASHES="$(cut -d':' -f 2 ${TARGET_ROOT_DIR}etc/shadow | grep -E '^\$.\$')" while read -r thishash; do USER="$(grep "${thishash}" ${TARGET_ROOT_DIR}etc/shadow | cut -d':' -f 1)" [ $VERBOSE ] && out " [-] Digging for hash: $thishash ($USER) ..." DUMP=`grep -C50 -E "$thishash" "$swap_dump_path";grep -C30 "_pammodutil_getpwnam" "$swap_dump_path";grep -A1 "^sudo " "$swap_dump_path";grep -C5 "gdm-password" "$swap_dump_path"` CTYPE="$(echo "$thishash" | cut -c-3)" SHADOWSALT="$(echo "$thishash" | cut -d'$' -f 3)" while read -r line; do #Escape quotes, backslashes, single quotes to pass into crypt SAFE=$(echo "$line" | sed 's/\\/\\\\/g; s/\"/\\"/g; s/'"'"'/\\'"'"'/g;') CRYPT="\"$SAFE\", \"$CTYPE$SHADOWSALT\"" if [[ $(python3 -c "import crypt; print(crypt.crypt($CRYPT))") == "$thishash" ]]; then #Find which user's password it is (useful if used more than once!) out " -> $USER:$line" passwordList=("${passwordList[@]}" "$line") break fi done <<< "$DUMP" done <<< "$SHADOWHASHES" nbHashes="$(cut -d':' -f 2 ${TARGET_ROOT_DIR}etc/shadow | grep -c -E '^\$.\$')" if [ ${#passwordList[@]} -lt $nbHashes ] && ask "Passwords not found. Attempt dictionary based attack? (Can last from 5 minutes to several hours depending on swap usage)" then out out " [+] Digging linux accounts credentials method 2 ... (dictionary attack)" out " [-] Generating wordlist file..." strings --bytes=8 "$swap_dump_path" | sort | uniq -d | sed '/^.\{20\}./d' > "$swap_wordlist_path" # For performance we have to assume password is present more than once and if between 8 and 20 char out " [-] Digging passwords in wordlist... (This may take 5min to few hours!)" SHADOWHASHES="$(cut -d':' -f 2 ${TARGET_ROOT_DIR}etc/shadow | grep -E '^\$.\$')" while read -r thishash; do [ $VERBOSE ] && out " [-] Digging for hash: $thishash ..." DUMP=`cat $swap_wordlist_path` CTYPE="$(echo "$thishash" | cut -c-3)" SHADOWSALT="$(echo "$thishash" | cut -d'$' -f 3)" while read -r line; do #Escape quotes, backslashes, single quotes to pass into crypt SAFE=$(echo "$line" | sed 's/\\/\\\\/g; s/\"/\\"/g; s/'"'"'/\\'"'"'/g;') CRYPT="\"$SAFE\", \"$CTYPE$SHADOWSALT\"" if [[ $(python3 -c "import crypt; print(crypt.crypt($CRYPT))") == "$thishash" ]]; then #Find which user's password it is (useful if used more than once!) USER="$(grep "${thishash}" ${TARGET_ROOT_DIR}etc/shadow | cut -d':' -f 1)" out " -> $USER:$line" passwordList=("${passwordList[@]}" "$line") break fi done <<< "$DUMP" done <<< "$SHADOWHASHES" fi nbHashes="$(cut -d':' -f 2 ${TARGET_ROOT_DIR}etc/shadow | grep -c -E '^\$.\$')" if [ ${#passwordList[@]} -lt $nbHashes ] then out if john 2> /dev/null | grep -q cracker && ask "Passwords not found. John was detected on the system, attempt to crack ${TARGET_ROOT_DIR}etc/shadow based on dumped swap wordlist?" then out out " [+] Digging linux accounts credentials method 3... (John attack)" out " [+] Cracking linux account passwords using John." out " [-] Generating wordlist file..." #uniq "$swap_dump_path" | sed '/^.\{40\}./d' > "$swap_wordlist_path" # account password are generally less then 40 char sort "$swap_dump_path" | uniq -d | sed '/^.\{40\}./d' > "$swap_wordlist_path" # You can use this line to go faster, account password are generally present more than once and less then 40 char out " [-] Cracking ${TARGET_ROOT_DIR}etc/shadow using wordlist... (This may take some time)" if john "${TARGET_ROOT_DIR}etc/shadow" -wordlist:"$swap_wordlist_path" then OLDIFS=$IFS; IFS=$'\n'; for creds in `john --show ${TARGET_ROOT_DIR}etc/shadow` do out " -> $creds" password=`echo $creds | cut -d ":" -f 2` passwordList=("${passwordList[@]}" "$password") # Add found password to list done IFS=$OLDIFS if ask "Do you wan to delete john pot?" then out " [-] clean John pot..." rm /root/.john/john.pot # use this to clear john db that now contains the clear text unix passwd fi fi fi fi } function dig_web_info () { # Looking for web passwords out out blue " ==== Web entered passwords and emails ===" out out " [+] Looking for web passwords method 1 (password in GET/POST)..." OLDIFS=$IFS; IFS=$'\n'; for entry in `grep "&password=" "$swap_dump_path"` do out " -> $entry" password=`echo "$entry" | grep -o 'password=[^&]\+' | cut -f 2 -d '='` passwdSize=`echo $password | wc -c` if [[ $passwdSize -gt 6 ]] then passwordList=("${passwordList[@]}" "$password") # Add found password to list fi done for entry in `grep "&pwd=" "$swap_dump_path"` do out " -> $entry" password=`echo "$entry" | grep -o 'pwd=[^&]\+' | cut -f 2 -d '='` passwdSize=`echo $password | wc -c` if [[ $passwdSize -gt 6 ]] then passwordList=("${passwordList[@]}" "$password") # Add found password to list fi done IFS=$OLDIFS out out " [+] Looking for web passwords method 2 (JSON) ..." OLDIFS=$IFS; IFS=$'\n'; for entry in `grep "password\",\"value\":\"" "$swap_dump_path"` do out " -> $entry" password=`echo "$entry" | grep -o 'password\",\"value\":\"[^\"]\+' | cut -f 5 -d '"' ` passwdSize=`echo $password | wc -c` if [[ $passwdSize -gt 6 ]] then passwordList=("${passwordList[@]}" "$password") # Add found password to list fi done IFS=$OLDIFS out out " [+] Looking for web passwords method 3 (HTTP Basic Authentication) ..." OLDIFS=$IFS; IFS=$'\n'; for entry in `grep -E '^Authorization: Basic.+=$' "$swap_dump_path" | cut -d' ' -f 3` do CREDS="$(echo "$entry" | base64 -d)" if [[ "$CREDS" ]]; then out " -> $CREDS" password=`echo "$CREDS" | cut -f 2 -d ":"` passwordList=("${passwordList[@]}" "$password") # Add found password to list fi done IFS=$OLDIFS # Looking for web entered email address out out " [+] Looking for web entered emails..." OLDIFS=$IFS; IFS=$'\n'; for entry in `grep -i 'email=' "$swap_dump_path" | grep @ | uniq` do email=`echo "$entry" | grep -o 'email=[^& ]\+' | cut -f 2 -d '='` emailList=("${emailList[@]}" "$email") # Add found email to list done IFS=$OLDIFS # Remove duplicates OLDIFS="$IFS" IFS=$'\n' emailList=(`for email in "${emailList[@]}"; do echo "$email" ; done | sort -du`) IFS="$OLDIFS" OLDIFS=$IFS; IFS=$'\n'; for email in ${emailList[*]} do out " -> $email" done IFS=$OLDIFS } function dig_xml() { out out blue " ==== XML data ===" out out " [+] Looking for xml passwords ..." OLDIFS=$IFS; IFS=$'\n'; for entry in `grep -o -E ".+" "$swap_dump_path"` do around=`grep -C1 "$entry" "$swap_dump_path"` out " -> $around" password=`echo "$entry" | cut -f 2 -d '>' | cut -f 1 -d '<'` passwdSize=`echo $password | wc -c` if [[ $passwdSize -gt 3 ]] then passwordList=("${passwordList[@]}" "$password") # Add found password to list fi done IFS=$OLDIFS } function dig_wifi_info () { # Looking for wifi credentials out out blue " ==== WiFi ===" out out " [+] Looking for wifi access points..." wifiNetworks=`grep -C 10 "Auto " "$swap_dump_path" | grep -C 10 wireless | grep "Auto " | grep -v "NetworkManager" | cut -d " " -f 2,3,4 | sort | uniq` out " [-] Potential wifi network list this computer accessed to:" OLDIFS=$IFS; IFS=$'\n'; for accesspoint in $wifiNetworks do out "$accesspoint" done IFS=$OLDIFS out out " [+] Looking for potential Wifi passwords...." wifiPasswords1=`grep -C 10 "Auto " "$swap_dump_path" | grep -A2 wpa-psk | egrep -v "wpa|addresses|NetworkManager|Auto|wireless|--|NMSetting" | sort | uniq` out " [-] Potential wifi password list (use them to crack above networks)" OLDIFS=$IFS; IFS=$'\n'; for password in $wifiPasswords1 do out "$password" done IFS=$OLDIFS out out " [+] Looking for potential Wifi passwords method 2...." wifiPasswords2=`grep -o 'psk=.\+' "$swap_dump_path" | cut -f 2 -d '=' | sort | uniq` out " [-] Potential wifi password list (use them to crack above networks)" OLDIFS=$IFS; IFS=$'\n'; for password in $wifiPasswords2 do out "$password" done IFS=$OLDIFS } function dig_keepass () { # Looking for keepass if grep -C 8 "\.kdb" "$swap_dump_path" | grep -q KeePass then out out blue " ==== KeePass ===" out out " [+] Keepass detected!" out " [-] Looking for KeePass DB name..." keepassDb=`grep -m1 ".*/.*\.kdb.$" "$swap_dump_path" ` if [ -n "$keepassDb" ] then out " -> Found at: $keepassDb" #out " [-] Generate wordlist file..." #strings --bytes=8 "$swap_dump_path" | uniq | sed '/^.\{40\}./d' > "$keepass_wordlist_path" # We suppose no one use < 8char password if they know about keepass fi fi } function stringContain() { [ -z "${2##*$1*}" ]; } function dig_history () { out out blue " ==== Mining most accessed resources ===" out out " [+] TOP 30 HTTP/HTTPS URLs (domains only)" OLDIFS=$IFS; IFS=$'\n'; for entry in `egrep -o 'https?://[-A-Za-z0-9\+&@#%?=~_|!:,.;]+' "$swap_dump_path" | sort | uniq -cd | sort -k1,1nr | head -n 30` do out " -> $entry" done IFS=$OLDIFS out out out " [+] TOP 30 FTP URLs" OLDIFS=$IFS; IFS=$'\n'; for entry in `egrep -o 'ftp://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]' "$swap_dump_path" | sort | uniq -c | sort -k1,1nr | head -n 30` do out " -> $entry" done IFS=$OLDIFS out out out " [+] TOP 30 .onion urls" OLDIFS=$IFS; IFS=$'\n'; for entry in `egrep -o 'https?://[-A-Za-z0-9\+&@#%?=~_|!:,.;]*\.onion/*[-A-Za-z0-9\+&@#/%=~_|]*' "$swap_dump_path" | sort | uniq -c | sort -k1,1nr | head -n 30` do out " -> $entry" done IFS=$OLDIFS out out out " [+] TOP 30 files" OLDIFS=$IFS; IFS=$'\n'; for entry in `egrep -o 'file://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]' "$swap_dump_path" | sort | uniq -cd | sort -k1,1nr | head -n 30` do out " -> $entry" done IFS=$OLDIFS out out out " [+] TOP 30 smb shares" OLDIFS=$IFS; IFS=$'\n'; for entry in `egrep -o 'smb://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]' "$swap_dump_path" | sort | uniq -cd | sort -k1,1nr | head -n 30` do out " -> $entry" done IFS=$OLDIFS out out out " [+] TOP 30 IP addresses (lots of false positives, ex. file versions)" OLDIFS=$IFS; IFS=$'\n'; for entry in `grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" swap_dump.txt | sort | uniq -c | sort -k1,1nr | head -n 30` do out " -> $entry" done IFS=$OLDIFS } function dig_hashes () { local N=5 out out blue " ==== Mining hashes ===" out OLDIFS=$IFS; IFS=$'\n'; # Grep for md5:-prefix followed by 32 hex-characters md5sums=( $(grep -o -i -E "^(md5:[a-fA-F0-9]{32})" "$swap_dump_path") ) if [ "${#md5sums[@]}" -eq 0 ]; then out " [-] No MD5-hashes found" else out " [+] MD5-hashes" fi for entry in "${md5sums[@]}"; do out " -> $entry" done # Grep for sha1:-prefix followed by 40 hex-characters sha1sums=( $(grep -o -i -E "^(sha1:[a-f0-9]{40})" "$swap_dump_path") ) if [ "${#sha1sums[@]}" -eq 0 ]; then out " [-] No SHA1-hashes found" else out " [+] SHA1-hashes" fi for entry in "${sha1sums[@]}"; do out " -> $entry" done # Grep for sha256:-prefix followed by 64 hex-characters sha256sums=( $(grep -o -i -E "^(sha256:[a-f0-9]{64})" "$swap_dump_path") ) if [ "${#sha256sums[@]}" -eq 0 ]; then out " [-] No SHA256-hashes found" else out " [+] SHA256-hashes" fi for entry in "${sha256sums[@]}" do out " -> $entry" done # Grep for sha512:-prefix followed by 32 hex-characters sha512sums=( $(grep -o -i -E "^(sha512:[a-f0-9]{128})" "$swap_dump_path") ) if [ "${#sha512sums[@]}" -eq 0 ]; then out " [-] No SHA512-hashes found" else out " [+] SHA512-hashes" fi for entry in "${sha512sums[@]}" do out " -> $entry" done # Grep for $2a$:-prefix followed by 75 hex-characters bfsums=( $(grep -o -i -E '^(\$2[ay]\$[0-9]*\$[.a-z0-9]{22}[.a-z/0-9]{31})' "$swap_dump_path") ) if [ "${#bfsums[@]}" -eq 0 ]; then out " [-] No Blowfish-hashes found" else out " [+] Blowfish-Hashes" fi for entry in "${bfsums[@]}" do out " -> $entry" done OLDIFS=$IFS; IFS=$'\n'; } function guessing () { out out blue " ==== Guessing ===" out # Remove duplicates OLDIFS="$IFS" IFS=$'\n' passwordList=(`for password in "${passwordList[@]}"; do echo "$password" ; done | sort -du`) IFS="$OLDIFS" note "Highly probable found passwords are:" OLDIFS=$IFS; IFS=$'\n'; for passwd in ${passwordList[*]} do out " -> $passwd" done IFS=$OLDIFS if [ ${#passwordList[@]} -lt 2 ] then warning " 2 or more passwords are needed for guessing feature." return fi out out " [+] Start statistic guessing round 1... (wait for it)" OLDIFS=$IFS; IFS=$'\n'; for passwd in ${passwordList[*]} do DUMP=`grep -C5 "$passwd" "$swap_dump_path" | egrep -vi "=|;|mail|session|nsI|login|number|desktop|<|/|\.com|--"` # We also remove special char responsible for too much false positive # Search for other words near password while read -r line; do passwdSize=`echo "$passwd" | wc -c` passwdSizeMin=$((passwdSize-2)) passwdSizeMax=$((passwdSize+6)) lineSize=`echo "$line" | wc -c` re='^[0-9]+$' if [[ $passwdSizeMin =~ $re ]] && [[ $lineSize =~ $re ]] && [ "$lineSize" -lt "$passwdSizeMax" ] && [ "$lineSize" -gt "$passwdSizeMin" ] then occurence=`grep -c "$line" "$swap_dump_path" 2>/dev/null` if [ $occurence -gt 0 ] then [ $VERBOSE ] && out " [-] Potential password: $line" guessedPasswordList=("${guessedPasswordList[@]}" "$line") fi fi done <<< "$DUMP" done IFS=$OLDIFS # Remove duplicates OLDIFS="$IFS" IFS=$'\n' guessedPasswordList=(`for password in "${guessedPasswordList[@]}"; do echo "$password" ; done | sort -du`) IFS="$OLDIFS" out out " [+] Start statistic guessing round 2... (waaaaait for it)" OLDIFS=$IFS; IFS=$'\n'; for passwd in ${guessedPasswordList[*]} do # Add it to password list passwordList=("${passwordList[@]}" "$passwd") DUMP=`grep -C5 "$passwd" "$swap_dump_path" | egrep -vi "=|;|${passwd}|mail|session|nsI|login|number|desktop|<|/|,|\.com|--"` # We also remove special char responsibl for too much false positive and word itself # Search for other words near password while read -r line; do passwdSize=`echo $passwd| wc -c` passwdSizeMin=$((passwdSize-2)) passwdSizeMax=$((passwdSize+6)) lineSize=`echo $line | wc -c` if [[ $passwdSizeMin =~ $re ]] && [[ $lineSize =~ $re ]] && [ $lineSize -lt $passwdSizeMax ] && [ $lineSize -gt $passwdSizeMin ] then occurence=`grep -c "$line" "$swap_dump_path" 2>/dev/null` if [ $occurence -gt 1 ] then [ $VERBOSE ] && out " [-] Potential password: $line" passwordList=("${passwordList[@]}" "$line") fi fi done <<< "$DUMP" done IFS=$OLDIFS # Remove duplicates OLDIFS="$IFS"; IFS=$'\n' passwordList=(`for password in "${passwordList[@]}"; do echo "$password" ; done | sort -du`) IFS="$OLDIFS" out out " [+] Guessed potential passwords list:" OLDIFS=$IFS; IFS=$'\n'; for passwd in ${passwordList[*]} do out " -> $passwd" done IFS=$OLDIFS out } function swap_digger () { # Find swap partition if [ -f "$swap_dump_path" ] then out " [+] Swap dump already available at $swap_dump_path" else if [ -e "$SWAP_PATH" ] then out " [+] Using $SWAP_PATH as swap partition" # Dumping swap strings out " [+] Dumping swap strings in $swap_dump_path ... (this may take some time) " strings --bytes=6 "$SWAP_PATH" > "$swap_dump_path" else out " [+] Looking for swap partition" swap=`cat /proc/swaps | grep -o "/[^ ]\+"` [ -f "$swap" ] || [ -b "$swap" ] || swap=`swapon -s | grep dev | cut -d " " -f 1` [ -e "$swap" ] || { error "Could not find swap partition -> abort!"; exit 1; } out " -> Found swap at ${swap}" # Dumping swap strings out " [+] Dumping swap strings in $swap_dump_path ... (this may take some time) " strings --bytes=6 "$swap" > "$swap_dump_path" fi fi swap_dump_size=`ls -lh $swap_dump_path | cut -d " " -f 5` [ $VERBOSE ] && out " [-] Swap dump size: $swap_dump_size" # Let the fun begin! [ $PASSWD ] && dig_unix_passwd [ $APPLICATION_DATA ] && { dig_web_info dig_xml dig_wifi_info dig_keepass dig_history dig_hashes } [ $GUESSING ] && guessing } # Test if is swap device / swap dump function isSwap () { if [ -e "$1" ] && strings "$1" 2>/dev/null | head -c20 | grep -q "SWAPSPACE" then return 0 else return 1 fi } # Search for available swap partitiont / files function swap_search () { out " [+] Current swap file:" swap=`cat /proc/swaps | grep -o "/[^ ]\+"` if isSwap "$swap" then out " -> $swap" else out " -> None" fi out " [+] ${TARGET_ROOT_DIR}etc/fstab swap files:" swap=`cat ${TARGET_ROOT_DIR}etc/fstab | grep swap | cut -d " " -f 1` isSwap "$swap" && out " -> $swap" swap=`cat ${TARGET_ROOT_DIR}etc/fstab | grep swap -m 1 | cut -d " " -f 5` isSwap "$swap" && out " -> $swap" out " [+] Looking for all available swap device files (will take some time):" OLDIFS=$IFS; IFS=$'\n'; for file in `find / -type b 2>/dev/null` do isSwap "$file" && out " -> $file" done IFS=$OLDIFS } # display_usage function display_usage () { echo "Searches for valuable and sensitive data in Linux SWAP memory." echo "Usage: $0 [ OPTIONS ]" echo echo "Options : " echo " -p, --passwd Search for system passwords" echo " -g, --guessing Try to guess potential passwords based on observations and stats." echo " hundreds false positives. (Warning: This option is not reliable, " echo " it may dig more passwords as well as " echo " -a, --app-data Run extended tests on the target swap to retrieve other interesting data" echo " (web passwords, emails, wifi creds, most accessed URLs, hashes etc)" echo " -v, --verbose Verbose mode." echo " -l, --log Log all outputs in a log file (protected inside the generated working directory)." echo " -c, --clean Automatically erase the generated working directory at end of script (will also remove log file)" echo " -r PATH, --root-path PATH Location of the target file-system root (default value is /)" echo " Change this value for forensic analysis when target is a mounted file system." echo " This option has to be used along the -s option to indicate path to swap device." echo " -s PATH, --swap-path PATH Location of swap device or swap dump to analyse" echo " Use this option for forensic/remote analysis of a swap dump or a mounted external swap partition." echo " This option should be used with the -r option where at least //etc/shadow exists." echo " -S, --swap-search Search for all available swap devices." echo " -h, --help Display this help." echo echo " For more details see the README.md file at https://github.com/sevagas/swap_digger" echo } # Script will start here # Transform long options to short ones for arg in "$@"; do shift case "$arg" in "--clean") set -- "$@" "-c" ;; "--app-data") set -- "$@" "-x" ;; "--guessing") set -- "$@" "-g" ;; "--log") set -- "$@" "-l" ;; "--passwd") set -- "$@" "-p" ;; "--help") set -- "$@" "-h" ;; "--verbose") set -- "$@" "-v" ;; "--root-path") set -- "$@" "-r" ;; "--swap-path") set -- "$@" "-s" ;; "--swap-search") set -- "$@" "-S" ;; "--"*) display_usage; exit 1 ;; *) set -- "$@" "$arg" esac done # Parse short options OPTIND=1 while getopts "acglphvS-r:s:" OPT do # options processing case $OPT in c) CLEAN=1 ;; g) GUESSING=1 ;; l) LOG=1 ;; p) PASSWD=1 ;; r) TARGET_ROOT_DIR="$OPTARG" ;; s) SWAP_PATH="$OPTARG" ;; a) APPLICATION_DATA=1 ;; h) display_usage | more; exit 3 ;; v) VERBOSE=1 ;; S) SWAP_SEARCH=1 ;; *) display_usage; exit 1 ;; esac done shift $(expr $OPTIND - 1) # remove options from positional parameters init if [ $SWAP_SEARCH ] then swap_search else swap_digger fi end # TODOs # grep "^network-probe:" swap_dump.txt # grep "^hls:" swap_dump.txt # cat swap_dump.txt | grep -C 50 "smb://" | grep -C 30 "WORKGROUP" # aeskeyfind, rsakeyfind (binary dump?) # mysql -u x -p y ?