├── README.md ├── checkrbl.py ├── cmspass.php ├── cpanelsec.sh ├── mitigate_ddos.py ├── pyclean.py ├── rbls └── shell_patterns /README.md: -------------------------------------------------------------------------------- 1 | Cpanel Security 2 | =============== 3 | 4 | About 5 | ----- 6 | 7 | Bash functions to help when administering cpanel servers, I found 8 | them helpful when doing abuse/security work. Simply source the file 9 | and you should be good to go, auto-complete offered in many cases. 10 | 11 | Includes several other tools written in PHP and Python for tasks 12 | such as CMS password changing, injection removal, server audits, 13 | and checking IPs against email blacklistings 14 | 15 | 16 | Requirements 17 | ------------ 18 | 19 | + CentOS 20 | + Cpanel 21 | + CSF Firewall (recommended) 22 | + [The Silver Surfer](https://github.com/ggreer/the_silver_searcher) (recommended) 23 | 24 | To use simple clone repo into a folder. Edit the `INSTALLDIR` bash variable at the top of cpanelsec.sh and checkrbl.py to reflect this location. 25 | Then just `source cpanelsec.sh`. Note if using silver surfer please install it into `$INSTALLDIR/ag/` 26 | 27 | Documentation 28 | ------------- 29 | 30 | Mail Functions 31 | -------------- 32 | 33 | **pwnmail [STRING]**: Removes email from exim mail queue given string, matches recipient, sender, or ID. 34 | Can remove frozen emails with "frozen" and old emails with the command `pwnoldmail` 35 | 36 | **addspf [USER]**: adds a 'strong' SPF record (-all) to the given cpanel user name's domains 37 | 38 | **adddkim [USER]**: adds domain keys (or DKIM) to given cpanel user's domain 39 | 40 | **chkmailabuse**: Shows scripts sending out mail, useful for finding malicious 41 | files blasting out spam. 42 | 43 | **check_rbl**: command line RBL checker, no argument checks current IPs, -a checks all. 44 | Or you can give it a specific IP as an argument. List of rbls is in rblist 45 | 46 | **switchmailip**: provides a list of all server IPs and prompts for which IP to send mail from 47 | 48 | **rdns_check**: does a check to ensure rDNS is properly configured 49 | 50 | **scramble_emaili [EMAIL ADDRESS]**: inserts !!ABUSE!! into the email hash for the address, 51 | allows user to reset the email password after a compromise while preventing further spam 52 | 53 | **train_sa [USER]**: Trains SpamAssassin for a given cpanel user, must have user create two email folders: 54 | HAM-TRAIN (with 200+ non-spam emails) and SPAM-TRAIN (200+ spam emails). 55 | 56 | **checkmail**: checks exim and prompts if recommended anti-spam settings are not enabled. Checks for SPF checking, 57 | Spamhaus RBL, and Spamcop RBL 58 | 59 | 60 | Malware Search/Cleanup 61 | ---------------------- 62 | 63 | **injectcleaner**: Uses the pyclean Python script to remove malicious injections. 64 | Given a regex pattern this allows you to visually see what will be matched before 65 | you remove it. Can be run without verification using -f and against a list of files 66 | with -l 67 | 68 | ``` 69 | Usage: injectcleaner [options] REGEX FILE 70 | 71 | Options: 72 | -h, --help show this help message and exit 73 | -l, --list-file use a list file 74 | -b, --backup make backup files 75 | -f, --force supress confirmation notice 76 | ``` 77 | 78 | **pwn [FILE]**: 'disables' file(s), sets targets to permissions 000 and owner root:root. Can be undone with `unpwn` 79 | 80 | **qgrep [-l -s -p] [-c CUSTOM]**: (quick)grep, searches for common base64 injections and shells across code files only. Flags are below: 81 | 82 | + no arguments defaults to base64 injection search 83 | + -l list files (analagous to grep -l) 84 | + -s shellsearch (searches for list on shells found in shell_patterns file) 85 | + -p ignores files with perm 000 86 | + -c CUSTOM, looks for custom string 87 | 88 | **qgrep_ag**: same as qgrep but uses silver surfer to search 89 | 90 | **shellscan**: searches across public_html folders for all cpanel users looking for shells, places results in 91 | $INSTALLDIR/possible_shells.txt. `shellscan_ag` is the ag version. 92 | 93 | **phishing_scams**: greps for common phishing words in all domain names 94 | 95 | **mitigate_ddos**: Uses a python script that automatically temp bans (using CSF) IPs with over 30 connections 96 | 97 | Account/System Maintenance 98 | -------------------------- 99 | 100 | **secimgdir**: modifies (or creates) .htaccess file in current directory to prevent script execution. 101 | Useful for folders such as "/images" or "/uploads" which shouldn't be executing anything 102 | 103 | **sysinfo**: Quick glance at CSF settings, exim queue size, external connections and disk 104 | quotas for users. 105 | 106 | **inodebreakdown**: If inode restrictions are in place this will give a pretty accurate listing 107 | of folders containing the most inodes for abuse notices. 108 | 109 | **grepuser [USER/DOMAIN]**: searches a string in userdomains and cpanel account names 110 | 111 | **trafficstats [DOMAIN]**: given a domain it returns the number of hits in the last 24 hours, autocompletes 112 | based on domain names in /etc/httpd/domlogs 113 | 114 | **lshtaccess**: find and prints .htaccess files recursively, useful for finding malicious redirects 115 | 116 | **chpass [USER]**: Generates random password for given user, also runs ftpupdate 117 | script to make cpanel happy 118 | 119 | **cmspass**: Automatically find and detect Joomla/WordPress installations and change 120 | all admin passwords to random 10 character strings 121 | 122 | **owner [USER]**: finds owner of cpanel account, auto-completes cpanel names 123 | 124 | **fixperms**: recursively sets files to 644 and folders to 755. Leaves cms config files as 600 125 | 126 | **rmsymlinks**: recursively removes symlinks (safely). For use in symlink attacks 127 | 128 | **www USER**: jumps to cpanel user's public_html folder, autocompletes cpanel account names 129 | 130 | **chkbackup [FILE]**: compares FILE with copies in daily, weekly, and monthly backups. Helpful when only a single file 131 | needs to be restore, avoids full account backup. 132 | 133 | **vzsuspend [VEID]**: suspends OpenVZ container, can be unsuspended with `vzunsuspend` 134 | 135 | **lscpanelsec**: lists all commands and arguments for easy reference 136 | -------------------------------------------------------------------------------- /checkrbl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import urllib 4 | import urllib2 5 | import re 6 | import sys 7 | import subprocess as sp 8 | import signal 9 | import struct 10 | import socket 11 | import array 12 | import fcntl 13 | import optparse 14 | 15 | INSTALLDIR = '/root/cpanelsec' 16 | 17 | parser = optparse.OptionParser(usage="check_rbl [options] [IP-Address]") 18 | parser.add_option('-a', '--all', help="check all interface IPs", default=False, 19 | dest='all_ips', action='store_true') 20 | 21 | (opts, args) = parser.parse_args() 22 | 23 | 24 | regex = re.compile("Email.Reputation.*?colspan.*?class=.(\w+)", re.MULTILINE|re.DOTALL) 25 | postdata = [('tos_accepted', 'Yes, I Agree')] 26 | postdata = urllib.urlencode(postdata) 27 | 28 | 29 | # get all interface IPs 30 | # http://code.activestate.com/recipes/439093-get-names-of-all-up-network-interfaces-linux-only/ 31 | def getIPs(): 32 | struct_size = 40 33 | if 8*struct.calcsize('P') == 32: 34 | struct_size -= 8 35 | 36 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 37 | max_possible = 8 38 | 39 | while True: 40 | bytes = max_possible * struct_size 41 | names = array.array('B', '\0' * bytes) 42 | outbytes = struct.unpack('iL', fcntl.ioctl(s.fileno(), 0x8912, 43 | struct.pack('iL', bytes, names.buffer_info()[0])))[0] 44 | if outbytes == bytes: 45 | max_possible *= 2 46 | else: 47 | break 48 | 49 | namestr = names.tostring() 50 | 51 | IPtuples = [(namestr[i:i+16].split('\0',1)[0],socket.inet_ntoa( 52 | namestr[i+20:i+24])) for i in range(0, outbytes, struct_size)] 53 | 54 | ips = [ x[1] for x in IPtuples if not '127.0.0' in x[1] and not '192.168.' in x[1] ] 55 | 56 | return ips 57 | 58 | 59 | def signal_handler(signal, frame): 60 | sys.exit(0) 61 | 62 | signal.signal(signal.SIGINT, signal_handler) 63 | 64 | def red(text): 65 | return '\033[31m' + text + '\033[0m' 66 | 67 | def green(text): 68 | return '\033[32m' + text + '\033[0m' 69 | 70 | def valid_IP(ip): 71 | try: 72 | socket.inet_pton(socket.AF_INET, ip) 73 | except socket.error: 74 | return False 75 | 76 | return True 77 | 78 | 79 | RBLs = open(INSTALLDIR + "/rbls", 'r').read().rstrip().split('\n') 80 | RBLs = [ x.split(';') for x in RBLs] 81 | reverseIP = lambda x: '.'.join(x.split('.')[::-1]) 82 | 83 | ipList = getIPs() 84 | if not opts.all_ips: 85 | ipList = [ipList[0]] 86 | 87 | if len(args) == 1 and valid_IP(args[0]): 88 | ipList = [args[0]] 89 | 90 | 91 | for ip in ipList: 92 | rev = reverseIP(ip) 93 | for rbl in RBLs: 94 | p = sp.Popen("dig +short " + rev + "." + rbl[1], stdout=sp.PIPE,shell=True) 95 | res = p.stdout.read() 96 | p.stdout.close() 97 | if res: 98 | print ip + red(" LISTED ") + "in " + rbl[0] + " - " + rbl[2] 99 | else: 100 | print ip + " not listed in " + rbl[0] 101 | 102 | print '' 103 | -------------------------------------------------------------------------------- /cmspass.php: -------------------------------------------------------------------------------- 1 | host, $this->user, $this->pass) 40 | or die(mysql_error()); 41 | 42 | mysql_select_db($this->dbname) or die(mysql_error()); 43 | 44 | $result = mysql_query($this->adminQuery()) or die (mysql_error()); 45 | 46 | print "\n[".$this->cms."] Location: ".$this->location."\n===\n"; 47 | while ($data = mysql_fetch_array($result)) { 48 | $password = $this->randpass(); 49 | mysql_query($this->chpassQuery($data, $password)) or die (mysql_error()); 50 | 51 | print $data[$this->uname]." - ".$password."\n"; 52 | } 53 | print "===\n"; 54 | 55 | mysql_close(); 56 | } 57 | } 58 | 59 | 60 | class WpCMS extends BaseCMS { 61 | 62 | function __construct($dir) { 63 | $this->location = dirname(realpath($dir."/wp-config.php")); 64 | $wpconfig = $this->wphack($dir."/wp-config.php"); 65 | require($wpconfig); 66 | 67 | $this->host = DB_HOST; 68 | $this->user = DB_USER; 69 | $this->pass = DB_PASSWORD; 70 | $this->dbname = DB_NAME; 71 | $this->prefix = $table_prefix; 72 | $this->cms = "WordPress"; 73 | $this->uname = "user_login"; 74 | 75 | unlink('./wpresstmp.php'); 76 | } 77 | 78 | protected function wphack($confFile) { 79 | $tmp = './wpresstmp.php'; 80 | copy($confFile, $tmp); 81 | //$evil = "require_once(ABSPATH . 'wp-settings.php');"; 82 | $evil = "/require_once\(\s*?ABSPATH.*?'wp-settings.php'\s*?\);/"; 83 | $data = file_get_contents($tmp); 84 | //$data = str_replace($evil,"",$data); 85 | $data = preg_replace($evil,"",$data); 86 | file_put_contents($tmp, $data); 87 | 88 | return $tmp; 89 | } 90 | 91 | protected function adminQuery() { 92 | return "SELECT um.user_id AS id, u.user_login FROM ".$this->prefix. 93 | "users u,".$this->prefix."usermeta um WHERE u.id = um.user_id ". 94 | "AND um.meta_key = '".$this->prefix."capabilities' AND ". 95 | "um.meta_value LIKE '%administrator%'"; 96 | } 97 | 98 | protected function chpassQuery($data, $password) { 99 | return "UPDATE ".$this->prefix."users SET user_pass = MD5('". 100 | $password."') WHERE id=".$data['id']; 101 | } 102 | } 103 | 104 | 105 | class JoomlaCMS extends BaseCMS { 106 | 107 | function __construct($dir) { 108 | $this->location = dirname(realpath($dir."/configuration.php")); 109 | require($dir."/configuration.php"); 110 | 111 | $joomla = new JConfig(); 112 | $this->host = $joomla->host; 113 | $this->user = $joomla->user; 114 | $this->pass = $joomla->password; 115 | $this->dbname = $joomla->db; 116 | $this->prefix = $joomla->dbprefix; 117 | $this->cms = "Joomla"; 118 | $this->uname = "username"; 119 | } 120 | 121 | protected function adminQuery() { 122 | 123 | if (mysql_query("DESCRIBE ".$this->prefix."core_acl_aro")) { 124 | return "SELECT id,username FROM ".$this->prefix."users WHERE usertype". 125 | " LIKE '%administrator%'"; 126 | } else { 127 | return "SELECT id,username FROM ".$this->prefix."users LEFT JOIN ". 128 | $this->prefix."user_usergroup_map ON (id = user_id) WHERE ". 129 | "group_id = 8"; 130 | } 131 | } 132 | 133 | protected function chpassQuery($data, $password) { 134 | 135 | return "UPDATE ".$this->prefix."users SET password=MD5('".$password. 136 | "') WHERE id=".$data['id']; 137 | 138 | } 139 | } 140 | 141 | 142 | class CMSFactory { 143 | 144 | public static function create($dir) { 145 | 146 | if (file_exists($dir.'/wp-config.php')) { 147 | return new WpCMS($dir); 148 | } elseif (file_exists($dir.'/configuration.php')) { 149 | return new JoomlaCMS($dir); 150 | } else { 151 | return null; 152 | } 153 | } 154 | } 155 | 156 | $dir = "."; 157 | if (sizeof($argv) > 1) { 158 | $dir = $argv[1]; 159 | } 160 | 161 | $cms = CMSFactory::create($dir); 162 | if ($cms == null) { 163 | file_put_contents('php://stderr', "Could not find CMS!\n"); 164 | exit(1); 165 | } 166 | 167 | 168 | $cms->run(); 169 | -------------------------------------------------------------------------------- /cpanelsec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | INSTALLDIR='/root/cpanelsec' 4 | 5 | yellow=$(tput setaf 3) 6 | blue=$(tput setaf 4) 7 | lblue=$(tput setaf 6) 8 | reset=$(tput sgr0) 9 | red=$(tput setaf 1) 10 | white=$(tput setaf 7) 11 | 12 | PS1="┌─[\[$blue\]\u \[$lblue\]\h\[$reset\]] - [\[$white\]\w\[$reset\]] - [\[$yellow\]\D{%Y-%m-%d} \t\[$reset\]]\n└─[\[$red\]$(echo \$?)\[$reset\]] " 13 | unalias cp 14 | unalias vi 15 | alias ag="${HOME}/ag --no-numbers" 16 | 17 | ag_check() { 18 | 19 | if [ -f "${INSTALLDIR}/ag" ];then 20 | return 21 | fi 22 | 23 | echo "Please install the Silver Surfer" 24 | return 25 | } 26 | 27 | 28 | pwnmail() { 29 | if [ -z "$1" ]; then 30 | echo "Usage: pwnmail STRING" 31 | return 32 | fi 33 | 34 | if [ "$1" == "frozen" ];then 35 | exiqgrep -z -i | xargs exim -Mrm 36 | return 37 | fi 38 | 39 | exim -bp | grep -B1 "$1" | grep '<.*>' | awk '{print $3}' | while read line; do exim -Mrm $line; done 40 | } 41 | 42 | 43 | addspf() { 44 | if [ -z "$1" ]; then 45 | echo "Usage: addspf USER" 46 | return 47 | fi 48 | /usr/local/cpanel/bin/spf_installer "$1" '' 1 1 49 | echo "Added SPF records for account $1" 50 | } 51 | 52 | 53 | 54 | cmspass() { 55 | 56 | if [ "$1" = "-r" ];then 57 | find -maxdepth 4 -type d -exec php "$INSTALLDIR"/cmspass {} 2> /dev/null \; 58 | else 59 | php "$INSTALLDIR"/cmspass.php "$@" 60 | fi 61 | 62 | } 63 | 64 | 65 | injectcleaner() { 66 | python "$INSTALLDIR"/pyclean.py "$@" 67 | } 68 | 69 | 70 | sysinfo() { 71 | echo '[===SYSTEM BUILD===]' 72 | uname -a 73 | 74 | echo '[===LANGUAGE HANDLERS===]' 75 | /usr/local/cpanel/bin/rebuild_phpconf --current 76 | 77 | echo '[===PHP CONFIG===]' 78 | egrep -i "(disable_fun)" /usr/local/lib/php.ini | sed 's/;//' 79 | 80 | echo '[===FIREWALL STATUS===]' 81 | egrep "(SMTP_BLOCK|SMTP_ALLOWLOCAL|SMTP_PORTS)[[:space:]]?=" /etc/csf/csf.conf 82 | csf -v 83 | 84 | echo '[===EMAIL STATUS===]' 85 | echo Emails per Hour: $(cat /var/cpanel/maxemailsperhour) 86 | echo Emails in Queue: $(exim -bpc) 87 | echo '[===RESOURCE ALLOCATION===]' 88 | OUT=$(/usr/local/cpanel/bin/dcpumonview | grep -v Top | sed -e 's#<[^>]*># #g' | while read i ; do NF=`echo $i | awk {'print NF'}` ; if [[ "$NF" == "5" ]] ; then USER=`echo $i | awk '{print $1}'`; OWNER=`grep -e "^OWNER=" /var/cpanel/users/$USER | cut -d= -f2` ; echo "$OWNER $i"; fi ; done) ; (echo "USER CPU" ; echo "$OUT" | sort -nrk4 | awk '{print $2,$4}' | head -5) | column -t ; echo; (echo -e "USER MEMORY" ; echo "$OUT" | sort -nrk5 | awk '{print $2,$5}' | head -5) | column -t 89 | 90 | echo '[===ESTABLISHED CONNECTIONS===]' 91 | PORTS=([80]=Apache [110]=POP3 [143]=IMAP [25]=SMTP [26]=SMTP [21]=FTP) 92 | netstat -plan > "$INSTALLDIR"/stats.txt 93 | for port in ${!PORTS[*]} 94 | do 95 | echo "$(tput bold)${PORTS[$port]}($port):$(tput sgr0)" 96 | grep $port "$INSTALLDIR"/stats.txt | awk {'print $5'} | grep -Po "\d{1,3}(?:\.\d{1,3}){3}" | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 | uniq -c | sort -nk 1 | grep -v "0.0.0.0" | tail -5 | awk '{ if ( $1 > 35 ) { printf "\033[1;31m" } else if ( $1 > 25 ) { printf "\033[1;33m" } else { printf "\033[1;32m" } ; print " ", $1, "\033[0;39m", $2 }' 97 | done; 98 | rm -f "$INSTALLDIR"/stats.txt 99 | 100 | echo '[===CONNECTIONS BY DOMAIN===]' 101 | lynx -dump -width=200 localhost/whm-server-status | grep 'POST\|GET' | awk '{print $12}' | sort | uniq -c 102 | 103 | echo '[===DISK ALLOCATION===]' 104 | df -h 105 | 106 | echo '[===INODE AUDIT===]' 107 | cat /etc/domainusers | cut -f1 -d: | sort -nk1 | while read USER; do quota -s $USER; done | grep '[0-9]k' -B 2 | grep -v "-" | grep '[0-9]k' -B 2 108 | 109 | echo '[===EXCLUDED USERS===]' 110 | cat /etc/cpbackup-userskip.conf 111 | screen -ls 112 | cat /etc/cpspamd.conf 113 | 114 | } 115 | 116 | 117 | inodebreakdown() { 118 | find . -maxdepth 1 -type d | while read line ; do echo "$( find "$line"| wc -l) $line" ; done | sort -rn 119 | } 120 | 121 | 122 | secimgdir() { 123 | if [ ! -f .htaccess ];then 124 | echo -e "AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi .php5 .php4 .php3 .phps .txt .bat .cmd .rb\nOptions -ExecCGI -Indexes" > .htaccess 125 | chattr +ai .htaccess 126 | else 127 | sed -i '1s/^/AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi .php5 .php4 .php3 .phps .txt .bat .cmd .rb\nOptions -ExecCGI -Indexes\n/' .htaccess 128 | chattr +ai .htaccess 129 | fi 130 | echo ".htaccess edited." 131 | } 132 | 133 | 134 | grepuser() { 135 | if [ -z "$1" ];then 136 | echo "Usage: grepuser USER" 137 | return 138 | fi 139 | grep "$1" /etc/userdomains 140 | } 141 | 142 | 143 | trafficstats() { 144 | if [ -z "$1" ];then 145 | echo "Usage: trafficstats [-f] DOMAIN" 146 | return 147 | fi 148 | if [ ! -f /etc/httpd/domlogs/"$1" ];then 149 | echo "Domain $1 not found." 150 | return 151 | fi 152 | 153 | local BEGIN=`head -n1 /etc/httpd/domlogs/"$1" | awk '{print $4$5}'` 154 | local END=`tail -n1 /etc/httpd/domlogs/"$1" | awk '{print $4$5}'` 155 | local HITS=`wc -l /etc/httpd/domlogs/"$1"| awk '{print $1}'` 156 | echo "From $BEGIN to $END there were $HITS hits for $1" 157 | } 158 | 159 | _trafficstats() { 160 | local cur 161 | cur=${COMP_WORDS[COMP_CWORD]} 162 | COMPREPLY=( $( compgen -f /etc/httpd/domlogs/$cur | perl -pi -e 's/.*\/(.*)/$1/g' ) ) 163 | } 164 | 165 | complete -o nospace -F _trafficstats trafficstats 166 | alias dcpumonview="/usr/local/cpanel/bin/dcpumonview" 167 | alias mc="exim -bpc" 168 | alias m="exim -bp" 169 | alias chkmailabuse='less /var/log/exim_mainlog | grep sendmail | grep -vE "csf|FCron"' 170 | alias grep="grep --color=auto" 171 | alias ll='/bin/ls -AlhF --color=tty' 172 | alias vb='exim -Mvb' 173 | alias vh='exim -Mvh' 174 | alias vl='exim -Mvl' 175 | alias lshtaccess='find -type f -name .htaccess -printf "\n\n=== %p ===\n" -exec cat {} \;' 176 | alias pwnoldmail='exiqgrep -i -o 86400 | xargs exim -Mrm' 177 | 178 | 179 | owner() { 180 | if [ -z "$1" ];then 181 | echo "Usage: owner USER" 182 | return 183 | fi 184 | grep "$1" /etc/trueuserowners 185 | } 186 | complete -o nospace -F _www owner 187 | 188 | 189 | pwn() { 190 | if [ -z "$1" ];then 191 | echo "Usage: pwn FILES" 192 | return 193 | fi 194 | until [ -z "$1" ];do 195 | chmod 000 "$1" 196 | chown 0:0 "$1" 197 | shift 198 | done 199 | } 200 | 201 | 202 | unpwn() { 203 | if [ -z "$1" ];then 204 | echo "Usage: unpwn FILES" 205 | return 206 | fi 207 | until [ -z "$1" ];do 208 | if [ -d "$1" ];then 209 | chmod 755 "$1" 210 | else 211 | chmod 644 "$1" 212 | fi 213 | chown `pwd | cut -d/ -f3`:`pwd | cut -d/ -f3` "$1" 214 | shift 215 | done 216 | } 217 | 218 | 219 | fixperms() { 220 | find -type f ! -perm 000 -exec bash -c 'if [[ "$1" =~ "wp-config.php" || "$1" =~ "configuration.php" ]];then chmod 600 "$1";else chmod 644 "$1";fi' bash '{}' \; 221 | find -type d ! -perm 000 -exec chmod 755 {} \; 222 | } 223 | 224 | 225 | rmsymlinks() { 226 | find -type l -exec unlink {} \; 227 | } 228 | 229 | 230 | www() { 231 | if [ -z "$1" ];then 232 | echo "Usage: www USER" 233 | return 234 | fi 235 | if [ ! -d /home/"$1"/public_html ];then 236 | echo "Public html directory for user $1 not found." 237 | return 238 | fi 239 | cd /home/"$1"/public_html 240 | } 241 | 242 | _www() { 243 | local cur 244 | cur=${COMP_WORDS[COMP_CWORD]} 245 | COMPREPLY=( $( compgen -f /var/cpanel/users/$cur | perl -pi -e 's/.*\/(.*)/$1/g' ) ) 246 | } 247 | 248 | complete -o nospace -F _www www 249 | complete -o nospace -F _www addspf 250 | 251 | 252 | chpass() { 253 | if [ -z "${ALLOW_PASSWORD_CHANGE+xxx}" ];then 254 | export ALLOW_PASSWORD_CHANGE=1 255 | fi 256 | if [ -z "$1" ];then 257 | echo "Usage: chpass USER" 258 | return 259 | fi 260 | 261 | local NEWPW=`cat /dev/urandom| tr -dc 'a-zA-Z0-9' | head -c 10` 262 | echo "Changing password for user $1 to: $NEWPW" 263 | /scripts/chpass "$1" "$NEWPW" 264 | if [ $? -ne 0 ];then 265 | return 266 | fi 267 | /scripts/ftpupdate 268 | } 269 | 270 | complete -o nospace -F _www chpass 271 | 272 | qgrep() { 273 | 274 | local OPTIND 275 | local OPTARG 276 | while getopts ":plsc:" opt; do 277 | case $opt in 278 | p ) local NONULL='! -perm 000' ;; 279 | l ) local LFILES='-EHil' ;; 280 | s ) local SHLLSRCH="($(cat "$INSTALLDIR"/shell_patterns) | tr ' ' '|')";; 281 | c ) local SHLLSRCH="($OPTARG)";; 282 | : ) echo "-$OPTARG requires an argument";return 1;; 283 | \? ) echo "Usage: qgrep [-l (list files)] [-s (shells) ] [-p (no perm 000) ] [-c SEARCHSTR]" 284 | return 1;; 285 | esac 286 | done 287 | 288 | GREPARGS=${LFILES:-'-EHi'} 289 | ARGS1=${NONULL:-''} 290 | SEARCH=${SHLLSRCH:-"(gzinflate|base64_decode)"} 291 | find -type f $ARGS1 -regex ".*\.\(htm\|html\|shtml\|asp\|php\|inc\|tmp\|js\|htaccess\|pl\)" -print0 | xargs -0 grep $GREPARGS $SEARCH --color=auto 292 | return 0 293 | } 294 | 295 | 296 | qgrep_ag() { 297 | 298 | ag_check 299 | 300 | local OPTIND 301 | local OPTARG 302 | while getopts ":plsc:" opt; do 303 | case $opt in 304 | p ) local NONULL='! -perm 000' ;; 305 | l ) local LFILES='-il' ;; 306 | s ) local SHLLSRCH="($(cat "INSTALLDIR"/shell_patterns) | tr ' ' '|')";; 307 | c ) local SHLLSRCH="($OPTARG)";; 308 | : ) echo "-$OPTARG requires an argument";return 1;; 309 | \? ) echo "Usage: qgrep [-l (list files)] [-s (shells) ] [-p (no perm 000) ] [-c SEARCHSTR]" 310 | return 1;; 311 | esac 312 | done 313 | 314 | GREPARGS=${LFILES:-'-i'} 315 | ARGS1=${NONULL:-''} 316 | SEARCH=${SHLLSRCH:-"(gzinflate|base64_decode)"} 317 | find -type f $ARGS1 -regex ".*\.\(htm\|html\|shtml\|asp\|php\|inc\|tmp\|js\|htaccess\|pl\)" -print0 | xargs -0 "${HOME}/ag" --no-numbers --noheading $GREPARGS $SEARCH 2> /dev/null 318 | return 0 319 | } 320 | 321 | 322 | shellscan() { 323 | 324 | pushd . 325 | 326 | if [ -f "$INSTALLDIR"/possible_shells.txt ];then 327 | rm "$INSTALLDIR"/possible_shells.txt -f 328 | fi 329 | 330 | SCAN_ARGS="-ps" 331 | if [ ! -z "$1" ];then 332 | if [ "$1" == "base64" ];then 333 | SCAN_ARGS="-p" 334 | else 335 | SCAN_ARGS="-c $1" 336 | fi 337 | fi 338 | 339 | for i in /var/cpanel/users/*;do 340 | echo -e "\n===\n$(basename $i)\n===\n" | tee -a "$INSTALLDIR"/possible_shells.txt 341 | cd /home/"$(basename $i)"/public_html 342 | if [ $? -eq 0 ];then 343 | qgrep $SCAN_ARGS | tee -a "$INSTALLDIR"/possible_shells.txt 344 | fi 345 | done 346 | 347 | 348 | popd 349 | } 350 | 351 | 352 | shellscan_ag() { 353 | 354 | ag_check 355 | 356 | if [ -f "$INSTALLDIR"/possible_shells.txt ];then 357 | rm "$INSTALLDIR"/possible_shells.txt -f 358 | fi 359 | 360 | SCAN_ARGS="-ps" 361 | if [ ! -z "$1" ];then 362 | if [ "$1" == "base64" ];then 363 | SCAN_ARGS="-p" 364 | else 365 | SCAN_ARGS="-c $1" 366 | fi 367 | fi 368 | 369 | for i in /var/cpanel/users/*;do 370 | echo -e "\n===\n$(basename $i)\n===\n" | tee -a "$INSTALLDIR"/possible_shells.txt 371 | cd /home/$(basename $i)/public_html 372 | if [ $? -eq 0 ];then 373 | qgrep_ag $SCAN_ARGS | tee -a "$INSTALLDIR"/possible_shells.txt 374 | fi 375 | done 376 | } 377 | 378 | 379 | chkbackup() { 380 | 381 | if [ -z "$1" ];then 382 | echo "Usage: chkbackup FILE" 383 | return 384 | fi 385 | local ACCOUNT=$(readlink -f "$1" | cut -d/ -f3) 386 | local TARGET=$(readlink -f "$1" | awk -F "public_html/" '{print $2}') 387 | 388 | BACKUPS=('daily' 'weekly' 'monthly') 389 | for i in ${BACKUPS[@]}; do 390 | if [ ! -f /backup/cpbackup/"$i"/"$ACCOUNT"/homedir/public_html/"$TARGET" ];then 391 | echo "No $i backup" 392 | else 393 | diff /backup/cpbackup/"$i"/"$ACCOUNT"/homedir/public_html/"$TARGET" /home/"$ACCOUNT"/public_html/"$TARGET" 2> /dev/null 394 | if [ $? -ne 0 ];then 395 | echo "Restore file? (y or n): " 396 | read option 397 | if [ "$option" == "y" ];then 398 | cp /backup/cpbackup/"$i"/"$ACCOUNT"/homedir/public_html/"$TARGET" $(dirname /home/"$ACCOUNT"/public_html/"$TARGET") 399 | return 400 | fi 401 | else 402 | echo "No changes in $i copy" 403 | fi 404 | fi 405 | done 406 | 407 | 408 | } 409 | 410 | 411 | vzsuspend() { 412 | if [ -z "$1" ];then 413 | echo "Usage: vzsuspend VEID" 414 | return 415 | fi 416 | 417 | vzlist -a | grep "$1" 1> /dev/null 418 | if [ "$?" -ne 0 ];then 419 | echo "VEID $1 not found!" 420 | return 421 | fi 422 | 423 | local HOSTNAME=$(vzlist -a | grep "$1" | awk '{print $5}') 424 | vzctl set "$1" --hostname "$HOSTNAME":SUSPENDED --save 425 | vzctl stop "$1" --fast 426 | vzctl set "$1" --disabled yes --save 427 | } 428 | 429 | 430 | vzunsuspend() { 431 | if [ -z "$1" ];then 432 | echo "Usage: vzunsuspend VEID" 433 | return 434 | fi 435 | 436 | vzlist -a | grep "$1" 1> /dev/null 437 | if [ "$?" -ne 0 ];then 438 | echo "VEID $1 not found!" 439 | return 440 | fi 441 | 442 | vzctl set "$1" --disabled no --save 443 | local HOSTNAME=$(vzlist -a | grep "$1" | awk '{print $5}' | awk -F':SUSPENDED' '{print $1}') 444 | vzctl set "$1" --hostname "$HOSTNAME" --save 445 | vzctl start "$1" 446 | } 447 | 448 | 449 | adddkim() { 450 | if [ -z "$1" ];then 451 | echo "Usage: adddkim USER" 452 | return 453 | fi 454 | if [ -e /usr/local/cpanel/bin/domain_keys_installer ];then 455 | /usr/local/cpanel/bin/domain_keys_installer "$1" 456 | echo "Added domain keys for user $1" 457 | else 458 | /usr/local/cpanel/bin/dkim_keys_install "$1" 459 | echo "Added DKIM for user $1" 460 | fi 461 | } 462 | 463 | complete -o nospace -F _www adddkim 464 | 465 | 466 | check_rbl() { 467 | 468 | "$INSTALLDIR"/checkrbl.py "$1" 469 | } 470 | 471 | 472 | alias vzusage="vzlist -o ctid,laverage,hostname" 473 | 474 | 475 | mitigate_ddos() { 476 | python "$INSTALLDIR"/mitigate_ddos.py 477 | } 478 | 479 | 480 | checkmail() { 481 | 482 | CHANGES=0 483 | RBLS=('acl_spf_bl' 'acl_spamcop_rbl' 'acl_spamhaus_rbl') 484 | NOT_USING=('NOT using SPF checking!' 'NOT using Spamcop RBL!' 'NOT using Spamhaus RBL!') 485 | USING=('SPF checking is enabled.' 'Spamcop RBL is enabled.' 'Spamhaus RBL is enabled.') 486 | 487 | index=0 488 | for bl in ${RBLS[@]};do 489 | local HAS_BL=$(grep "$bl" /etc/exim.conf.localopts | cut -d'=' -f2) 490 | grep acl_spf_bl /etc/exim.conf.localopts 1> /dev/null 491 | if [[ $? -ne 0 || $HAS_BL -ne 1 ]];then 492 | echo "${NOT_USING[$index]} Would you like to enable this feature? (y or n): " 493 | read choice 494 | if [ "$choice" == "y" ];then 495 | sed -i "/$bl/d" /etc/exim.conf.localopts 496 | echo "$bl=1" >> /etc/exim.conf.localopts 497 | CHANGES=1 498 | fi 499 | else 500 | echo ${USING[$index]} 501 | fi 502 | index=$[ $index + 1 ] 503 | done 504 | 505 | if [ $CHANGES -eq 1 ];then 506 | /scripts/buildeximconf 1> /dev/null 507 | service exim restart 508 | fi 509 | 510 | } 511 | 512 | 513 | switchmailip() { 514 | 515 | IPs=($(ifconfig | grep 'inet addr' | awk '{print $2}'| sed 's#addr:##g' | grep -v 127.0.0.1 | sed 's/^/ /' | tr '\n' ' ')) 516 | index=1 517 | mainIP=${IPs[0]} 518 | curIP=$mainIP 519 | 520 | altIP=$(grep -E "^\*:" /etc/mailips | cut -d':' -f2) 521 | if [ ! -z $altIP ];then 522 | curIP=$altIP 523 | fi 524 | 525 | echo -e "Current mailing IP is: $curIP\n" 526 | 527 | for ip in ${IPs[@]};do 528 | echo "$index.) $ip ----> $(host $ip | cut -d' ' -f5 | sed 's/.$//')" 529 | index=$[ $index + 1 ] 530 | done 531 | 532 | echo -e "Enter new mailing IP: " 533 | read choice 534 | 535 | newip=${IPs[$[ $choice - 1 ]]} 536 | echo "new IP is $newip" 537 | 538 | chattr -ai /etc/mailips 539 | sed -i '/^\*:/d' /etc/mailips 540 | sed -i '/per_domain_mailips/d' /etc/exim.conf.localopts 541 | if [ "$newip" == "$mainIP" ];then 542 | echo "per_domain_mailips=0" >> /etc/exim.conf.localopts 543 | else 544 | echo "per_domain_mailips=1" >> /etc/exim.conf.localopts 545 | echo -e "*: $newip\n$(cat /etc/mailips)" > /etc/mailips 546 | grep $newip /etc/mail_reverse_dns 1> /dev/null 547 | if [ $? -ne 0 ];then 548 | echo "$newip: $(host $ip | cut -d' ' -f5 | sed 's/.$//')" >> /etc/mail_reverse_dns 549 | fi 550 | fi 551 | 552 | /scripts/buildeximconf 1> /dev/null 553 | service exim restart 554 | 555 | chattr +ai /etc/mailips 556 | } 557 | 558 | rdns_check() { 559 | 560 | ERRORS=0 561 | 562 | host $(hostname) 1> /dev/null 563 | if [ $? -ne 0 ];then 564 | echo "$(hostname) ----> Invalid domain name!" 565 | ERRORS=1 566 | else 567 | echo "$(hostname) ----> $(host $(hostname) | grep address | cut -d' ' -f4)" 568 | fi 569 | 570 | PTR=$(host $(hostname -i) | cut -d' ' -f5 | sed 's/.$//') 571 | echo "$(hostname -i) ----> $PTR" 572 | 573 | if [ "$PTR" != "$(hostname)" ];then 574 | ERRORS=1 575 | fi 576 | 577 | if [ $ERRORS -eq 1 ];then 578 | echo -e "rDNS check: \033[0;31mFAILED\033[m\017" 579 | else 580 | echo -e "rDNS check: \033[0;32mPASSED\033[m\017" 581 | fi 582 | } 583 | 584 | alias phishing_scams='grep -iE "ebay|chase|webscr|hotmail|yahoo|gmail|google|remax|fidelity|santander|visa|amazon|paypal|mastercard|signin" /etc/userdomains' 585 | 586 | scramble_email() { 587 | 588 | if [ -z "$1" ];then 589 | echo "Usage: scramble_email user@domain.com" 590 | return 591 | fi 592 | 593 | USER=$(echo "$1" | cut -d'@' -f1) 594 | DOMAIN=$(echo "$1" | cut -d'@' -f2) 595 | ACCT=$(grep "^$DOMAIN" /etc/userdomains | awk -F": " '{print $2}') 596 | 597 | grep "^$USER" /home/"$ACCT"/etc/"$DOMAIN"/shadow | grep -viE "ABUSE|LOCKED" 1> /dev/null 598 | if [ $? -ne 0 ];then 599 | echo "Error: $1 may be suspended, already locked, or does not exist" 600 | return 601 | fi 602 | 603 | sed -i "s/^$USER:/$USER:!!ABUSE!!/" /home/"$ACCT"/etc/"$DOMAIN"/shadow 604 | 605 | echo "Scrambled password for $1 under '$ACCT'" 606 | service exim restart 607 | } 608 | 609 | 610 | train_sa() { 611 | 612 | if [ -z "$1" ];then 613 | echo "Usage: train_sa USER" 614 | return 615 | fi 616 | 617 | su "$1" -s /bin/bash -c "sa-learn --dump magic" 618 | su "$1" -s /bin/bash -c "sa-learn --clear" 619 | su "$1" -s /bin/bash -c "sa-learn --sync" 620 | rm auto-whitelist 2> /dev/null 621 | 622 | echo "Please enter the email account with SPAM-TRAIN and HAM-TRAIN folders" 623 | read email 624 | 625 | USER=$(echo $email | cut -d'@' -f1) 626 | DOMAIN=$(echo $email | cut -d'@' -f2) 627 | 628 | if [[ ! -d /home/"$1"/mail/"$DOMAIN"/"$USER"/.SPAM-TRAIN || ! -d /home/"$1"/mail/"$DOMAIN"/"$USER"/.HAM-TRAIN ]];then 629 | echo "Could not find HAM-TRAIN or SPAM-TRAIN folders!" 630 | return 631 | fi 632 | 633 | echo -e "\nTraining with SPAM-TRAIN tokens:" 634 | su "$1" -s /bin/bash -c "sa-learn --progress --spam /home/$1/mail/$DOMAIN/$USER/.SPAM-TRAIN/cur" 635 | 636 | echo -e "\nTraining with HAM-TRAIN tokens:" 637 | su "$1" -s /bin/bash -c "sa-learn --progress --ham /home/$1/mail/$DOMAIN/$USER/.HAM-TRAIN/cur" 638 | 639 | sed -i '/use_auto_whitelist/d' /home/"$1"/.spamassassin/user_prefs 640 | sed -i '/URIBL_DBL_SPAM/d' /home/"$1"/.spamassassin/user_prefs 641 | sed -i '/URIBL_JP_SURBL/d' /home/"$1"/.spamassassin/user_prefs 642 | sed -i '/URIBL_WS_SURBL/d' /home/"$1"/.spamassassin/user_prefs 643 | 644 | echo "use_auto_whitelist 0" >> /home/"$1"/.spamassassin/user_prefs 645 | echo "URIBL_DBL_SPAM 6.0" >> /home/"$1"/.spamassassin/user_prefs 646 | echo "URIBL_JP_SURBL 4.0" >> /home/"$1"/.spamassassin/user_prefs 647 | echo "URIBL_WS_SURBL 4.0" >> /home/"$1"/.spamassassin/user_prefs 648 | } 649 | 650 | complete -o nospace -F _www train_sa 651 | 652 | lscpanelsec() { 653 | echo -e "pwnmail STRING\ncmscheck\naddspf USER\ninjectcleaner [-l] [-b] PATTERN [FILE|LIST]\nsysinfo\ninodebreakdown\nsecimgdr" 654 | echo -e "grepuser USER\ntrafficstats [-f] DOMAIN\npwn FILE\nfixperms\nrmsymlinks\nwww USER\nchpass USER\nchkmailabuse" 655 | echo -e "qgrep [-f (full)] [-l (list)] [-h (hack|shell) ] [-p (no perm 000) ] [search str]" 656 | echo -e "chkbackup FILE\nowner USER\nvzsuspend VEID\nvzunsuspend VEID" 657 | echo -e "adddkim USER\nshowusage\nunpwn USERS\nvzusage\nmitigate_ddos\ncheck_rbl\npwnoldmail\ncheckmail" 658 | echo -e "phishing_scams\nrdns_check\nswitchmailip\nscramble_email EMAIL\ntrain_sa USER" 659 | } 660 | -------------------------------------------------------------------------------- /mitigate_ddos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import subprocess as sp 4 | from time import sleep 5 | import signal 6 | import sys 7 | import struct 8 | import socket 9 | import array 10 | import fcntl 11 | 12 | 13 | def signal_handler(signal, frame): 14 | sys.exit(0) 15 | 16 | COUNT = 0 17 | ADDR = 1 18 | 19 | 20 | def getIPs(): 21 | p = sp.Popen("netstat -plan | grep :80 | awk '{print $5}' | cut -d : -f1 | sort -nk1 | uniq -c | sort -rnk1", shell=True, stdout=sp.PIPE) 22 | output = p.stdout.readlines() 23 | return [ x.split() for x in output ] 24 | 25 | 26 | def isDropped(ip): 27 | p = sp.Popen("csf -g " + ip[ADDR] + " | grep DROP", shell=True, stdout=sp.PIPE) 28 | if p.stdout.read(): 29 | return True 30 | 31 | return False 32 | 33 | 34 | def deny(ip, sec): 35 | sp.Popen("csf -td " + ip[ADDR] + " " + str(sec), shell=True, stdout=sp.PIPE) 36 | print ip[ADDR] + " has " + ip[COUNT] + " connections....dropping for " + str(sec/60) + " minutes!" 37 | 38 | 39 | def get_local_IPs(): 40 | struct_size = 40 41 | if 8*struct.calcsize('P') == 32: 42 | struct_size -= 8 43 | 44 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 45 | max_possible = 8 46 | 47 | while True: 48 | bytes = max_possible * struct_size 49 | names = array.array('B', '\0' * bytes) 50 | outbytes = struct.unpack('iL', fcntl.ioctl(s.fileno(), 0x8912, 51 | struct.pack('iL', bytes, names.buffer_info()[0])))[0] 52 | if outbytes == bytes: 53 | max_possible *= 2 54 | else: 55 | break 56 | 57 | namestr = names.tostring() 58 | 59 | IPtuples = [(namestr[i:i+16].split('\0',1)[0],socket.inet_ntoa( 60 | namestr[i+20:i+24])) for i in range(0, outbytes, struct_size)] 61 | 62 | ips = [ x[1] for x in IPtuples ] 63 | 64 | return ips 65 | 66 | if __name__ == "__main__": 67 | 68 | signal.signal(signal.SIGINT, signal_handler) 69 | local_IPs = get_local_IPs() 70 | 71 | while True: 72 | 73 | for ip in getIPs(): 74 | if ip in local_IPs: 75 | continue 76 | 77 | if isDropped(ip): 78 | continue 79 | 80 | cons = int(ip[COUNT]) 81 | 82 | # getIPs sorts results based on number of connections, so if we hit an 83 | # IP with less than 30 connections, all the rest will also be < 30 84 | if cons < 30: 85 | break 86 | 87 | elif cons >= 30 and cons < 60: 88 | deny(ip, 300) 89 | 90 | elif cons >= 60 and cons < 90: 91 | deny(ip, 600) 92 | 93 | elif cons >= 90: 94 | deny(ip, 1800) 95 | 96 | sleep(10) 97 | -------------------------------------------------------------------------------- /pyclean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Injection removal tool 3 | # Andrew D. 4 | 5 | from optparse import OptionParser 6 | import sys 7 | import re 8 | import shutil 9 | import signal 10 | import sre_constants 11 | import platform 12 | 13 | class InjectCleaner: 14 | 15 | def __init__(self, options, args): 16 | self.force = options.force 17 | self.backup = options.backup 18 | self.listfile = options.listfile 19 | self.args = args 20 | try: 21 | self.regex = re.compile(args[0], re.MULTILINE | re.DOTALL) 22 | except re.error: 23 | print "\nInvalid regular expression! (check your syntax)" 24 | sys.exit(1) 25 | 26 | def listMode(self): 27 | return self.listfile 28 | 29 | def __red(self, text): 30 | if platform.system() == "Windows": 31 | return text 32 | return '\033[91m' + text + '\033[0m' 33 | 34 | def removeInjections(self, fname = None): 35 | if fname == None: 36 | fname = self.args[1] 37 | buffer = open(fname).read() 38 | 39 | if not self.force: 40 | print "\nFILE: " + fname 41 | self.__confirm(buffer) 42 | 43 | if self.backup: 44 | shutil.copyfile(fname, fname + '.ibak') 45 | 46 | buffer = self.regex.sub('', buffer) 47 | 48 | output = open(fname, 'w') 49 | output.write(buffer) 50 | output.close() 51 | 52 | def __confirm(self, buffer): 53 | print "\nThe following text will be matched:\n" 54 | 55 | matches = self.regex.findall(buffer) 56 | if matches: 57 | for match in matches: 58 | print self.__red(match) + "\n" 59 | else: 60 | print self.__red("*** No match ***\n") 61 | 62 | choice = None 63 | while choice == None: 64 | try: 65 | choice = raw_input("Is this ok? (Y)es, (N)o, (A)lways confirm ").lower() 66 | except EOFError: 67 | sys.exit(0) 68 | 69 | if choice == 'y': 70 | self.force = False 71 | elif choice == 'n': 72 | sys.exit(0) 73 | elif choice == 'a': 74 | self.force = True 75 | else: 76 | choice = None 77 | 78 | 79 | def signal_handler(signal, frame): 80 | sys.exit(1) 81 | 82 | 83 | def main(): 84 | signal.signal(signal.SIGINT, signal_handler) 85 | 86 | parser = OptionParser(usage='usage: %prog [options] REGEX FILE') 87 | parser.add_option("-l", "--list-file", action='store_const', dest='listfile', const=True, default=False, help="use a list file") 88 | parser.add_option("-b", "--backup", action='store_const', dest='backup', const=True, default=False, help="make backup files") 89 | parser.add_option("-f", "--force", action='store_const', dest='force', const=True, default=False, help="supress confirmation notice") 90 | 91 | (options, args) = parser.parse_args() 92 | 93 | if len(args) != 2: 94 | parser.print_help() 95 | sys.exit(1) 96 | 97 | pyCleaner = InjectCleaner(options, args) 98 | 99 | try: 100 | if pyCleaner.listMode(): 101 | for line in open(args[1]).readlines(): 102 | pyCleaner.removeInjections(line.strip()) 103 | else: 104 | pyCleaner.removeInjections() 105 | except IOError: 106 | print "\nFile " + args[1] + " not found!" 107 | sys.exit(1) 108 | 109 | print "\nRemoved injections (hopefully)." 110 | 111 | 112 | if __name__ == "__main__": 113 | main() 114 | 115 | -------------------------------------------------------------------------------- /rbls: -------------------------------------------------------------------------------- 1 | Backscatterer;ips.backscatterer.org;http://www.backscatterer.org/?target=test 2 | Barracuda;b.barracudacentral.org;http://www.barracudacentral.org/rbl/removal-request 3 | CBL;cbl.abuseat.org;http://cbl.abuseat.org/lookup.cgi 4 | Lashback;ubl.unsubscore.com;http://www.lashback.com/blacklist/ 5 | Mailspike;bl.mailspike.net;http://mailspike.org/iplookup.html 6 | McAfee;cidr.bl.mcafee.com;stub 7 | PSBL;psbl.surriel.com;http://psbl.org/listing 8 | Senderscore;bl.score.senderscore.com;https://www.senderscore.org/blacklistlookup/ 9 | SORBS;spam.dnsbl.sorbs.net;http://www.sorbs.net/lookup.shtml 10 | Spamcop;bl.spamcop.net;http://www.spamcop.net/bl.shtml 11 | Spamhaus;zen.spamhaus.org;http://www.spamhaus.org/lookup/ 12 | -------------------------------------------------------------------------------- /shell_patterns: -------------------------------------------------------------------------------- 1 | c3284d 2 | psbt 3 | iframe.name.twitter.scrolling 4 | mjdu 5 | gdsg 6 | filesman 7 | system.file.do.not.delete 8 | 2e922c 9 | r57shell 10 | default_use_ajax 11 | tryag_vb 12 | priv8 13 | pgems 14 | @error_reporting\(0\) 15 | 0c0896 16 | tress.x61 17 | _REQUEST..........;.eval.........;.exit..; 18 | yabod1 19 | SEC-ADVISOR 20 | .x65.x64 21 | Hadidi44 22 | d21vd12v 23 | dnnViewState 24 | str_1replace 25 | 0f2490 26 | 74ed9f 27 | keywordsRegex 28 | ba...se...64_d 29 | POST..veio 30 | a9a007 31 | m4d3x 32 | --------------------------------------------------------------------------------