程序自动化扫描漏洞,需要从页面中解析出有效url及其参数,然后加上payload进行漏洞验证
从页面中可以获得的有三类请求
1、a标签的href属性、iframe的src属性、form的action属性
2、js动态发出的ajax请求(前后端分离架构中,自动发出的ajax请求)
3、人机交互(onclick、onmouseover等)产生的请求
本篇关注第2类请求,借助phantomJS(一种无界面的模拟浏览器环境)的网络监听功能,获取页面自动发出的ajax请求
一、phantomJS环境搭建
wget下载http://phantomjs.org/download.html中对应版本
比如centos 64位:
wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
解压tar xvf phantomjs-2.1.1-linux-x86_64.tar.bz2即可
随服务器环境而变,可能需要安装bzip2,fontconfig : yum -y install bzip2 fontconfig
然后切换目录 cd phantomjs, ,执行./bin/phantomjs -v输出版本信息,环境即搭建成功
二、编写js调用phantomJS的onResourceRequested功能
可以多参考phantomJS官方实例:http://phantomjs.org/examples
计划实现的功能:根据输入的url,获取页面中ajax请求,保存到相应文件
代码如下(get_ajax.js)//运行phantomjs get_ajax.js www.baidu.com baidu.txt
"use strict";
var page = require('webpage').create(),
system = require('system'),
fs = require('fs'),
address;
if (system.args.length !== 3) {
console.log('Usage: get_ajax.js www.douyu.com file');
phantom.exit(1);
} else {
if(system.args[1].indexOf('http') !=0){
page.address = 'http://'+system.args[1];
}else{
page.address = system.args[1];
}
page.urls = '';
page.onResourceRequested = function (req) {
//console.log('requested: ' + JSON.stringify(req, undefined, 4));
if (req.url.indexOf('.js') != -1 || req.url.indexOf('.png') != -1 ||
req.url.indexOf('.jpg') != -1 || req.url.indexOf('.gif') != -1 ||
req.url.indexOf('.woff') != -1 || req.url.indexOf('.css') != -1) return;
if(req.method == 'POST'){
//其他格式json等 忽略
var page_url = req.url+'{postreq}?';
if(req.postData){
var q = req.postData.split('&');
for(var i in q){
if(q[i].indexOf('=') != -1){
page_url += q[i].split('=')[0] + '=&';
}else{//json or other
page_url += btoa(req.postData) + '{json}&';
}
}
}
page_url = page_url.substring(0, page_url.length-1)
page.urls += page_url + "\n";
console.log(page_url)
}else{
if(req.url.indexOf('?') != -1){
var page_url = req.url.split('?')[0]+'?';
var q = req.url.split('?')[1];
q = q.split('&');
Object.keys(q).forEach(function(key){
page_url += q[key].split('=')[0] + '=&';
});
page_url = page_url.substring(0, page_url.length-1)
page.urls += page_url + "\n";
console.log(page_url)
}
}
};
page.onResourceReceived = function (res) {
//console.log('received: ' + JSON.stringify(res, undefined, 4));
};
page.onLoadFinished = function(res) {
//console.log("page.onLoadFinished");
};
page.open(page.address, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address');
}
setTimeout(function(){try {
fs.write(system.args[2], page.urls, 'a');
} catch(e) {
console.log(e);
};
phantom.exit()},
30000);
});
}
有几点提示:
1、page.onLoadFinished事件发生之后,然后会有ajax请求发出。所以使用setTimeout等待一会儿再退出程序
2、这里可输入域名,url,去除掉图片、js、css、字体请求后,剩下的请求保存在”域名.txt“文件
3、参数值均已被清空(方便url去重)。post请求数据格式多变(json、xml、multiparty-form等),这里简单处理,非常规格式直接使用btoa转base64保存
ps:
1、人机交互产生的请求,自动化测试中有盲点击技术,待研究
2、是否监听websocket网络连接未知,漏洞扫描器不打算处理此类请求
3、使用代理抓请求包、获取测试服务器网络访问日志是两种更有效获取请求url的方式