├── SECURITY.md ├── .obsidian ├── app.json ├── hotkeys.json ├── appearance.json ├── core-plugins.json ├── core-plugins-migration.json └── workspace.json ├── README.md └── zwatcher.sh /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.obsidian/app.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.obsidian/hotkeys.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.obsidian/appearance.json: -------------------------------------------------------------------------------- 1 | { 2 | "accentColor": "" 3 | } -------------------------------------------------------------------------------- /.obsidian/core-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "file-explorer", 3 | "global-search", 4 | "switcher", 5 | "graph", 6 | "backlink", 7 | "canvas", 8 | "outgoing-link", 9 | "tag-pane", 10 | "page-preview", 11 | "daily-notes", 12 | "templates", 13 | "note-composer", 14 | "command-palette", 15 | "editor-status", 16 | "bookmarks", 17 | "outline", 18 | "word-count", 19 | "file-recovery" 20 | ] -------------------------------------------------------------------------------- /.obsidian/core-plugins-migration.json: -------------------------------------------------------------------------------- 1 | { 2 | "file-explorer": true, 3 | "global-search": true, 4 | "switcher": true, 5 | "graph": true, 6 | "backlink": true, 7 | "canvas": true, 8 | "outgoing-link": true, 9 | "tag-pane": true, 10 | "properties": false, 11 | "page-preview": true, 12 | "daily-notes": true, 13 | "templates": true, 14 | "note-composer": true, 15 | "command-palette": true, 16 | "slash-command": false, 17 | "editor-status": true, 18 | "bookmarks": true, 19 | "markdown-importer": false, 20 | "zk-prefixer": false, 21 | "random-note": false, 22 | "outline": true, 23 | "word-count": true, 24 | "slides": false, 25 | "audio-recorder": false, 26 | "workspaces": false, 27 | "file-recovery": true, 28 | "publish": false, 29 | "sync": false 30 | } -------------------------------------------------------------------------------- /.obsidian/workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": { 3 | "id": "5bef82b35b47f53d", 4 | "type": "split", 5 | "children": [ 6 | { 7 | "id": "2ed7797eb02f7252", 8 | "type": "tabs", 9 | "children": [ 10 | { 11 | "id": "1bcd99ca6a4d1b5e", 12 | "type": "leaf", 13 | "state": { 14 | "type": "markdown", 15 | "state": { 16 | "file": "README.md", 17 | "mode": "source", 18 | "source": true 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | ], 25 | "direction": "vertical" 26 | }, 27 | "left": { 28 | "id": "ecf4bfe6aca546a3", 29 | "type": "split", 30 | "children": [ 31 | { 32 | "id": "10dd97e35c6ca2e6", 33 | "type": "tabs", 34 | "children": [ 35 | { 36 | "id": "183801c2e0035409", 37 | "type": "leaf", 38 | "state": { 39 | "type": "file-explorer", 40 | "state": { 41 | "sortOrder": "alphabetical" 42 | } 43 | } 44 | }, 45 | { 46 | "id": "093b37172ff5c0d0", 47 | "type": "leaf", 48 | "state": { 49 | "type": "search", 50 | "state": { 51 | "query": "", 52 | "matchingCase": false, 53 | "explainSearch": false, 54 | "collapseAll": false, 55 | "extraContext": false, 56 | "sortOrder": "alphabetical" 57 | } 58 | } 59 | }, 60 | { 61 | "id": "cef7aae2a6e46ee4", 62 | "type": "leaf", 63 | "state": { 64 | "type": "bookmarks", 65 | "state": {} 66 | } 67 | } 68 | ] 69 | } 70 | ], 71 | "direction": "horizontal", 72 | "width": 300 73 | }, 74 | "right": { 75 | "id": "60632b7747fbd18e", 76 | "type": "split", 77 | "children": [ 78 | { 79 | "id": "832815b78373560f", 80 | "type": "tabs", 81 | "children": [ 82 | { 83 | "id": "bd48b2f144ab6137", 84 | "type": "leaf", 85 | "state": { 86 | "type": "backlink", 87 | "state": { 88 | "file": "README.md", 89 | "collapseAll": false, 90 | "extraContext": false, 91 | "sortOrder": "alphabetical", 92 | "showSearch": false, 93 | "searchQuery": "", 94 | "backlinkCollapsed": false, 95 | "unlinkedCollapsed": true 96 | } 97 | } 98 | }, 99 | { 100 | "id": "fc32026915882fc5", 101 | "type": "leaf", 102 | "state": { 103 | "type": "outgoing-link", 104 | "state": { 105 | "file": "README.md", 106 | "linksCollapsed": false, 107 | "unlinkedCollapsed": true 108 | } 109 | } 110 | }, 111 | { 112 | "id": "1aab74e13a00678a", 113 | "type": "leaf", 114 | "state": { 115 | "type": "tag", 116 | "state": { 117 | "sortOrder": "frequency", 118 | "useHierarchy": true 119 | } 120 | } 121 | }, 122 | { 123 | "id": "392bea0608d4f796", 124 | "type": "leaf", 125 | "state": { 126 | "type": "outline", 127 | "state": { 128 | "file": "README.md" 129 | } 130 | } 131 | } 132 | ] 133 | } 134 | ], 135 | "direction": "horizontal", 136 | "width": 300, 137 | "collapsed": true 138 | }, 139 | "left-ribbon": { 140 | "hiddenItems": { 141 | "switcher:Open quick switcher": false, 142 | "graph:Open graph view": false, 143 | "canvas:Create new canvas": false, 144 | "daily-notes:Open today's daily note": false, 145 | "templates:Insert template": false, 146 | "command-palette:Open command palette": false 147 | } 148 | }, 149 | "active": "1bcd99ca6a4d1b5e", 150 | "lastOpenFiles": [] 151 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zWATCHER 2 | 3 | zWATCHER is a simple bash script that allows you to monitor a sub/domain or a list of sub/domains or java script files for changes in status codes and content length. If any changes are detected, it will notify you. 4 | 5 | # [![Twitter Follow](https://img.shields.io/twitter/follow/71ntr?style=social)](https://twitter.com/71ntr) [![LinkedIn Connect](https://img.shields.io/badge/LinkedIn-Connect-blue)](https://www.linkedin.com/in/71ntr/) 6 | ## Features 7 | 8 | - Monitor a single sub/domain or a list of sub/domains for changes. 9 | - Monitor a JS "java script" files for changes. 10 | - Compare HTTP status codes and content length to detect changes. 11 | - You can use any [httpx](https://github.com/projectdiscovery/httpx/releases) tool flag in comparing and changes. 12 | - Notify the user when changes are detected. 13 | - Specify the scan interval in seconds. 14 | - Save scan results to an output file. 15 | 16 | ## Prerequisites 17 | 18 | - `httpx`: Make sure you have `httpx` installed. You can install it using `go` or use the pre-built binary from the following link: [httpx](https://github.com/projectdiscovery/httpx/releases). 19 | - `notify`: Make sure you have `notify` installed. You can install it using `go` or use the pre-built binary from the following link: [notify](https://github.com/projectdiscovery/notify). 20 | 21 | ## Usage 22 | 23 | ```bash 24 | Usage: zwatcher.sh [OPTIONS] 25 | 26 | Options: 27 | -u Specify a single domain to scan 28 | -l Specify a file containing a list of domains to scan 29 | -s Specify the scan interval in seconds 30 | -n Specify the notification ID 31 | -o Specify the output file to save scan results 32 | -h Display this help message 33 | httpx-flags 34 | -sc response status-code 35 | -cl response content-length 36 | -title http title 37 | you can all httpx flags in zwatcher 38 | Example: 39 | ./zwatcher.sh -u x.com -s 60 -o out.txt -mc 200 -sc -title -n notifyid 40 | ./zwatcher.sh -u x.com/script.js -s 60 -o out.txt -mc 200 -sc -title -n notifyid 41 | 42 | ``` 43 | 44 | ## Examples 45 | 46 | 1. Monitor a single domain with a scan interval of 60 seconds and save the results to `scanresults.txt`: 47 | 48 | ```bash 49 | ./zwatcher.sh -u example.com -s 60 -o scanresults.txt 50 | ``` 51 | 52 | 1. Monitor a list of domains from a file called `domains.txt` with a scan interval of 120 seconds and save the results to `scanresults.txt`: 53 | 54 | ```bash 55 | ./zwatcher.sh -l domains.txt -s 120 -o scanresults.txt 56 | ``` 57 | 58 | ### Examples for javascript files 59 | 60 | 1. Monitor a list of js files in list called `js-urls.txt` with a scan interval of 120 seconds and save the results to `scanresults.txt`: 61 | 62 | ```bash 63 | ./zwatcher.sh -l js-urls.txt -s 120 -o scanresults.txt 64 | ``` 65 | 66 | 1. Monitor one js file `https://hackerone/scripts/admin.js` with a scan interval of 120 seconds and save the results to `scanresults.txt`: 67 | 68 | ```bash 69 | ./zwatcher.sh -u https://hackerone/scripts/admin.js -s 120 -o scanresults.txt 70 | ``` 71 | 72 | 73 | ## Notifications 74 | 75 | zwatcher can notify you when changes are detected. To enable notifications, you need to have the `notify` command installed, which allows sending notifications to the desktop. 76 | 77 | The `notify` command can be installed using the following command: 78 | 79 | ```arduino 80 | go install -v github.com/projectdiscovery/notify/cmd/notify@latest 81 | ``` 82 | 83 | After installing `notify`, you can specify the notification ID "from notify config file" using the `-n` flag: 84 | 85 | ```bash 86 | ./zwatcher.sh -u example.com -s 60 -o scanresults.txt -n mynotifyid 87 | ``` 88 | 89 | When changes are detected, zwatcher will send a notification with notify. 90 | 91 | ## Notes 92 | 93 | - If the output file (`o` flag) does not exist, zwatcher will create it when the first scan is completed. 94 | - If you specify a file containing a list of domains (`l` flag), zwatcher will continuously scan each domain in the list with the specified scan interval. 95 | 96 | ## Disclaimer 97 | 98 | This tool is for educational and monitoring purposes only. Use it responsibly and only on domains you have permission to scan. The author is not responsible for any misuse or damage caused by this script. 99 | -------------------------------------------------------------------------------- /zwatcher.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | outputfile="zwatcheroutput.txt" 4 | 5 | RESET="\e[0m" 6 | GREEN="\e[1;32m" 7 | RED="\e[1;31m" 8 | YELLOW="\e[1;33m" 9 | CYAN="\e[1;36m" 10 | PLUS="++++++++++" 11 | 12 | displaybanner() { 13 | echo -e "${RED}" 14 | cat << "BANNER" 15 | ███████╗██╗ ██╗████████╗ ██████╗██╗ ██╗██████╗ 16 | ╚══███╔╝██║ ██║╚══██╔══╝██╔════╝██║ ██║██╔══██╗ 17 | ███╔╝ ██║ █╗ ██║ ██║ ██║ ███████║██████╔╝ 18 | ███╔╝ ██║███╗██║ ██║ ██║ ██╔══██║██╔══██╗ 19 | ███████╗╚███╔███╔╝ ██║ ╚██████╗██║ ██║██║ ██║ 20 | ╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ v2.1 21 | BY H1NTR0X01 @71ntr 22 | SECURITY is a myth. Hacking is not. 23 | BANNER 24 | echo -e "${RESET}" 25 | } 26 | 27 | displayusage() { 28 | echo -e "${CYAN}Usage: zwatcher.sh [OPTIONS]" 29 | echo 30 | echo -e "Options:" 31 | echo -e " -u Specify a single domain to scan" 32 | echo -e " -l Specify a file containing a list of domains to scan" 33 | echo -e " -s Specify the scan interval in seconds" 34 | echo -e " -n Specify the notification ID" 35 | echo -e " -o Specify the output file to save scan results" 36 | echo -e " -h Display this help message" 37 | echo -e "httpx-flags" 38 | echo -e " -sc response status-code" 39 | echo -e " -cl response content-length" 40 | echo -e " -title http title" 41 | echo -e " you can add httpx flags in zwatcher" 42 | echo -e "Example:" 43 | echo -e "${RED} ./zwatcher.sh -u x.com -s 60 -o out.txt -mc 200 -sc -title" 44 | echo -e "${RED} ./zwatcher.sh -u x.com -s 60 -o out.txt -mc 200 -sc -title -n notifyid" 45 | echo -e "${RED} ./zwatcher.sh -u x.com/script.js -s 60 -o out.txt -mc 200 -sc -title -n notifyid" 46 | } 47 | 48 | check_dependencies() { 49 | local missing=0 50 | for cmd in httpx notify anew; do 51 | if ! command -v "$cmd" &> /dev/null; then 52 | echo -e "${RED}Error: $cmd is not installed or not in PATH.${RESET}" 53 | missing=1 54 | fi 55 | done 56 | if [ $missing -eq 1 ]; then 57 | exit 1 58 | fi 59 | } 60 | 61 | runhttpx() { 62 | if [ -e "$outputfile" ]; then 63 | echo -e "${GREEN}STARTING SCAN...${RESET}" 64 | else 65 | echo -e "${RED} CREATING : $outputfile${RESET}" 66 | # Initial scan 67 | if [ -n "$DOMAIN" ]; then 68 | httpx -silent "${httpx_flags[@]}" -u "$DOMAIN" | tee "$outputfile" 69 | elif [ -n "$LIST_FILE" ]; then 70 | httpx -silent "${httpx_flags[@]}" -l "$LIST_FILE" | tee "$outputfile" 71 | fi 72 | echo -e "${GREEN}FIRST SCAN COMPLETED & SAVED >> $outputfile${RESET}" 73 | fi 74 | 75 | # Subsequent scans to temp file 76 | if [ -n "$DOMAIN" ]; then 77 | httpx -silent "${httpx_flags[@]}" -u "$DOMAIN" > "$(dirname "$outputfile")/.tmp-$(basename "$outputfile")" 78 | elif [ -n "$LIST_FILE" ]; then 79 | httpx -silent "${httpx_flags[@]}" -l "$LIST_FILE" > "$(dirname "$outputfile")/.tmp-$(basename "$outputfile")" 80 | fi 81 | } 82 | 83 | comparescans() { 84 | diffoutput=$(cat "$(dirname "$outputfile")/.tmp-$(basename "$outputfile")" | anew "$outputfile") 85 | if [ -z "$diffoutput" ]; then 86 | echo -e "${YELLOW}NOTHING NEW FOUND ${RESET}" 87 | echo -e "${CYAN}SLEEPING FOR : $SLEEP_INTERVAL SECONDS${RESET}" 88 | else 89 | echo -e "${CYAN}NEW CHANGES FOUND...${RESET}" 90 | echo -e "${GREEN}$PLUS${RESET}" 91 | echo -e "$diffoutput" 92 | echo -e "${GREEN}$PLUS${RESET}" 93 | 94 | if [ -n "$notifyid" ]; then 95 | echo -e "${CYAN}zwatcher found: $diffoutput${RESET}" | notify -id "$notifyid" > /dev/null 2>&1 96 | else 97 | echo -e "${YELLOW}SKIPPING NOTIFICATION...${RESET}" 98 | fi 99 | echo -e "${CYAN}SLEEPING FOR : $SLEEP_INTERVAL SECONDS${RESET}" 100 | fi 101 | } 102 | 103 | if [ $# -eq 0 ]; then 104 | displaybanner 105 | displayusage 106 | exit 1 107 | fi 108 | 109 | check_dependencies 110 | 111 | while [[ $# -gt 0 ]]; do 112 | case "$1" in 113 | -u) DOMAIN="$2"; shift ;; 114 | -l) 115 | LIST_FILE="$2" 116 | if [ ! -f "$LIST_FILE" ]; then 117 | echo -e "\n${RED}FILE NOT FOUND! : $LIST_FILE${RESET}" >&2 118 | exit 1 119 | fi 120 | shift 121 | ;; 122 | -s) SLEEP_INTERVAL="$2"; shift ;; 123 | -n) notifyid="$2"; shift ;; 124 | -o) 125 | outputfile="$2" 126 | if [ -z "$outputfile" ]; then 127 | echo -e "\n${RED}NO OUTPUT FILE SPECIFIED!${RESET}" >&2 128 | exit 1 129 | fi 130 | if [ ! -w "$(dirname "$outputfile")" ] && [ -e "$(dirname "$outputfile")" ]; then 131 | # Check if directory is writable only if it exists, otherwise we assume current dir or valid path 132 | # Actually, simpler check: 133 | touch "$outputfile" 2>/dev/null 134 | if [ $? -ne 0 ]; then 135 | echo -e "\n${RED}CANNOT WRITE TO FILE : $outputfile${RESET}" >&2 136 | exit 1 137 | fi 138 | fi 139 | shift 140 | ;; 141 | -sc) httpx_flags+=("-sc") ;; 142 | -cl) httpx_flags+=("-cl") ;; 143 | -title) httpx_flags+=("-title") ;; 144 | -mc) 145 | shift 146 | mc_arg="$1" 147 | httpx_flags+=("-mc" "$mc_arg") 148 | ;; 149 | -ml) 150 | shift 151 | ml_arg="$1" 152 | httpx_flags+=("-ml" "$ml_arg") 153 | ;; 154 | -mlc) 155 | shift 156 | mlc_arg="$1" 157 | httpx_flags+=("-mlc" "$mlc_arg") 158 | ;; 159 | -mwc) 160 | shift 161 | mwc_arg="$1" 162 | httpx_flags+=("-mwc" "$mwc_arg") 163 | ;; 164 | -mfc) 165 | shift 166 | mfc_arg="$1" 167 | httpx_flags+=("-mfc" "$mfc_arg") 168 | ;; 169 | -ms) 170 | shift 171 | ms_arg="$1" 172 | httpx_flags+=("-ms" "$ms_arg") 173 | ;; 174 | -mr) 175 | shift 176 | mr_arg="$1" 177 | httpx_flags+=("-mr" "$mr_arg") 178 | ;; 179 | -mcdn) 180 | shift 181 | mcdn_arg="$1" 182 | httpx_flags+=("-mcdn" "$mcdn_arg") 183 | ;; 184 | -mrt) 185 | shift 186 | mrt_arg="$1" 187 | httpx_flags+=("-mrt" "$mrt_arg") 188 | ;; 189 | -mdc) 190 | shift 191 | mdc_arg="$1" 192 | httpx_flags+=("-mdc" "$mdc_arg") 193 | ;; 194 | -er) 195 | shift 196 | er_arg="$1" 197 | httpx_flags+=("-er" "$er_arg") 198 | ;; 199 | -ep) 200 | shift 201 | ep_arg="$1" 202 | httpx_flags+=("-ep" "$ep_arg") 203 | ;; 204 | -fc) 205 | shift 206 | fc_arg="$1" 207 | httpx_flags+=("-fc" "$fc_arg") 208 | ;; 209 | -fep) httpx_flags+=("-fep") ;; 210 | -fl) 211 | shift 212 | fl_arg="$1" 213 | httpx_flags+=("-fl" "$fl_arg") 214 | ;; 215 | -flc) 216 | shift 217 | flc_arg="$1" 218 | httpx_flags+=("-flc" "$flc_arg") 219 | ;; 220 | -fwc) 221 | shift 222 | fwc_arg="$1" 223 | httpx_flags+=("-fwc" "$fwc_arg") 224 | ;; 225 | -ffc) 226 | shift 227 | ffc_arg="$1" 228 | httpx_flags+=("-ffc" "$ffc_arg") 229 | ;; 230 | -fs) 231 | shift 232 | fs_arg="$1" 233 | httpx_flags+=("-fs" "$fs_arg") 234 | ;; 235 | -fe) 236 | shift 237 | fe_arg="$1" 238 | httpx_flags+=("-fe" "$fe_arg") 239 | ;; 240 | -fcdn) 241 | shift 242 | fcdn_arg="$1" 243 | httpx_flags+=("-fcdn" "$fcdn_arg") 244 | ;; 245 | -frt) 246 | shift 247 | frt_arg="$1" 248 | httpx_flags+=("-frt" "$frt_arg") 249 | ;; 250 | -fdc) 251 | shift 252 | fdc_arg="$1" 253 | httpx_flags+=("-fdc" "$fdc_arg") 254 | ;; 255 | -strip) httpx_flags+=("-strip") ;; 256 | -t) 257 | shift 258 | t_arg="$1" 259 | httpx_flags+=("-t" "$t_arg") 260 | ;; 261 | -rl) 262 | shift 263 | rl_arg="$1" 264 | httpx_flags+=("-rl" "$rl_arg") 265 | ;; 266 | -rlm) 267 | shift 268 | rlm_arg="$1" 269 | httpx_flags+=("-rlm" "$rlm_arg") 270 | ;; 271 | -h) 272 | displaybanner 273 | displayusage 274 | exit 0 275 | ;; 276 | \?) 277 | echo -e "\n${RED}INVALID OPTION -$OPTARG${RESET}" >&2 278 | displayusage 279 | exit 1 280 | ;; 281 | :) 282 | echo -e "\n${RED}OPTION -$OPTARG REQUIRES AN ARGUMENT!${RESET}" >&2 283 | displayusage 284 | exit 1 285 | ;; 286 | *) 287 | echo -e "\n${RED}FLAG PROVIDED BUT NOT DEFINED: $1${RESET}" >&2 288 | exit 1 289 | ;; 290 | esac 291 | shift 292 | done 293 | 294 | displaybanner 295 | 296 | if [ -z "$DOMAIN" ] && [ -z "$LIST_FILE" ]; then 297 | echo -e "${RED}Error: You must specify either a domain (-u) or a list of domains (-l).${RESET}" 298 | displayusage 299 | exit 1 300 | fi 301 | 302 | if [ -z "$SLEEP_INTERVAL" ]; then 303 | SLEEP_INTERVAL=60 # Default to 60 seconds if not specified 304 | fi 305 | 306 | while true; do 307 | runhttpx 308 | comparescans 309 | sleep "$SLEEP_INTERVAL" 310 | done 311 | --------------------------------------------------------------------------------