#!/bin/bash set -e ## Global var SCRIPT_NAME="${0##*/}" ## Style RED='\e[31m' GREEN='\e[32m' BLUE='\e[34m' YELLOW='\e[93m' BOLD='\e[1m' DIM='\e[2m' ITALIC='\e[3m' N='\e[0m' ## Util function die(){ if [ -n "$BASH_LINENO" ];then err "${SCRIPT_NAME}: ${BOLD}Error:Line:${BASH_LINENO[0]}${N} $*" >&2 else err "${SCRIPT_NAME}: ${BOLD}Error${N} $*" >&2 fi exit 1 } msg(){ echo -e "${GREEN}[+]${N} $*" } info(){ echo -e "${BLUE}[-]${N} $*" } err(){ echo -e "${RED}[x]${N} $*" >&2 } show_help() { echo "Usage: $SCRIPT_NAME [--xml XML] [-h] [-v]" echo echo "Options:" echo " --xml XML Specify the path to web.xml (default web.xml)" echo " -v, --verbose Increase verbosity" echo " -h, --help Display this help message" } show_progress() { local width=50 local percent=$(( 100 * $1 / $2 )) local filled=$(( width * $1 / $2 )) local empty=$(( width - filled )) local fill_char=$(printf " %.0s" {1..101}) printf "\r[" printf "\e[47m" printf "%.*s" "$filled" "$fill_char" printf "\e[0m" printf "%.*s" "$empty" "$fill_char" printf "] %3d%% (%d/%d)" "$percent" "$1" "$2" if [ "$1" -eq "$2" ]; then echo "" # move to next line when complete fi # Show progress arg 1 is count and arg 2 is the total # echo -en "\r${BLUE}[-]${N} Progress ${DIM}$percent${N}/${BOLD}100%${N}\e[K" # echo -en "\r[] $1/$2\e[K" } if ! command -v xq 2&>/dev/null;then err "Command xq not found, please run: ${BOLD}pip3 install yq${N}" fi if ! command -v jq 2&>/dev/null;then err "Command jq not found, please run: ${BOLD}sudo apt install -y jq${N}" fi WEB_XML="web.xml" VERBOSE=0 while [[ "$#" -gt 0 ]]; do case "$1" in -h) show_help exit 0 ;; --xml) if [[ -n "$2" && "$2" != -* ]]; then WEB_XML="$2" shift else echo "Error: --xml requires valid xml" exit 1 fi ;; -v|--verbose) VERBOSE=1 ;; *) echo "Unknown option: $1" show_help exit 1 ;; esac shift done if [ ! -f "$WEB_XML" ];then err "File not found: $WEB_XML" exit 1 fi if [ "$VERBOSE" -eq 1 ];then info "Processing $WEB_XML" info "Recovering ${GREEN}servlets${N} ${ITALIC}${DIM}(can take some time)${N}" fi # Parse all servlet mappings into a lookup: servlet-name -> list of url-patterns declare -A servlet_class_map declare -A servlet_urls_map xq_output=$(xq -c ' .["web-app"]["servlet"][] as $s | { name: $s["servlet-name"], class: $s["servlet-class"], urls: ( .["web-app"]["servlet-mapping"] | map(select(.["servlet-name"] == $s["servlet-name"])["url-pattern"]) | flatten ) } ' $WEB_XML) count=1 total_lines=$(printf "%s\n" "$xq_output" |wc -l) while IFS= read -r entry; do if [ "$VERBOSE" -eq 1 ];then show_progress "$count" "$total_lines" let "count=count+1" fi name=$(jq -r '.name' <<< "$entry") class=$(jq -r '.class' <<< "$entry") urls=$(jq -r '.urls[]' <<< "$entry" | paste -sd "|" -) servlet_class_map["$name"]="$class" servlet_urls_map["$name"]="$urls" done < <(printf "%s\n" "$xq_output") if [ "$VERBOSE" -eq 1 ];then info "Recovering ${GREEN}filters${N}" fi # Parse all filters and map filter-name to list of patterns declare -A filter_class_map declare -A filter_patterns_map xq_output=$(xq -c ' .["web-app"]["filter"][] as $f | { name: $f["filter-name"], class: $f["filter-class"], patterns: ( .["web-app"]["filter-mapping"] | map(select(.["filter-name"] == $f["filter-name"])["url-pattern"]) | flatten ) } ' $WEB_XML) count=1 total_lines=$(printf "%s\n" "$xq_output" |wc -l) while IFS= read -r entry; do if [ "$VERBOSE" -eq 1 ];then show_progress "$count" "$total_lines" let "count=count+1" fi name=$(jq -r '.name' <<< "$entry") class=$(jq -r '.class' <<< "$entry") patterns=$(jq -r '.patterns[]' <<< "$entry" | paste -sd "|" -) filter_class_map["$name"]="$class" filter_patterns_map["$name"]="$patterns" done < <(printf "%s\n" "$xq_output") # Process each servlet for servlet in "${!servlet_class_map[@]}"; do class="${servlet_class_map[$servlet]}" IFS='|' read -ra urls <<< "${servlet_urls_map[$servlet]}" declare -A filter_set=() # Match servlet URLs with all filter patterns for filter in "${!filter_patterns_map[@]}"; do IFS='|' read -ra patterns <<< "${filter_patterns_map[$filter]}" for u in "${urls[@]}"; do for p in "${patterns[@]}"; do regex="^${p//\*/.*}$" if [[ "$u" =~ $regex ]]; then filter_set["$filter"]=1 fi done done done # Output result echo -e "Servlet : ${GREEN}${servlet}${N}" echo -e " Class : ${BOLD}${class}${N}" echo -e " URLs :" for u in "${urls[@]}"; do echo " - $u"; done echo " Filters:" if [[ ${#filter_set[@]} -eq 0 ]]; then echo " (none)" else for f in "${!filter_set[@]}"; do echo " - $f" done fi echo done