开源项目 dirsearch 的一些阅读感想

安全工具 2019-11-10

本文作者:Turn it up.(信安之路作者团队成员)

最近开始阅读一些优秀的开源项目,读完之后就顺手谢谢读后感吧,今天说说 dirsearch,开头嘛,先读个简单点的,哈哈。

1、解决 Debug

程序参数是从命令行获取的,而 debug 模式则是将一个 py 脚本作为程序入口的,笔者开始有点不知所措,突然临机一动,用下面这个代码不就解决了?

import dirsearch
import sys
sys.argv= ['dirsearch.py', '-u', 'http://192.168.1.55', '-e', 'jsp', '--proxy', 'http://127.0.0.1:18080', '-w', 'db/dicc_test.txt']
dirsearch.Program()

2、简说程序

dirsearch 是一款使用 python3 编写的,用于暴力破解目录的工具,其 README 有写到下面一点

Heuristically detects invalid web pages(启发式地检测无效 web 页面)

在读程序之前,我带着下面几点疑惑/好奇

1、它是如果做到”启发式“这一点的;

2、其线程方面的代码,是否有什么亮点;

3、有啥比较骚的功能不。

2.1 dirsearch 的启发式

从底层核心类开始说起。首先是 Scanner,主要用于分析并存储当前网站对各类无效目录/无效文件真正的 HTTP Resonse 的模式。

Scanner 在测试时,使用的路径/文件是一个包含 12 个随机字符的字符串,如 68yK0OccrHpt、68yK0OccrHpt.php

self.testPath= RandomUtils.randString()

有的网站系统,对请求无效 WEB 页面的 HTTP Request,返回的是 200 的状态码,当然,界面是一个友好界面;有的网站则会返回一个 301/302/307 的跳转。

当 Scanner 访问这些随机字符串路径时,如果服务器返回的状态码是 404,则 Scanner 不继续分析,直接返回;服务器返回的状态码不是 404,Scanner 会发送第二次请求,依然是随机字符串的路径/文件,之后分析两次Response Body 的相似度并保存该相似度的浮点值,如果两次 Response 都发生了跳转(301/302/307),那么还会为 Location 字段值(URL)生成一个正则,如下面所示。

img

generateRedirectRegExp("http://www.test.com","http://123.test.com")) ^.http://..test.com.*$

之后访问一个目录/文件时,发生跳转中的 Location 的值需要匹配该正则,也页面相似度不小于当前值时,该目录/文件才被认为是无效的。可以说,dirsearch 在这里做得很细致啊。

Scanner 是被 Fuzzer 创建并调用的,Fuzzer 为无后缀斜线目录(/dir)、有后缀斜线目录(/dir/)、用户指定扩展文件(/xx.php、/xx.jsp 等)分别创建了一个 Scanner,Scanner 在执行 setup() 函数时,会如本节开头所说的,会分析出该种目录/文件的无效目录/无效文件所对应的 HTTP Response 的模式。

2.2 dirsearch 的多线程

有人说 dirsearch 速度很快,笔者以为在多线程方面会有亮点,比如说用协程,但并没有啥亮点。

虽然有 GIL 这东西然人感到不舒服,但也习惯了用 threading,编写起来也快,笔者想着下一个项目还是得要求自己用用协程。

2.3 dirsearch的迭代遍历

--recursive 用于递归目录遍历,默认是关闭的,而设置该选项时,还可以设置 --exclude-subdi 排除不想做迭代的目录。

在 Controller 中设置了 matchCallbacks 函数,该函数会将当前有效的不在 exclude 中的目录添加到当前

self.fuzzer= Fuzzer(self.requester, self.dictionary, testFailPath=self.arguments.testFailPath,                    threads=self.arguments.threadsCount, matchCallbacks=matchCallbacks,                    notFoundCallbacks=notFoundCallbacks, errorCallbacks=errorCallbacks)

在测试该功能时还发现了一个 BUG,已经提交至 Issues。问题的来源是这样的,Requester 中有这样一行代码

url= urllib.parse.urljoin(url, self.basePath)

但是,这个 urllib 库者 urljoin 函数有点问题。

>>>from urllib import parse
>>>parse.urljoin("http://192.168.237.136","//admin/")
>>>'http://admin/'

笔者提交的修补代码是。

while True:
    path_tmp= self.basePath.replace('//', '/')
    if path_tmp== self.basePath:
        break
    self.basePath= path_tmp

比较郁闷的一点时,dirsearch 对待 wordlist 中结尾有“/”的,且该目录在当前目标 URL 中为有效时才会进行迭代遍历,比如:

访问 http://www.test.com/admin 时的 HTTP Response 状态码为 200 ,dirsearch 不会对该目录进行迭代遍历,访问 http://www.test.com/admin/ 时的 HTTP Response 状态码 200,dirsearch 会对该目录进行迭代遍历。为啥要把选择权交给 wordlist,作者为啥要做这种区分,吾不知所以然啊。

2.4 IP 选项

在渗透测试时,有时候做目录遍历时,不得不只能能用 BurpSuit,不知道同学们对此是否有所体会。其中的痛点需求是,我们希望底层的 Socket 连接的是一个指定的 IP,然后 HTTP 中的 Host 字段值则是另外一个指定的域名 /IP。

dirsearch 就很巧妙地解决了以上痛点需求。requests 传入的 URL 中的 host 值是来源于-ip,另外设置Headers 中的Host字段值为 --url 中的值。

3、不足之处

笔者十分在意的另外一点是,dirsearch 在扫目录时,没有主动区分 ”/dir"、“/dir/”,这两类目录(当然,前文也说了,作者把这两类作为是否迭代遍历的标志)。笔者的意思是,有时候,访问

http://www.test.com/admin

HTTP Response 状态码为 301;访问

http://www.test.com/admin/

HTTP Response 状态码为 404。所以笔者十分在意这一点,这也是一个痛点啊,dirsearch 并没有对此做一个主动性的区分。

结尾,dirsearch 的启发式识别 URL 是否有效确实挺不错的,可能是不同人有不同的想法,所以项目的一些地方会让笔者感到疑惑不解,而项目的整体逻辑也挺不错,适合像笔者这样的初学者好好看,好好学。


本文由 信安之路 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

楼主残忍的关闭了评论