Last active
August 8, 2025 07:54
-
-
Save jantytgat/68419642be9c068b0d28324678b1387e to your computer and use it in GitHub Desktop.
NetScaler IOC Checker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| NAME=$1 | |
| UPDATE=$2 | |
| OUTLOG=/var/tmp/$NAME.log | |
| echo "Sending output to $OUTLOG" | |
| echo "RUNNING CHECKS FOR $NAME AGAINST DATE $UPDATE" | tee -a $OUTLOG | |
| echo "##### 01 - Check for modified files in /var/nsinstall with extension .php #####" | tee -a $OUTLOG | |
| T01=$(find /var/nsinstall/ -type f -iname '*.php' -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 02 - Check for modified files in /var/nsproflog with extension .php #####" | tee -a $OUTLOG | |
| T02=$(find /var/nsproflog/ -type f -iname '*.php' -newermt $UPDATE -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 03 - Check for modified files in /var/netscaler/ns_gui/ with extension .php #####" | tee -a $OUTLOG | |
| T03=$(find /var/netscaler/ns_gui/ -type f -iname '*.php' -newermt $UPDATE -not -path "/var/netscaler/ns_gui/admin_ui/*" -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 04 - Check for modified files in /var/netscaler/gui/ with extension .php #####" | tee -a $OUTLOG | |
| T04=$(find /var/netscaler/gui/ -type f -iname '*.php' -newermt $UPDATE -not -path "/var/netscaler/gui/admin_ui/*" -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 05 - Check for modified files in /var/vpn/ #####" | tee -a $OUTLOG | |
| T05=$(find /var/vpn/ -type f -newermt $UPDATE -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 06 - Check for modified files in /var/netscaler/logon/ #####" | tee -a $OUTLOG | |
| T06=$(find /var/netscaler/logon/ -type f -newermt $UPDATE -not -path "/var/netscaler/logon/themes/*/resources/*.xml" -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 07 - Check for modified files in /var/netscaler/logon/ with extension .php #####" | tee -a $OUTLOG | |
| T07=$(find /var/netscaler/logon/ -type f -iname '*.php' -newermt $UPDATE -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 08 - Check for modified files in /var/python/ #####" | tee -a $OUTLOG | |
| T08=$(find /var/python/ -type f -newermt $UPDATE -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 09 - Check files in /netscaler/ns_gui/ with extension .php #####" | tee -a $OUTLOG | |
| echo "WARNING ---> These files may change timestamps during system reboots — use this only as an indicator, not proof." >> $OUTLOG | |
| T09=$(find /netscaler/ns_gui/ -type f -iname '*.php' -newermt $UPDATE -not -path "/netscaler/ns_gui/admin_ui/*" -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 10 - Check files in /netscaler/gui/ with extension .php #####" | tee -a $OUTLOG | |
| T10=$(find /netscaler/gui/ -type f -iname '*.php' -newermt $UPDATE -not -path "/netscaler/gui/admin_ui/*" -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 11 - Check files in /netscaler/portal/ with extension .php #####" | tee -a $OUTLOG | |
| T11=$(find /netscaler/portal/ -type f -iname '*.php' -newermt $UPDATE -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 12 - Check for 'Graceful' in /var/log/httperror.log #####" | tee -a $OUTLOG | |
| T12=$(grep "Graceful" /var/log/httperror.log | grep -v ":00:" >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 13 - Check for 'Graceful' in /var/log/httperror.log.* (compressed files) #####" | tee -a $OUTLOG | |
| T13=$(gzcat /var/log/httperror.log.*.gz | grep Graceful | grep -v ":00:" >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 14 - Check for suspicious pipes #####" | tee -a $OUTLOG | |
| T14=$(pgrep -i nsppe | xargs -I% sh -c 'lsof -p % 2>>$OUTLOG| egrep -q "PIPE" && echo "%: suspicious pipe"') | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 15 - Check files in /var/vpn/ with extension .php #####" | tee -a $OUTLOG | |
| T15=$(find /var/vpn -regex '/var/vpn/vpn.*' -type f -iname '*.php' -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 16 - Check files in /var/netscaler/logon/LogonPoint with extension .php #####" | tee -a $OUTLOG | |
| T16=$(find /var/netscaler/logon/LogonPoint -depth 1 -type f -iname '*.php' -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 18 - Check for '.sh' in /var/log/httperror.log* #####" | tee -a $OUTLOG | |
| T18=$(zgrep '.sh' /var/log/httperror.log* >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 19 - Check for '.php' in /var/log/httperror.log* #####" | tee -a $OUTLOG | |
| T19=$(zgrep '.php' /var/log/httperror.log* >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 20 - Check for '.pl' in /var/log/httperror.log #####" | tee -a $OUTLOG | |
| T20=$(zgrep '.pl' /var/log/httperror.log* >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 21 - Check /var/log/sh.log #####" | tee -a $OUTLOG | |
| T21=$(zgrep -E 'database.php|/flash/nsconfig/keys/updated|/flash/nsconfig/keys|/ns_gui/vpn|LDAPTLS_REQCERT|ldapsearch|openssl|/nsconfig/ns.conf|del /etc/auth.conf|cp /usr/bin/bash|.F1.key|.F2.key|nobody' /var/log/sh.log* >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 22 - Check /var/log/bash.log #####" | tee -a $OUTLOG | |
| T22=$(zgrep -E 'database.php|/flash/nsconfig/keys/updated|/flash/nsconfig/keys|/ns_gui/vpn|LDAPTLS_REQCERT|ldapsearch|openssl|/nsconfig/ns.conf|del /etc/auth.conf|cp /usr/bin/bash|.F1.key|.F2.key|nobody' /var/log/bash.log* >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 23 - Check for httpd processes running as 'nobody' #####" | tee -a $OUTLOG | |
| T23=$(ps aux | grep nobody | grep -v '/bin/httpd' >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 24 - Check /etc/crontab #####" | tee -a $OUTLOG | |
| T24=$(grep '' /etc/crontab >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 25 - Check crontab for user 'nobody' #####" | tee -a $OUTLOG | |
| T25=$(crontab -l -u nobody >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 28 - Check files in /var/core/1 #####" | tee -a $OUTLOG | |
| T28=$(ls -ll /var/core/1 >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 29 - Check for running python processes #####" | tee -a $OUTLOG | |
| T29=$(ps -aux | grep python >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 30 - Check for running perl processes #####" | tee -a $OUTLOG | |
| T30=$(ps -aux | grep perl >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 31 - Top 10 running processes #####" | tee -a $OUTLOG | |
| T31=$(top -n 10 >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 32 - Check for illegal remote commands #####" | tee -a $OUTLOG | |
| T32=$(grep -v '127.0.0' /var/log/*.log | grep 'nc -l|/etc/passwd|curl|python -c|.php' >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 33 - Check file permissions in /var #####" | tee -a $OUTLOG | |
| T33=$(find /var -perm -4000 -user root -not -path "/var/nslog/*" -newermt $UPDATE -exec ls -l {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 34 - Check 'nsfsyncd' process #####" | tee -a $OUTLOG | |
| T34=$(ps aux | grep nsfsyncd >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 35 - Check /var/tmp for callhome_tmps #####" | tee -a $OUTLOG | |
| T35=$(find /var/tmp -type f -iname 'callhome_tmps*' -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 36 - Find Root-owned SUID files #####" | tee -a $OUTLOG | |
| T36=$(find /var \( -perm -4001 -or \( -perm -4010 -group nobody \) \) -user root -exec ls -al {} \; 2>>$OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 37 - Find backdoors in rc.netscaler #####" | tee -a $OUTLOG | |
| T37=$(grep python /flash/nsconfig/rc.netscaler >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 17 - Run python script to get newest timestamps #####" | tee -a $OUTLOG | |
| T17=$(python -c "import os, glob, time; newest_timestamp = max(os.stat(f).st_mtime for f in glob.glob('/var/nsinstall/*')); print('\n'.join(os.path.join(dirpath, f) for dir in ['/var/netscaler/logon/', '/var/python/', '/var/vpn/'] for dirpath, _, files in os.walk(dir) for f in files if os.stat(os.path.join(dirpath, f)).st_mtime > newest_timestamp))" >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 26 - Check /var/log/httpaccess-vpn.log* for status code 200 but not 'CitrixReceiver'#####" | tee -a $OUTLOG | |
| T26=$(zgrep -E -v 'CitrixReceiver' /var/log/httpaccess-vpn.log* | grep ' 200 ' >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "##### 27 - Check /var/log/httpaccess-vpn.log* for 'HeadlessChrome' #####" | tee -a $OUTLOG | |
| T27=$(zgrep 'HeadlessChrome' /var/log/httpaccess-vpn.log* >> $OUTLOG) | |
| echo "#############################################################" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "" >> $OUTLOG | |
| echo "Checking results..." | |
| RESULT= | |
| [ -z "$T01" ] || RESULT="$T01\n" | |
| [ -z "$T02" ] || RESULT="$RESULT$T02\n" | |
| [ -z "$T03" ] || RESULT="$RESULT$T03\n" | |
| [ -z "$T04" ] || RESULT="$RESULT$T04\n" | |
| [ -z "$T05" ] || RESULT="$RESULT$T05\n" | |
| [ -z "$T06" ] || RESULT="$RESULT$T06\n" | |
| [ -z "$T07" ] || RESULT="$RESULT$T07\n" | |
| [ -z "$T08" ] || RESULT="$RESULT$T08\n" | |
| [ -z "$T09" ] || RESULT="$RESULT$T09\n" | |
| [ -z "$T10" ] || RESULT="$RESULT$T10\n" | |
| [ -z "$T11" ] || RESULT="$RESULT$T11\n" | |
| [ -z "$T12" ] || RESULT="$RESULT$T12\n" | |
| [ -z "$T13" ] || RESULT="$RESULT$T13\n" | |
| [ -z "$T14" ] || RESULT="$RESULT$T14\n" | |
| [ -z "$T15" ] || RESULT="$RESULT$T15\n" | |
| [ -z "$T16" ] || RESULT="$RESULT$T16\n" | |
| [ -z "$T17" ] || RESULT="$RESULT$T17\n" | |
| [ -z "$T18" ] || RESULT="$RESULT$T18\n" | |
| [ -z "$T19" ] || RESULT="$RESULT$T19\n" | |
| [ -z "$T20" ] || RESULT="$RESULT$T20\n" | |
| [ -z "$T21" ] || RESULT="$RESULT$T21\n" | |
| [ -z "$T22" ] || RESULT="$RESULT$T22\n" | |
| [ -z "$T23" ] || RESULT="$RESULT$T23\n" | |
| [ -z "$T24" ] || RESULT="$RESULT$T24\n" | |
| [ -z "$T25" ] || RESULT="$RESULT$T25\n" | |
| [ -z "$T26" ] || RESULT="$RESULT$T26\n" | |
| [ -z "$T27" ] || RESULT="$RESULT$T27\n" | |
| [ -z "$T28" ] || RESULT="$RESULT$T28\n" | |
| [ -z "$T29" ] || RESULT="$RESULT$T29\n" | |
| [ -z "$T30" ] || RESULT="$RESULT$T30\n" | |
| [ -z "$T31" ] || RESULT="$RESULT$T31\n" | |
| [ -z "$T32" ] || RESULT="$RESULT$T32\n" | |
| [ -z "$T33" ] || RESULT="$RESULT$T33\n" | |
| [ -z "$T34" ] || RESULT="$RESULT$T34\n" | |
| [ -z "$T35" ] || RESULT="$RESULT$T35\n" | |
| [ -z "$T36" ] || RESULT="$RESULT$T36\n" | |
| [ -z "$T37" ] || RESULT="$RESULT$T37\n" | |
| echo "Done." | |
| echo "" | |
| echo "" | |
| echo "#############################################################" | |
| # [ -z "$RESULT" ] || RESULT="$RESULT$(ps auxd)\n$(sysctl -a netscaler.version kern.boottime)" | |
| [ -z "$RESULT" ] || echo -e "$RESULT\n!! Scan possibly identified one or more IOCs" | |
| [ -n "$RESULT" ] || echo "Scan OK, don't forget to look through the log file" | |
| echo "#############################################################" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment