Advertisement
Jackspade9624

Untitled

Mar 12th, 2025
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 33.32 KB | None | 0 0
  1. #!/usr/bin/env bash
  2. # @author: Danilo Basanta
  3. # @author-linkedin: https://www.linkedin.com/in/danilobasanta/
  4. # @author-github: https://github.com/dabasanta
  5.  
  6. # GLOBAL VARS - DO NOT MODIFY
  7. export DOMAIN="None"
  8. export EXTENDED_CHECKS=false
  9. export zone_transfer="No"
  10. export dns_servers_count=0
  11. export subdomains_count=0
  12. export webservers_count=0
  13. # Modify the DNS_BRUTE_THREADS variable to set the number of threads to use in the custom-dictionary attack.
  14. # By default, the script will use 15% of the number of records in the dictionary.
  15. export DNS_BRUTE_THREADS=0
  16.  
  17. # CRTL+C handler
  18. function scape() {
  19. clean
  20. }
  21. trap scape INT
  22.  
  23. # Creating the tmp directory
  24. tmpdir="/tmp/dnsexplorer"
  25. mkdir -p $tmpdir
  26. mkdir -p $tmpdir/whatweb
  27. mkdir -p $tmpdir/wafw00f
  28. tput civis
  29.  
  30. end="\e[0m"
  31. info="\e[36m[+]"
  32. cyan="\e[36m"
  33. output_color="\e[0m\e[36m"
  34. error="\e[1m\e[91m[!]"
  35. question="\e[93m"
  36. yellow="\e[1m\e[93m"
  37. green="\e[92m"
  38. ok="\e[1m\e[92m"
  39. resalted_output="\e[1;37m"
  40.  
  41. # Clean -exit- function
  42. clean(){
  43. echo -e "\n\n"
  44. rm -rf $tmpdir
  45. echo -e "${end}Happy hunting."
  46. tput cnorm
  47. exit 0
  48. }
  49.  
  50. # Custom dicctionary attack function
  51. dictionaryAttackCustom() { #5
  52. dicc_outfile="$tmpdir/dicctionary.results.txt"
  53. : > "$dicc_outfile"
  54. check=0
  55. while [ "$check" -eq 0 ]; do
  56. echo -e "$question"
  57. read -rp "Ingrese la ruta del archivo de diccionario> " dfile
  58. echo -e "$end"
  59.  
  60. if [ ! -f "$dfile" ] || [[ $(file "$dfile" | awk '{print $2}') != @(ASCII|Unicode) ]]; then
  61. echo -e "$error El archivo $dfile no existe o no es un archivo de texto ASCII/Unicode."
  62. else
  63. check=1
  64. fi
  65. done
  66.  
  67. lon_dicc=$(wc -l < "$dfile")
  68. tput civis
  69.  
  70. threads=$(echo "scale=0; ($lon_dicc * 0.15 + 0.5)/1" | bc)
  71. [ "$threads" -lt 1 ] && threads=1
  72. [ "$threads" -gt 40 ] && threads=40
  73. [ "$DNS_BRUTE_THREADS" -ne 0 ] && threads="$DNS_BRUTE_THREADS"
  74. echo -e " ${question}This file has $lon_dicc records, $threads parallel processes will be used to speed up the attack, press any key to start\n"
  75. read -n 1 -s -r -p ""
  76.  
  77. grep -Eva '[^a-zA-Z0-9\-_]' < "$dfile" | xargs -P $threads -I {} sh -c '
  78. GREEN="\033[32m"
  79. resalted_output="\e[1;37m"
  80. RESET="\033[0m"
  81. lon_dicc="$4"
  82. if host "$1.$2" 2>/dev/null | head -1 | grep -q "has address"; then
  83. echo "$1.$2" >> "$3"
  84. printf " [+] Found: ${resalted_output}%s.%s${RESET}\n" "$1" "$2"
  85. fi
  86.  
  87. echo "." >> /tmp/dnsexplorer/tracker.txt
  88. len=$(wc -l < /tmp/dnsexplorer/tracker.txt)
  89. dicc=$()
  90. percent=$(echo "scale=2; ($len / $lon_dicc) * 100" | bc)
  91. printf "${GREEN}[%.0f%%] Reading file...${RESET}\r" $percent
  92. ' _ {} "$DOMAIN" "$dicc_outfile" "$lon_dicc"
  93.  
  94. total=$(wc -l < $dicc_outfile)
  95. echo ""
  96. echo -e "${info} $total Subdomains found.${end}"
  97. echo ""
  98. crtSH "dicattack"
  99. }
  100.  
  101. # Dictionary attack function
  102. dictionaryAttack(){ #5
  103. tput civis
  104. bitquark="$tmpdir/bit.txt"
  105. dicc_outfile="$tmpdir/dicctionary.results.txt"
  106. echo "" > $dicc_outfile
  107. echo -e "\n${info}Using SECLISTS: bitquark-subdomains-top100000.txt${end}\n"
  108. curl -s https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/bitquark-subdomains-top100000.txt -o $bitquark
  109. l_bitq=$(cat $bitquark | wc -l)
  110. touch $tmpdir/tracker.txt
  111. if [ $l_bitq -gt 999 ];then
  112. grep -v '^ *#' < "$bitquark" | xargs -P 40 -I {} sh -c '
  113. GREEN="\033[32m"
  114. resalted_output="\e[1;37m"
  115. RESET="\033[0m"
  116.  
  117. if host "$1.$2" | head -1 | grep -q "has address"; then
  118. echo "$1.$2" >> "$3"
  119. printf " [+] Found: ${resalted_output}%s.%s${RESET}\n" "$1" "$2"
  120. fi
  121.  
  122. echo "." >> /tmp/dnsexplorer/tracker.txt
  123. len=$(wc -l < /tmp/dnsexplorer/tracker.txt)
  124. percent=$(echo "scale=2; ($len / 100000) * 100" | bc)
  125. printf "${GREEN}[%.0f%%] Reading file...${RESET}\r" $percent
  126. ' _ {} "$DOMAIN" "$dicc_outfile"
  127. total=$(wc -l < $dicc_outfile)
  128. echo ""
  129. echo -e "${info} $total Subdomains found.${end}"
  130. echo ""
  131. crtSH "dicattack"
  132. else
  133. echo -e "$error Could not download dictionary from seclists url.$end"
  134. dictionaryAttackCustom
  135. fi
  136. }
  137.  
  138. # DNS Brute Force handler function - Trigger the dictorinary attack
  139. bruteForceDNS(){
  140. echo -e "
  141. ██████╗ ██╗ ██████╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗ █████╗ ██████╗ ██╗ ██╗
  142. ██╔══██╗██║██╔════╝██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║██╔══██╗██╔══██╗╚██╗ ██╔╝
  143. ██║ ██║██║██║ ██║ ██║ ██║██║ ██║██╔██╗ ██║███████║██████╔╝ ╚████╔╝
  144. ██║ ██║██║██║ ██║ ██║ ██║██║ ██║██║╚██╗██║██╔══██║██╔══██╗ ╚██╔╝
  145. ██████╔╝██║╚██████╗╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║██║ ██║██║ ██║ ██║
  146. ╚═════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝
  147.  
  148. █████╗ ████████╗████████╗ █████╗ ██████╗██╗ ██╗
  149. ██╔══██╗╚══██╔══╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝
  150. ███████║ ██║ ██║ ███████║██║ █████╔╝
  151. ██╔══██║ ██║ ██║ ██╔══██║██║ ██╔═██╗
  152. ██║ ██║ ██║ ██║ ██║ ██║╚██████╗██║ ██╗
  153. ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
  154.  
  155. \n\t\t$output_color Fuzzing subdomains of $1[++]$end\n
  156. ${question}Do yo want to use a custom dictionary? [c=custom/d=default]$end
  157. $info Default: Provides a dictionary with the top 1000 of the most commonly used subdomains.
  158. $info Custom: Use your own custom dictionary.$question\n"
  159.  
  160. while true; do
  161. read -rp "[d/c]> " dc
  162. case $dc in
  163. [Dd]* ) dictionaryAttack; break;;
  164. [Cc]* ) dictionaryAttackCustom; break;;
  165. * ) echo -e "$error Please answer$green D$end \e[1m\e[91mor$end$green\e[1m C$end\e[1m\e[91m.$end\n";;
  166. esac
  167. done
  168. }
  169.  
  170. # Check if the subdomain has webserver
  171. check_web_server() { #8
  172. local end="\e[0m"
  173. local cyan="\e[1m\e[36m"
  174. local ok="\e[1m\e[92m"
  175. local resalted_output="\e[1;37m"
  176. local -r webservers_outfile=$(mktemp /tmp/dnsexplorer/XXXX.webservers.txt)
  177.  
  178. local response=$(curl -m 3 --head --silent --output /dev/null --write-out '%{http_code}' "http://${1}")
  179. if ((response >= 100 && response <= 599)); then
  180. [ "$protocol" == "https" ] && secure=" secure"
  181. echo -e "${end}The domain ${resalted_output}$1${end} has a web server. [${cyan}HTTP${end}:$ok$response$end]"
  182. echo "http://$1" >> "$webservers_outfile"
  183. fi
  184.  
  185. local response=$(curl -m 3 --head --silent --output /dev/null --write-out '%{http_code}' "https://${1}")
  186. if ((response >= 100 && response <= 599)); then
  187. [ "$protocol" == "https" ] && secure=" secure"
  188. echo -e "${end}The domain $resalted_output$1$end has a secure web server. [${cyan}HTTPS${end}:$ok$response$end]"
  189. echo "https://$1" >> "$webservers_outfile"
  190. fi
  191. }
  192. export -f check_web_server
  193.  
  194. # Abuse of crt.sh website - Internet connection required.
  195. crtSH(){ #7
  196. declare -r call_source="$1"
  197.  
  198. # Make sure the function is called from another function
  199. if [ -z "$call_source" ]; then
  200. echo -e "$error The function 'crtSH' must be called from another function.$end"
  201. return 1
  202. fi
  203.  
  204. crtshoutput="$tmpdir/crtsh-output.txt" # crt.sh RAW output
  205. crtsh_parsed_output="$tmpdir/crt.sh.reg" # crt.sh parsed output
  206. subdomain_file="$output/$DOMAIN.subdomains.txt" # Subdomains results without wildcard
  207. subdomain_wildcard_file="$output/$DOMAIN.wildcard.txt" # Subdomains results with wildcard
  208. final_outputfile="$output/$DOMAIN-all.txt" # Final output subdomain file
  209. webservers_outfile="$output/$DOMAIN.webservers" # Final output subdomain file
  210. SANs_tmp_file=$(mktemp $tmpdir/XXX.SAN.tmp) # Final output SAN certificates file
  211. new_SANs="$tmpdir/found_new_SAN.tmp"
  212.  
  213. if [ "$call_source" == "dicattack" ];then
  214. previus_result="$tmpdir/dicctionary.results.txt" # Dictionary attack results
  215. fi
  216. if [ "$call_source" == "zonetransfer" ];then
  217. previus_result="$output/$DOMAIN.zoneTransfer.txt" # Dictionary attack results
  218. #zonetransfer_tmp_data=$(cat "$previus_result"| grep -E "([a-zA-Z0-9.-]+)\.$DOMAIN.*" | awk '{print $1}' | sort -u | grep -v '_' | sed 's/\.$//')
  219. cat "$previus_result" | grep -E "([a-zA-Z0-9.-]+)\.$DOMAIN.*" | awk '{print $1}' | sort -u | grep -v '_' | sed 's/\.$//' > $tmpdir/zonetransfer.results.txt
  220. zonetransfer_tmp_data="$tmpdir/zonetransfer.results.txt"
  221. fi
  222. if [ "$call_source" == "None" ];then
  223. previus_result="None" # Dictionary attack results
  224. fi
  225.  
  226. echo "" > $subdomain_file && echo "" > $subdomain_wildcard_file && echo "" > $SANs_tmp_file && echo "" > $new_SANs
  227. echo -e "\n$info Finding subdomains - abusing Certificate Transparency Logs using https://crt.sh/\n$end"
  228.  
  229. max_retries=3
  230. retry_count=0
  231. crtsh_susscess=1
  232.  
  233. while [ $retry_count -lt $max_retries ]; do
  234. # Make sure we have a valid response
  235. crtsh_response=$(curl -s -w "%{size_download} %{http_code}" "https://crt.sh/?q=${DOMAIN}&output=json" -o $crtshoutput)
  236. crtsh_response_size=$(echo $crtsh_response | awk '{print $1}')
  237. crtsh_response_code=$(echo $crtsh_response | awk '{print $2}')
  238.  
  239. if [ "$crtsh_response_size" -gt 2 ] && [ "$crtsh_response_code" -eq 200 ]; then
  240. real_response_size=$(wc -c < $crtshoutput)
  241.  
  242. if [ "$real_response_size" -gt 2 ]; then
  243.  
  244. ### INTEGRAR VALIDACION DE SI EL ATAQUE DE DICCIONARIO SE LLEVO A CABO
  245.  
  246.  
  247. grep -o '"common_name":"[^"]*' $crtshoutput | awk -F ':"' '{ print $2 }' | sort -u > $crtsh_parsed_output
  248. size_crtsh_output=$(wc -l < $crtsh_parsed_output)
  249.  
  250. # Filter and sort subdomains only once
  251. sorted_subdomains=$(sort -u $crtsh_parsed_output)
  252.  
  253. # Check if there are wildcard subdomains
  254. if echo "$sorted_subdomains" | grep -q '^\*\.'; then
  255. # Calculate the size of the output list - with wildcard
  256. crtsh_parsed_output_wildcard_size=$(echo "$sorted_subdomains" | grep '^\*\.' | wc -l)
  257.  
  258. # Calculate the size of the output list - without wildcard
  259. crtsh_parsed_output_no_wildcard_size=$(echo "$sorted_subdomains" | grep -v '^\*\.' | wc -l)
  260.  
  261. # Save subdomains without wildcard
  262. echo "$sorted_subdomains" | sed 's/^\*\.//g' > $subdomain_file
  263.  
  264. # Save subdomains with wildcard
  265. echo "$sorted_subdomains" | grep '^\*\.' > $subdomain_wildcard_file
  266.  
  267. # Print results
  268. echo -e "$ok[$resalted_output$crtsh_parsed_output_no_wildcard_size$ok] subdomains found"
  269. echo -e "$ok[$resalted_output$crtsh_parsed_output_wildcard_size$ok] wildcard subdomains found"
  270. echo -e "$ok[$resalted_output$size_crtsh_output$ok] total subdomains"
  271. crtsh_susscess=0
  272. else
  273. # Save subdomains without wildcard
  274. echo "$sorted_subdomains" > $subdomain_file
  275.  
  276. # Print results
  277. echo -e "$info CRTsh results\n[$size_crtsh_output] total subdomains found"
  278. crtsh_susscess=0
  279. fi
  280.  
  281. if [ "$call_source" == "zonetransfer" ]; then
  282. cat "$zonetransfer_tmp_data" "$subdomain_wildcard_file" "$subdomain_file" | sed '/^$/d' | sed 's/*\.//g' | sort -u > "$final_outputfile"
  283. elif [ "$call_source" == "dicattack" ]; then
  284. cat "$previus_result" "$subdomain_wildcard_file" "$subdomain_file" | sed '/^$/d' | sed 's/*\.//g' | sort -u > "$final_outputfile"
  285. else
  286. cat "$subdomain_wildcard_file" "$subdomain_file" | sed '/^$/d' | sed 's/*\.//g' | sort -u > "$final_outputfile"
  287. fi
  288.  
  289. # Calculate the number of threads to use
  290. count_domains=$(wc -l < "$final_outputfile")
  291. threads=$(echo "scale=0; ($count_domains * 0.15 + 0.5)/1" | bc)
  292. [ "$threads" -lt 1 ] && threads=1
  293. [ "$threads" -gt 25 ] && threads=25
  294.  
  295. # Print info
  296. echo -e "$info Loaded $count_domains targets...$end\n\n"
  297.  
  298. # Execute the check_web_server function in parallel
  299. sort -u "$final_outputfile" | parallel -j "$threads" check_web_server
  300.  
  301. break
  302. else
  303. echo -e "$error Unable to connect to CTR.sh$end"
  304. retry_count=$((retry_count + 1))
  305. fi
  306. else
  307. echo -e "$error Unable to connect to CTR.sh$end"
  308. retry_count=$((retry_count + 1))
  309. fi
  310. done
  311.  
  312. # if we have reached the max number of retries
  313. if [ "$max_retries" -eq "$retry_count" ]; then
  314.  
  315. # if the previus_result variable is empty and the crtsh was not success
  316. if [[ "$call_source" == "None" && "$crtsh_susscess" -eq 1 ]]; then
  317.  
  318. # No previus result and crtsh was not success, try to enumerate the main domain
  319. echo -e "$error It was not possible to find subdomains using any conventional enumeration method. Running the extra mile......$end"
  320. check_web_server "$DOMAIN"
  321. cat /tmp/dnsexplorer/*.webservers.txt > "$webservers_outfile"
  322. webservers_count=$(wc -l < $webservers_outfile)
  323.  
  324. # Check if there are webservers
  325. if [ "$webservers_count" -gt 0 ]; then
  326. echo -e "$ok[$resalted_output$webservers_count$ok] webservers found"
  327. protocol=$(grep "https://" "$webservers_outfile" | head -1 | awk -F'://' '{print $1}')
  328.  
  329. # Check if there are https webservers
  330. if [ "$protocol" == "https" ]; then
  331. echo -e "$info Checking for SANs in the certificate$end"
  332. echo "" > "$SANs_tmp_file"
  333. grep "https://" "$webservers_outfile" | xargs -I {} -P 1 -n 1 bash -c 'checkCertificateSubjectsAlternativeNames "$1" "$2" "$3"' _ {} 443 "$SANs_tmp_file"
  334.  
  335. # Check if there are http webservers
  336. elif [ "$protocol" == "http" ]; then
  337. if $EXTENDED_CHECKS;then
  338. local -r webEnumOutputCSV="$output/$DOMAIN.webenum.csv"
  339. echo "URL,HTTPServer,IP,PoweredBy,X-Powered-By,Country,WAF" > "$webEnumOutputCSV"
  340.  
  341. count_webservers=$(wc -l < "$webservers_outfile")
  342. threads_webenum=$(echo "scale=0; ($count_webservers * 0.15 + 0.5)/1" | bc)
  343. [ "$threads_webenum" -lt 1 ] && threads=1
  344. [ "$threads_webenum" -gt 25 ] && threads=25
  345.  
  346. sort -u "$webservers_outfile" | parallel -j "$threads_webenum" webEnum
  347. cat $tmpdir/whatweb/*.csv >> "$webEnumOutputCSV"
  348.  
  349. printResults 0.05
  350. # FIN
  351. fi
  352. fi
  353. else
  354. echo -e "$error No webservers found$end"
  355. printResults 0.05
  356. clean
  357. # FIN
  358. fi
  359. else
  360.  
  361. # Check if the previus result is not empty
  362. if [ "$call_source" == "zonetransfer" ];then
  363. echo "$zonetransfer_tmp_data" > "$final_outputfile"
  364. count_domains=$(wc -l < "$final_outputfile")
  365. threads=$(echo "scale=0; ($count_domains * 0.15 + 0.5)/1" | bc)
  366. [ "$threads" -lt 1 ] && threads=1
  367. [ "$threads" -gt 25 ] && threads=25
  368. echo -e "$info Loaded $count_domains targets...$end\n\n"
  369. sort -u "$final_outputfile" | parallel -j "$threads" check_web_server
  370.  
  371. # Check if the previus result is not empty
  372. elif [ "$call_source" == "dicattack" ];then
  373. cp "$previus_result" "$final_outputfile"
  374. count_domains=$(wc -l < "$final_outputfile")
  375. threads=$(echo "scale=0; ($count_domains * 0.15 + 0.5)/1" | bc)
  376. [ "$threads" -lt 1 ] && threads=1
  377. [ "$threads" -gt 25 ] && threads=25
  378. echo -e "$info Loaded $count_domains targets...$end\n\n"
  379. sort -u "$final_outputfile" | parallel -j "$threads" check_web_server
  380. fi
  381. fi
  382. fi
  383.  
  384. # Even if crt.sh has no results, the script takes the data from the source and performs the web server check, even if dicct attacks was not successful.
  385.  
  386. # Merge all the webservers files
  387. cat /tmp/dnsexplorer/*.webservers.txt | sort -u > "$webservers_outfile"
  388. https_count=$(grep "https://" "$webservers_outfile" | wc -l)
  389. threads_enumSANs=$(echo "scale=0; ($https_count * 0.15 + 0.5)/1" | bc)
  390. [ "$threads_enumSANs" -lt 1 ] && threads=1
  391. [ "$threads_enumSANs" -gt 25 ] && threads=25
  392.  
  393. # Check if there are SANs
  394. grep "https://" "$webservers_outfile" | xargs -I {} -P "$threads_enumSANs" -n 1 bash -c 'checkCertificateSubjectsAlternativeNames "$1" "$2" "$3"' _ {} 443 "$SANs_tmp_file"
  395.  
  396. # Discover new SANs
  397. sort -u $SANs_tmp_file | sed 's/^\*\.//g' | grep -E '.*\.'$domain'\\b' > $new_SANs
  398. new_subdomains=$(mktemp $tmpdir/XXX.new_subdomains.tmp)
  399. curated_previus_webservers=$(mktemp $tmpdir/XXX.curated_previus_webservers.tmp)
  400. cat "$webservers_outfile" | sed 's/http\:\/\///g' | sed 's/https\:\/\///g' | sort -u > $curated_previus_webservers
  401. grep -Fxv -f $curated_previus_webservers $new_SANs > $new_subdomains
  402. count_newsubdomains=$(wc -l < $new_subdomains)
  403.  
  404. # Print results
  405. if [ "$count_newsubdomains" -gt 0 ]; then
  406. echo -e "\n${info}${count_newsubdomains} New subdomains was found${end}"
  407. cat $new_subdomains
  408. cat $new_subdomains >> $final_outputfile
  409. else
  410. echo -e "\n${cyan}No new subdomains found"
  411. fi
  412.  
  413. webservers_count=$(wc -l < $webservers_outfile)
  414. subdomains_count=$(wc -l < $final_outputfile)
  415.  
  416. # ExtendedChecks
  417. if $EXTENDED_CHECKS;then
  418. local -r webEnumOutputCSV="$output/$DOMAIN.webenum.csv"
  419. echo "URL,HTTPServer,IP,PoweredBy,X-Powered-By,Country,WAF" > "$webEnumOutputCSV"
  420.  
  421. # Calculate the number of threads to use and launch the webEnum function in parallel
  422. count_webservers=$(wc -l < "$webservers_outfile")
  423. threads_webenum=$(echo "scale=0; ($count_webservers * 0.15 + 0.5)/1" | bc)
  424. [ "$threads_webenum" -lt 1 ] && threads=1
  425. [ "$threads_webenum" -gt 25 ] && threads=25
  426. echo "" # Just a blank line :)
  427. sort -u "$webservers_outfile" | parallel -j "$threads_webenum" webEnum
  428.  
  429. # Merge all the CSV files
  430. cat $tmpdir/whatweb/*.csv >> "$webEnumOutputCSV"
  431. fi
  432.  
  433. printResults 0.05
  434. }
  435.  
  436. # Print results function
  437. printResults() {
  438. delay=$1
  439.  
  440. DNSExplorerResults="Domain:${DOMAIN}
  441. DNS Servers: ${dns_servers_count}
  442. Zone Transfer: ${zone_transfer}
  443. Subdomains: ${subdomains_count}
  444. Webservers: ${webservers_count}"
  445. echo -e "\e[92;1m"
  446. for i in $(seq 0 $((${#DNSExplorerResults} - 1))); do
  447. echo -ne "${DNSExplorerResults:$i:1}"
  448. sleep "$delay"
  449. done
  450. echo -e "\e[0m" # New line
  451. }
  452.  
  453. # Extended checks capabilities
  454. webEnum() { #9
  455. info="\e[36m[+]"
  456. end="\e[0m"
  457. if [ -z "$1" ]; then
  458. return 1
  459. fi
  460.  
  461. if [[ $1 != http://* && $1 != https://* ]]; then
  462. return 1
  463. fi
  464.  
  465. local -r wafwoof_txt_tmp_output=$(mktemp /tmp/dnsexplorer/wafw00f/XXX.wafw00f)
  466. local -r output_txt_webenum_file=$(mktemp /tmp/dnsexplorer/whatweb/XXX.csv)
  467.  
  468. # Check if the site has a WAF
  469. wafw00f "$1" -f json -o "$wafwoof_txt_tmp_output" > /dev/null 2>&1
  470. firewall_detected=$(cat "$wafwoof_txt_tmp_output" | grep -oE '"firewall": "[^"]+"' | awk -F': ' '{gsub(/[",]/, "", $2); print $2}')
  471. [ -z "$firewall_detected" ] && firewall_detected="None"
  472.  
  473. # Check webserver technologies
  474. local -r ww_result=$(whatweb --no-errors --open-timeout=7 --read-timeout=15 --colour=never "$1" 2>/dev/null)
  475.  
  476. echo -e "${info} Testing webserver ${end}$1"
  477.  
  478. # Get the webserver technologies
  479. httpserver=$(echo "$ww_result" | grep -o 'HTTPServer\[[^]]*\]' | cut -d'[' -f2 | cut -d']' -f1)
  480. [ -z "$httpserver" ] && httpserver="None"
  481. ip=$(echo "$ww_result" | grep -o 'IP\[[^]]*\]' | cut -d'[' -f2 | cut -d']' -f1 | head -1)
  482. [ -z "$ip" ] && ip="None"
  483. poweredby=$(echo "$ww_result" | grep -o 'PoweredBy\[[^]]*\]' | cut -d'[' -f2 | cut -d']' -f1)
  484. [ -z "$country" ] && country="None"
  485. xpoweredby=$(echo "$ww_result" | grep -o 'X-Powered-By\[[^]]*\]' | cut -d'[' -f2 | cut -d']' -f1)
  486. [ -z "$poweredby" ] && poweredby="None"
  487. country=$(echo "$ww_result" | grep -o 'Country\[[^]]*\]' | cut -d'[' -f2 | cut -d']' -f1)
  488. [ -z "$xpoweredby" ] && xpoweredby="None"
  489.  
  490. # Save results
  491. echo "\"$1\",\"$httpserver\",\"$ip\",\"$poweredby\",\"$xpoweredby\",\"$country\",\"$firewall_detected\"" > "$output_txt_webenum_file"
  492. }
  493. export -f webEnum
  494.  
  495. # Funcion for checking if the site has Subject Alternative Names
  496. checkCertificateSubjectsAlternativeNames() { #6
  497. port=$2
  498. declare output_file="$3"
  499.  
  500. if [ -z "$1" ]; then
  501. return 1
  502. fi
  503.  
  504. if [ -z "$port" ]; then
  505. port=443
  506. fi
  507.  
  508. if [ -z "$output_file" ]; then
  509. return 1
  510. fi
  511.  
  512. server=$(echo "$1" | sed 's/http:\/\///' | sed 's/https:\/\///' | sed 's/\/$//')
  513.  
  514. # Make sure opnessl can connect to the site
  515. connected=$(echo -n | openssl s_client -connect "$server:$port" 2>/dev/null | head -1 | awk -F "(" '{print $1}')
  516.  
  517. # Check if the site has a webserver
  518. if [[ "$connected" == "CONNECTED" ]];then
  519.  
  520. # Check if the site has DNS names
  521. DNS=$(echo -n | openssl s_client -connect "$server:$port" 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | openssl x509 -text 2> /dev/null | sed 's/\ //'|grep -i "DNS:" | awk -F ":" '{print $1}')
  522.  
  523. # Make sure the site has DNS names
  524. if [[ "$DNS" == "DNS" ]];then
  525.  
  526. # Get the number of Subject Alternative Names
  527. len_subjects=$(echo -n | openssl s_client -connect "$server:$port" 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | openssl x509 -text 2>/dev/null | grep "DNS:" 2>/dev/null | tr ',' '\n' | sed 's/\ //' | wc -l)
  528.  
  529. # Check if the site has almost one Subject Alternative Names
  530. if [ $len_subjects -ge 1 ];then
  531.  
  532. # Get the Subject Alternative Names
  533. SANs=$(echo -n | openssl s_client -connect "$server:$port" 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | openssl x509 -text | grep "DNS:"| tr ',' '\n' | sed 's/\ //' | sed 's/\s//g' | sed 's/DNS://g')
  534.  
  535. # return the Subject Alternative Names
  536. echo "$SANs" >> "$output_file"
  537. else
  538. return 1
  539. fi
  540. else
  541. return 1
  542. fi
  543. else
  544. return 1
  545. fi
  546. }
  547. export -f checkCertificateSubjectsAlternativeNames
  548.  
  549. # Initial recon
  550. initHostRecon(){ #3
  551. echo -e "\n${info} A records for ${resalted_output}${DOMAIN}${end}${cyan} domain${end}"
  552. # A Records
  553. host "$DOMAIN" | grep 'has address' | awk '{print $4}'
  554.  
  555. echo -e "\n${info} AAA records for ${resalted_output}${DOMAIN}${end}${cyan} domain${end}"
  556. # AAA Records
  557. if host "$DOMAIN" | grep 'IPv6' >/dev/null 2>&1;then
  558. host "$DOMAIN" | grep 'IPv6'| awk '{print $5}'
  559. else
  560. echo -e "$question Hosts $DOMAIN has not IPv6 address"
  561. fi
  562.  
  563. echo -e "\n${info} MX records for ${resalted_output}${DOMAIN}${end}${cyan} domain${end}"
  564. # MAIL Records
  565. if host -t MX "$DOMAIN" | grep 'mail' >/dev/null 2>&1;then
  566. host "$DOMAIN" | grep 'mail' | awk '{print $6,$7}'
  567. else
  568. echo -e "$question Hosts $DOMAIN has not mail server records\n"
  569. fi
  570.  
  571. echo -e "\n${info} CNAME records for ${resalted_output}${DOMAIN}${end}${cyan} domain${end}"
  572. # CNAME Records
  573. if host -t CNAME "$DOMAIN" | grep 'alias' >/dev/null 2>&1;then
  574. host -t CNAME "$DOMAIN" | awk '{print $1,$4,$6}'
  575. else
  576. echo -e "$question Hosts $DOMAIN has not alias records"
  577. fi
  578.  
  579. echo -e "\n${info} TXT records for ${resalted_output}${DOMAIN}${end}${cyan} domain${end}"
  580. ` # TXT Records`
  581. if host -t txt "$DOMAIN" | grep 'descriptive' >/dev/null 2>&1;then
  582. host -t txt "$DOMAIN" | grep 'descriptive'
  583. else
  584. echo -e "$question Hosts $DOMAIN has not description records\n"
  585. fi
  586. }
  587.  
  588. # Zone transfer attack function
  589. doZoneTransfer(){ #4
  590. success=1
  591. if host -t NS "$DOMAIN" | grep 'name server' >/dev/null 2>&1;then
  592. echo -e "\n${info} Enumerating DNS Servers..."
  593. host -t NS "$DOMAIN" | cut -d " " -f 4 > $tmpdir/NameServers.txt
  594.  
  595. ns=$(wc -l $tmpdir/NameServers.txt | awk '{print $1}')
  596.  
  597. if [ $ns -ge 1 ];then
  598. echo -e " ${green}[${ns}] DNS Servers was found, trying ZoneTransfer on these servers${end}"
  599. dns_servers_count=$ns
  600.  
  601. # Verify if the DNS servers accept zone transfer
  602. while IFS= read -r nameserver;do
  603. host -t axfr "$DOMAIN" "$nameserver" | grep -E 'Received ([0-9]+) bytes from [0-9\.]+#[0-9]+ in ([0-9]+) ms' >/dev/null 2>&1
  604.  
  605. if [ $? -eq 0 ];then
  606. axfr_tmp_file="$tmpdir/axfr.tmp" && echo "" > "$axfr_tmp_file"
  607. axfr_parsed_file="$tmpdir/parsed_axfr.tmp" && echo "" > "$axfr_tmp_file"
  608. host -t axfr "$DOMAIN" "$nameserver" > "$axfr_tmp_file"
  609. declare -a record_types=("A" "AAA" "AXFR" "CNAME" "MX" "NS" "SOA" "SRV" "TXT")
  610. total_records=0
  611. success=0
  612.  
  613. # SHow blinking message
  614. for i in {1..3}; do
  615. echo -ne "${ok}\e[5;7mNameServer ${nameserver} accept ZoneTransfer\e[0m"
  616. sleep 0.5
  617. echo -ne "\r\e[K"
  618. sleep 0.5
  619. done
  620.  
  621. for record_type in "${record_types[@]}"; do
  622. # Extract the current records of the current type
  623. current_records=$(cat "$axfr_tmp_file" | grep "IN[[:space:]]\+$record_type" | sort -u | awk '{print $1 "\t" $NF}' | column -t -s $'\t')
  624.  
  625. # Verify if there are records of the current type
  626. if [ -n "$current_records" ]; then
  627. count_current_records=$(cat "$axfr_tmp_file" | grep "IN[[:space:]]\+$record_type" | sort -u | wc -l)
  628. echo -e "${info} ${count_current_records} '$record_type' records found:${end}\n$current_records\n"
  629. echo -e "$current_records" >> "$axfr_parsed_file"
  630. total_records=$((total_records + count_current_records))
  631. fi
  632. done
  633. echo -e "${ok}[${total_records}] Records found in $nameserver$end\nPlease take note of the other DNS servers, they may do zone transfers as well.${end}"
  634. break
  635. else
  636. echo -e " $error NameServer $nameserver does not accept zone transfer$end"
  637. fi
  638. done < <(grep -v '^ *#' < $tmpdir/NameServers.txt)
  639. else
  640. echo -e "$error No DNS servers found for $DOMAIN$end"
  641. fi
  642.  
  643. # Check if the zone transfer was successful
  644. if [ $success -eq 0 ];then
  645. echo -e "\n$ok DNS zone transfer was possible, no bruteforce attacks on the subdomains are required. $end\n"
  646.  
  647. cp "$axfr_parsed_file" $output/$DOMAIN.zoneTransfer.txt
  648. zone_transfer="Yes"
  649. crtSH "zonetransfer"
  650. clean
  651.  
  652. # If the zonetransfer was not successful, then call to bruteforce
  653. else
  654. echo -e "\n$error DNS zone transfer was not possible, DNS servers are not accept it"
  655.  
  656. while true; do
  657. echo ""
  658. tput cnorm
  659. echo -e "$question"
  660. read -rp "Do you want to brute force subdomains? [Y/n]> " yn
  661. echo -e "$end"
  662.  
  663. case $yn in
  664. [Yy]* ) bruteForceDNS; clean; break;;
  665. [Nn]* ) crtSH "None"; clean;;
  666. * ) echo -e "$error Please answer yes or no.$end\n";;
  667. esac
  668. done
  669. fi
  670. fi
  671. }
  672.  
  673. # Init recon with 'host' command
  674. basicRecon(){ #2
  675. initHostRecon
  676. doZoneTransfer
  677. }
  678.  
  679. # Check dependencies: curl, host, parallel.
  680. checkDependencies() {
  681. declare -A dependencies=(
  682. ["host"]="bind-utils/dnsutils"
  683. ["curl"]="curl"
  684. ["parallel"]="Parallel"
  685. ["bc"]="BC"
  686. )
  687. for cmd in "${!dependencies[@]}"; do
  688. if ! command -v "$cmd" &> /dev/null; then
  689. echo -e "$error '$cmd' command is not available, please install the ${dependencies[$1]} package. $end"
  690. clean
  691. fi
  692. done
  693. }
  694.  
  695. # Check opt dependencies: wafw00f, whatweb.
  696. optDependencies() {
  697. declare -A dependencies=(
  698. ["whatweb"]="whatweb"
  699. ["wafw00f"]="wafw00f"
  700. )
  701. for cmd in "${!dependencies[@]}"; do
  702. if ! command -v "$cmd" &> /dev/null; then
  703. echo -e "$error '$cmd' command is not available, please install the ${dependencies[$1]} package for extended checks. $end"
  704. clean
  705. fi
  706. done
  707. }
  708.  
  709. banner(){
  710. echo -e "\e[91m
  711. ▓█████▄ ███▄ █ ██████ ▓█████ ▒██ ██▒ ██▓███ ██▓ ▒█████ ██▀███ ▓█████ ██▀███
  712. ▒██▀ ██▌ ██ ▀█ █ ▒██ ▒ ▓█ ▀ ▒▒ █ █ ▒░▓██░ ██▒▓██▒ ▒██▒ ██▒▓██ ▒ ██▒▓█ ▀ ▓██ ▒ ██▒
  713. ░██ █▌▓██ ▀█ ██▒░ ▓██▄ ▒███ ░░ █ ░▓██░ ██▓▒▒██░ ▒██░ ██▒▓██ ░▄█ ▒▒███ ▓██ ░▄█ ▒
  714. ░▓█▄ ▌▓██▒ ▐▌██▒ ▒ ██▒▒▓█ ▄ ░ █ █ ▒ ▒██▄█▓▒ ▒▒██░ ▒██ ██░▒██▀▀█▄ ▒▓█ ▄ ▒██▀▀█▄
  715. ░▒████▓ ▒██░ ▓██░▒██████▒▒░▒████▒▒██▒ ▒██▒▒██▒ ░ ░░██████▒░ ████▓▒░░██▓ ▒██▒░▒████▒░██▓ ▒██▒
  716. ▒▒▓ ▒ ░ ▒░ ▒ ▒ ▒ ▒▓▒ ▒ ░░░ ▒░ ░▒▒ ░ ░▓ ░▒▓▒░ ░ ░░ ▒░▓ ░░ ▒░▒░▒░ ░ ▒▓ ░▒▓░░░ ▒░ ░░ ▒▓ ░▒▓░
  717. ░ ▒ ▒ ░ ░░ ░ ▒░░ ░▒ ░ ░ ░ ░ ░░░ ░▒ ░░▒ ░ ░ ░ ▒ ░ ░ ▒ ▒░ ░▒ ░ ▒░ ░ ░ ░ ░▒ ░ ▒░
  718. ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ▒ ░░ ░ ░ ░░ ░
  719. ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
  720. v:2.0 ░ $end By: Danilo Basanta (https://github.com/dabasanta/) ░ (https://www.linkedin.com/in/danilobasanta/)\n\n
  721.  
  722.  
  723. \033[3mThe author does not promote malicious actions or the use of the script for illegal operations. Remember to always obtain prior permission from the target company's system administrators before performing any malicious actions.\033[0m\n\n"
  724. }
  725.  
  726. help(){ # Simply help function
  727. echo -e "\e[91m
  728. @@@ @@@ @@@@@@@@ @@@ @@@@@@@
  729. @@@ @@@ @@@@@@@@ @@@ @@@@@@@@
  730. @@! @@@ @@! @@! @@! @@@
  731. !@! @!@ !@! !@! !@! @!@
  732. @!@!@!@! @!!!:! @!! @!@@!@!
  733. !!!@!!!! !!!!!: !!! !!@!!!
  734. !!: !!! !!: !!: !!:
  735. :!: !:! :!: :!: :!:
  736. :: ::: :: :::: :: :::: ::
  737. : : : : :: :: : :: : : :
  738. v:2.0 ░ By: Danilo Basanta (https://github.com/dabasanta/) ░ (https://www.linkedin.com/in/danilobasanta/)\n\n${end}
  739. "
  740.  
  741. options=$(cat <<- EOM
  742. ${resalted_output}Usage:${end} ${green}\e[3m./DNSExplorer.sh <domain>${end}
  743.  
  744. ${resalted_output}Extended:${end} ${green}\e[3m./DNSExplorer.sh <domain> --extended${end}
  745.  
  746. ${resalted_output}Help:${end} ${green}\e[3m-h, --help Display this help and exit${end}
  747.  
  748. EOM
  749. )
  750. echo -e "$options"
  751. tput cnorm
  752. }
  753.  
  754. main(){ #1
  755. export output="$DOMAIN.out"
  756. mkdir -p $output
  757.  
  758. banner
  759. checkDependencies
  760. if ping -c 1 "$DOMAIN" > /dev/null 2>&1;then
  761. if host "$DOMAIN" > /dev/null 2>&1;then
  762. basicRecon "$DOMAIN"
  763. else
  764. echo -e "$error No route to host, please verify your DNS server or internet connection$end"
  765. clean
  766. fi
  767. else
  768. echo -e "${question}PING was not success, does server ignoring ICMP packets?$end"
  769. if host "$DOMAIN" > /dev/null 2>&1;then
  770. echo -e "${info}Running checks anyway$end\n"
  771. basicRecon "$DOMAIN"
  772. else
  773. echo -e "$error No route to host, please verify your DNS server or internet connection$end"
  774. clean
  775. fi
  776. fi
  777. }
  778.  
  779. # Init flow
  780. if [ "$1" = "-h" ] || [ "$1" = "help" ] || [ "$1" = "--help" ] || [ "$2" = "-h" ] || [ "$2" = "--help" ] || [ "$2" = "help" ]; then
  781. help
  782. elif [ $# -eq 2 ]; then
  783.  
  784. # Check if the second parameter is --extended
  785. if [ "$2" = "--extended" ]; then
  786. DOMAIN=$1
  787. EXTENDED_CHECKS=true
  788. optDependencies
  789. main "$DOMAIN"
  790. else
  791. echo -e "$error Parameter '$2' is not recognized $end"
  792. help
  793. tput cnorm
  794. exit 1
  795. fi
  796. elif [ $# -eq 0 ]; then
  797. help
  798. tput cnorm
  799. exit 1
  800. else
  801. DOMAIN=$1
  802. main "$DOMAIN"
  803. fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement