#!/bin/bash # Name: SearchSploit - Exploit-DB's CLI search tool # Version: 3.6.1 (Release date: 2016-09-20) # Written by: Offensive Security, Unix-Ninja & g0tmi1k # Homepage: https://github.com/offensive-security/exploit-database # ## NOTE: # Exit code '0' means finished normally # Exit code '1' means something went wrong # Exit code '2' means finished help screen # Exit code '6' means updated from GitHub ## OS settings (get the path of where the script is stored + database file) gitpath="$( cd "$( dirname "$(realpath ${BASH_SOURCE[0]})" )" && pwd)" csvpath="${gitpath}/files.csv" ## Program settings gitremote="https://github.com/offensive-security/exploit-database.git" progname="$( basename "$0" )" ## Default options CLIPBOARD=0 COLOUR=1 EDBID=0 EXACT=0 EXAMINE=0 FILEPATH=1 GETPATH=0 JSON=0 MIRROR=0 OVERFLOW=0 SCASE=0 WEBLINK=0 COLOUR_TAG="" TAGS="" SEARCH="" CASE_TAG_GREP="-i" CASE_TAG_FGREP="tolower" ## Set LANG variable to avoid illegal byte sequence errors LANG=C ## Usage info function usage() { echo " Usage: ${progname} [options] term1 [term2] ... [termN]" echo echo "==========" echo " Examples " echo "==========" echo " ${progname} afd windows local" echo " ${progname} -t oracle windows" echo " ${progname} -p 39446" echo echo "=========" echo " Options " echo "=========" echo " -c, --case [Term] Perform a case-sensitive search (Default is inSEnsITiVe)." echo " -e, --exact [Term] Perform an EXACT match on exploit title (Default is AND) [Implies \"-t\"]." echo " -h, --help Show this help screen." echo " -j, --json [Term] Show result in JSON format." echo " -m, --mirror [EDB-ID] Mirror (aka copies) an exploit to the current working directory." echo " -o, --overflow [Term] Exploit titles are allowed to overflow their columns." echo " -p, --path [EDB-ID] Show the full path to an exploit (and also copies the path to the clipboard if possible)." echo " -t, --title [Term] Search JUST the exploit title (Default is title AND the file's path)." echo " -u, --update Check for and install any exploitdb package updates (deb or git)" echo " -w, --www [Term] Show URLs to Exploit-DB.com rather than the local path." echo " -x, --examine [EDB-ID] Examine (aka opens) the exploit using $PAGER." echo " --colour Disable colour highlighting in search results." echo " --id Display the EDB-ID value rather than local path." echo echo "=======" echo " Notes " echo "=======" echo " * You can use any number of search terms." echo " * Search terms are not case-sensitive (by default), and ordering is irrelevant." echo " * Use '-c' if you wish to reduce results by case-sensitive searching." echo " * And/Or '-e' if you wish to filter results by using an exact match." echo " * Use '-t' to exclude the file's path to filter the search results." echo " * Remove false positives (especially when searching using numbers - i.e. versions)." echo " * When updating from git or displaying help, search terms will be ignored." echo "" exit 2 } ## Update database check function update() { dpkg -l exploitdb 2>/dev/null >/dev/null if [[ "$?" == "0" ]]; then # Update from the repos (e.g. Kali) updatedeb else # Update via git updategit fi } ## Update database (via .deb/apt) function updatedeb() { echo -e '[i] Updating via package management. Expect weekly-ish updates.\n' sudo apt update \ || echo -e '\n[!] Issue with apt update (Please check network connectivity & apt SourcesList)' 1>&2 sudo apt -y install exploitdb \ || echo -e '\n[!] Issue with apt install' 1>&2 echo -e "\n[*] Update finished." exit 6 } ## Update database (via GIT) function updategit() { echo -e '[i] Updating via git. Expect daily updates.\n' ## Make sure we are in the correct folder mkdir -p "${gitpath}/" cd "${gitpath}/" ## Are we in a git repo? if [[ "$( git rev-parse --is-inside-work-tree )" != "true" ]]; then if [[ "$( ls )" = "" ]]; then # If directory is empty, just clone echo -e '\n[i] Nothing here. Starting fresh...' git clone "${gitremote}" . fi fi # Is our git remote added? (aka homebrew) if [[ "$( git remote -v )" != *"${gitremote}"* ]]; then echo -e '\n[i] Missing git remote:' "${gitremote}" git init >/dev/null git remote add origin "${gitremote}" 2>/dev/null fi # Make sure to prep checkout first git checkout -- . # Update from git git pull origin master # If conflicts, clean and try again if [[ "$?" -ne 0 ]]; then git clean -d -fx "" git pull origin master fi echo -e "\n[*] Update finished." exit 6 } ## Printing dotted lines in the correct manner function drawline() { printf "%0.s-" $( eval echo {1..$(( COL1 + 1 ))} ) echo -n " " printf "%0.s-" $( eval echo {1..$(( COL2 - 1 ))} ) echo "" } ## Check for empty args if [[ $# -eq 0 ]]; then usage >&2 fi ## Parse long arguments ARGS="-" for param in "$@"; do if [[ "${param}" == "--case" ]]; then SCASE=1 elif [[ "${param}" == "--exact" ]]; then EXACT=1 elif [[ "${param}" == "--examine" ]]; then GETPATH=1 EXAMINE=1 elif [[ "${param}" == "--help" ]]; then usage >&2 elif [[ "${param}" == "--json" ]]; then JSON=1 elif [[ "${param}" == "--mirror" ]]; then GETPATH=1 MIRROR=1 elif [[ "${param}" == "--overflow" ]]; then OVERFLOW=1 elif [[ "${param}" == "--path" ]]; then GETPATH=1 CLIPBOARD=1 elif [[ "${param}" == "--title" ]]; then FILEPATH=0 elif [[ "${param}" == "--update" ]]; then update elif [[ "${param}" == "--www" ]]; then WEBLINK=1 elif [[ "${param}" == "--colour" ]] || [[ "${param}" == "--color" ]]; then COLOUR="" elif [[ "${param}" == "--id" ]]; then EDBID=1 else if [[ "${param:0:1}" == "-" ]]; then ARGS=${ARGS}${param:1} shift continue fi TAGS="${TAGS} ${param//\`/_}" fi done ## Parse short arguments while getopts "cehjmoptuwx" arg "${ARGS}"; do if [[ "${arg}" = "?" ]]; then usage >&2; fi case ${arg} in c) SCASE=1;; e) EXACT=1;; h) usage >&2;; j) JSON=1;; m) GETPATH=1; MIRROR=1;; o) OVERFLOW=1;; p) GETPATH=1; CLIPBOARD=1;; t) FILEPATH=0;; u) update;; w) WEBLINK=1;; x) GETPATH=1; EXAMINE=1;; esac shift $(( OPTIND - 1 )) done ## If we cannot find files.csv if [[ ! -f "${csvpath}" ]]; then echo '[!] Could not find: ' ${csvpath} exit 1 fi ## Print the full path. If pbcopy/xclip is available then copy to the clipboard if [[ "${GETPATH}" -eq 1 ]]; then for exploit in $(echo ${TAGS}); do ## Get EDB-ID from input edbdb="$( echo ${exploit} | tr -dc '0-9' )" ## Check files.csv location=$( cut -d, -f2 "${csvpath}" | grep -m 1 -E "/${edbdb}(\..*)?$" ) title=$( grep -m 1 "${location}" "${csvpath}" | cut -d, -f3 | sed 's/"//g' ) ## Join paths location="${gitpath}/${location}" ## Did we find the exploit? if [[ -f "${location}" ]]; then ## Display out echo "Exploit: ${title}" echo " URL: https://www.exploit-db.com/exploits/${edbdb}/" echo " Path: ${location}" echo "" ## Copy to clipboard? if [[ "${CLIPBOARD}" -eq 1 ]]; then ## Are any copy programs available? if hash xclip 2>/dev/null || hash pbcopy 2>/dev/null; then ## Linux (Will require $DISPLAY) if hash xclip 2>/dev/null; then echo -ne "${location}" | xclip -selection clipboard 2>/dev/null echo "Copied EDB-ID ${edbdb}'s path to the clipboard." ## OSX elif hash pbcopy 2>/dev/null; then echo -ne "${location}" | pbcopy echo "Copied EDB-ID ${edbdb}'s path to the clipboard." fi fi ## Done (early!) exit 0 fi ## Open the exploit up? if [[ "${EXAMINE}" -eq 1 ]]; then if [[ "${PAGER}" ]]; then /bin/sh -c "${PAGER} ${location}" elif [[ -f "$( which pager 2>/dev/null )" ]]; then pager "${location}" else less "${location}" fi echo -e "\n" fi if [[ "${MIRROR}" -eq 1 ]]; then echo "Copied to '$(pwd)/'" cp -i "${location}" "$(pwd)/" echo -e "\n" fi else ## Feedback echo "Could not find EDB-ID #${edbdb}" echo -e "\n" fi done ## Done exit 0 fi ## If we are doing an exact match, do not check folder path. if [[ "${EXACT}" -eq 1 ]]; then FILEPATH=0 fi ## Case sensitive? if [[ "${SCASE}" -eq 1 ]]; then ## Remove the default flags CASE_TAG_GREP="" CASE_TAG_FGREP="" fi ## Dynamically set column widths to the current screen size if [[ "${WEBLINK}" -eq 1 ]]; then COL2=45 else COL2=$(( ${#gitpath} + 15 )) fi COL1=$(( $( tput cols ) - COL2 - 1 )) ## Remove leading space TAGS="$(echo ${TAGS} | sed -e 's/^[[:space:]]//')" ## Print header if not in JSON if [[ "${JSON}" -eq 0 ]]; then drawline printf "%-${COL1}s %s" " Exploit Title" if [[ "${WEBLINK}" -eq 1 ]]; then echo "| URL" elif [[ "${EDBID}" -eq 1 ]]; then echo "| EDB-ID" else echo "| Path" printf "%-${COL1}s " echo "| (${gitpath}/platforms)" fi drawline ## Print JSON header else echo "{" echo " \"SEARCH\": \"${TAGS}\"," echo " \"RESULTS\": [" fi ## EXACT search command? if [[ "${EXACT}" -eq 1 ]]; then ## Case sensitive? if [[ "${SCASE}" -eq 1 ]]; then SEARCH="${TAGS}" else SEARCH="$( echo ${TAGS} | tr '[:upper:]' '[:lower:]' )" fi ## If we are to use colour, add the values to search for if [[ "${COLOUR}" -eq 1 ]]; then COLOUR_TAG="${SEARCH}" fi ## or AND search command? else ## For each term for tag in ${TAGS}; do ## If we are to use colour, add the values to search for between "or" if [[ "${COLOUR}" -eq 1 ]]; then if [[ "${COLOUR_TAG}" ]]; then COLOUR_TAG="${COLOUR_TAG}\|" fi COLOUR_TAG="${COLOUR_TAG}${tag}" fi ## Search both title and path? if [[ "${FILEPATH}" -eq 1 ]]; then ## Is there a value already? if [[ "${SEARCH}" ]]; then SEARCH="${SEARCH} |" fi ## Search command for each term SEARCH="${SEARCH} fgrep ${CASE_TAG_GREP} \"${tag}\"" ## Search just the title, not the path else ## If there is already a value, prepend text to get ready if [[ "${SEARCH}" ]]; then SEARCH="${SEARCH}/ && ${CASE_TAG_FGREP}(\$1) ~ /" fi ## Case sensitive? if [[ "${SCASE}" -eq 1 ]]; then SEARCH="${SEARCH}${tag}" else SEARCH="${SEARCH}$( echo ${tag} | tr '[:upper:]' '[:lower:]' )" fi fi done fi ## If we are not to use the path name if [[ "${FILEPATH}" -eq 0 ]]; then SEARCH="awk -F '[|]' '${CASE_TAG_FGREP}(\$1) ~ /${SEARCH}/ {print}'" fi ## If we are to use colour, add the value here if [[ "${COLOUR_TAG}" ]] && [[ "${JSON}" -eq 0 ]]; then SEARCH="${SEARCH} | grep --color=always -ie \"\${COLOUR_TAG}\"" fi ## Search, format, and print results if [[ "${OVERFLOW}" -eq 1 ]]; then FORMAT=${COL1} else FORMAT=${COL1}'.'${COL1} fi ## Magic search Fu ## Web link format? if [[ "${WEBLINK}" -eq 1 ]]; then OUTPUT="$( awk -F "\"*,\"*" '{ printf "%-'${FORMAT}'s | %s\n", $3, "https://www.exploit-db.com/exploits/"$1"/"}' "${csvpath}" \ | eval "${SEARCH}" )" ## Just the EDB-ID? elif [[ "${EDBID}" -eq 1 ]]; then OUTPUT="$( awk -F "\"*,\"*" '{ printf "%-'${FORMAT}'s | %s\n", $3, $1}' "${csvpath}" \ | eval "${SEARCH}" )" ## Print JSON format (full options) elif [[ "${JSON}" -eq 1 ]]; then OUTPUT="$( awk -F "\"*,\"*" '{ printf "\r\t\t'{'\"Exploit\":\"%s\",\"Path\":\"'${gitpath}/'%s\",\"EDB-ID\":%s},\n", $3, $2, $1}' "${csvpath}" \ | eval "${SEARCH}" \ | sed '$ s/,$//g' )" ## Default view else OUTPUT="$( awk -F "\"*,\"*" '{ printf "%-'${FORMAT}'s | %s\n", $3, $2}' "${csvpath}" \ | eval "${SEARCH}" \ | sed "s/| platforms/| ./" )" fi echo "${OUTPUT}" ## Print footer if not in JSON if [[ "${JSON}" -eq 0 ]]; then drawline ## Print JSON footer else echo " ]" echo "}" fi ## Done exit 0