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

作者:北门喂猫 来源: http://www.freebuf.com/articles/web/131350.html

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

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

0X01 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 #显示文件的备用数据流

# -*- coding: cp936 -*-import os,os.pathimport re
 def searchNTFS(catalog):                  #搜索所有ntfs ads文件目录,返回list    resultL= []
    forroot,dirs,files in os.walk(catalog):           #利用os.walk()递归遍历文件        line= ''       command = 'cd '+ root + '&' + 'dir /r'        r =os.popen(command)
        info= r.readlines()
        forl in info:
           line = line + l
        reN= '\s(\S+)\:\$DATA'        res= re.findall(reN,line)
        forre1 in res:
           if re1 != '':
               result = root + '\\' + re1
               resultL.append(result)    
    returnresultL
 def searchInclude(catalog):    resultL= []
    resultD= {}
    forroot,dirs,files in os.walk(catalog):
        forf in files:
           dir = os.path.join(root,f)
           if dir[-4:] == '.asp':
               try :
                   fp = open(dir,'r')
                   for line in fp.readlines():
                        reN = '<\!--#include\S+="(\S+)"-->'                        res = re.findall(reN,line)
                        for re1 in res:
                            if re1 != '':
                                result = root +'\\' + re1
                                resultD[result]= root + '\\' +f
               except:
                   print "File :" + dir + " can't be read"    returnresultD
 if __name__ == "__main__":
    reD =searchInclude('C:\inetpub\wwwroot')
    reN =list(set(reD.keys()).intersection(set(searchNTFS('C:\inetpub\wwwroot'))))
    reI = []
    for re1in reN:
       reI.append(reD[re1])
    if reI!= []:
        forre2 in reN :
           print '###############################################################'           print "[+]Suspicious ADS files found : " + re2
        for re3 in reI :
           print '###############################################################'           print "[+]Including files: " + re3 + "  \n Please check it."    else :
       print "[+]No suspicious ADS files found."

0X02 畸形文件名、保留文件名隐藏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 文件名产生的短名称

# -*- coding: cp936 -*-import os,os.pathimport re
 def searchSFN(catalog):    resultL = []
    resultL2 = []
    for root,dirs,files in os.walk(catalog):            #利用os.walk()递归遍历文件        line = ''        command = 'cd '+ root + '&' + 'dir/x'        r = os.popen(command)
        info = r.readlines()
        for l in info:
            line = line + l
        reN1 = '\s+(\S+\~\S+)\s+\S+\.\.+'        res = re.findall(reN1,line)
        for re1 in res:
            if re1 != '':
                result = '\\\\.\\' + root + '\\'+ re1
                resultL.append(result)
       
 reN2 
='\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+'        res2 = re.findall(reN2,line)
        for re2 in res2:
            if re2 != '':
                result2 = '\\\\.\\' + root +'\\' + re2[0]
                resultL2.append(result2)
    return resultL,resultL2
 
defdeleteSFN(list,list2):
    for l1 in list :
        str = raw_input('Do you want to delete: ' + l1 + '? (y/n)')
        if str == 'y' :
            command = 'rd /s /q ' + l1
            r = os.popen(command)
        else :
            pass    for l2 in list2 :
        str = raw_input('Do you want to delete: ' + l2 + '? (y/n)')
        if str == 'y' :
            command = 'del /f /q /a ' + l2
            r = os.popen(command)
        else :
            pass if __name__ =="__main__":
    list,list1 =searchSFN('C:\inetpub\wwwroot')
    deleteSFN(list,list1)

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

0X03 驱动隐藏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的服务名。(这里写成脚本模式是为了方便后续写成插件加入传统查杀工具,否则直接使用命令即可)

# -*- coding: cp936 -*-import os,os.pathimport re
 def searchEFL():    line = ''    command1 = 'sc qc xlkfs'         #插看是否存在xlkfs服务,返回1060则判定不存在
    command2 = 'net stop xlkfs' + '&' + 'sc delete xlkfs'      #停止并删除服务
    r =os.popen(command1)
    info = r.readlines()
    for l in info:
        line = line+ l
    if"1060" in line:
        print'[+]No XLKFS service found.'    else :
        r =os.popen(command2)
        print'[+]XLKFS service found. Has been cleared.' if __name__ == "__main__":
    searchEFL()

0X04 总结

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

原文发布于微信公众号 - 马哥Linux运维(magedu-Linux)

原文发表时间:2017-04-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏MixLab科技+设计实验室

设计师编程指南之Sketch插件开发 1

发现网上关于sketch插件开发的指南太少了,而且都不一定可以成功运行,于是我就写了这个系列的文章: 1 我们需要了解的语法特点 sketch 是基于 Coc...

5708
来自专栏酷玩时刻

微信公众号开发之扫码支付

上一篇文章介绍了微信提供的那些支付方式以及公众号支付http://www.jianshu.com/p/cb2456a2d7a7

3863
来自专栏后端技术探索

纯干货!-- Memcache详解

网址:http://www.cnblogs.com/xrq730/p/4948707.html

692
来自专栏FreeBuf

Kali Linux下社工密码字典生成工具Cupp和Cewl教程

Cupp是一款用Python语言写成的可交互性的字典生成脚本。尤其适合社会工程学,当你收集到目标的具体信息后,你就可以通过这个工具来智能化生成关于目标的字典。当...

4576
来自专栏信安之路

记一次小型 APT 恶意攻击

在经历过期末学习怠倦期后,我战战兢兢地打开了(自己搭的蜜罐抓不到样本(╥ω╥`) )

1370
来自专栏后端技术探索

纯干货!-- Memcache详解

网址:http://www.cnblogs.com/xrq730/p/4948707.html

1531
来自专栏涤生的博客

天池中间件大赛——单机百万消息队列存储设计与实现

这次天池中间件性能大赛初赛和复赛的成绩都正好是第五名,本次整理了复赛《单机百万消息队列的存储设计》的思路方案分享给大家,实现方案上也是决赛队伍中相对比较特别的。

1901
来自专栏从零开始学自动化测试

python接口自动化21-规范的API接口文档示例

前言 接口文档到底长啥样?做接口测试最大的障碍在于没有接口文档,很多公司不注重接口文档的编写,导致测试小伙伴没见过接口文档。 运气好一点的测试小伙伴可能厚着脸皮...

1.3K8
来自专栏大史住在大前端

一统江湖的大前端(4)shell.js——穿上马甲我照样认识你

码农界存在着无数条鄙视链,linux使用者对windows的鄙视便是其中之一,cli使用者对GUI用户的嘲讽也是如此,在这样一个讲究逼格的时代,如果你的桌面上没...

1985
来自专栏码农阿宇

海量数据即时查询引擎ElasticSearch入门 附.Net Core例子

Elasticsearch是基于Lucene的搜索引擎。它提供了一个分布式,支持多租户的全文搜索引擎,它具有HTTP Web界面和无模式JSON文档。 Elas...

2102

扫码关注云+社区

领取腾讯云代金券