NetScaler responder policy - block PHP / web shell requests ============================================================ ------------------------------------------------------------ STEP 1 - Audit log action (records who is being blocked) ------------------------------------------------------------ add audit messageaction act_log_php ALERT "\"BLOCKED php/webshell request: \" + CLIENT.IP.SRC + \" \" + HTTP.REQ.METHOD + \" \" + HTTP.REQ.URL.HTTP_URL_SAFE" -logtoNewnslog YES ------------------------------------------------------------ STEP 2 - Responder policy (starts in LOG-ONLY mode: NOOP) ------------------------------------------------------------ Matches: - PHP-type extensions in the path (.php, .php5, .phtml, .phar), incl. URL-encoded - POST requests to .deb / .sig files (disguised shells; legit downloads use GET) - Hidden path segments such as /.ctxs.receiver add responder policy pol_block_php "HTTP.REQ.URL.PATH.SET_TEXT_MODE(URLENCODED).DECODE_USING_TEXT_MODE.REGEX_MATCH(re#\.(php\d?|phtml|phar)(/|$)#i) || (HTTP.REQ.METHOD.EQ(POST) && HTTP.REQ.URL.PATH.SET_TEXT_MODE(IGNORECASE).REGEX_MATCH(re#\.(deb|sig)$#)) || HTTP.REQ.URL.PATH.REGEX_MATCH(re#/\.[^/]#)" NOOP -logAction act_log_php FALLBACK - if the command above is rejected on your build, use this simpler version (drops the URL-decode step): add responder policy pol_block_php "HTTP.REQ.URL.PATH.SET_TEXT_MODE(IGNORECASE).REGEX_MATCH(re#\.(php\d?|phtml|phar)(/|$)#) || (HTTP.REQ.METHOD.EQ(POST) && HTTP.REQ.URL.PATH.SET_TEXT_MODE(IGNORECASE).REGEX_MATCH(re#\.(deb|sig)$#)) || HTTP.REQ.URL.PATH.REGEX_MATCH(re#/\.[^/]#)" NOOP -logAction act_log_php ------------------------------------------------------------ STEP 3 - Bind the policy (choose ONE) ------------------------------------------------------------ Option A - Global (covers Gateway, AAA and LB vservers): bind responder global pol_block_php 10 END -type REQ_OVERRIDE Option B - Gateway vserver only (replace ): bind vpn vserver -policy pol_block_php -priority 10 -gotoPriorityExpression END -type REQUEST ------------------------------------------------------------ STEP 4 - Monitor for a day or two (still log-only) ------------------------------------------------------------ show responder policy pol_block_php shell "grep 'BLOCKED php' /var/log/ns.log | tail -50" Expect 0 hits during normal use (Workspace app logons, EPA, client downloads, SAML). Any hit is either an attack probe or legitimate traffic that needs excluding before you switch to DROP. ------------------------------------------------------------ STEP 5 - Switch to blocking ------------------------------------------------------------ set responder policy pol_block_php -action DROP save ns config (Use -action RESET instead of DROP if you want clients to get an immediate TCP reset rather than a timeout.) ------------------------------------------------------------ ROLLBACK ------------------------------------------------------------ Back to log-only: set responder policy pol_block_php -action NOOP Remove completely (unbind first - use the line matching how you bound it): unbind responder global pol_block_php -type REQ_OVERRIDE unbind vpn vserver -policy pol_block_php -type REQUEST rm responder policy pol_block_php rm audit messageaction act_log_php save ns config