qjk2ddlZddlZddlZddlmZddlmZddlmZm Z m Z m Z ddl m Z ddlmZddlmZmZmZddlmZdd lmZmZmZdd lmZmZmZdd lmZdd l m!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/m0Z0ddl1m2Z2ddl3m4Z4ej5e6Z7edej8Z9edej8Z:edZ;edZej?dddZ@deAdeBfd ZCGd!d"eeZDdS)#N)Path) Coroutine)ANTIVIRUS_MODEConfigValidationError SystemConfig UserConfig) HookEvent) MessageType) MessageSink MessageSourceexpect) hosting_panel) load_stateregister_lock_file save_state)Scopeimporterrecurring_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.flagzimav.malwarelib.model MalwareHit)modulenamedefaultstarted_timestampreturnc|ttdgSt|S)z Get malware hits cleaned since the given timestamp with lazy import fallback. Returns empty list if imav.malwarelib is not available. Nz;imav.malwarelib not available, returning empty cleaned hits) _MalwareHitloggerdebug cleaned_since)r)s V/opt/imunify360/venv/lib/python3.11/site-packages/defence360agent/plugins/wordpress.py_get_cleaned_malware_hitsr1Js?  I     $ $%6 7 77c 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)Nr4 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_senderr changelog_processor_site_processing_task)selfstatepersisted_enableds r0__init__zImunifySecurityPlugin.__init__[s  233&+ii &<&<#"IIi00!,  2  "(!?!A!A!'!8!:!:>@#(.'K'M'M$  7 9 9 +7;26<@$47EE$#4"5"5-//#5#7#7 :>"""r2c KdSN)rPloops r0 create_sinkz!ImunifySecurityPlugin.create_sink|s  r2cK||_||_|j||_|j||_tr|d{Vnt d| d{VdS)NT) missing_ok) r8r9 create_taskrefresh_auth_files_update_auth_taskprocess_wordpress_sitesrOr_apply_first_install_configFIRST_INSTALL_FLAGunlink _recover_installation_on_startup)rPrWsinks r0 create_sourcez#ImunifySecurityPlugin.create_sources  !%!7!7  # # % %" " &*Z%;%;  ( ( * *& & "  72244 4 4 4 4 4 4 4 4  % % % 6 6 63355555555555r2c,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-recoveryTrc) r;rr<r-infor=process_installationrinstall_everywherer9rGadd_done_callback_mark_installation_donerPs r0rbz6ImunifySecurityPlugin._recover_installation_on_startups  ' 4  F  /   "&''  %4: 6 6 6           ! -  " 4 4,      . -r2cfKtsdStjd{VdkrKt t}t dt dS)Ni) r`existsr HostingPanel users_countFIRST_INSTALL_CONFIG_PATH write_textFIRST_INSTALL_CONFIG_FILE read_textchmodra)rP_s r0r_z1ImunifySecurityPlugin._apply_first_install_configs!((**  F+--99;; ; ; ; ; ; ;q @ @)44)3355A & + +E 2 2 2!!#####r2cK|j|jd{V|jr(|j|jd{VdSdSrU)r]cancelrOrls r0shutdownzImunifySecurityPlugin.shutdowns %%'''$$$$$$$$  % -  & - - / / /, , , , , , , , , , - -r2ct||std|dSt||}|duo)| o| S)NzUnknown task '%s'F)hasattrr-errorgetattrdone cancelled)rPtask_attr_nametasks r0_task_in_progressz'ImunifySecurityPlugin._task_in_progresssit^,,  LL,n = = =5t^,,4L OLDNNFeature was disabled during installation, skipping flag updateT)rr-rg exceptionr}r=r;r)rPrexcs r0rkz-ImunifySecurityPlugin._mark_installation_dones >>    KK9 : : : Fnn ? LL7 = = = F%  KK'    F&*# %%'''''r2FcorocK|dr\|r|dS|jr=|j |jd{Vn#tj$rYnwxYw|dr0t d|dSt j||_ dS)NrHrGzInstallation is already running) rcloserHryasyncioCancelledErrorr-warningr[rG)rPr for_new_sitess r0rhz*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)NrGrHzDeleting is already running) rrGryrrr-rr[rH)rPrs r0process_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{VdSNrf)rrrupdate_auth_everywherer9rls r0r\z(ImunifySecurityPlugin.refresh_auth_files s`    "// ! ! ! ! ! ! !+<<<<<<<<<<<zAImunifySecurityPlugin.process_wordpress_sites..:s>>>!QX>>>r2)domainsrcT)delete_after_processing)daysz*Error in WordPress periodic processing: %s)r-r.rrNprocess_changelogs_for_sitesr9r#rLcollect_incidents_for_sitesrMsend_incidentsr$ Exceptionr})rPsitesaffected_sites incidentses r0r^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)rrir9rKupdate)installed_sitesrPs r0install_and_trackzFImunifySecurityPlugin._install_on_new_sites..install_and_trackRsT$*$=4:$N$N$NNNNNNNO E,33ODDD" "r2T)rN)rKclearrh)rPrs` r0_install_on_new_sitesz+ImunifySecurityPlugin._install_on_new_sitesMs $**,,, # # # # # ''    (           r2c\Ktj|j|jd{Vtj|jd{Vt jsW|tj|jd{Vd|_ d|_ | dSdS)zCTidy up sites from which the WordPress plugin was deleted manually.)rcrKNrfF) rtidy_up_manually_deletedr9rK$fix_data_file_permissions_everywhererr<rremove_all_installedr;r=rrls r0_tidy_upzImunifySecurityPlugin._tidy_up]s-$($@          9tzJJJJJJJJJJ0 ,''+<<<       +0D '%*D "  ) ) + + + + +  , ,r2cKtj|jd{V}|r|j|dSdS)zFAdopt sites where plugin is installed but not tracked in our database.rfN)radopt_found_sitesr9rKr)rP adopted_sitess r0_adopt_found_sitesz(ImunifySecurityPlugin._adopt_found_sitesms^$6DJGGGGGGGGG   ?  ( / / > > > > > ? ?r2cJKtj|jd{VdS)z1Update plugin on all sites where it is installed.rfN)rupdate_everywherer9rls r0_update_existingz&ImunifySecurityPlugin._update_existingus4&DJ777777777777r2cK|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)rrGrrrrls r0_run_install_and_updatez-ImunifySecurityPlugin._run_install_and_updateys((*********  ! )( ( ( ( ( ( ( (%%'''''''''mmoo##%%%%%%%%%%%r2cRKtd|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-rgactionmethodrrr;rrrrr[rrI)rPmessages r0manage_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 1r2cKt|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 yetrfrG) isinstancerrr<r=r;dict_to_configr?rr-r.rDrrErFrhrir9rGrjrkrrrr)rPrcurrent_config_values r0manage_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)rrrr<r;rrCrErDrFr8run_in_executorrupdate_plugin_config_on_siteslen)rPrcurrent_enabledcurrent_presetrwrittens r0manage_ai_bot_protection_configz5ImunifySecurityPlugin.manage_ai_bot_protection_configs'&/<88  F0  F*  F >@@DFF t; ; ;$"EEE Fj007JKKKKKKKK +:D (2@D / Fr WAF_ENABLEDr?remove_waf_rules_for_all_sitesredeploy_waf_for_all_sitesKeyError WAF_DEFAULTrAapply_waf_default_change) rPrr config_dict waf_valueprev new_effectivecurrentcurrent_defaults r0manage_waf_configz'ImunifySecurityPlugin.manage_waf_config0s0  Fv))++ OOK4488GG dJ ' '( < 266t}dKK<F&,&DM''!!!!!! J J 6t}EEEEEEEEEEJ-J :4=IIIIIIIIID7;;DMJJJJ9BD ' 6 BF$B$D$D B6t}EEEEEEEEEEE24=AAAAAAAAAAA l + + < B#/d444-4D*"B$CEEEEEEEEEE$?AAAAAAAAA     <"+"7#d&<<<- no sites found for cleaned hitsz1Cleanup finished => %s site(s) need to be updatedc8g|]\}}t|d|S))docrootruidr)r site_pathrs r0rzIImunifySecurityPlugin.handle_malware_cleanup_finished..s;    3 9RS 9 9 9   r2z"%s site(s) updated after a cleanup)r=r:r1rJ resource_typepwdgetpwnamuserrpw_uid orig_file startswithaddrr-r.rgrrupdate_data_on_sitesr9) rPrhits site_pathshit user_info user_sitesrrwordpress_sitess r0handle_malware_cleanup_finishedz5ImunifySecurityPlugin.handle_malware_cleanup_finishedbs %  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) r=r:rr-r.rgrrrr9)rPrr rs r0handle_malware_scan_finishedz2ImunifySecurityPlugin.handle_malware_scan_finisheds8%  F KK ! !T ) );;v&& *;;w'' * Fv!$''  LLF M M M F  P>P.->P@ VI -..4C4C/.4C4C4Cr2r4)Erloggingrpathlibrtypingr defence360agent.contracts.configrrrr%defence360agent.contracts.hook_eventsr "defence360agent.contracts.messagesr !defence360agent.contracts.pluginsr r r defence360agent.subsys.panelsr'defence360agent.subsys.persistent_staterrrdefence360agent.utilsrrr defence360agent.utils.check_lockrdefence360agent.utils.commonrdefence360agent.wordpressrrdefence360agent.model.wordpressr)defence360agent.wordpress.site_repositoryrrr$defence360agent.wordpress.proxy_authrrr r!r" defence360agent.wordpress.pluginr#(defence360agent.model.wordpress_incidentr$ getLoggerr r-rrr CONFIG_DIRrtrrr`r:r,floatlistr1r4rVr2r0r.sf  <;;;;;:::::: 877777 CBBBBBBBBB777777,,,,,,,,,,,,666666222222  LKKKKK  8 $ $  }en = = ..u~TA B B  DL')KK"CChl "t 8 84 8 8 8 8@ C@ C@ C@ C@ CK@ C@ C@ C@ C@ Cr2