a hX@sdZddlmZddlZddlZddlZddlmZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlmZddlZddlZddlmZmZddlmZmZmZddlmZmZmZdd lmZddlZddlZddl Z ddl!Z!ddl"m#Z$dd l%m&Z&e 'dkZ(d Z)d Z*d Z+dZ,dZ-dZ.dZ/e0edd1Z2e3dej4Z5e3dZ6ee7e8j9Z:e3dZ;eGdddZGdddZ?ddZ@eAeBeAeAdd d!ZCeDeAeeAdfd"d#d$ZEdd%eDeeeAdfd&d'd(ZFeed)d*d+ZGd,d-ZHdS).zClamscan and freshclam classes) ExitStackN)Path) dataclass)IOUnion)PopenCalledProcessErrorTimeoutExpired)runDEVNULLPIPE) timedelta)Procz,https://repo.imhadmin.net/open/shellscan/v3/)zimh.yara)zheuristic.yaraz/opt/imh-scan/sigs/heuri/z/opt/imh-scan/sigs/yara/z!/opt/imh-scan/sigs/last_freshclamz/opt/imh-scan/sigs/new/new.yara)Zweeksz(.*)\: (.*) FOUND$z(?:YARA.)?[Hh]euristicz (/home[0-9]?/[a-zA-Z0-9]{1,16})/c@sveZdZUdZeed<eed<eeefed<eeefed<eed<e eddd Z e eeefdd d Z d S) ScanResultzClamscan resultrcodecommand hits_found heur_foundsummary)returncCs6|j|jdd|jDdd|jD|jdS)NcSsi|]\}}t||qSstr.0kvrr.//opt/imh-scan/clamlib.py :z'ScanResult.__dict__..cSsi|]\}}t||qSrrrrrrr;r rrrrr)rrritemsrrselfrrr__dict__5s zScanResult.__dict__cCs |j|jBSN)rrr#rrr all_found?szScanResult.all_foundN) __name__ __module__ __qualname____doc__int__annotations__rdictrpropertyr%r'rrrrr+s  rcsfeZdZdZeedeeedfdd Z ddZ dd Z ed d d Z eeed dddZ ZS) ClamParserz"Thread for parsing clamscan stdoutScannerprocscanner open_logfiles print_itemscsNtj|jdd||_||_d|_||_i|_i|_g|_ ||_ | dS)NT)targetZdaemonF) super__init__parser3r4_scanning_summary _print_itemsrr summary_linesr5start)r$r3r4r5r6 __class__rrr9GszClamParser.__init__cCsB|D]4}|jr2|jr$t|dd|j|q||qdS)N)end) _iter_foundr;r<printr=append _handle_foundr$linerrrr:Ys   zClamParser.parseccsd}|jjD]n}|jD]}||q|jr4|Vq |drPd|_d}|Vq |drr||Vd}q ||7}q dS)NrAzSCAN SUMMARY ----------- TzFOUND )r3stdoutr5writer;endswithrstrip)r$prevrHZlog_filerrrrCbs      zClamParser._iter_found)datacCst|}|s"|jjd|dS|\}}t|}|sR|jjd|dStt |}rp||j |<n ||j |<| |||dS)Nz imh-scan bug: Regex failed on %rzimh-scan bug? %r is not a file)FOUND_REmatchr4logerrorgroupsris_filebool HEURISTIC_REsearchrr _print_found)r$rNrPZpath_strrulepathis_heurrrrrFus    zClamParser._handle_foundN)rZrYr[rcCsB|js dS|rtjntj}ttt|||dddddS)Nz FOUNDz: T)sepflush)r<cyellowredrDshlexquoter)r$rZrYr[colorrrrrXs zClamParser._print_found)r(r)r*r+rrlistrrUr9r:rCrFrX __classcell__rrr?rr0Ds r0c@seZdZdZeeeeeeeeeeeeeed ddZeeedddZdd Z d d Z eed d dZ eedddZ ddZ ddZeeeeeejdffeedddZeeeeeeeeed ddZd$eeeeeeejdffeeddd Zed!d"d#ZdS)%r1z(Handles executing clamscan and freshclam) excludeverbose extra_heuriinstallupdate heuristicphishing disable_mediadisable_excludesdisable_defaultdisable_freshclamenable_maldetectdisable_new_yarac  Csj||_||_||_tjdd|r$tjntjtj dd|_ |j | | | d|_ |j ||||| | || | d |_dS)zInitializes variablesNzimh_scan.Scannerz %(message)s)rZnameZloglevelZ print_outZfmtrqrpro) rmrlrkrfrrrnrhrqro)rgrirjradsZ setup_loggingloggingDEBUGINFOsysrIrQ _check_deps cmd_paths _make_commandr)r$rfrgrhrirjrkrlrmrnrorprqrrrrrr9s4zScanner.__init__rtc Cstdkotjdk }| }| o(| }|}d|dgdd||ddd gd||d gd d||d d gd||d dgdd}g} g} i} |D]\} } | dkr| drt| dsttd| dsqt| d}|r|j d||| | <q|j d| | ds*|j d| | | q| dd kr| d| vr| | dq| r~|j d| |j d| t d| s| S|| }|s|j d| t d| S)z^error handling and installing of dependencies, only supports installing from EPEL reporsharedTZclamav)z/usr/bin/clamscanz /bin/clamscanz'/usr/local/cpanel/3rdparty/bin/clamscan)needpermitpkgpathsz clamav-dataz/var/lib/clamavz /var/clamavzclamav-freshclam)z/usr/bin/freshclamz(/usr/local/cpanel/3rdparty/bin/freshclamz/bin/freshclamz/etc/freshclam.confrAz/usr/local/maldetect/sigs)clamscan clamav-db freshclam freshconfmaldetrr~rz maldet-imh is deprecated and no installation found. This scan will proceed and maldet related errors can be ignored. If you wish to utilize maldetect, please install from source. z found path %szmissing dependancy %srz#not permitted to install missing %srzmissing pkgs: %szallowed to install: %srz!Failed to install dependancies %s)osgetuidruIMH_ROLEr" _find_binaryrDr^r`rQdebugrRrEryexit _install_deps)r$rqrproZ shared_permitZ clamdb_needZfreshclam_needZ maldet_needZdeps_dZ install_listZ failed_listrdepZoptsZ found_pathreqrrrrzs     /        zScanner._check_depsc Cs|jr d}ntd|ddd}|dkr>|jdtdz$tgd ||jrVdntd d Wn`t y}z"|j |td WYd}~n0d}~0t y|j d td Yn0d S)NyzWould you like to install z? (y|n))rn)charsrZexitingr)Zyumz-yriT)rIZcheckrzerror running yum, exiting) ri ask_promptrQwarningryrr rgr FileNotFoundErrorrRrfatal)r$rZretexcrrrr+s,         zScanner._install_depscCsFtd}td}||kr<|jd||tdq dSq dS)Nrrz5Load too high to start clamscan (%s/%s), sleeping 30s)psutil cpu_countr getloadavgrQrtimesleep)r$Z cpu_limitZloadavgrrrcpu_waitDs   zScanner.cpu_wait)rprocCsttfD]}t|jddddq|jdtttD](}t|}t|}| ||q8tD](}t|}t|}| ||qf|j r|j d| t d|s|rdS| dS)zUpdates the custom definitionsiTmodeparentsexist_okzDefinitions to get: %szJust updating defintionsrN)DEFS_DIRHEUR_DIRrmkdirrQr DEF_FILES HEUR_FILES DEFS_SERVER_download_filerjr _freshclamryr)r$rproZdir_nameZdef_fileurlrZrrr update_defsRs$       zScanner.update_defs)rdestc Cs|jd||ztj|dddf}|tt|dd,}|jddD]}||qLWdn1sp0YWdn1s0YWn6tj y}z|j d ||WYd}~n d}~00t |d|dS) NzDownloading %s to %sTr)streamtimeoutz.tmpwbi )Z chunk_sizez"Unable to retrieve %s, skipping %s) rQrrequestsgetZraise_for_statusopenrZ iter_contentrJZRequestExceptionrRrrename)r$rrrfilechunkrrrrrgsL&zScanner._download_filec Cstt}tjtr|jsttdd}z>t| }|d|krh|j dWWddSWn4t y}z|j dt|WYd}~n d}~00Wdn1s0Yd|jd}|jd |g}|j d |zXt|td d 4}|jD]}|jsq||qWdn1s60YWn6tyx}z|j d |WYd}~dSd}~00|jr|j ddSttddd}|t|Wdn1s0Y|jdS)zRuns freshclam for systemasciiencodingiQz+freshclam ran less than a day ago, skippingNzerror reading %s %sz--config-file=rrzfreshclam command: %sutf-8)rIrzERROR: freshclam failed: %sz=ERROR: freshclam failed, database.clamav.net probably offlinew)r,rrrZexists FRESH_CACHErjrreadstriprQr ExceptionrRr{rrr rIrg_freshclam_printOSError returncoderJrclose) r$ZnowrZlast_runrZfreshclam_confZ fresh_cmdr3rHrrrrss@  D 2.zScanner._freshclamcCsNztj|d}|Wn"ty:|jd|YdS0|jd|dS)N)dirz%s is not writeableFz%s is writeableT)tempfileZ TemporaryFilerrrQr)r$rZZtestfilerrrwrite_oks   zScanner.write_okN)stack log_tuplesrc Csg}|D]\}}z2|jjdddd|dur@t|j|j|jWn<ty~}z$|jd|t dWYd}~n d}~00| | |j ddd|durt||j|j|jd d q|S) NTrz%s error in _init_logsarri)r)parentrrchownZpw_uidZpw_gidrrQrryrrE enter_contextrchmod)r$rrfileslog_pathownerrrrr _init_logss   zScanner._init_logs) rmrlrkrrrnrhrqrorfc Cs|jdddddg} |r"| d|r0| d|sH| d|jd g| dtg|rn| d|jd g|stjtr| dtg|r| dtg|r| d |s| d | r| D]} | d | gq| d| S)Nrz-rz--normalize=noz--cross-fs=yesz-iz--heuristic-alerts=yesz--phishing-sigs=yesz-drrz7--exclude=\.(jpe?g|png|gif|mp(eg|4|g)|mov|avi|wmv|flv)$z--exclude=/home[0-9]?/[^/]*/(quarantine*|mail/|etc/|logs/.*(\.tar)?\.gz|tmp/awstats/.*.txt|tmp/webalizer/(.*usage_.*.html|webalizer\.current))z --excludez--) r{rEextendrrrZrDUMMYr) r$rmrlrkrrrnrhrqrorfcmdrZrrrr|s@    zScanner._make_commandF) scan_pathsrr6rc Csttt|}|sJ|j}|||jdt t |zt }| ||}zt|ttddddT}t||||d} z|jtdWnty|Yn0| Wdn1s0YWn(ty||jdYn 0|jd kr$|jd |j Wdn1s:0YWn>ty} z$|jd | td WYd} ~ n d} ~ 00|jd kr|D]f\} } t| d dd<} | d|j d|jdkr| dWdn1s0YqnZ| j sZ| j!sZ|D]D\} } t| ddd} | dWdn1sL0Yq| t"|jt || j | j!d | j#dS)z Runs clamscanzScan command: %sNrsurrogateescape)ZlimrIstderrrerrorsr2)rz>Scan interrupted; continuing with what it found so far, if anyrz\The clamscan process was killed with signal %d; continuing with what it found so far, if anyzError: clamav fatal error: %srrrz&Scan was interrupted with kill signal  iz.This usually means an out-of-memory condition rzNo malware detected rAr!)$rdmaprrcopyrrQrr^cyanrajoinrrrrrr r0waitCOMMAND_TIMEOUTr killKeyboardInterruptrRrrrryrrrJrrrr=)r$rrr6Zscan_path_strsrrr5r3parserrr_rrrrscans    *  (    * . z Scanner.scan)rHcCshtdtd|}tdtdd|}tdtdd|}tdtd|}|j|dS)z$Styles clamscan output and prints itz(ClamAV update process started)z\1z!(WARNING|(?:YARA.)?[Hh]euristic)::z(ERROR):z!((?:main|daily|bytecode)\.c[lv]d)N) resubr^boldr_r`rrQrrGrrrr7szScanner._freshclam_print)F)r(r)r*r+rdrrUr9rzrrrrrrrtuplerrpwdZ struct_passwdrrr|rrrrrrrr1s^ / m %   6 Mr1cCs tddS)NzPrompt timed out) TimeoutError)ZsignumZ_framerrr_prompt_timeoutBsr)linesrrcGs\d}d}d|}ttjtt|||vrNtt|d }q*td|S)zSimple yes or no checkeri: rArr) rsignalSIGALRMralarminputr^rrlower)rrZone_weekZanswerZquestionrrrrFs   r)paths_to_checkrcCs"|D]}tj|r|SqdS)z!used to find clamav and freshclamN)rrZr)rrZrrrrSs  r)time_str)rrc Cs|durttt}|s(tddSg}|D]}tt|}rdt|d}|d|}n,tj dkrt rtd|}nt d|}||vrtd|| |zt ||Wq0ty}z$t|d|d tjd WYd}~q0d}~00q0dS) z4Decides the quarantine dir per file and runs jail_mvNzNothing to quarantinerzquarantine/quarantine_r}z"/home/t1bin/quarantine/quarantine_zQuarantine root: %szError: quarantine failed for r)r\r)rr,rrDHOME_RErPrgrouprurIS_ROOT CUR_USER_HOMErEjail_mvrryr)rrZ printed_roots file_pathrPZ user_home jail_rootrrrr jail_files[s2  r)rrcCs|jddddt|d|t|jd}|jdddt|j|t|j|||j }t ||t||t |t|ddS)z+Quarantine function retaining dir structurerTr/)rrrN) rrrrrlstripshutilZcopystat copy_uid_guidrsZcopy2remove)rrZdest_dirZ dest_pathrrrrys      rcCs^t|}t|}|j|jkr0|j|jkr0dSzt||j|jWntyXYn0dSr&)rstatst_uidst_gidrr)srcZdstZ src_statsZ dst_statsrrrrs     r)Ir+ contextlibrZgetpassrrvpathlibrrarrryrZ threadingZ dataclassesrrrtypingrr subprocessrrr r r r Zdatetimer rrrruZ rads.colorrcr^Zcprocrrrrrrrrrrr,Z total_secondsrcompileDOTALLrOrVgetpwnamZgetuserpw_dirrrrZThreadr0r1rrrrrdrrrrrrrrsd         J7 "