
Modified searchsploit's Nmap XML parsing to correctly extract software versions. Also, these versions are no longer split on '.'.
1051 lines
35 KiB
Bash
Executable file
1051 lines
35 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Name: SearchSploit - Exploit-DB's CLI search tool
|
|
# Version: 4.2.1 (2022-11-11)
|
|
# Written by: Offensive Security, Unix-Ninja, and g0tmi1k
|
|
# Homepage: https://gitlab.com/exploit-database/exploitdb
|
|
# Manual: https://www.exploit-db.com/searchsploit
|
|
#
|
|
## NOTE:
|
|
# Exit code '0' means finished successfully
|
|
# Exit code '1' means something went wrong
|
|
# Exit code '2' means help screen
|
|
# Exit code '6' means updated packages (APT, brew or Git)
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
## Settings File
|
|
rc_file=""
|
|
|
|
## Default options
|
|
CLIPBOARD=0
|
|
COLOUR=1
|
|
CVE=0
|
|
EDBID=0
|
|
EXACT=0
|
|
EXAMINE=0
|
|
FILEPATH=1
|
|
FUZZY=1
|
|
GETPATH=0
|
|
JSON=0
|
|
MIRROR=0
|
|
OVERFLOW=0
|
|
SCASE=0
|
|
VERBOSE=0
|
|
WEBLINK=0
|
|
XML=0
|
|
COLOUR_TAG=""
|
|
TAGS=""
|
|
SEARCH=""
|
|
EXCLUDE=""
|
|
CASE_TAG_GREP="-i"
|
|
CASE_TAG_FGREP="tolower"
|
|
AWK_SEARCH=""
|
|
FUZZY_SEARCH=""
|
|
VERSION=
|
|
COLOUR_OFF_GREP=
|
|
COLOUR_ON_GREP=
|
|
REGEX_GREP=
|
|
|
|
## Check if our grep supports --color (BSD vs GNU)
|
|
if grep --help 2>&1 | grep "[-]-color" >/dev/null 2>&1; then
|
|
COLOUR_OFF_GREP="--color=never"
|
|
COLOUR_ON_GREP="--color=always"
|
|
fi
|
|
|
|
## Check if our grep supports --perl-regexp (BSD vs GNU)
|
|
if grep --help 2>&1 | grep "[-]-perl-regexp" >/dev/null 2>&1; then
|
|
REGEX_GREP="-P"
|
|
else
|
|
REGEX_GREP="-E"
|
|
fi
|
|
|
|
## Set LANG variable to avoid illegal byte sequence errors
|
|
LANG=C
|
|
|
|
## Set TERM
|
|
export TERM=xterm-256color
|
|
|
|
## Usage info
|
|
## - https://www.tldp.org/LDP/abs/html/standard-options.html
|
|
## - https://monkey.org/~marius/unix-tools-hints.html
|
|
## - https://clig.dev/
|
|
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 " ${progname} linux kernel 3.2 --exclude=\"(PoC)|/dos/\""
|
|
echo " ${progname} -s Apache Struts 2.0.0"
|
|
echo " ${progname} linux reverse password"
|
|
echo " ${progname} -j 55555 | jq"
|
|
echo " ${progname} --cve 2021-44228"
|
|
echo ""
|
|
echo " For more examples, see the manual: https://www.exploit-db.com/searchsploit"
|
|
echo ""
|
|
echo "========="
|
|
echo " Options "
|
|
echo "========="
|
|
echo "## Search Terms"
|
|
echo " -c, --case [term] Perform a case-sensitive search (Default is inSEnsITiVe)"
|
|
echo " -e, --exact [term] Perform an EXACT & order match on exploit title (Default is an AND match on each term) [Implies \"-t\"]"
|
|
echo " e.g. \"WordPress 4.1\" would not be detect \"WordPress Core 4.1\")"
|
|
echo " -s, --strict Perform a strict search, so input values must exist, disabling fuzzy search for version range"
|
|
echo " e.g. \"1.1\" would not be detected in \"1.0 < 1.3\")"
|
|
echo " -t, --title [term] Search JUST the exploit title (Default is title AND the file's path)"
|
|
echo " --exclude=\"term\" Remove values from results. By using \"|\" to separate, you can chain multiple values"
|
|
echo " e.g. --exclude=\"term1|term2|term3\""
|
|
echo " --cve [CVE] Search for Common Vulnerabilities and Exposures (CVE) value"
|
|
echo ""
|
|
echo "## Output"
|
|
echo " -j, --json [term] Show result in JSON format"
|
|
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 " -v, --verbose Display more information in output"
|
|
echo " -w, --www [term] Show URLs to Exploit-DB.com rather than the local path"
|
|
echo " --id Display the EDB-ID value rather than local path"
|
|
echo " --disable-colour Disable colour highlighting in search results"
|
|
echo ""
|
|
echo "## Non-Searching"
|
|
echo " -m, --mirror [EDB-ID] Mirror (aka copies) an exploit to the current working directory"
|
|
echo " -x, --examine [EDB-ID] Examine (aka opens) the exploit using \$PAGER"
|
|
echo ""
|
|
echo "## Non-Searching"
|
|
echo " -h, --help Show this help screen"
|
|
echo " -u, --update Check for and install any exploitdb package updates (brew, deb & git)"
|
|
echo ""
|
|
echo "## Automation"
|
|
echo " --nmap [file.xml] Checks all results in Nmap's XML output with service version"
|
|
echo " e.g.: nmap [host] -sV -oX file.xml"
|
|
echo ""
|
|
echo "======="
|
|
echo " Notes "
|
|
echo "======="
|
|
echo " * You can use any number of search terms"
|
|
echo " * By default, search terms are not case-sensitive, ordering is irrelevant, and will search between version ranges"
|
|
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 " * And/Or '-s' if you wish to look for an exact version 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 using '--nmap', adding '-v' (verbose), it will search for even more combinations"
|
|
echo " * When updating or displaying help, search terms will be ignored"
|
|
echo ""
|
|
exit 2
|
|
}
|
|
|
|
## Update database check
|
|
function update() {
|
|
arraylength="${#files_array[@]}"
|
|
for (( i=0; i<${arraylength}; i++ )); do
|
|
## Check to see if we already have the value
|
|
[[ "${tmp_package[*]}" =~ "${package_array[${i}]}" ]] \
|
|
&& continue
|
|
|
|
## Else save all the information
|
|
tmp_git+=("${git_array[${i}]}")
|
|
tmp_path+=("${path_array[${i}]}")
|
|
tmp_package+=("${package_array[${i}]}")
|
|
done
|
|
|
|
## Loop around all the new arrays
|
|
arraylength="${#tmp_git[@]}"
|
|
for (( i=0; i<${arraylength}; i++ )); do
|
|
git="${tmp_git[${i}]}"
|
|
path="${tmp_path[${i}]}"
|
|
package="${tmp_package[${i}]}"
|
|
|
|
## Update from the repos (e.g. Kali)
|
|
apt=$( apt-cache search "^${package}$" 2>/dev/null ) #dpkg -l "${package}" 2>/dev/null >/dev/null
|
|
if [[ "$?" == "0" ]] && [[ "${apt}" != "" ]]; then
|
|
updatedeb "${package}"
|
|
else
|
|
## Update from homebrew (e.g. macOS/OSX)
|
|
brew 2>/dev/null >/dev/null
|
|
if [[ "$?" == "0" ]]; then
|
|
## This only really only updates "./searchsploit". The rest (can) come via git as its updated more frequently
|
|
updatedbrew "${package}"
|
|
fi
|
|
|
|
## Update via Git
|
|
updategit "${package}" "${path}" "${git}"
|
|
fi
|
|
done
|
|
|
|
## Done
|
|
exit 6
|
|
}
|
|
|
|
## Update database (via .deb/apt)
|
|
function updatedeb() {
|
|
package_in="${1}"
|
|
|
|
echo -e "[i] Updating via apt package management (Expect weekly-ish updates): ${package_in}\n"
|
|
|
|
sudo apt update \
|
|
|| echo -e "\n[-] Issue with apt update (Please check network connectivity & apt SourcesList values)" 1>&2
|
|
sudo apt -y install "${package_in}" \
|
|
|| echo -e "\n[-] Issue with apt upgrade" 1>&2
|
|
|
|
echo -e "\n[*] apt update finished"
|
|
}
|
|
|
|
## Update database (via homebrew)
|
|
function updatedbrew() {
|
|
package_in="${1}"
|
|
|
|
echo -e "[i] Updating via brew package management\n"
|
|
|
|
brew update \
|
|
|| echo -e "\n[-] Issue with brew update (Please check network connectivity)" 1>&2
|
|
brew upgrade "${package_in}"
|
|
|
|
echo -e "\n[*] Brew update finished"
|
|
}
|
|
|
|
## Update database (via Git)
|
|
function updategit() {
|
|
package_in="${1}"
|
|
path_in="${2}"
|
|
git_in="${3}"
|
|
|
|
echo -e "[i] Updating via Git (Expect daily updates): ${package_in} ~ ${path_in}\n"
|
|
|
|
## Make sure we are in the correct folder
|
|
mkdir -p "${path_in}/" 2>/dev/null \
|
|
|| sudo mkdir -p "${path_in}/"
|
|
cd "${path_in}/"
|
|
|
|
## Are we in a Git repo?
|
|
if [[ "$( git rev-parse --is-inside-work-tree 2>/dev/null )" != "true" ]]; then
|
|
if [[ "$( ls )" = "" ]]; then
|
|
# If directory is empty, just clone
|
|
echo -e "\n[-] Nothing here (${path_in}). Starting fresh..."
|
|
git clone -v "${git_in}" "${path_in}/" 2>/dev/null \
|
|
|| sudo git clone -v "${git_in}" "${path_in}/"
|
|
fi
|
|
fi
|
|
|
|
# Is our Git remote added? (aka wouldn't be via homebrew method)
|
|
if [[ "$( git remote -v )" != *"upstream"*"${git_in}"* ]]; then
|
|
echo -e "\n[-] Missing Git remote upstream (${git_in})"
|
|
git init 2>/dev/null \
|
|
|| sudo git init
|
|
git remote add upstream "${git_in}" 2>/dev/null \
|
|
|| sudo git remote add upstream "${git_in}"
|
|
fi
|
|
|
|
# Make sure to prep checkout first
|
|
git checkout -- . 2>/dev/null \
|
|
|| sudo git checkout -- .
|
|
|
|
# Update from git
|
|
echo -e "\n[i] Git pull'ing"
|
|
git pull -v upstream master 2>/dev/null \
|
|
|| sudo git pull -v upstream master
|
|
|
|
# If conflicts, clean and try again
|
|
if [[ "$?" -ne 0 ]]; then
|
|
echo -e "\n[-] Git conflict"
|
|
git clean -d -fx "" \
|
|
|| sudo git clean -d -fx ""
|
|
git pull -v upstream master \
|
|
|| sudo git pull -v upstream master
|
|
fi
|
|
|
|
echo -e "\n[*] Git update finished"
|
|
echo "[i] Path: ${path_in}/"
|
|
}
|
|
|
|
## 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 ""
|
|
}
|
|
|
|
## Used in searchsploitout/nmap's XML
|
|
function validterm() {
|
|
## Check to see if its any phrases which would give a TON of incorrect results
|
|
if [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "microsoft" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "microsoft windows" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "windows" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "apache" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "ftp" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "http" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "linux" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "net" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "network" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "oracle" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "ssh" ] \
|
|
|| [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "unknown" ]; then
|
|
echo -e "[-] Skipping term: ${1} (Term is too general. Please re-search manually: $0 ${arg} ${1})\n" 1>&2
|
|
## Issues, return with something
|
|
return 1
|
|
fi
|
|
|
|
## No issues, return without anything
|
|
return 0
|
|
}
|
|
|
|
## Used in searchsploitout/nmap's XML
|
|
function searchsploitout() {
|
|
## Make sure there is a value
|
|
[ "${software}" = "" ] \
|
|
&& return
|
|
|
|
#echo "" 1>&2
|
|
|
|
arg="-t" ## Title search by default!
|
|
[[ "${COLOUR}" != "1" ]] \
|
|
&& arg="${arg} --disable-colour"
|
|
[[ "${EDBID}" == "1" ]] \
|
|
&& arg="${arg} --id"
|
|
[[ "${JSON}" == "1" ]] \
|
|
&& arg="${arg} --json"
|
|
[[ "${OVERFLOW}" == "1" ]] \
|
|
&& arg="${arg} --overflow"
|
|
[[ "${FUZZY}" != "1" ]] \
|
|
&& arg="${arg} --strict"
|
|
[[ "${WEBLINK}" == "1" ]] \
|
|
&& arg="${arg} --www"
|
|
|
|
## Try and remove terms that could confuse searches
|
|
#software=$( echo "${software}" | sed 's_/_ _g' )
|
|
software=$( echo "${software}" | sed -e 's/[^a-zA-Z0-9.]/ /g' )
|
|
|
|
if [[ "${VERBOSE}" -eq 1 ]]; then
|
|
## Loop each word?
|
|
tmp=""
|
|
for word in $( echo ${software} ); do
|
|
## Add current search term on
|
|
tmp="${tmp}${word}"
|
|
|
|
## Check to see if its any phrases which would give a TON of incorrect results
|
|
validterm "${tmp}" \
|
|
|| continue
|
|
|
|
## Feedback
|
|
echo "[i] $0 ${arg} ${tmp}" 1>&2
|
|
out=$( bash "$0" ${arg} ${tmp} )
|
|
|
|
## Are there too many results?
|
|
lines=$( echo -e "${out}" | wc -l )
|
|
if [[ "${lines}" -gt 100 ]]; then
|
|
echo -e "[-] Skipping output: ${tmp} (Too many results, 100+. You'll need to force a search: $0 ${arg} ${tmp})\n" 1>&2
|
|
## Are there any results?
|
|
elif [[ "${lines}" -gt 5 ]]; then
|
|
echo -e "${out}\n\n"
|
|
## If there's no results
|
|
else
|
|
## Exit for loop
|
|
break
|
|
fi
|
|
|
|
## Space out for the next word
|
|
tmp="${tmp} "
|
|
done
|
|
|
|
## Padding between loops
|
|
echo -e "\n\n" 1>&2
|
|
else
|
|
## Check to see if its any phrases which would give a TON of incorrect results
|
|
validterm "${software}" \
|
|
|| return
|
|
|
|
## Feedback
|
|
echo "[i] $0 ${arg} ${software}" 1>&2
|
|
out=$( bash "$0" ${arg} ${software} )
|
|
|
|
## Are there too many results?
|
|
lines=$( echo -e "${out}" | wc -l )
|
|
if [[ "${lines}" -gt 100 ]]; then
|
|
echo -e "[-] Skipping output: ${software} (Too many results, 100+. You'll need to force a search: $0 ${arg} ${software})\n" 1>&2
|
|
## Are there any results?
|
|
elif [[ "${lines}" -gt 5 ]]; then
|
|
echo -e "${out}\n\n"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
## Read XML file
|
|
function nmapxml() {
|
|
## Feedback to the end user
|
|
echo -e "[i] Reading: '${FILE}'\n" 1>&2
|
|
|
|
## Read in XMP (IP, name, service and version)
|
|
xmllint --xpath '//address/@addr|//service/@name|//service/@product|//service/@version' "${FILE}" \
|
|
| sed -e $'s/addr=/\\\n[IP] /g; s/name=/\\\n[NAME] /g; s/product=/\\\n[PRODUCT] /g; s/version=/\\\n[VERSION] /g; s/"//g' \
|
|
| grep -v '\[IP\].*\:' \
|
|
| while read line; do
|
|
type=$( echo "${line}" | cut -d" " -f 1 )
|
|
input=$( echo "${line}" | cut -d" " -f 2- )
|
|
|
|
case "${type}" in
|
|
"[IP]")
|
|
#[[ "${VERBOSE}" -eq 1 ]] && echo -e "\n\n\e[32m[*] IP: ${input}\e[39m" 1>&2
|
|
;;
|
|
"[NAME]")
|
|
## If we have already looped around and got something, save it before moving onto the current value
|
|
if [[ "${software}" ]]; then
|
|
#searchsploitout
|
|
echo "${software}"
|
|
fi
|
|
## Something is better than nothing. Will just go on the default service that matches the port. e.g. domain
|
|
software="${input}"
|
|
## Might not get any more than this, if -sV failed
|
|
;;
|
|
"[PRODUCT]")
|
|
## We have a name, but no version (yet?) e.g. dnsmasq
|
|
echo "${software}"
|
|
software="${input}"
|
|
echo "${software}"
|
|
;;
|
|
"[VERSION]")
|
|
software="${software} ${input}"
|
|
## Name & version. There isn't any more information to get, game over. e.g. dnsmasq 2.72
|
|
echo "${software}"
|
|
software=
|
|
;;
|
|
esac
|
|
done | tr '[:upper:]' '[:lower:]' | awk '!x[$0]++' | while read software; do
|
|
searchsploitout
|
|
done
|
|
}
|
|
|
|
## Build search terms
|
|
function buildterms() {
|
|
tag_in="${1}"
|
|
|
|
## If we are to use colour ("--disable-colour"), add the values to search for between "or"
|
|
if [[ "${COLOUR}" -eq 1 ]]; then
|
|
[[ "${COLOUR_TAG}" ]] \
|
|
&& COLOUR_TAG="${COLOUR_TAG}|"
|
|
COLOUR_TAG="${COLOUR_TAG}${tag_in}"
|
|
fi
|
|
|
|
## Some regex to try and detect version
|
|
## Basic: major.minor[.build][.revision] // major.minor[.maintenance][.build] -- example: 1.2.3.4)
|
|
## Plus alphanumeric (e.g. alpha, beta): 1a, 2.2b, 3.3-c, 4.4-rc4, 5.5-r
|
|
if ! echo "${tag_in}" | grep ${REGEX_GREP} -q "^(\d+)(\.?\d*)(\.?\d*)((\.|\-)?(\w*))$"; then
|
|
FUZZY_SEARCH="${FUZZY_SEARCH} | grep ${COLOUR_OFF_GREP} -F ${CASE_TAG_GREP} \"${tag_in}\""
|
|
fi
|
|
|
|
## Search both title AND path
|
|
if [[ "${FILEPATH}" -eq 1 ]]; then
|
|
## Search command for each term (with case sensitive flag, "-c")
|
|
SEARCH="${SEARCH} | grep ${COLOUR_OFF_GREP} -F ${CASE_TAG_GREP} \"${tag_in}\""
|
|
|
|
## Search just the title, NOT the path ("-t"/"-e")
|
|
else
|
|
## If there is already a value, prepend text to get ready
|
|
[[ "${AWK_SEARCH}" ]] \
|
|
&& AWK_SEARCH="${AWK_SEARCH}/ && ${CASE_TAG_FGREP}(\$3) ~ /"
|
|
|
|
## Escape any slashes
|
|
tag_in="$( echo ${tag_in} | sed 's_/_\\/_g' )"
|
|
|
|
## Case sensitive ("-c")
|
|
if [[ "${SCASE}" -eq 1 ]]; then
|
|
AWK_SEARCH="${AWK_SEARCH}${tag_in}"
|
|
else
|
|
AWK_SEARCH="${AWK_SEARCH}$( echo ${tag_in} | tr '[:upper:]' '[:lower:]' )"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
## Read in the values from files_*.csv
|
|
function findresults() {
|
|
file_in="${1}"
|
|
path_in="${2}"
|
|
name_in="${3}"
|
|
|
|
if [[ "${name_in}" == "Paper"* ]]; then
|
|
url="papers"
|
|
elif [[ "${name_in}" == "Shellcode"* ]]; then
|
|
url="shellcodes"
|
|
else
|
|
url="exploits"
|
|
fi
|
|
|
|
## JSON require full options ("--json")
|
|
if [[ "${JSON}" -eq 1 ]] || [[ "${FUZZY}" -eq 1 ]]; then
|
|
## Read (id, path, title, date_published, author, type, platform, port, date_added, date_updated, verified, codes, tags, aliases, screenshot_url, application_url, source_url) separated between commas
|
|
## Needs to end with a `,` to match the awk search later for FUZZY_SEARCH with "sort -u"
|
|
SEARCH="awk -F '[,]' '{print \$1\",\"\$2\",\"\$3\",\"\$4\",\"\$5\",\"\$6\",\"\$7\",\"\$8\",\"\$9\",\"\$10\",\"\$11\",\"\$12\",\"\$13\",\"\$14\",\"\$15\",\"\$16\",\"\$17}' \"${path_in}/${file_in}\""
|
|
## Read (id, path, title) separated between commas & search for less than (and grater than values) too
|
|
FUZZY_SEARCH="awk -F '[,]' '{print \$1\",\"\$2\",\"\$3}' \"${path_in}/${file_in}\" | grep ${COLOUR_OFF_GREP} \"<\|>\""
|
|
## CVE ("--cve")
|
|
elif [[ "${CVE}" -eq 1 ]]; then
|
|
## Read (id, path, title, codes) separated between commas (as these are the visible/common fields)
|
|
SEARCH="awk -F '[,]' '{print \$1\",\"\$2\",\"\$3\",\"\$12}' \"${path_in}/${file_in}\""
|
|
else
|
|
## Read (id, path, title) separated between commas (as these are the only visible fields)
|
|
SEARCH="awk -F '[,]' '{print \$1\",\"\$2\",\"\$3}' \"${path_in}/${file_in}\""
|
|
fi
|
|
|
|
## EXACT search command ("-e")
|
|
if [[ "${EXACT}" -eq 1 ]]; then
|
|
buildterms "${TAGS}"
|
|
## or AND search command?
|
|
else
|
|
## For each term
|
|
for TAG in ${TAGS}; do
|
|
buildterms "${TAG}"
|
|
done
|
|
fi
|
|
|
|
## If we are NOT to use the path name ("-t"/"-e")
|
|
[[ "${FILEPATH}" -eq 0 ]] \
|
|
&& SEARCH="${SEARCH} | awk -F '[,]' '${CASE_TAG_FGREP}(\$3) ~ /${AWK_SEARCH}/ {print}'"
|
|
|
|
## Remove any terms not wanted from the search
|
|
[[ "${EXCLUDE}" ]] \
|
|
&& SEARCH="${SEARCH} | grep ${REGEX_GREP} -vi '${EXCLUDE}'"
|
|
[[ "${EXCLUDE}" ]] && [[ "${FUZZY}" -eq 1 ]] \
|
|
&& FUZZY_SEARCH="${FUZZY_SEARCH} | grep ${REGEX_GREP} -vi '${EXCLUDE}'"
|
|
|
|
## If we are to use colour ("--disable-colour"), add the value here
|
|
if [[ "${COLOUR_TAG}" ]] && [[ "${JSON}" -eq 0 ]]; then
|
|
COLOUR_TAG="grep ${COLOUR_ON_GREP} -iE \"${COLOUR_TAG}|$\""
|
|
fi
|
|
|
|
## Dynamically set column widths to the current screen size
|
|
[[ "${WEBLINK}" -eq 1 ]] \
|
|
&& COL2=45 \
|
|
|| COL2=$(( 34 )) ## Max length + 2 ~ $ find . ! -path '*/.*' -type f | awk '{ print length, $0 }' | sort -n -s | cut -d" " -f2- | tail -n 1
|
|
#|| COL2=$(( ${#path_in} + 21 ))
|
|
|
|
COL1=$(( $( tput cols ) - COL2 - 1 ))
|
|
|
|
## Search, format, and print results (--overflow)
|
|
[[ "${OVERFLOW}" -eq 1 ]] \
|
|
&& FORMAT_COL1=${COL1} \
|
|
|| FORMAT_COL1=${COL1}'.'${COL1}
|
|
|
|
## Maximum length COL2 can be
|
|
FORMAT_COL2=$(( ${COL2} - 2 ))
|
|
|
|
## Are we doing a fuzzy search & did we manage to detect the version
|
|
if [[ "${FUZZY}" -eq 1 ]] && [[ -n "${VERSION}" ]]; then
|
|
## SubShells - http://mywiki.wooledge.org/BashFAQ/024
|
|
while IFS= read -r TITLE; do
|
|
while IFS= read -r RANGE; do
|
|
## Read in input and trim
|
|
MIN=$( echo "${RANGE}" | awk -F '<' '{print $1}' | xargs )
|
|
MAX=$( echo "${RANGE}" | awk -F '<' '{print $2}' | xargs )
|
|
|
|
## As its optional to put it, set a value if blank
|
|
[ -z "${MIN}" ] \
|
|
&& MIN=0
|
|
|
|
RESULT="$( printf '%s\n' "${MIN}" "${VERSION}" "${MAX}" | sort -V )"
|
|
## Sub if sort -v isn't working? if (( $( echo "${MIN} <= ${VERSION}" | bc -l ) )) && (( $( echo "${MAX} >= ${VERSION}" | bc -l ) )); then
|
|
## ...else there is dpkg (if Debian)
|
|
if [[ "$( echo "${RESULT}" | head -n 1 )" == "${MIN}" ]] && [[ "$( echo "${RESULT}" | tail -n 1 )" == "${MAX}" ]]; then
|
|
[ -n "${ID}" ] \
|
|
&& ID="${ID}|"
|
|
ID="${ID}$( echo ${TITLE} | awk -F ',' '{print $1}' )"
|
|
## Found one, no point going on
|
|
break
|
|
fi
|
|
done < <(
|
|
echo "${TITLE}" \
|
|
| grep ${REGEX_GREP} -o "((\d+)(\.?\d*)(\.?\d*)((\.|\-)?(\d|x)*)(\s*))?((<|>)=?)(\s*)(\d+)(\.?\d*)(\.?\d*)((\.|\-)?(\d|x)*)" \
|
|
| sed 's_=__; s_>_<_'
|
|
)
|
|
## Do the same search (just without the version) & loop around all the exploit titles (as thats where the versions are)
|
|
## Two main "parts"
|
|
## (a.b.c.d )(<= e.f.g.h)
|
|
## This can be broken down more:
|
|
## Group 1 == a & e == major = [0-9]
|
|
## Group 2 == b & f == minor = .[0-9] (optional)
|
|
## Group 3 == c & g == build/maintenance = .[0-9] (optional)
|
|
## Group 4a == d & h == revision/build = . OR - (optional)
|
|
## Group 4b == = x OR [0-9] (optional)
|
|
## So it really is more like ~ (a)(.b)(.c)(.d)( )(<=)( )(e)(.f)(.g)(.h)
|
|
## NOTE: ..."x" is used as a wild card in titles
|
|
## Quick regex recap
|
|
## Digit == \d
|
|
## Space == \s
|
|
## Group == ( )
|
|
## OR == |
|
|
## 1 or more == +
|
|
## 0 or more == *
|
|
## 0 or 1 == ?
|
|
## Should support:
|
|
## Exploit < 1 / <= 1.2 / < 1.2.3.4 / < 1.2.3.x
|
|
## Exploit 1.0 < 1.2.3.4
|
|
## ...This can be better so it doesn't search in brackets: "Linux Kernel (Solaris 10 / < 5.10 138888-01) - Local Privilege Escalation"
|
|
done < <(
|
|
eval "${FUZZY_SEARCH}"
|
|
)
|
|
fi
|
|
|
|
## Magic search Fu + strip double quotes + Fix any escaping `\` (need todo it again for JSON only later: issues/#173)
|
|
OUTPUT="$(
|
|
( \
|
|
eval ${SEARCH}; \
|
|
awk "/^(${ID}),/ {print}" "${path_in}/${file_in}" \
|
|
) \
|
|
| sed 's/\"//g; s_\\_\\\\_g' \
|
|
| sort -u
|
|
)"
|
|
|
|
## If there are no results, no point going on
|
|
[[ -z "${OUTPUT}" ]] \
|
|
&& return
|
|
|
|
## Print JSON format (full options) ("--json")?
|
|
if [[ "${JSON}" -eq 1 ]]; then
|
|
## Web link format ("--json --www")?
|
|
if [[ "${WEBLINK}" -eq 1 ]]; then
|
|
OUTPUT="$( echo "${OUTPUT}" \
|
|
| sed 's_\\_\\\\_g' \
|
|
| awk -F ',' '{ printf "\\n\\t\\t'{'\"Title\":\"%s\",\"URL\":\"https://www.exploit-db.com/'${url}'/%s\"},", $3, $1 }' )"
|
|
## Just the EDB-ID ("--json --id")?
|
|
elif [[ "${EDBID}" -eq 1 ]]; then
|
|
OUTPUT="$( echo "${OUTPUT}" \
|
|
| sed 's_\\_\\\\_g' \
|
|
| awk -F ',' '{ printf "\\n\\t\\t'{'\"Title\":\"%s\",\"EDB-ID\":\"%s\",\"Path\":\"'${path_in}/'%s\"},", $3, $1, $2 }' )"
|
|
## Default JSON ("--json")?
|
|
else
|
|
OUTPUT="$( echo "${OUTPUT}" \
|
|
| sed 's_\\_\\\\_g' \
|
|
| awk -F ',' '{ printf "\\n\\t\\t'{'\"Title\":\"%s\",\"EDB-ID\":\"%s\",\"Date_Published\":\"%s\",\"Date_Added\":\"%s\",\"Date_Updated\":\"%s\",\"Author\":\"%s\",\"Type\":\"%s\",\"Platform\":\"%s\",\"Port\":\"%s\",\"Verified\":\"%s\",\"Codes\":\"%s\",\"Tags\":\"%s\",\"Aliases\":\"%s\",\"Screenshot\":\"%s\",\"Application\":\"%s\",\"Source\":\"%s\",\"Path\":\"'${path_in}/'%s\"},", $3, $1, $4, $9, $10, $5, $6, $7, $8, $11, $12, $13, $14, $15, $16, $17, $2}' )"
|
|
fi
|
|
OUTPUT="$( echo -e ${OUTPUT} \
|
|
| sort -f \
|
|
| sed '$ s/,$//' )"
|
|
## Web link format ("--www")?
|
|
elif [[ "${WEBLINK}" -eq 1 ]]; then
|
|
OUTPUT="$( echo "${OUTPUT}" \
|
|
| awk -F ',' '{ printf "%-'${FORMAT_COL1}'s | %s\n", $3, "https://www.exploit-db.com/'${url}'/"$1 }' \
|
|
| sort -f )"
|
|
## Just the EDB-ID ("--id")?
|
|
elif [[ "${EDBID}" -eq 1 ]]; then
|
|
OUTPUT="$( echo "${OUTPUT}" \
|
|
| awk -F ',' '{ printf "%-'${FORMAT_COL1}'s | %s\n", $3, $1 }' \
|
|
| sort -f )"
|
|
## Default view
|
|
else
|
|
OUTPUT="$( echo "${OUTPUT}" \
|
|
| sed 's_,exploits/_,_; s_,shellcodes/_,_; s_,papers/_,_' \
|
|
| awk -F ',' '{ printf "%-'${FORMAT_COL1}'s | %.'${FORMAT_COL2}'s\n", $3, $2 }' \
|
|
| sort -f )"
|
|
fi
|
|
|
|
## Display colour highlights ("--disable-colour")?
|
|
if [[ "${COLOUR_TAG}" ]] && [[ "${JSON}" -eq 0 ]] && [[ "${OUTPUT}" ]]; then
|
|
OUTPUT=$( echo -e "${OUTPUT}" | eval ${COLOUR_TAG} )
|
|
fi
|
|
}
|
|
|
|
function printresults() {
|
|
title_in="${1}"
|
|
path_in="${2}"
|
|
json_title="$( echo ${title_in} | tr /a-z/ /A-Z/ )"
|
|
|
|
## Print header if in JSON ("--json")
|
|
if [[ "${JSON}" -eq 1 ]]; then
|
|
printf ",\n\t\"DB_PATH_${json_title}\": \"${path_in}\",\n"
|
|
printf "\t\"RESULTS_${json_title}\": ["
|
|
## ASCII table
|
|
else
|
|
drawline
|
|
printf "%-${COL1}s %s" " ${title_in} Title"
|
|
if [[ "${WEBLINK}" -eq 1 ]]; then
|
|
echo "| URL"
|
|
elif [[ "${EDBID}" -eq 1 ]]; then
|
|
echo "| EDB-ID"
|
|
else
|
|
echo "| Path"
|
|
#echo " > Results (0)"
|
|
#
|
|
#printf "%-${COL1}s "
|
|
#echo "| (${path_in}/)"
|
|
fi
|
|
drawline
|
|
fi
|
|
|
|
## Show content
|
|
[[ "${OUTPUT}" ]] \
|
|
&& echo "${OUTPUT}"
|
|
|
|
## Print footer if in JSON ("--json")
|
|
if [[ "${JSON}" -eq 1 ]]; then
|
|
printf "\t]"
|
|
else
|
|
drawline
|
|
fi
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
## Locate setting file
|
|
## User home folder config
|
|
if [[ -f "${HOME}/.searchsploit_rc" ]]; then
|
|
rc_file="${HOME}/.searchsploit_rc"
|
|
## Global config
|
|
elif [[ -f "/etc/searchsploit_rc" ]]; then
|
|
rc_file="/etc/searchsploit_rc"
|
|
## Method #1 - File itself
|
|
elif [[ -f "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/.searchsploit_rc" ]]; then
|
|
rc_file="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/.searchsploit_rc"
|
|
## Method #2 - Symbolic link
|
|
elif [[ -f "$( dirname "$( readlink "$0" )" )/.searchsploit_rc" ]]; then
|
|
rc_file="$( dirname "$( readlink "$0" )" )/.searchsploit_rc"
|
|
## Manually specified?
|
|
elif [[ ! -f "${rc_file}" ]]; then
|
|
echo "[!] Could not find: rc_file ~ ${rc_file}"
|
|
exit 1
|
|
fi
|
|
|
|
## Use config file
|
|
source "${rc_file}"
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
## Check for empty arguments
|
|
if [[ $# -eq 0 ]]; then
|
|
usage >&2
|
|
fi
|
|
|
|
## Parse long arguments
|
|
ARGS="-"
|
|
for param in "$@"; do
|
|
if [[ "${param}" == "--case" ]]; then
|
|
SCASE=1
|
|
elif [[ "${param}" == "--disable-colour" ]] || [[ "${param}" == "--disablecolour" ]] || [[ "${param}" == "--disable-color" ]] || [[ "${param}" == "--disablecolor" ]]; then
|
|
COLOUR=""
|
|
elif [[ "${param}" == "--cve" ]]; then
|
|
CVE=1
|
|
elif [[ "${param}" == "--exact" ]]; then
|
|
EXACT=1
|
|
elif [[ "${param}" == "--examine" ]] || [[ "${param}" == "--open" ]] || [[ "${param}" == "--view" ]]; then
|
|
GETPATH=1
|
|
EXAMINE=1
|
|
elif [[ "${param}" == "--help" ]]; then
|
|
usage >&2
|
|
elif [[ "${param}" == "--id" ]]; then
|
|
EDBID=1
|
|
elif [[ "${param}" == "--json" ]]; then
|
|
JSON=1
|
|
elif [[ "${param}" == "--mirror" ]] || [[ "${param}" == "--copy" ]] || [[ "${param}" == "--dup" ]] || [[ "${param}" == "--duplicate" ]]; then
|
|
GETPATH=1
|
|
MIRROR=1
|
|
elif [[ "${param}" == "--nmap" ]]; then
|
|
XML=1
|
|
elif [[ "${param}" == "--overflow" ]]; then
|
|
OVERFLOW=1
|
|
elif [[ "${param}" == "--path" ]]; then
|
|
GETPATH=1
|
|
CLIPBOARD=1
|
|
elif [[ "${param}" == "--strict" ]]; then
|
|
FUZZY=0
|
|
elif [[ "${param}" == "--title" ]]; then
|
|
FILEPATH=0
|
|
elif [[ "${param}" == "--update" ]]; then
|
|
update
|
|
elif [[ "${param}" == "--verbose" ]]; then
|
|
VERBOSE=1
|
|
elif [[ "${param}" == "--www" ]]; then
|
|
WEBLINK=1
|
|
elif [[ "${param}" =~ "--exclude=" ]]; then
|
|
EXCLUDE="$( echo "${param}" | cut -d '=' -f 2- )"
|
|
else
|
|
if [[ "${param:0:1}" == "-" ]]; then
|
|
ARGS=${ARGS}${param:1}
|
|
shift
|
|
continue
|
|
fi
|
|
TAGS="${TAGS} ${param//[\`\']/_}"
|
|
fi
|
|
done
|
|
|
|
## Parse short arguments
|
|
while getopts "cehjmnopstuvwx" 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;;
|
|
n) XML=1;;
|
|
o) OVERFLOW=1;;
|
|
p) GETPATH=1; CLIPBOARD=1;;
|
|
s) FUZZY=0;;
|
|
t) FILEPATH=0;;
|
|
u) update;;
|
|
v) VERBOSE=1;;
|
|
w) WEBLINK=1;;
|
|
x) GETPATH=1; EXAMINE=1;;
|
|
esac
|
|
shift $(( OPTIND - 1 ))
|
|
done
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
## Check for files_*.csv
|
|
arraylength="${#files_array[@]}"
|
|
for (( i=0; i<${arraylength}; i++ )); do
|
|
files="${path_array[${i}]}/${files_array[${i}]}"
|
|
|
|
if [[ -f "${files}" ]]; then
|
|
continue
|
|
## Method #1 - File itself
|
|
elif [[ -f "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/${files_array[${i}]}" ]]; then
|
|
echo "[i] Found (#1): $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/${files_array[${i}]}" 1>&2
|
|
echo "[i] To remove this message, please edit \"${rc_file}\" which has \"package_array: ${package_array[${i}]}\" to point too: path_array+=(\"$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )\")" 1>&2
|
|
echo 1>&2
|
|
path_array[${i}]="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
## Method #2 - Symbolic link
|
|
elif [[ -f "$( dirname "$( readlink "$0" )" )/${files_array[${i}]}" ]]; then
|
|
echo "[i] Found (#2): $( dirname "$( readlink "$0" )" )/${files_array[${i}]}" 1>&2
|
|
echo "[i] To remove this message, please edit \"${rc_file}\" which has \"package_array: ${package_array[${i}]}\" to point too: path_array+=(\"$( dirname "$( readlink "$0" )" )\")" 1>&2
|
|
echo 1>&2
|
|
path_array[${i}]="$( dirname "$( readlink "$0" )" )"
|
|
else
|
|
#echo "[!] Could not find: ${files}" 1>&2
|
|
#echo "[i] To remove this message, please remove \"${files_array[${i}]}\" (package_array: ${package_array[${i}]}) from \"${rc_file}\"" 1>&2
|
|
#echo 1>&2
|
|
unset "files_array[${i}]"
|
|
unset "path_array[${i}]"
|
|
unset "name_array[${i}]"
|
|
unset "git_array[${i}]"
|
|
unset "package_array[${i}]"
|
|
fi
|
|
done
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
## Read in XML
|
|
if [[ "${XML}" -eq 1 ]]; then
|
|
## Trim white spaces
|
|
FILE=$( echo ${TAGS} | xargs )
|
|
|
|
## Is there a file?
|
|
if [[ ! -f "${FILE}" ]]; then
|
|
echo -e "\n[!] Could not find file: ${FILE}" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! hash xmllint 2>/dev/null; then
|
|
echo -e "\n[!] Please install xmllint" 1>&2
|
|
echo -e "[i] Kali Linux: sudo apt -y install libxml2-utils" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${VERBOSE}" -ne 1 ]]; then
|
|
echo "[i] SearchSploit's XML mode (without verbose enabled). To enable: ${progname} -v --xml..." 1>&2
|
|
fi
|
|
|
|
## Do the magic
|
|
nmapxml
|
|
|
|
## Done
|
|
exit 0
|
|
fi
|
|
|
|
## Print the full path. If pbcopy/xclip is available then copy to the clipboard
|
|
if [[ "${GETPATH}" -eq 1 ]]; then
|
|
for exploit in ${TAGS}; do
|
|
## Get EDB-ID from input
|
|
edbdb="$( echo ${exploit} | rev | cut -d '/' -f1 | rev | cut -d'-' -f1 | cut -d'.' -f1 | tr -dc '0-9' )"
|
|
|
|
## Loop until we find something
|
|
arraylength="${#files_array[@]}"
|
|
for (( i=0; i<${arraylength}; i++ )); do
|
|
files="${path_array[${i}]}/${files_array[${i}]}"
|
|
|
|
## Check to see if the files_*.csv has a value
|
|
line=$( grep -m 1 -E "^${edbdb}," "${files}" )
|
|
|
|
if [[ "${line}" ]]; then
|
|
path="$( echo ${line} | cut -d ',' -f 2 )"
|
|
location="${path_array[${i}]}/${path}"
|
|
name="${name_array[${i}]}"
|
|
|
|
if [[ "${name}" == "Paper"* ]]; then
|
|
url="papers/${edbdb}"
|
|
elif [[ "${name}" == "Shellcode"* ]]; then
|
|
url="shellcodes/${edbdb}"
|
|
else
|
|
url="exploits/${edbdb}"
|
|
fi
|
|
|
|
break
|
|
fi
|
|
done
|
|
|
|
## Did we find the exploit?
|
|
if [[ -f "${location}" ]]; then
|
|
## Get title
|
|
title=$( grep -m 1 "${path}" "${files}" | cut -d ',' -f 3 | sed 's/"//g' )
|
|
|
|
## Get codes
|
|
codes=$( grep -m 1 "${path}" "${files}" | cut -d ',' -f 12 | sed 's/"//g; s/;/, /g' )
|
|
if [ -z "${codes}" ]; then
|
|
codes="N/A"
|
|
fi
|
|
|
|
## Get verified status
|
|
verified=$( grep -m 1 "${path}" "${files}" | cut -d ',' -f 11 | sed 's/"//g' )
|
|
if [ "${verified}" = "1" ]; then
|
|
verified="True"
|
|
else
|
|
verified="False"
|
|
fi
|
|
|
|
## File type
|
|
fileinfo="$( file -b "${location}" 2>/dev/null || echo "<missing file package>" )"
|
|
|
|
## How long is the name?
|
|
PADDING=$(( 9 - ${#name} ))
|
|
|
|
## Display out
|
|
printf "%-${PADDING}s%s"
|
|
echo "${name}: ${title}"
|
|
echo " URL: https://www.exploit-db.com/${url}"
|
|
## Path is useful doing --mirror
|
|
echo " Path: ${location}"
|
|
echo " Codes: ${codes}"
|
|
echo " Verified: ${verified}"
|
|
echo "File Type: ${fileinfo}"
|
|
# 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"
|
|
## macOS/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
|
|
cp -i "${location}" "$( pwd )/"
|
|
echo "Copied to: $( pwd )/$( basename ${location} )"
|
|
echo -e "\n"
|
|
fi
|
|
else
|
|
## Feedback
|
|
echo "[!] Could not find EDB-ID #${edbdb}"
|
|
echo -e "\n"
|
|
fi
|
|
done
|
|
|
|
## Done
|
|
exit 0
|
|
fi
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
## Are we are doing an exact match ("-e")? If so, do NOT check folder path (Implies "-t").
|
|
[[ "${EXACT}" -eq 1 ]] \
|
|
&& FILEPATH=0
|
|
|
|
## Case sensitive ("-c"), remove the default flags
|
|
[[ "${SCASE}" -eq 1 ]] \
|
|
&& CASE_TAG_GREP="" \
|
|
&& CASE_TAG_FGREP=""
|
|
|
|
## Remove leading space
|
|
TAGS="$( echo ${TAGS} | sed -e 's/^[[:space:]]//' )"
|
|
|
|
## Check to see if the version of "sort" is supported
|
|
echo | sort -V 2>/dev/null >/dev/null
|
|
if [ $? -ne "0" ]; then
|
|
echo "[-] 'sort' doesn't support '-V'" 1>&2
|
|
echo "[i] Enabling '${progname} --strict'" 1>&2
|
|
FUZZY=0
|
|
fi
|
|
|
|
## Some regex to try and detect version
|
|
## Basic: major.minor[.build][.revision] // major.minor[.maintenance][.build] -- example: 1.2.3.4)
|
|
## Plus alphanumeric (e.g. alpha, beta): 1a, 2.2b, 3.3-c, 4.4-rc4, 5.5-r
|
|
for tag_in in ${TAGS}; do
|
|
if echo "${tag_in}" | grep ${REGEX_GREP} -q "^(\d+)(\.?\d*)(\.?\d*)((\.|\-)?(\w*))$"; then
|
|
## 1.2.3-4abc
|
|
VERSION=$( echo "${tag_in}" | grep ${REGEX_GREP} -o "^(\d+)(\.?\d*)(\.?\d*)((\.|\-)?(\w*))$" )
|
|
[[ -n "${VERSION}" ]] && [[ "${VERBOSE}" -eq 1 ]] \
|
|
&& echo "[i] Version ID: ${VERSION}"
|
|
|
|
## 1.2.3-4
|
|
CLEANVERSION=$( echo "${tag_in}" | grep ${REGEX_GREP} -o "^(\d*\.?)(\d*\.?)(\d*\.?)((\.|\-)?(\d+))" )
|
|
if [[ -n "${CLEANVERSION}" ]] && [[ "${CLEANVERSION}" != "${VERSION}" ]]; then
|
|
VERSION="${CLEANVERSION}"
|
|
|
|
[[ "${VERBOSE}" -eq 1 ]] \
|
|
&& echo "[i] Clean ID: ${VERSION}"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
## Did not get a version? If so, no point doing a fuzzy search
|
|
if [[ "${FUZZY}" -eq 1 ]] && [[ -z "${VERSION}" ]] && [[ "${VERBOSE}" -eq 1 ]]; then
|
|
echo "[i] Unable to detect version in terms: ${TAGS}" 1>&2
|
|
echo "[i] Enabling '${progname} --strict'" 1>&2
|
|
FUZZY=0
|
|
fi
|
|
|
|
## Is it just a single tag, disable fuzzy
|
|
[[ "${TAGS}" != *" "* ]] \
|
|
&& FUZZY=0
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
## Print header if in JSON ("--json")
|
|
[[ "${JSON}" -eq 1 ]] \
|
|
&& printf "{\n\t\"SEARCH\": \"${TAGS}\""
|
|
|
|
## Check for files_*.csv
|
|
arraylength="${#files_array[@]}"
|
|
for (( i=0; i<${arraylength}; i++ )); do
|
|
## Search
|
|
findresults "${files_array[${i}]}" "${path_array[${i}]}" "${name_array[${i}]}"
|
|
## Print results if in JSON ("--json") or if there are any results
|
|
if ([[ "${JSON}" -eq 1 ]] || [[ "${OUTPUT}" ]]); then
|
|
printresults "${name_array[${i}]}" "${path_array[${i}]}"
|
|
## Summary if NOT JSON ("--json")
|
|
elif [[ "${JSON}" -eq 0 ]]; then
|
|
echo "${name_array[${i}]}s: No Results"
|
|
fi
|
|
## Reset
|
|
COLOUR_TAG=""
|
|
done
|
|
|
|
## Print footer if in JSON ("--json")
|
|
[[ "${JSON}" -eq 1 ]] \
|
|
&& printf "\n}\n"
|
|
|
|
## Done
|
|
exit 0
|