bzkddlZddlZddlZddlmZddlmZddlmZm Z m Z m Z ddl m Z ddlmZddlmZmZmZddlmZdd lmZmZmZdd lmZmZdd lmZdd lm Z dd l!m"Z"ddlm#Z#ddl$m%Z%ddl&m'Z'm(Z(m)Z)ddl*m+Z+m,Z,ddl!m-Z-m.Z.m/Z/ddl0m1Z1ddl2m3Z3ej4e5Z6edej7Z8edej7Z9edZ:edZ;e:dz Zde?fdZ@GddeeZAdS) N)Path) Coroutine)ANTIVIRUS_MODEConfigValidationError SystemConfig UserConfig) HookEvent) MessageType) MessageSink MessageSourceexpect) hosting_panel) load_stateregister_lock_file save_state)Scoperecurring_check) check_lock)DAY)plugin) WordpressWPSite)get_sites_by_pathget_sites_for_userget_installed_sites)is_secret_expired rotate_secret)ChangelogProcessorIncidentCollectorIncidentSender)update_disabled_rules_on_sites)delete_old_wordpress_incidentsz wp-gen-authzwp-site-processz-/etc/sysconfig/imunify360/imunify360.config.dzF/opt/imunify360/venv/share/imunify360/11_on_first_install_wp_av.configz 11_on_first_install_wp_av.configz.11_on_first_install_wp_av.flagstarted_timestampreturnc ddlm}||S#t$rtdgcYSwxYw)z Get malware hits cleaned since the given timestamp with lazy import fallback. Returns empty list if imav.malwarelib is not available. r) MalwareHitz;imav.malwarelib not available, returning empty cleaned hits)imav.malwarelib.modelr' cleaned_since ImportErrorloggerdebug)r$r's V/opt/imunify360/venv/lib/python3.11/site-packages/defence360agent/plugins/wordpress.py_get_cleaned_malware_hitsr.Fsm 444444''(9:::  I    s&AAc eZdZejZdZdZdZdZ dZ dZ dZ dZ d ejfd Zd d efd ZdZeedeedZeeddedZdZdZdZdZdZe e!j"dZ#e e!j$dZ%e e!j$dZ&e e!j$dZ'e e(j)dZ*e e(j+dZ,dS)!ImunifySecurityPlugincfd|_d|_td}|d|_|d}||n t j|_tj |_ tj |_ i|_ tj|_tj|_d|_d|_d|_t+|_t/|_t3|_t7|_d|_dS)Nr0 installedenabled)_loop_sinkrgetinstallation_completedrSECURITY_PLUGIN_ENABLEDlast_config_valuer_get_global_waf_enabled_last_waf_enabled_get_waf_default_last_waf_default_last_user_waf_enabled_get_global_ai_bot_protection_last_ai_bot_protection$_get_global_ai_bot_protection_preset_last_ai_bot_protection_presetinstallation_task deleting_taskinstall_and_update_tasksetfreshly_installed_sitesr incident_collectorr!incident_senderrchangelog_processor_site_processing_task)selfstatepersisted_enableds r-__init__zImunifySecurityPlugin.__init__Zs  233&+ii &<&<#"IIi00!,  2  "(!?!A!A!'!8!:!:>@#(.'K'M'M$  7 9 9 +7;26<@$47EE$#4"5"5-//#5#7#7 :>"""c KdSN)rLloops r- create_sinkz!ImunifySecurityPlugin.create_sink{s  rPcK||_||_|j||_|j||_tr|d{Vnt d| d{VdS)NT) missing_ok) r4r5 create_taskrefresh_auth_files_update_auth_taskprocess_wordpress_sitesrKr_apply_first_install_configFIRST_INSTALL_FLAGunlink _recover_installation_on_startup)rLrTsinks r- create_sourcez#ImunifySecurityPlugin.create_source~s  !%!7!7  # # % %" " &*Z%;%;  ( ( * *& & "  72244 4 4 4 4 4 4 4 4  % % % 6 6 63355555555555rPc,K|js tjsdStdd|_|tj|j d{V|j !|j |j dSdS)a Self-heal when the installation state was lost. If the feature is enabled but installation_completed is falsy (state file missing, earlier install interrupted, etc.), manage_plugin_installation can never recover: its True == True guard always returns early. Trigger install_everywhere once per restart to repopulate the wordpress_site table and flip the flag. NzXInstallation state is missing while feature is enabled; triggering startup self-recoveryTr`) r7rr8r+infor9process_installationrinstall_everywherer5rCadd_done_callback_mark_installation_donerLs r-r_z6ImunifySecurityPlugin._recover_installation_on_startups  ' 4  F  /   "&''  %4: 6 6 6           ! -  " 4 4,      . -rPcfKtsdStjd{VdkrKt t}t dt dS)Ni) r]existsr HostingPanel users_countFIRST_INSTALL_CONFIG_PATH write_textFIRST_INSTALL_CONFIG_FILE read_textchmodr^)rL_s r-r\z1ImunifySecurityPlugin._apply_first_install_configs!((**  F+--99;; ; ; ; ; ; ;q @ @)44)3355A & + +E 2 2 2!!#####rPcK|j|jd{V|jr(|j|jd{VdSdSrR)rZcancelrKris r-shutdownzImunifySecurityPlugin.shutdowns %%'''$$$$$$$$  % -  & - - / / /, , , , , , , , , , - -rPct||std|dSt||}|duo)| o| S)NzUnknown task '%s'F)hasattrr+errorgetattrdone cancelled)rLtask_attr_nametasks r-_task_in_progressz'ImunifySecurityPlugin._task_in_progresssit^,,  LL,n = = =5t^,,4L OLDNNFeature was disabled during installation, skipping flag updateT)r}r+rd exceptionrzr9r7r)rLrexcs r-rhz-ImunifySecurityPlugin._mark_installation_dones >>    KK9 : : : Fnn ? LL7 = = = F%  KK'    F&*# %%'''''rPFcorocK|dr\|r|dS|jr=|j |jd{Vn#tj$rYnwxYw|dr0t d|dSt j||_ dS)NrDrCzInstallation is already running) rcloserDrvasyncioCancelledErrorr+warningrXrC)rLr for_new_sitess r-rez*ImunifySecurityPlugin.process_installations  ! !/ 2 2   ! "))+++,,,,,,,,,-D  ! !"5 6 6  NN< = = = JJLLL F!(!4T!:!:s AA10A1cPK|drD|jr=|j |jd{Vn#tj$rYnwxYw|drt ddStj||_dS)NrCrDzDeleting is already running) rrCrvrrr+rrXrD)rLrs r-process_deletingz&ImunifySecurityPlugin.process_deletings  ! !"5 6 6 % &--///000000000-D  ! !/ 2 2  NN8 9 9 9 F$066s AAAT)check_period_firstcheck_lock_period lock_filecKtrtd{Vtj|jd{VdSNrc)rrrupdate_auth_everywherer5ris r-rYz(ImunifySecurityPlugin.refresh_auth_files s`    "// ! ! ! ! ! ! !+<<<<<<<<<<<zAImunifySecurityPlugin.process_wordpress_sites..9s>>>!QX>>>rP)domainsr`T)delete_after_processing)daysz*Error in WordPress periodic processing: %s)r+r,rrJprocess_changelogs_for_sitesr5r"rHcollect_incidents_for_sitesrIsend_incidentsr# Exceptionrz)rLsitesaffected_sites incidentses r-r[z-ImunifySecurityPlugin.process_wordpress_sitess   A   ! J'))E  F.KK4:   4>>~>>>-II,0J &55dj)LL L L L L L L L * 3 3 3 3 3 3 J J J LLEq I I I I I I I I I Js*C2 B&C22 D"<DD"cKjfd}|dd{VdS)z&Install plugin on new WordPress sites.cKtjjd{V}|rj||Sr)rrfr5rGupdate)installed_sitesrLs r-install_and_trackzFImunifySecurityPlugin._install_on_new_sites..install_and_trackQsT$*$=4:$N$N$NNNNNNNO E,33ODDD" "rPT)rN)rGclearre)rLrs` r-_install_on_new_sitesz+ImunifySecurityPlugin._install_on_new_sitesLs $**,,, # # # # # ''    (           rPc\Ktj|j|jd{Vtj|jd{Vt jsW|tj|jd{Vd|_ d|_ | dSdS)zCTidy up sites from which the WordPress plugin was deleted manually.)r`rGNrcF) rtidy_up_manually_deletedr5rG$fix_data_file_permissions_everywhererr8rremove_all_installedr7r9rris r-_tidy_upzImunifySecurityPlugin._tidy_up\s-$($@          9tzJJJJJJJJJJ0 ,''+<<<       +0D '%*D "  ) ) + + + + +  , ,rPcKtj|jd{V}|r|j|dSdS)zFAdopt sites where plugin is installed but not tracked in our database.rcN)radopt_found_sitesr5rGr)rL adopted_sitess r-_adopt_found_sitesz(ImunifySecurityPlugin._adopt_found_sitesls^$6DJGGGGGGGGG   ?  ( / / > > > > > ? ?rPcJKtj|jd{VdS)z1Update plugin on all sites where it is installed.rcN)rupdate_everywherer5ris r-_update_existingz&ImunifySecurityPlugin._update_existingts4&DJ777777777777rPcK|d{V|jr |jd{V|d{V|d{V|d{VdS)z Combined operation: install on new sites, adopt found sites, tidy up, and update existing plugins. This runs all operations sequentially to avoid race conditions. N)rrCrrrris r-_run_install_and_updatez-ImunifySecurityPlugin._run_install_and_updatexs((*********  ! )( ( ( ( ( ( ( (%%'''''''''mmoo##%%%%%%%%%%%rPcRKtd|j|j|dr"td|jdS|jdkr%|jsdS|d{VdS|dr"td|jdS|dr"td|jdS|jd kr|d{VdS|jd kr| d{VdS|jd krP|jstd dStj | |_ dSdS) NzInstallation is not completed yet, skipping install_and_update)r+rdactionmethodrrr7rrrrrXrrE)rLmessages r-manage_plugin_actionz*ImunifySecurityPlugin.manage_plugin_actions J N N     ! !"; < <  NNI    F >3 3 3. ,,.. . . . . . . . F  ! !"5 6 6  NNC    F  ! !/ 2 2  NNG    F >. . .'')) ) ) ) ) ) ) ) F >Y & &--// ! ! ! ! ! ! ! F >1 1 1. * ,3+>,,..,,D ( ( ( 2 1rPcKt|dtsdStj}||jkrdS||_|r-|js% tdddiid|_n*#t$rt dYnwxYw tdddiid|_ tj |_n*#t$rt dYnwxYw|tj|j d{V|j!|j|jdSdS|sl|js|d rR|tj|j d{Vd|_|dSdSdS) Nconf WORDPRESS waf_enabledTz9waf_enabled config reset skipped, field not in schema yetai_bot_protectionFz?ai_bot_protection config reset skipped, field not in schema yetrcrC) isinstancerrr8r9r7dict_to_configr;rr+r,r@rrArBrerfr5rCrgrhrrrr)rLrcurrent_config_values r-manage_plugin_installationz0ImunifySecurityPlugin.manage_plugin_installations'&/<88  F(@ 4#9 9 9 F"6 , ,(C, , -- =$"78*.&&(    O  -- #6">?05,?AA33)    /  ++)tz:::       %1&88021 & ,  ' ,%%&9:: ,''+<<<       +0D '  ) ) + + + + + , , , ,s% ,A99$B B $AC))$DDcKt|dtsdStjsdS|jsdSt j}t j}||jkr ||j krdS|j dtd{V}|s||_||_ dSt j |d{V}|t|kr||_||_ dSdS)a Propagate admin toggles of WORDPRESS.ai_bot_protection and WORDPRESS.ai_bot_protection_preset to every managed WP install's plugin_config.php immediately, so the WP plugin picks up the change at the next request rather than waiting for a scan cycle. Phase 2 per-account support extends *this* handler with a UserConfig branch (mirroring manage_waf_config); do not add a sibling handler. rN)rrrr8r7rr?rAr@rBr4run_in_executorrupdate_plugin_config_on_siteslen)rLrcurrent_enabledcurrent_presetrwrittens r-manage_ai_bot_protection_configz5ImunifySecurityPlugin.manage_ai_bot_protection_configs'&/<88  F0  F*  F >@@DFF t; ; ;$"EEE Fj007JKKKKKKKK +:D (2@D / Fpopusernameris_waf_enabled_for_userredeploy_wp_rules_for_userremove_waf_rules_for_userr:r WAF_ENABLEDr;remove_waf_rules_for_all_sitesredeploy_wp_rulesKeyError WAF_DEFAULTr=apply_waf_default_change) rLrr config_dict waf_valueprev new_effectivecurrentcurrent_defaults r-manage_waf_configz'ImunifySecurityPlugin.manage_waf_config/s0  Fv))++ OOK4488GG dJ ' '( < 266t}dKK<F&,&DM''!!!!!! J J ;DMJJJJJJJJJJJ-J :4=IIIIIIIIID7;;DMJJJJ9BD ' 6 GF$B$D$D G6t}EEEEEEEEEEE7 FFFFFFFFFFF l + + < 9#/d444-4D*"9$CEEEEEEEEEE$6888888888     <"+"7#d&<<<- no sites found for cleaned hitsz1Cleanup finished => %s site(s) need to be updatedc8g|]\}}t|d|S))docrootruidr)r site_pathrs r-rzIImunifySecurityPlugin.handle_malware_cleanup_finished..s;    3 9RS 9 9 9   rPz"%s site(s) updated after a cleanup)r9r6r.rF resource_typepwdgetpwnamuserrpw_uid orig_file startswithaddrr+r,rdrrupdate_data_on_sitesr5) rLrhits site_pathshit user_info user_sitesrrwordpress_sitess r-handle_malware_cleanup_finishedz5ImunifySecurityPlugin.handle_malware_cleanup_finishedas %  F ;;x D ( ( I0F0F ( F));<<UU   C F**  # SX 6 6I!3I!>!>J,5? ((4&0"" =33I>>"&NNIs+;<<<!E" D+  LLN O O O F ?  OO     ",    )$*oFFFFFFFFF 8#o:N:NOOOOOs/A+C C('C(cK|jsdS|ddks*|dr|dsdS|d}t|}|std|dStdt |tj|j |d{Vtdt |dS) a INFO [2025-02-24 11:57:17,968] imav.plugins.wordpress: Malware scan finished: HookEvent.MalwareScanningFinished( { 'scan_id': 'b9bd136aff0a4d87a248c859cfe41c47', 'scan_type': 'user', 'path': '/home/user1' } ) INFO [2025-02-24 12:00:10,740] imav.plugins.wordpress: Malware scan finished: HookEvent.MalwareScanningFinished( { 'scan_id': 'a74271d2cdd04e0c9bd49ef6de23e0d8', 'scan_type': 'user', 'path': '/home/user4', 'started': 1740398383, 'total_files': 39229, 'total_malicious': 3, 'error': None, 'status': 'ok', 'scan_params': {'intensity_cpu': 2, 'intensity_io': 2, 'intensity_ram': 2048, 'initiator': None, 'file_patterns': None, 'exclude_patterns': None, 'follow_symlinks': False, 'detect_elf': True}, 'stats': {'scan_time': 27, 'mem_peak': 28217344, 'smart_time_hs': 0.004, 'scan_time_hs': 1.1751, 'smart_time_preg': 0, 'scan_time_preg': 2.7391, 'finder_time': 13.5896, 'cas_time': 0.7562, 'deobfuscate_time': 0.8998, 'total_files': 39229} } ) Nrrpathstatsz+Scan finished => no sites found for path=%sz.Scan finished => %s site(s) need to be updatedz%s site(s) updated after a scan) r9r6rr+r,rdrrrr5)rLrrrs r-handle_malware_scan_finishedz2ImunifySecurityPlugin.handle_malware_scan_finisheds8%  F KK ! !T ) );;v&& *;;w'' * Fv!$''  LLF M M M F  P>P.->P@ VI -..4C4C/.4C4C4CrPr0)Brloggingrpathlibrtypingr defence360agent.contracts.configrrrr%defence360agent.contracts.hook_eventsr "defence360agent.contracts.messagesr !defence360agent.contracts.pluginsr r r defence360agent.subsys.panelsr'defence360agent.subsys.persistent_staterrrdefence360agent.utilsrr defence360agent.utils.check_lockrdefence360agent.utils.commonrdefence360agent.wordpressrrdefence360agent.model.wordpressr)defence360agent.wordpress.site_repositoryrrr$defence360agent.wordpress.proxy_authrrrr r! defence360agent.wordpress.pluginr"(defence360agent.model.wordpress_incidentr# getLoggerr r+r rr CONFIG_DIRrqror]floatlistr.r0rSrPr-r+s@  <;;;;;:::::: 877777 98888888777777,,,,,,,,,,,,666666222222  LKKKKK  8 $ $  }en = = ..u~TA B B  DL')KK"CC4"@ C@ C@ C@ C@ CK@ C@ C@ C@ C@ CrP