Cendertron = Crawler + Rendertronphp
Cendertron https://url.wx-coder.cn/HinPM 是基于 Puppeteer 的 Web 2.0 动态爬虫与敏感信息泄露检测工具。其依托于 xe-crawler 的通用爬虫、调度与缓存模型,新增了 Monkey Test 以及 Request Intercept 等特性,以期尽量多地挖掘页面与请求。同时针对渗透测试的场景,Cendertron 内置了目录扫描、敏感文件扫描的能力,可以模拟用户实际在浏览器登陆状态下的自定义字典爆破。Cendertron 在大量实践的基础上设置了自身的去重策略,可以尽量地避免重复爬取,加快扫描速度。Cendertron 同时也是正在闭源开发的 Chaos-Scanner 模块化安全扫描解决方案的一部分,为基础扫描与智能扫描提供前置输入。git
在本地开发中,咱们只须要如正常的 Node 项目同样启动,其会使用 Puppeteer 内置的 Headless Chrome 来执行界面渲染操做:github
$ git clone https://github.com/wx-chevalier/Chaos-Scanner $ cd cendertron $ yarn install $ npm run dev 复制代码
启动以后能够按提示打开浏览器界面:web
这里咱们能够以 DVWA 做为测试目标,在输入框内输入 http://localhost:8082/
而后执行爬取,便可获得以下结果:算法
{ "isFinished": true, "metrics": { "executionDuration": 116177, "spiderCount": 51, "depth": 4 }, "spiderMap": { "http://localhost:8082/vulnerabilities/csrf/": [ { "url": "http://localhost:8082/vulnerabilities/view_source.php?id=csrf&security=low", "parsedUrl": { "host": "localhost:8082", "pathname": "/vulnerabilities/view_source.php", "query": { "id": "csrf", "security": "low" } }, "hash": "localhost:8082#/vulnerabilities/view_source.php#idsecurity", "resourceType": "document" } // ... ] } } 复制代码
须要说明的是,由于 DVWA 是须要登陆后爬取,所以若是想进行完整的测试请参考下文的 POST 方式建立任务。chrome
# build image $ docker build -t cendertron . # run as contaner $ docker run -it --rm -p 3033:3000 --name cendertron-instance cendertron # run as container, fix with Jessie Frazelle seccomp profile for Chrome. $ wget https://raw.githubusercontent.com/jfrazelle/dotfiles/master/etc/docker/seccomp/chrome.json -O ~/chrome.json $ docker run -it -p 3033:3000 --security-opt seccomp=$HOME/chrome.json --name cendertron-instance cendertron # or $ docker run -it -p 3033:3000 --cap-add=SYS_ADMIN --name cendertron-instance cendertron # use network and mapping logs $ docker run -d -p 3033:3000 --cap-add=SYS_ADMIN --name cendertron-instance --network wsat-network cendertron 复制代码
Install cendertron from NPM:docker
# set not downloading chromium $ PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true $ yarn add cendertron # or $ npm install cendertron -S 复制代码
Import Crawler
and use in your code:npm
const crawler = new Crawler(browser, { onFinish: () => { callback(crawler.spidersRequestMap); } }); let pageUrl = evtStr.length !== 0 && evtStr.indexOf('{') !== 0 ? evtStr : 'https://www.aliyun.com'; crawler.start(pageUrl); 复制代码
If you want to use it in Alibaba Function Computing Service, cendertron-fc provides simple template.json
Cendertron 的内部架构以下所示:浏览器
Crawler Scheduler 会负责按期重启 Headless Chrome 以控制缓存,而且针对待爬取的请求返回已缓存的内容。Crawler Scheduler 会为每一个无缓存的目标建立 Crawler,Crawler 会根据策略建立不一样的 Spider,每一个 Spider 依次执行而且将结果推送到 Crawler 中;Crawler 在所有 Spider 执行完毕后会将结果推送到缓存而且通知 Crawler Scheduler:
export interface CrawlerOption { // 爬取深度,若是设置为 1 就是单页面爬虫 depth: number; // 爬虫的惟一编号 uuid?: string; // 爬虫缓存 crawlerCache?: CrawlerCache; // 单页面爬取出的最多的子节点数 maxPageCount: number; // 总站点的总延时 timeout: number; // 单页面的延时 pageTimeout: number; // 是否仅爬取同站内容 isSameOrigin: boolean; // 是否忽略媒体资源 isIgnoreAssets: boolean; // 是否设置为移动模式 isMobile: boolean; // 是否开启缓存 useCache: boolean; // 是否使用弱口令扫描 useWeakfile: boolean; // 页面 Cookie cookie: string; // 页面的 localStorage localStorage: object; } 复制代码
Cendertron 内置了 Click Monkey, Gremlins 等多种随机执行器,会点击按钮而且执行一些随机操做:
function initGermlins() { gremlins .createHorde() .gremlin(gremlins.species.formFiller()) .gremlin(gremlins.species.clicker().clickTypes(['click'])) .gremlin(gremlins.species.toucher()) .gremlin(gremlins.species.scroller()) .gremlin(function() { if ('$' in window) { window.$ = function() {}; } }) .unleash(); } 复制代码
Cendertron 会监听打开的页面与全部的 Ajax 请求:
await page.setRequestInterception(true); // 设置目标监听 const targetCreatedListener = (target: puppeteer.Target) => { const opener = target.opener(); if (!opener) { return; } // 记录全部新打开的界面 opener.page().then(_page => { if (_page === page) { target.page().then(_p => { if (!_p.isClosed()) { openedUrls.push(target.url()); _p.close(); } }); } }); }; // 监听全部当前打开的页面 browser.on('targetcreated', targetCreatedListener); page.on('request', interceptedRequest => { // 屏蔽全部的图片 if (isMedia(interceptedRequest.url())) { interceptedRequest.abort(); } else if ( interceptedRequest.isNavigationRequest() && interceptedRequest.redirectChain().length !== 0 ) { interceptedRequest.continue(); } else { interceptedRequest.continue(); } requests.push(transformInterceptedRequestToRequest(interceptedRequest)); // 每次调用时候都会回调函数 cb(requests, openedUrls, [targetCreatedListener]); }); 复制代码
所谓的 URL 归一化,就是将同一资源下被随机串处理的 Path 们泛化成同一个 Pattern,从而减小重复爬取的数目;固然,在安全扫描的场景下咱们须要进行尽量地去重,而在数据爬取的场景下,则每每不须要进行过多的过滤。目前 Cendertron 只是采起了简单的 UTL 归一化算法,而且使用 Set 进行过滤,若是你想了解更复杂的 URL 归一化与聚类算法,能够参考天然语言处理 https://url.wx-coder.cn/JcINy 或者哈希表实战 https://url.wx-coder.cn/WfdWP 中的关联章节。
export function hashUrl(url: string): string { // 将 URL 进行格式化提取 const _parsedUrl = parse(url, url, true); let urlHash = ''; if (!_parsedUrl) { return urlHash; } // 提取出 URL 中的各个部分 const { host, pathname, query, hash } = _parsedUrl; // 判断是否存在查询参数 const queryKeys = Object.keys(query).sort((k1, k2) => (k1 > k2 ? 1 : -1)); if (queryKeys.length > 0) { // 若是存在查询参数,则默认全路径加查询参数进行解析 urlHash = `${host}#${pathname}#${queryKeys.join('')}`; } else { // 若是不存在查询参数,则去除 pathname 的最后一位,而且添加进来 const pathFragments = pathname.split('/'); // 判断路径是否包含多个项目,若是包含,则将全部疑似 UUID 的替换为 ID if (pathFragments.length > 1) { urlHash = `${host}#${pathFragments .filter(frag => frag.length > 0) .map(frag => (maybeUUID(frag) ? 'id' : frag)) .join('')}`; } else { urlHash = `${host}#${pathname}`; } } if (hash) { const hashQueryString = hash.replace('#', ''); const queryObj = parseQuery(hashQueryString); Object.keys(queryObj).forEach(n => { if (n) { urlHash += n; } }); } return urlHash; } 复制代码
以 DVWA 为例,能够用 Docker 快速开启测试环境:docker run --rm -it -p 8082:80 vulnerables/web-dvwa
,而后向 /scrape
提交 POST 请求:
{ "url": "http://localhost:8082/vulnerabilities/csrf/", "cookies": "tid=xx; PHPSESSID=xx; security=low" } 复制代码
在 Cendertron 中,其会使用以下方式设置 Cookie:
const puppeteer = require('puppeteer'); let rockIt = async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); var cookie = [ // cookie exported by google chrome plugin editthiscookie { domain: 'httpbin.org', expirationDate: 1597288045, hostOnly: false, httpOnly: false, name: 'key', path: '/', sameSite: 'no_restriction', secure: false, session: false, storeId: '0', value: 'value!', id: 1 } ]; await page.setCookie(...cookie); await page.goto('https://httpbin.org/headers'); console.log(await page.content()); await page.close(); await browser.close(); }; rockIt(); 复制代码
将来也会支持 localStorage 等存储方式:
await page.evaluate(() => { localStorage.setItem('token', 'example-token'); }); 复制代码