Last active
March 22, 2017 16:35
-
-
Save maurorappa/0e92df25be62bbb48535a5e0c8a8b965 to your computer and use it in GitHub Desktop.
HTTP obfuscator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM alpine:3.5 | |
LABEL type=proxy-in | |
MAINTAINER Zerolatency - Mauro Rappa | |
RUN apk --update --no-cache add lua luarocks gcc make lua-dev musl-dev openssl | |
RUN luarocks-5.1 install copas | |
# remove fairness in copas client handling | |
RUN sed -i 's/90/0/' /usr/local/share/lua/5.1/copas.lua | |
RUN wget -O proxy-in.lua https://gist.githubusercontent.com/maurorappa/0e92df25be62bbb48535a5e0c8a8b965/raw/feb4bc8e4b8fddb41e16410ce85f9eada9f06833/proxy-in.lua | |
CMD ["lua","proxy-in.lua","*:8080","127.0.0.1:80"] | |
EXPOSE 8080 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env lua | |
require 'socket' | |
local copas = require 'copas' | |
assert(arg[1],"Must pass host and port to listen") | |
assert(arg[2],"Must pass host and port to proxy") | |
local config = { | |
newhost=string.gsub(arg[1],"([^:]+):(%d+)","%1"), | |
newport=string.gsub(arg[1],"([^:]+):(%d+)","%2"), | |
oldhost=string.gsub(arg[2],"([^:]+):(%d+)","%1"), | |
oldport=string.gsub(arg[2],"([^:]+):(%d+)","%2") | |
} | |
print("Proxying from ".. config.newhost .. ":" .. config.newport | |
.." to ".. config.oldhost .. ":" .. config.oldport) | |
function log(s) | |
print(s) | |
end | |
local server = socket.bind(config.newhost,config.newport) | |
local headers_parsers = { | |
[ "connection" ]= function(h) | |
return "Connection: close" | |
end, | |
[ "host" ]= function(h) | |
return "Host: " .. config.oldhost ..":"..config.oldport | |
end, | |
[ "location" ]= function(h) | |
local new, old ; | |
if config.newport == "80" then new = config.newhost else new = config.newhost .. ":" .. config.newport end | |
if config.oldport == "80" then old = config.oldhost else old = config.oldhost .. ":" .. config.oldport end | |
return string.gsub(h,old,new,1); | |
end | |
} | |
function string.fuzzer() | |
local charset = {} | |
-- qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM | |
for i = 48, 57 do table.insert(charset, string.char(i)) end | |
for i = 65, 90 do table.insert(charset, string.char(i)) end | |
local count = (os.date("%M")%16)+1 | |
print('#### '.. count) | |
local fuzz = '' | |
math.randomseed(os.time()) | |
for i = 1, count do fuzz = fuzz .. charset[math.random(1,34)] end | |
return fuzz | |
end | |
function get_method(l) | |
return string.gsub(l,"^(%w+).*$","%1") | |
end | |
function parse_header(l) | |
local head, last | |
for k in string.gmatch(l,"([^:%s]+)%s?:") do head = string.lower(k) ; break end | |
if headers_parsers[head] ~= nil then | |
l = headers_parsers[head](l) | |
end | |
if string.len(l) == 0 then last = true end | |
return l .. "\r\n",last, l | |
end | |
function pass_headers(reader,writer,dir) | |
local method, len | |
while true do | |
local req = reader:receive() | |
if req == nil then req = "" end | |
if dir == ">" and method == nil then method = get_method(req) end | |
if string.lower(string.sub(req,0,14)) == "content-length" then len = string.gsub(req,"[^:]+:%s*(%d+)","%1") end | |
local header, last, h = parse_header(req) | |
if dir == ">" and not last then header = string.fuzzer() .. header end | |
writer:send(header) | |
log(dir .. " " .. req) | |
log(dir .. " " .. header) | |
if last then break end | |
end | |
return method, len | |
end | |
function pass_body(reader,writer, len, dir) | |
if len == nil then | |
while true do | |
local res, err, part = reader:receive(512) | |
if err == "closed" or err == 'timeout' then | |
if part ~= nil then log(part); writer:send(part) end | |
break | |
end | |
--log(res) | |
writer:send(res) | |
end | |
else | |
if len == 0 then return nil end | |
local res, err, part = reader:receive(len) | |
--log(res) | |
writer:send(res) | |
end | |
end | |
function handler(sk8) | |
local c = copas.wrap(sk8) | |
local s = socket.connect(config.oldhost,config.oldport) | |
s:settimeout(10) | |
local method,len = pass_headers(c,s,">") | |
if len ~= nil then pass_body(c,s,tonumber(len),">") end | |
local _, len2 = pass_headers(s,c,"<") | |
pass_body(s,c,len2,"<") | |
s:close() | |
end | |
copas.addserver(server, handler) | |
copas.loop() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env lua | |
local socket = require 'socket' | |
local copas = require 'copas' | |
assert(arg[1],"Must pass host and port to listen") | |
assert(arg[2],"Must pass host and port to proxy") | |
local config = { | |
newhost=string.gsub(arg[1],"([^:]+):(%d+)","%1"), | |
newport=string.gsub(arg[1],"([^:]+):(%d+)","%2"), | |
oldhost=string.gsub(arg[2],"([^:]+):(%d+)","%1"), | |
oldport=string.gsub(arg[2],"([^:]+):(%d+)","%2") | |
} | |
print("Proxying from ".. config.newhost .. ":" .. config.newport | |
.." to ".. config.oldhost .. ":" .. config.oldport) | |
function log(s) | |
print(s) | |
end | |
local server = socket.bind(config.newhost,config.newport) | |
local headers_parsers = { | |
[ "connection" ]= function(h) | |
return "Connection: close" | |
end, | |
[ "host" ]= function(h) | |
return "Host: " .. config.oldhost ..":"..config.oldport | |
end, | |
[ "location" ]= function(h) | |
local new, old ; | |
if config.newport == "80" then new = config.newhost else new = config.newhost .. ":" .. config.newport end | |
if config.oldport == "80" then old = config.oldhost else old = config.oldhost .. ":" .. config.oldport end | |
return string.gsub(h,old,new,1); | |
end | |
} | |
function get_method(l) | |
return string.gsub(l,"^(%w+).*$","%1") | |
end | |
function parse_header(l) | |
local head, last | |
for k in string.gmatch(l,"([^:%s]+)%s?:") do head = string.lower(k) ; break end | |
if headers_parsers[head] ~= nil then | |
l = headers_parsers[head](l) | |
end | |
if string.len(l) == 0 then last = true end | |
return l .. "\r\n",last, l | |
end | |
function pass_headers(reader,writer,dir) | |
local method, len | |
while true do | |
local req = reader:receive() | |
if req == nil then req = "" end | |
if dir == ">" and method == nil then method = get_method(req) end | |
if string.lower(string.sub(req,0,14)) == "content-length" then len = string.gsub(req,"[^:]+:%s*(%d+)","%1") end | |
local header, last, h = parse_header(req) | |
local count = (os.date("%M")%16)+2 | |
print('#### ' .. count) | |
if dir == ">" and not last then header = header:sub(count) end | |
writer:send(header) | |
log(dir .. " " .. req) | |
log(dir .. " " .. header) | |
if last then break end | |
end | |
return method, len | |
end | |
function pass_body(reader,writer, len, dir) | |
if len == nil then | |
while true do | |
local res, err, part = reader:receive(64000) | |
if err == "closed" or err == 'timeout' then | |
if part ~= nil then writer:send(part) end | |
break | |
end | |
-- log("body2: "..res) | |
writer:send(res) | |
end | |
else | |
if len == 0 then return nil end | |
local res, err, part = reader:receive(len) | |
if res ~= nil then | |
-- log("body3: "..res) | |
writer:send(res) | |
end | |
end | |
end | |
function handler(sk8) | |
local c = copas.wrap(sk8) | |
local s = socket.connect(config.oldhost,config.oldport) | |
s:settimeout(10) | |
local method,len = pass_headers(c,s,">") | |
if len ~= nil then pass_body(c,s,tonumber(len),">") end | |
local _, len2 = pass_headers(s,c,"<") | |
pass_body(s,c,len2,"<") | |
s:close() | |
end | |
copas.addserver(server, handler) | |
copas.loop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment