其他 · 2018年1月25日 0

用AnyProxy代理服务器做JS注入

简介

  • AnyProxy是一个基于NodeJS的,可供插件配置的HTTP/HTTPS代理服务器。开放二次开发能力,允许自定义请求处理逻辑,提供GUI界面,用以观察请求。
  • AnyProxy表面上是一个代理服务器,提供了可视化的界面,类似于http的各种抓包工具,但是实际上它能够实现的远远不止于此。

AnyProxy的处理流程如下图:
处理流程
可以看到AnyProxyServer拦截了所有的http请求,无论是request还是response都必须要经过Server,之后转发到浏览器Client。这个流程和普通的代理服务器基本一致。那么既然请求都经过了同一个地方,我们是不是可以修改请求的内容?比如给某个页面插入一个特定的js脚本,输出一段特定的内容。这就是本篇文章要实现的东西。
(理论上传统的代理服务器也可以实现上述功能,但并未开放对应的接口。)

官方网址:
http://anyproxy.io/cn/

GIT地址:
https://github.com/alibaba/anyproxy

本文的适用范围是AnyProxy 4.0


1. AnyProxy安装启动测试

1.1 安装

安装的过程很简单,这里使用Windows环境。
首先需要安装nodejs环境,菜鸟教程中有详细的介绍:
http://www.runoob.com/nodejs/nodejs-install-setup.html

这里用npm全局安装anyproxy:

$ npm install -g anyproxy

如需要引用为npm模块,官方教程有说详细说明。

1.2 启动

命令行启动AnyProxy,默认端口号8001

$ anyproxy

启动后将终端http代理服务器配置为127.0.0.1:8001即可
访问http://127.0.0.1:8002 ,web界面上能看到所有的请求信息

启动的参数选项:

#改变端口号
$ anyproxy --port 1080
#解析所有https请求
$ anyproxy --intercept
#加载指定规则,后续有讲rule如何定义
$ anyproxy --rule sample.js

1.3 测试运行

将浏览器的代理服务器设置为127.0.0.1:8001,然后命令行输入:

$ anyproxy

之后再浏览器中打开http://127.0.0.1:8002/将会看到如下的界面

至此我们的AnyProxy已经完成可以使用。

2. rule接口实例

以下是AnyProxy提供的所有外部接口,所有方法都是可选的,只需实现业务感兴趣的部分即可。

module.exports = {
    // 模块介绍
    summary: 'my customized rule for AnyProxy',
    // 发送请求前拦截处理
    *beforeSendRequest(requestDetail) { /* ... */ },
    // 发送响应前处理
    *beforeSendResponse(requestDetail, responseDetail) { /* ... */ },
    // 是否处理https请求
    *beforeDealHttpsRequest(requestDetail) { /* ... */ },
    // 请求出错的事件
    *onError(requestDetail, error) { /* ... */ },
    // https连接服务器出错
    *onConnectError(requestDetail, error) { /* ... */ }
};

其中*beforeSendResponse(requestDetail, responseDetail) { /* ... */ },
就是这一次我们要修改实现的地方,先来个例子看一看:

module.exports = {
    summary: 'Rule to modify request data',
    *beforeSendResponse(requestDetail, responseDetail) {
        //这里的意思是:如果URL包含http://nm1024.com就修改请求结果,返回一句特定的内容
        if (requestDetail.url.indexOf('http://nm1024.com') == 0) {

            const newResponse = responseDetail.response;
            var newDataStr = 'i-am-anyproxy-modified-post-data';
            newResponse.body = newDataStr;

            return new Promise((resolve, reject) => {
                resolve({ response: newResponse });
            });
        }
    },
};

将以上代码保存至某个路径如:D:\anyproxy-master\rule_sample\rule_nm1024.js。
接着进入命令行执行

$ D:
$ cd \anyproxy-master\rule_sample
$ anyproxy --rule rule_nm1024.js

记得设置浏览器的代理服务器。

此时用浏览器打开http://nm1024.com/

可以看到站点的首页已经打不开了,只输出了‘i-am-anyproxy-modified-post-data’

这里我们已经成功了一半,可以确定的是我们已经完全修改了请求的返回内容。

3. 在12306网站注入JS

在此之前需要补充的一件事情是,AnyProxy代理https需要信任证书。

3.1 代理HTTPS

AnyProxy默认不对https请求做处理,如需看到明文信息,需要配置CA证书。

解析https请求的原理是中间人攻击(man-in-the-middle),用户必须信任AnyProxy生成的CA证书,才能进行后续流程。

$ anyproxy-ca #生成rootCA证书,生成后需要手动信任
$ anyproxy --intercept #启动AnyProxy,并解析所有https请求

生成的证书在“C:\Users\user\.anyproxy\rootCA.crt”;
双击执行-->安装证书-->下一步-->选择‘将所有的证书放入下列存储’-->浏览-->选择‘受信任的根证书颁发机构’-->确定。。。之后一直下一步直到完成。

3.2 在12306网站注入JS

module.exports = {
    summary: 'Rule to modify request data',
    *beforeSendResponse(requestDetail, responseDetail) {
        if (requestDetail.url.indexOf('https://kyfw.12306.cn/otn/index/init') == 0) {
            const newResponse = responseDetail.response;
            var newDataStr = "";
            newDataStr += "<script>";
            newDataStr += `
alert(1111);
`;
            newDataStr += "</script>";
            newResponse.body += newDataStr;
            return new Promise((resolve, reject) => {
                resolve({ response: newResponse });
            });
        }
    },
};

先看以上代码尝试注入一个alert(1111);
保存替换掉刚才的文件,开始执行:

$ anyproxy --intercept --rule rule_nm1024.js

打开https://kyfw.12306.cn/otn/index/init

到此我们的注入可以说已经完成了,并且支持https,至于注入什么内容,大家可以随意发挥。
文章末尾会提供一个稍微复杂一点的rule文件。

4. 总结

  • 例子中我们仅仅使用了beforeSendResponse(发送响应前处理)这一个方法,还有如下方法,每一个都可以拓展出很多功能:
  1. beforeSendRequest(requestDetail) // 发送请求前拦截处理
  2. beforeSendResponse(requestDetail, responseDetail) // 发送响应前处理
  3. beforeDealHttpsRequest(requestDetail) // 是否处理https请求
  4. onError(requestDetail, error) // 请求出错的事件
  5. onConnectError(requestDetail, error) // https连接服务器出错
  • 就此可以看出来,用此方法在本地注入js,难点只是对目标网站的分析,调用其各种js方法。目标脚本再怎么复杂总是可以找到的,总是可以用js触发,就怕目标网站频繁迭代,就需要频繁更新对应的脚本。
  • AnyProxy代理服务器设计者的本意可能并不是用来注入,主要功能还是一个代理服务器。但由此衍生的用法可能有无数种,实现各种抢购、模拟用户操作、网站SEO。。。亦或者借此开发一个梯子,注入挖矿的js等等。理论上可以注入js后,js能做的我们也就能做,可以发挥的空间很大。
  • 也可见我们的前端是非常不安全的,需要在服务器端做更多的规则来解决对应的安全问题。

12306注入示例

module.exports = {
    summary: 'a rule to hack response',
    *beforeSendResponse(requestDetail, responseDetail) {
        if (requestDetail.url.indexOf('https://kyfw.12306.cn/otn/index/init') == 0) {
            const newResponse = responseDetail.response;

            var newDataStr = "";
            newDataStr += "<script>";
            newDataStr += `
$(function(){
$("#fromStationText").val("上海");
$("#toStationText").val("西安");
$("#train_date").val("2018-02-13");
$("#a_search_ticket").click();
})
`;
            newDataStr += "</script>";
            newResponse.body += newDataStr;

            return new Promise((resolve, reject) => {
                resolve({ response: newResponse });
            });
        }
        if (requestDetail.url.indexOf('https://kyfw.12306.cn/otn/leftTicket/init') == 0) {
            const newResponse = responseDetail.response;
            newResponse.body += '- AnyProxy Hacked!';

            var newDataStr = "";
            newDataStr += "<script>";
            newDataStr += `
$(function () {
    initcxl();
    whileSearch();
})
function initcxl(){
    $("#fromStationText").val("上海");
    $("#toStationText").val("西安");
    $("#train_date").val("2018-02-13");
    $("#show_more").click();

    $("input[name='cc_type']").each(function () {
        if ($(this).val() == "G" && !$(this).is(":checked")) {
            $(this).attr("checked", true);
        }
        if ($(this).val() == "D" && !$(this).is(":checked")) {
            $(this).attr("checked", true);
        }
    });
}
function initpw(){
    $("#fromStationText").val("武汉");
    $("#toStationText").val("上海");
    $("#train_date").val("2018-02-22");
    $("input[name='cc_type']").each(function () {
        if ($(this).val() == "G" && !$(this).is(":checked")) {
            $(this).attr("checked", true);
        }
        else if ($(this).val() == "D" && !$(this).is(":checked")) {
            $(this).attr("checked", true);
        }
        else if ($(this).val() == "Z" && !$(this).is(":checked")) {
            $(this).attr("checked", true);
        }
        else if ($(this).val() == "T" && !$(this).is(":checked")) {
            $(this).attr("checked", true);
        }
    });

    $.showSelectBuyer();
    $.closeSelectBuyer();
    $.showYxTrain();
    Choicecheci();
}
var num=0;
function whileSearch() {
    num++;
    if(num==10){
        initpw();
    }
    if (!$("#avail_ticket").is(":checked")) {
        $("#avail_ticket").attr("checked", true);
    }
    $("#query_ticket").click();
    setTimeout(whileSearch, 2000);

}
function Choicebuyer() {
    if ($("#buyer-list").find("li").length > 0) {
        $("#buyer-list").find("li")[0].click();
        Choicebuyer();
        if ($("#autoSubmit").is(":checked")) {
            $("#autoSubmit").attr("checked", false);
        }
        if ($("#auto_query").is(":checked")) {
            $("#auto_query").attr("checked", false);
        }
    }else{
        setTimeout(Choicebuyer, 100);
    }
}
function Choicecheci() {
    if ($("#yxtrain_code").find("li").length > 0) {
        $("#yxtrain_code").find("li")[0].click();
        $("#yxtrain_code").find("li")[1].click();
        $("#yxtrain_code").find("li")[2].click();
        $("#yxtrain_close").click();
        if ($("#autoSubmit").is(":checked")) {
            $("#autoSubmit").attr("checked", false);
        }
        if ($("#auto_query").is(":checked")) {
            $("#auto_query").attr("checked", false);
        }
    }else{
        setTimeout(Choicecheci, 100);
    }
}
`;
            newDataStr += "</script>";
            newResponse.body += newDataStr;
            return new Promise((resolve, reject) => {
                resolve({ response: newResponse });
            });
        }
    },
};

.
.
.
.
.
.
.
【本文章出自NM1024.com,转载请注明作者出处。】






>>转载请注明原文链接地址:用AnyProxy代理服务器做JS注入