Python安全运维实战:针对几种特定隐藏方式的Webshell查杀

简介:

Webshell一直都是网站管理员痛恨看到的东西,一旦在网站目录里看到了陌生的webshell基本说明网站已经被攻击者拿下了。站在攻击者的角度,要想渗透一台网站服务器,第一个目标也是想方设法的寻找漏洞上传webshell。

对于webshell的防护通常基于两点:一是在攻击者上传和访问时通过特征匹配进行检测拦截或限制文件类型阻止上传;二就是日常基于webshell文件特征的静态查杀(也有基于日志的,在这里不做讨论)。第一种方法不是我们今天要讨论的,waf、安全狗等一系列工具可以实现相应的功能。第二种方式静态查杀,通常会匹配一些关键字、危险函数、一些特征代码及他们的各种加密形式,以遍历文件的方式来进行查杀。然而还有很多种通过破坏遍历规则(使恶意文件无法被遍历到)的隐藏方式,通常可以达到避免被查杀的目的。今天我们要说的就是: 如何利用python实现针对这几种特定隐藏方式的webshell查杀。

一、ntfs交换数据流隐藏webshell

NTFS交换数据流(alternate data streams,简称ADS)是NTFS磁盘格式的一个特性,在NTFS文件系统下,每个文件都可以存在多个数据流,就是说除了主文件流之外还可以有许多非主文件流寄宿在主文件流中。它使用资源派生来维持与文件相关的信息,虽然我们无法看到数据流文件,但是它却是真实存在于我们的系统中的。

利用ntfs交换数据流隐藏文件的方式很久以前就出现了,介绍利用这种方式来隐藏webshell的文章也不少。这种隐藏方式主要针对一句话木马,因为如果被包含的文件为大马则失去了隐藏的意义(若被包含的文件为大马,会直接跳转到大马页面,原页面也就相当于被篡改了,很容易就会被发现)。前两天做了个测试,却发现自己手头经常使用的几个webshell查杀工具居然都检测不出来,最好的结果只报了一个可疑文件包含,便考虑自己动手写一写。

整体逻辑很简单,首先遍历web应用所在的文件夹,找出所有利用ntfs交换数据流隐藏的文件,组成一个list;其次遍历所有.asp文件(以asp为例),找出所有采用了包含头的.asp文件,将其路径作为value,将被包含的文件路径作为key,建立一个dict。与之前的list做对比,若在dict中发现了存在于list中的元素,则断定它为webshell,最后将其路径输出,并同时将包含它的.asp文件路径输出。说白了就是以这个包含了ntfs交换数据流文件的动作来断定它是否为webshell。

使用到的windows命令:dir /r #显示文件的备用数据流

使用到的windows命令:dir /r #显示文件的备用数据流

 
  1. # -*- coding: cp936 -*- 
  2. import os,os.path 
  3. import re 
  4.   
  5. def searchNTFS(catalog):                  #搜索所有ntfs ads文件目录,返回list 
  6.     resultL= [] 
  7.     forroot,dirs,files in os.walk(catalog):           #利用os.walk()递归遍历文件 
  8.         line'' 
  9.        command = 'cd '+ root + '&' + 'dir /r' 
  10.         r =os.popen(command) 
  11.         infor.readlines() 
  12.         forl in info: 
  13.            lineline = line + l 
  14.         reN'\s(\S+)\:\$DATA' 
  15.         reres= re.findall(reN,line) 
  16.         forre1 in res: 
  17.            if re1 != '': 
  18.                result = root + '\\' + re1 
  19.                resultL.append(result)     
  20.     returnresultL 
  21.   
  22. def searchInclude(catalog):    resultL= [] 
  23.     resultD= {} 
  24.     forroot,dirs,files in os.walk(catalog): 
  25.         forf in files: 
  26.            dir = os.path.join(root,f) 
  27.            if dir[-4:] == '.asp': 
  28.                try : 
  29.                    fp = open(dir,'r') 
  30.                    for line in fp.readlines(): 
  31.                         reN = '<\!--#include\S+="(\S+)"-->' 
  32.                         reres = re.findall(reN,line) 
  33.                         for re1 in res: 
  34.                             if re1 != '': 
  35.                                 result = root +'\\' + re1 
  36.                                 resultD[result]= root + '\\' +f 
  37.                except: 
  38.                    print "File :" + dir + " can't be read" 
  39.     returnresultD 
  40.   
  41. if __name__ == "__main__": 
  42.     reD =searchInclude('C:\inetpub\wwwroot') 
  43.     reN =list(set(reD.keys()).intersection(set(searchNTFS('C:\inetpub\wwwroot')))) 
  44.     reI = [] 
  45.     for re1in reN: 
  46.        reI.append(reD[re1]) 
  47.     if reI!= []: 
  48.         forre2 in reN : 
  49.            print '###############################################################' 
  50.            print "[+]Suspicious ADS files found : " + re2 
  51.         for re3 in reI : 
  52.            print '###############################################################' 
  53.            print "[+]Including files: " + re3 + "  \n Please check it." 
  54.     else : 
  55.        print "[+]No suspicious ADS files found." 

二、畸形文件名、保留文件名隐藏webshell

简单科普下,windows的畸形目录名有很多种,通常是指文件名中存在多个.号,例如\a…\,图形界面下无法访问和删除,命令行界面也只能通过windows的短文件名进行访问。

Windows的保留文件名,例如aux、prn、con、nul、com1~9、lpt1~9等等,windows不允许用户以常规方式自行创建,但可以通过copy或者echo等命令加上网络位置\\.\来创建,访问也要在绝对路径前加上\\.\来访问(例如type \\.\C:\inetpub\wwwroot\aux.asp)。

利用的时候可以单种使用也可以一起使用,例如C:\inetpub\wwwroot\a…\aux.asp

我们需要用到命令:dir /x #显示为非 8.3 文件名产生的短名称

畸形文件名、保留文件名隐藏webshell

 
  1. # -*- coding: cp936 -*- 
  2. import os,os.path 
  3. import re 
  4.   
  5. def searchSFN(catalog): 
  6.     resultL = [] 
  7.     resultL2 = [] 
  8.     for root,dirs,files in os.walk(catalog):            #利用os.walk()递归遍历文件 
  9.         line = '' 
  10.         command = 'cd '+ root + '&' + 'dir/x' 
  11.         r = os.popen(command) 
  12.         info = r.readlines() 
  13.         for l in info: 
  14.             lineline = line + l 
  15.         reN1 = '\s+(\S+\~\S+)\s+\S+\.\.+' 
  16.         reres = re.findall(reN1,line) 
  17.         for re1 in res: 
  18.             if re1 != '': 
  19.                 result = '\\\\.\\' + root + '\\'+ re1 
  20.                 resultL.append(result) 
  21.         
  22.  reN2  
  23. ='\s+((aux|prn|con|nul|com1|com2|com3|com4|com5|com6|com7|com8|com9|lpt1|lpt2|lpt3|lpt4|lpt5|lpt6|lpt7|lpt8|lpt)\.\S+)\s+' 
  24.         reres2 = re.findall(reN2,line) 
  25.         for re2 in res2: 
  26.             if re2 != '': 
  27.                 result2 = '\\\\.\\' + root +'\\' + re2[0] 
  28.                 resultL2.append(result2) 
  29.     return resultL,resultL2 
  30.   
  31. defdeleteSFN(list,list2): 
  32.     for l1 in list : 
  33.         str = raw_input('Do you want to delete: ' + l1 + '? (y/n)') 
  34.         if str == 'y' : 
  35.             command = 'rd /s /q ' + l1 
  36.             r = os.popen(command) 
  37.         else : 
  38.             pass 
  39.     for l2 in list2 : 
  40.         str = raw_input('Do you want to delete: ' + l2 + '? (y/n)') 
  41.         if str == 'y' : 
  42.             command = 'del /f /q /a ' + l2 
  43.             r = os.popen(command) 
  44.         else : 
  45.             pass 
  46.   
  47. if __name__ =="__main__": 
  48.     list,list1 =searchSFN('C:\inetpub\wwwroot') 
  49.     deleteSFN(list,list1) 

这里提供了两个函数,searchSFN()找出应用目录中所有畸形目录名对应的短文件名和所有windows保留文件名,返回两个目录列表,deleteSFN()决定是否删除他们。

三、驱动隐藏webshell(Easy File Locker)

驱动隐藏的原理是在windows的指针遍历到一个文件夹的时,增加一个文件夹大小的偏移量,直接跳过文件夹,从而达到隐藏的目的。现在最常见到的驱动隐藏通常是借助第三方软件Easy File Locker实现的,几年前也就存在了,但是说说我自己测试的结果吧,手头的webshell查杀工具全军覆没,没有一个能反映出一点痕迹的。简单写了个函数用于查看是否存在Easy File Locker的服务并删除。利用了windows下的sc qc xlkfs、net stop xlkfs和sc delete xlkfs三条命令,xlkfs是Easy File Locker的服务名。(这里写成脚本模式是为了方便后续写成插件加入传统查杀工具,否则直接使用命令即可)

 
  1. # -*- coding: cp936 -*- 
  2. import os,os.path 
  3. import re 
  4.   
  5. def searchEFL(): 
  6.     line = '' 
  7.     command1 = 'sc qc xlkfs'         #插看是否存在xlkfs服务,返回1060则判定不存在 
  8.     command2 = 'net stop xlkfs' + '&' + 'sc delete xlkfs'      #停止并删除服务 
  9.     r =os.popen(command1) 
  10.     info = r.readlines() 
  11.     for l in info: 
  12.         lineline = line+ l 
  13.     if"1060" in line: 
  14.         print'[+]No XLKFS service found.' 
  15.     else : 
  16.         r =os.popen(command2) 
  17.         print'[+]XLKFS service found. Has been cleared.' 
  18.   
  19. if __name__ == "__main__": 
  20.     searchEFL() 

四、总结

对于这几种通过破坏遍历规则的隐藏方式,其实都可以从其隐藏的动作直接判定它就是不怀好意的文件,不然为什么要做贼心虚的隐藏呢?但更可靠的方式就是先恢复遍历,让被隐藏的文件都能够被遍历到,然后再对文件进行常规的查杀。第一部分和第二部分提供的函数的最终目的都是为了最后提供对应的可访问的目录名列表,第三部分停止并删除了Easy File Locker的服务,文件自然就恢复了可遍历性。这里提供的函数单独也可以使用,但更推荐的做法是将其写成插件的形式加入传统查杀的工具中,使文件能够被遍历后,再对文件进行常规查杀规则的匹配。Github上有很多python的webshell查杀项目,匹配的一些特征库什么的已经很全了,写成插件加入后亲测效果不错,大家有兴趣可以自己动动手去实现。

(以上实验环境基于windows server 2008r2 standard,iis 7.0)

作者:北门喂猫
来源:51CTO

相关文章
|
10天前
|
存储 机器学习/深度学习 数据处理
NumPy:从初识到实战,探索Python科学计算的无限可能
NumPy:从初识到实战,探索Python科学计算的无限可能
35 0
|
10天前
|
Python Windows
【Python进阶必备】一文掌握re库:实战正则表达式
【Python进阶必备】一文掌握re库:实战正则表达式
9 0
|
12天前
|
中间件 数据库连接 API
Python面试:FastAPI框架原理与实战
【4月更文挑战第18天】FastAPI是受欢迎的高性能Python Web框架,以其简洁的API设计、强大的类型提示和优秀的文档生成能力著称。本文将探讨FastAPI面试中的常见问题,包括路由、响应对象、Pydantic模型、数据库操作、中间件和错误处理。同时,还会指出一些易错点,如类型提示不准确、依赖注入误解,并提供实战代码示例。通过理解和实践FastAPI,可以在面试中展示出色的Web开发技能。
24 1
|
26天前
|
存储 IDE 测试技术
探索Python中的变量宇宙:详尽解读与实战避坑指南
【4月更文挑战第4天】本文深入探讨了Python变量,包括其声明与赋值、数据类型,以及常见错误和应对策略。通过实例展示了变量在存储用户输入、计算、控制流程和函数参数等方面的应用。强调了理解变量作用域、避免类型不匹配和未初始化的错误,同时提出了最佳实践,如明确命名、避免冗余、适时复用和使用类型提示,以提升编程效率和代码质量。
36 2
|
26天前
|
存储 缓存 JavaScript
python实战篇:利用request库打造自己的翻译接口
python实战篇:利用request库打造自己的翻译接口
33 1
python实战篇:利用request库打造自己的翻译接口
|
12天前
|
API 数据库 数据安全/隐私保护
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】Django REST framework (DRF) 是用于构建Web API的强力工具,尤其适合Django应用。本文深入讨论DRF面试常见问题,包括视图、序列化、路由、权限控制、分页过滤排序及错误处理。同时,强调了易错点如序列化器验证、权限认证配置、API版本管理、性能优化和响应格式统一,并提供实战代码示例。了解这些知识点有助于在Python面试中展现优秀的Web服务开发能力。
24 1
|
2天前
|
机器学习/深度学习 数据采集 TensorFlow
【Python机器学习专栏】使用Python进行图像分类的实战案例
【4月更文挑战第30天】本文介绍了使用Python和深度学习库TensorFlow、Keras进行图像分类的实战案例。通过CIFAR-10数据集,展示如何构建和训练一个卷积神经网络(CNN)模型,实现对10个类别图像的识别。首先安装必要库,然后加载数据集并显示图像。接着,建立基本CNN模型,编译并训练模型,最后评估其在测试集上的准确性。此案例为初学者提供了图像分类的入门教程,为进一步学习和优化打下基础。
|
7天前
|
人工智能 安全 Java
Python 多线程编程实战:threading 模块的最佳实践
Python 多线程编程实战:threading 模块的最佳实践
123 5
|
9天前
|
人工智能 Python
【AI大模型应用开发】【LangChain系列】实战案例1:用LangChain写Python代码并执行来生成答案
【AI大模型应用开发】【LangChain系列】实战案例1:用LangChain写Python代码并执行来生成答案
14 0
|
12天前
|
SQL 中间件 API
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】**Flask是Python的轻量级Web框架,以其简洁API和强大扩展性受欢迎。本文深入探讨了面试中关于Flask的常见问题,包括路由、Jinja2模板、数据库操作、中间件和错误处理。同时,提到了易错点,如路由冲突、模板安全、SQL注入,以及请求上下文管理。通过实例代码展示了如何创建和管理数据库、使用表单以及处理请求。掌握这些知识将有助于在面试中展现Flask技能。**
16 1
Flask框架在Python面试中的应用与实战