分享一个wiki敏感信息扫描工具

背景

日常的安全运营中总是发现很多开发的同学将代码片段和一些技术文档在企业内部搭建的wiki中进行记录,其中经常会包含一些密码、数据库连接字符串、认证token之类的敏感信息。而这些文章往往是public的权限任何wiki普通用户都可以浏览到,因此带来了极大的内部安全风险。一旦黑客获得其中一个员工的账号权限进入内网,wiki往往是获得大量可用敏感信息的首选途径,因此减少public权限的公开敏感信息就尤为重要。另外账号的暴露也不利于内部的安全审计,账户、口令被员工获取后恶意利用,进行未授权的访问,增加了企业的内部风险,而因为账号密码的泄漏往往会使安全事件的调查更加困难。
在这里插入图片描述(2018.9.7 丰宁坝上草原)

开始吧

在此背景下,搜索了网上也没找到针对wiki的审查工具,那么古语云“工欲善其事必先利其器”,既然没有现成的工具就自己new一个吧。

功能设计说明

wikiscan是根据password、key等关键词在企业内网搭建的confluence wiki平台审计相关敏感文件和内容暴露的扫描工具,其设计思路如下:

  • 根据关键词在wiki中进行全局搜索,如(password、pwd、Authorization、密码),将搜索结果的页面路径信息去重整理得到搜索匹配的所有url集合;
  • 正则匹配url集合中是否为数据文件或代码形式的后缀,如(txt、csv、xml、xsl、log、py、php、java、jsp、go),这些文件中包含密码等字段的关键字且本身就不太适合作为public权限的文档存在于wiki中,因此直接将该url作为风险结果保存;
  • 不满足敏感后缀的url继续进入下面的检测逻辑,通过request遍历请求每一个wiki页面,正则匹配敏感关键字符合正则模式的放入风险结果中保存;
  • 日常的用户进行wiki文章编辑会出现很多带有密码关键字的语句,很多实际并不是包含真正的密码或认证的凭证,需要通过正则减少误报量。
  • 部分用户对文章中的密码关键字的value值有时会使用如 xxxxx、中文:密码、123456等进行掩码显示,根据企业中具体场景,可在正则中可对这些内容进行排除;
  • 尽管正则尽量降低了搜索关键字带来的误报,仍然可能会有一些各种各样的特殊情况,我们可以通过白名单来排除这些实际上确认后没这么敏感的url;
  • 我们并没有使用confluence官方提供的搜索接口,因为想到通过cookie虽然每次可能需要重新获得cookie值,但其实感觉更灵活些。

此外,我们通过参数可以支持两种扫描模式,全局扫描和单页扫描。全局扫描可以通过参数指定扫描搜索结果的url条数,单页扫描可以通过参数输入具体的wiki url来扫描这个页面是否包含敏感内容。

程序使用帮助

wikiscan v1.0 命令行参数方式执行:

USAGE:
    -l  wiki url,singlepage scan mode use.
    -c  Number of search results.
    -h  Show help information.

-l:选填参数,单页扫描某个wiki url是否有敏感关键字;
-c:必填参数,用于全局模式设置扫描搜索的结果条数;
-h:帮助信息。

参数使用说明:-l 仅用于单页模式,-c 全局模式必填,单页模式无需填写

代码

#!/usr/bin/env python
#-*- coding:utf-8 -*-
#author:Darkpot

import requests
import json
import re
import yagmail
import argparse

class MyClass:
    
    parser = argparse.ArgumentParser(description='wiki 敏感信息扫描')
    parser.add_argument("-l", help="wiki url,singlepage scan mode use", type=str)
    parser.add_argument("-c", help="Number of search results", type=int)
    args = parser.parse_args()
    input1 = args.l
    count =  args.c
    def globalScan(self,count):
        try:      
        #请求参数头设置
            keydict = ['siteSearch+~+"password"','siteSearch+~+"密码"','siteSearch+~+"pwd"','siteSearch+~+"Authorization"']
            url = 'http://wiki.com/rest/searchv3/1.0/cqlSearch'
            headers = {'cookie':'wiki.sso.cookie='}
            alist = []
            keywords=[]
            keyword_suffix=[]
        #白名单
            whitelist=['/pages/viewpage.action?pageId=12345']
        #根据关键词将搜索结果uri全部收集起来
            for b in keydict:
                params = {"cql":b,"start":0,"limit":count,"includeArchivedSpaces":"false"}
                req = requests.get(url,params=params,headers=headers)
                a = req.text
                middle = json.loads(a)
                size = middle["size"]
                for i in range(size):
                    href = middle["results"][i]["url"]
                    if href not in (alist+whitelist):
                        alist.append(href)
        #将xml等数据格式的直接挑出来,其他的正则匹配关键字
        #正则匹配样例:password= “”、password “”、password=12345、<password>123</password>
            for q in alist:
                url1='http://wiki.com'+q
                houzui = re.findall(r"(\.txt|\.xml|\.csv|\.xsl|\.log|\.py|\.php|\.go|\.java|\.jsp)$",url1)
                if houzui:
                    keyword_suffix.append(url1)
                else:
                    req1 =requests.get(url1,headers=headers)
                    text =req1.text
                    password = re.findall(r"(?i)(password(s)?|pwd(s)?)\s*(={0,1}\s*(\&quot;|')((?!密码|'|,)\S)+(\&quot;|')|=\s*((?!密码|\&quot)\S)+(,|\b))",text)
                    password1 = re.findall(r"(?i)\-p\s+(((?!密码|\&quot|123456)\S)+(,|\b)|(\&quot;|')((?!密码|123456)\S)+(\&quot;|'))",text)
                    password2 = re.findall(r"密码:((?!密码)\S)+(,|\b)",text)
                    password3 = re.findall(r"(?i)\&lt;password(s)?\&gt;((?!密码)\S)+\&lt;/password(s)?\&gt;",text)
                    password6 = re.findall(r"\&quot;\s*(password(s)?|pwd(s)?|Authorization)\s*\&quot;:\&quot;\s*((?!密码)\w)+\s*\&quot;",text)
                    password10 = re.findall(r"\s+(password(s)?|pwd(s)?|Authorization)\s*(:|:)\s*((?!密码|\&quot)\S)+(,|\b)",text)
                    password12 = re.findall(r"\&quot;(password(s)?|pwd(s)?)\&quot;\s*(,\s*\[\&quot;((?!密码)\S)+\&quot;\]|=&gt;\s*\&quot;((?!密码)\S)+\&quot;,)",text)
                    if password:
                        keywords.append(url1)                   
                    elif password1:
                        keywords.append(url1)                    
                    elif password2:
                        keywords.append(url1)                   
                    elif password3:
                        keywords.append(url1)
                    elif password6:
                        keywords.append(url1)
                    elif password10:
                        keywords.append(url1)
                    elif password12:
                        keywords.append(url1)
            yag = yagmail.SMTP(user = '[email protected]', password = 'password', host = 'smtp.163.com')
            yag.send(to = ['[email protected]'], subject = 'wiki 敏感信息扫描', contents = ['关键词正则匹配:\n',str(keywords),'关键词+数据文件后缀匹配:\n',str(keyword_suffix)])

        except:
            print("\n程序执行失败\n")

    def singlePage(self,wiki):
        try:
            keywords0=[]
            keyword_suffix0=[]
            headers = {'cookie':'wiki.sso.cookie='}
            houzhui = re.findall(r"(\.txt|\.xml|\.csv|\.xsl|\.log|\.py|\.php|\.go|\.java|\.jsp)$",wiki)
            if houzhui:
                keyword_suffix0.append(wiki)
            else:
                req0 =requests.get(wiki,headers=headers)
                text0 =req0.text
                password0 = re.findall(r"(?i)(password(s)?|pwd(s)?)\s*(={0,1}\s*(\&quot;|')((?!密码|'|,)\S)+(\&quot;|')|=\s*((?!密码|\&quot)\S)+(,|\b))",text0)
                password7 = re.findall(r"(?i)\-p\s+(((?!密码|\&quot|123456)\S)+(,|\b)|(\&quot;|')((?!密码|123456)\S)+(\&quot;|'))",text0)
                password8 = re.findall(r"密码:((?!密码)\S)+(,|\b)",text0)
                password9 = re.findall(r"(?i)\&lt;password(s)?\&gt;((?!密码)\S)+\&lt;/password(s)?\&gt;",text0)
                password5 = re.findall(r"\&quot;\s*(password(s)?|pwd(s)?|Authorization)\s*\&quot;:\&quot;\s*((?!密码)\w)+\s*\&quot;",text0)
                password4 = re.findall(r"\s+(password(s)?|pwd(s)?|Authorization)\s*(:|:)\s*((?!密码|\&quot)\S)+(,|\b)",text0)
                password11 = re.findall(r"\&quot;(password(s)?|pwd(s)?)\&quot;\s*(,\s*\[\&quot;((?!密码)\S)+\&quot;\]|=&gt;\s*\&quot;((?!密码)\S)+\&quot;,)",text0)
                if password0:
                    keywords0.append(wiki)          
                elif password7:
                    keywords0.append(wiki)      
                elif password8:
                    keywords0.append(wiki)          
                elif password9:
                    keywords0.append(wiki)
                elif password5:
                    keywords0.append(wiki)
                elif password4:
                    keywords0.append(wiki)
                elif password11:
                    keywords0.append(wiki)
            print("关键词正则匹配:\n"+str(keywords0))
            print("关键词数据文件后缀匹配:\n"+str(keyword_suffix0))
        except:
            print("\n程序执行失败\n")	
        
x = MyClass()

if x.input1:
    x.singlePage(x.input1)
else:
    x.globalScan(x.count)

	

结语

以上就是分享的wiki敏感字段的扫描工具,后续会继续更新对token、key、secret等关键词以及jira系统的支持。大家可以参考这个思路定制符合自己企业的内部系统敏感信息收集工具,感谢大家关注。
Github:(https://github.com/hashwormer/wikiscan)

猜你喜欢

转载自blog.csdn.net/sacredbook/article/details/107881962