Backups Created:
/home/polycorc/public_html/wp-admin/admin-wolf.php
/home/polycorc/public_html/wp-content/edit-wolf.php
/home/polycorc/public_html/wp-includes/widgets/class-wp-wolf-widget.php
Savvy
W
olf -
MANAGER
Edit File: cms_counter.py
#!/usr/lib/cwprads/venv/bin/python3 """ CMS Counter 2.3 02/01/2024 Corey S ------- CWP Specific Version - Hardcoded Server Type as VPS and Panel Type as CWP - Removed cms_counter_cpanel() function as cPanel will not exist - Adjusted main() function to accommodate these differences - Customized Apache config checks """ import os import subprocess import sys from pathlib import Path import argparse def run(command=None, check_flag=True): output = None if command and str(command): try: output = ( subprocess.run( command, shell=True, check=check_flag, stdout=subprocess.PIPE, ) .stdout.decode("utf-8") .strip() ) except Exception as e: print(e) return output def identify_apache_config(): """ Function to determine Apache config file to use to check domains as different installs/versions can store the config in different files, starting w/ config for 2.2 and checking different 2.4 config locations to end """ if os.path.exists('/usr/local/apache/conf.d/vhosts'): return '/usr/local/apache/conf.d/vhosts/*.conf' if os.path.exists('/usr/local/apache/conf/httpd.conf'): return '/usr/local/apache/conf/httpd.conf' if os.path.exists('/etc/httpd/conf/httpd.conf'): return '/etc/httpd/conf/httpd.conf' if os.path.exists('/etc/apache2/httpd.conf'): return '/etc/apache2/httpd.conf' if os.path.exists('/etc/apache2/conf/httpd.conf'): return '/etc/apache2/conf/httpd.conf' sys.exit('Unable to determine Apache config!\nQuitting...') def identify_nginx_config(): """ Function to find NGINX config file """ if os.path.exists('/etc/nginx/vhosts'): return '/etc/nginx/vhosts' if os.path.exists('/etc/nginx/conf.d/vhosts'): return '/etc/nginx/conf.d/vhosts' if os.path.exists('/etc/nginx/nginx.conf'): return '/etc/nginx/nginx.conf' sys.exit("Unable to locate NGINX config file! Quitting...") def find_nodejs(docroot=None, domain=None): """ Find possible Node.JS installs per doc root """ install_list = [] if docroot and '\n' not in str(docroot): user = docroot.split('/')[2] if os.path.exists(f"""{docroot}/.htaccess"""): try: with open( f"""{docroot}/.htaccess""", encoding='utf-8' ) as htaccess: for line in htaccess.readlines(): if 'PassengerAppRoot' in line: install_dir = line.split()[1].strip().strip('"') if ( f"""{domain}:{install_dir}""" not in install_list ): # Dont want a dictionary as a single domain # could have multiple subdir installs install_list.append( f"""{domain}:{install_dir}""" ) except Exception: return # If not found in htaccess, check via procs instead if len(install_list) == 0: user_id = run(f"""id -u {user}""", check_flag=False) if user_id and user_id.isdigit(): # Only return procs whose true owner is the user ID of the # currently checked user node_procs = run( f"""pgrep -U {user_id} node""", check_flag=False ).split('\n') if len(node_procs) > 0: for pid in node_procs: try: cwd = run( f"""pwdx {pid} | cut -d ':' -f 2""", check_flag=False, ) command = run( f"""ps --no-headers -o command {pid} | """ + """awk '{print $2}'""", check_flag=False, ).split('.')[1] install_dir = cwd + command except Exception: return if ( install_dir and os.path.exists(install_dir) and f"""{domain}:{install_dir}""" not in install_list ): install_list.append(f"""{domain}:{install_dir}""") return install_list def determine_cms(docroot=None): """ Determine CMS manually with provided document root by matching expected config files for known CMS """ docroot = str(docroot) cms_dictionary = { f"""{docroot}/concrete.php""": 'Concrete', f"""{docroot}/Mage.php""": 'Magento', f"""{docroot}/configuration.php""": 'Joomla', f"""{docroot}/ut.php""": 'PHPList', f"""{docroot}/passenger_wsgi.py""": 'Django', f"""{docroot}/wp-login.php""": 'Wordpress', f"""{docroot}/sites/default/settings.php""": 'Drupal', f"""{docroot}/includes/configure.php""": 'ZenCart', f"""{docroot}/config/config.inc.php""": 'Prestashop', f"""{docroot}/config/settings.inc.php""": 'Prestashop', f"""{docroot}/app/etc/env.php""": 'Magento', f"""{docroot}/app/etc/local.xml""": 'Magento', f"""{docroot}/vendor/laravel""": 'Laravel', } for config_file, content in cms_dictionary.items(): if os.path.exists(config_file): return content if os.path.exists(f"""{docroot}/config.php"""): if os.path.exists(f"""{docroot}/admin/config.php"""): return 'OpenCart' try: with open(f"""{docroot}/config.php""", encoding='utf-8') as config: if 'Moodle' in config.readline(): return 'Moodle' return 'phpBB' except Exception as e: print(e) return None def cms_counter_no_cpanel(verbose=False, user_list=None): """ Function to get counts of CMS from all servers without cPanel """ if not user_list: user_list = [] # Set Variables nginx = 0 apache = 0 web_server_config = None domains_cmd = None domains_list = None domains = {} docroot_list = [] users = [] # List of system users not to run counter against - parsed from /etc/passwd sys_users = [ 'root', 'bin', 'daemon', 'adm', 'sync', 'shutdown', 'halt', 'mail', 'games', 'ftp', 'nobody', 'systemd-network', 'dbus', 'polkitd', 'rpc', 'tss', 'ntp', 'sshd', 'chrony', 'nscd', 'named', 'mailman', 'cpanel', 'cpanelcabcache', 'cpanellogin', 'cpaneleximfilter', 'cpaneleximscanner', 'cpanelroundcube', 'cpanelconnecttrack', 'cpanelanalytics', 'cpses', 'mysql', 'dovecot', 'dovenull', 'mailnull', 'cpanelphppgadmin', 'cpanelphpmyadmin', 'rpcuser', 'nfsnobody', '_imunify', 'wp-toolkit', 'redis', 'nginx', 'telegraf', 'sssd', 'scops', 'clamav', 'tier1adv', 'inmotion', 'hubhost', 'tier2s', 'lldpd', 'patchman', 'moveuser', 'postgres', 'cpanelsolr', 'saslauth', 'nagios', ] try: nginx_status = run( """systemctl status nginx 1>/dev/null 2>/dev/null;echo $?""" ) apache_status = run( """systemctl status httpd 1>/dev/null 2>/dev/null;echo $?""" ) except Exception as e: print(e) # Determine Domain List if str(apache_status) == '0': # If Apache detected we want that, it's easier, so elif here - only use # NGiNX if Apache is not detected apache = 1 web_server_config = identify_apache_config() if web_server_config: domains_cmd = ( f"""grep ServerName {web_server_config} | """ + r"""awk '{print $2}' | sort -g | uniq""" ) elif str(nginx_status) == '0': nginx = 1 web_server_config = identify_nginx_config() if web_server_config: # THIS MAY NEED REFINED - is this compatible with all NGiNX configs # we're checking for? I think one doesn't end in .conf at least domains_cmd = ( f"find {web_server_config} -type f -name '*.conf' -print | " "grep -Ev '\\.ssl\\.conf' | xargs -d '\n' -l basename" ) if domains_cmd: try: domains_list = run(domains_cmd) # Get list of domains except Exception as e: print(e) if domains_list: for domain in domains_list.split(): if apache == 1: docroot_cmd = ( f"grep 'ServerName {domain}' {web_server_config} -A3 | " "grep DocumentRoot | awk '{print $2}' | uniq" ) domain_name = domain elif nginx == 1: domain_name = domain.removesuffix('.conf') if r'*' in domain_name: continue # Skip wildcard subdomain configs if domain_name.count('_') > 0: new_domain = '' if domain_name.split('_')[1] == '': # user__domain_tld.conf domain_name = domain_name.split('_') limit = len(domain_name) - 1 start = 2 while start <= limit: new_domain += domain_name[start] if start != limit: new_domain += '.' start += 1 domain_name = new_domain else: # domain_tld.conf limit = len(domain_name) - 1 start = 0 while start <= limit: new_domain += domain_name[start] if start != limit: new_domain += '.' start += 1 domain_name = new_domain # This is the file name, above we extracted the actual domain # for use later nginx_config = f"""{web_server_config}/{domain}""" if os.path.exists(nginx_config): docroot_cmd = ( f"""grep root {nginx_config} | """ + r"""awk '{print $2}' | uniq | tr -d ';'""" ) else: docroot_cmd = None if docroot_cmd: try: docroot = run(docroot_cmd) except Exception: print(f"""Cannot determine docroot for: {domain_name}""") continue else: print(f"""Cannot determine docroot for: {domain_name}""") continue if docroot and os.path.exists(docroot): node_installs = [] docroot_list.append(docroot) domains.update({f"""{docroot}""": f"""{domain_name}"""}) try: node_installs += find_nodejs( docroot=docroot, domain=domain_name ) # Try and find NodeJS installs except Exception: pass # Check sub-directories bad_dirs = [ f"""{docroot}/wp-admin""", f"""{docroot}/wp-includes""", f"""{docroot}/wp-content""", f"""{docroot}/admin""", f"""{docroot}/cache""", f"""{docroot}/temp""", f"""{docroot}/tmp""", ] docroot_dir = Path(docroot) for d in docroot_dir.iterdir(): if d.is_dir() and d not in bad_dirs: try: node_installs += find_nodejs( docroot=str(d), domain=domain_name ) except Exception: pass dirname = str(os.path.basename(d)) d = str(d) # Convert from Path object to String docroot_list.append(d) domains.update( {f"""{d}""": f"""{domain_name}/{dirname}"""} ) bad_dirs.append(d) # Determine User List if len(user_list) >= 1: users = user_list # Get users if they weren't passed already - if cPanel was detected but not # Softaculous for instance if os.path.exists('/home') and len(user_list) == 0: users_dir = Path('/home') try: with open('/etc/passwd', encoding="utf-8") as passwd: passwd_file = passwd.readlines() except Exception: sys.exit('Unable to read /etc/passwd!\nExiting...') for u in users_dir.iterdir(): if u.is_dir(): limit = len(u.parts) - 1 for line in passwd_file: if ( u.parts[limit] == line.split(':')[0] and u.parts[limit] not in sys_users ): users.append(u.parts[limit]) if len(users) >= 1 and len(docroot_list) >= 1: for docroot in docroot_list: get_cms = None docroot_user = None for user in users: if user in sys_users: continue # Go to next user if current user is System user if user in docroot.split('/'): docroot_user = user break get_cms = determine_cms(docroot=docroot) if get_cms and docroot_user and docroot_user not in sys_users: domain = domains.get(f"""{docroot}""", None) if verbose: print(f"""VPS CWP {docroot_user} {domain} {get_cms}""") else: print(f"""{docroot_user} {domain} {get_cms}""") for install in node_installs: if verbose: print(f"""VPS CWP {docroot_user} {install} NodeJS""") else: print(f"""{docroot_user} {install} NodeJS""") return def main(): """ Main function, initializes global variables as globals, gets hostname and call relevant checks after determining enviroment """ parser = argparse.ArgumentParser( description='CMS Counter 2.0 -- CWP Version' ) parser.add_argument( '-v', '--verbose', dest='verbose', help='Include Panel Type and Server Type in output', action='store_const', const=True, default=False, ) args = vars(parser.parse_args()) verb = args['verbose'] cms_counter_no_cpanel(verbose=verb) return if __name__ == "__main__": main()