NSSCTF第8页(1)

[HGAME 2023 week1]Classic Childhood Game

js代码审计,找关键语句,发现event.js里边东西是最多的

找到了通关语句

他下边应该是就关键代码了,有一串16进制代码

解出来是base64,接着解  两次base64 解码,就得到了flag, 把前缀换成NSSCTF就ok

prize_p5

源代码:

<?php
error_reporting(0);

class catalogue{
    public $class;
    public $data;
    public function __construct()
    {
        $this->class = "error";
        $this->data = "hacker";
    }
    public function __destruct()
    {
        echo new $this->class($this->data);
    }
}
class error{
    public function __construct($OTL)
    {
        $this->OTL = $OTL;
        echo ("hello ".$this->OTL);
    }
}
class escape{                                                                   
    public $name = 'OTL';                                                 
    public $phone = '123666';                                             
    public $email = 'sweet@OTL.com';                          
}
function abscond($string) {
    $filter = array('NSS', 'CTF', 'OTL_QAQ', 'hello');
    $filter = '/' . implode('|', $filter) . '/i';
    return preg_replace($filter, 'hacker', $string);
}
if(isset($_GET['cata'])){
    if(!preg_match('/object/i',$_GET['cata'])){
        unserialize($_GET['cata']);
    }
    else{
        $cc = new catalogue(); 
        unserialize(serialize($cc));           
    }    
    if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){
        if (preg_match("/flag/i",$_POST['email'])){

            die("nonono,you can not do that!");
        }
        $abscond = new escape();
        $abscond->name = $_POST['name'];
        $abscond->phone = $_POST['phone'];
        $abscond->email = $_POST['email'];
        $abscond = serialize($abscond);
        $escape = get_object_vars(unserialize(abscond($abscond)));
        if(is_array($escape['phone'])){
        echo base64_encode(file_get_contents($escape['email']));
        }
        else{
            echo "I'm sorry to tell you that you are wrong";
        }
    }
}
else{
    highlight_file(__FILE__);
}
?>
 

PHP原生类的利用_慕晨sekurlsa的博客-CSDN博客 

https://www.cnblogs.com/bcxc/articles/17052527.html (php原生类利用)

还是,要构造pop链,这里有一个利用点。

这里可以利用反序列化原生类

 public function __destruct()
    {
        echo new $this->class($this->data);
    }
}

这里可以实例化任意类,而且配合echo输出,那么自然想到就是原生类读文件了。这里利用FilesystemIterator来读取根目录有哪些文件。 

还有一个利用点是file_get_contents()函数,读取文件,路径可控

 if(is_array($escape['phone'])){
        echo base64_encode(file_get_contents($escape['email']));

过滤点:

<1>对于第一个反序列化点
只对get传入的序列化字符串内容进行正则匹配,匹配object关键字,忽略大小写
<2>对于第二个文件读取点
(0)get要设置cata的值
(1)对post传入的email参数进行匹配,匹配关键字flag,忽略大小写
(2)对生成的catalogue序列化字段进行关键字的替换,关键字'NSS', 'CTF', 'OTL_QAQ', 'hello'替换成'hacker'
(3)post phone要传入一个数组

读到了文件是/flag,接着来

 

 在根目录下有一个flag文件,我们利用SplFileObject这个原生类,同时他对object进行了过滤

利用编码绕过即可。

这里有一个知识点:

方便数据的传输,反序列化内容中大写的S表示字符串,可以识别内容里的十六进制

把序列化中的s变成大写就可以进行绕过,通过这个知识点,把object里边的一个字母变成16进制,就可以实现绕过,这里把b变成\62就可以

 payload:

O:9:"catalogue":2:{s:5:"class";S:13:"SplFileO\62ject";s:4:"data";s:5:"/flag";}

得到flag

这里只是一种解法,还可以利用字符替换,进行字符串逃逸,然后利用file_get_contenes()进行文件读取

推荐一篇大佬的博客

nssprize5 - 刷题记录 |Yume Shoka = Xilzy's blog = Just have fun in cyberspace!

[HDCTF 2023]YamiYami 

Linux内核:进程管理——进程文件系统 /proc详解 - 知乎 

Linux下 /proc文件夹内容解析(/proc文件系统解析)_proc environ-CSDN博客 

有一种非预期解法,就是利用/proc来读取环境变量,得到flag

在第一个链接来读取

先访问一下/etc/passwd

发现能读取,那就读取环境变量得到flag  file:///proc/1/environ

这是一个Linux系统特有的文件路径,其中的“/proc”目录是一个特殊的虚拟文件系统,提供了对内核数据结构的访问和控制。在这个目录下,“1”代表的是PID为1的进程(也就是init进程)。而“environ”文件则保存了该进程启动时设置的环境变量,以及之后在该进程中使用 putenv() 或者 setenv() 等相关函数修改的环境变量。
 

他在最后一个链接提到了/app ,应该是他源码存在的地方,尝试访问

发现读取不出来

 /flag也是读取不出来,应该是有限制,利用url编码来读取

app/app.py -> %61%70%70/%61%70%70%2E%70%79 --> %2561%2570%2570/%2561%2570%2570%252E%2570%2579

成功读取到源码


#encoding:utf-8
import os
import re, random, uuid
from flask import *
from werkzeug.utils import *
import yaml
from urllib.request import urlopen
app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = False
BLACK_LIST=["yaml","YAML","YML","yml","yamiyami"]
app.config['UPLOAD_FOLDER']="/app/uploads"
 
@app.route('/')
def index():
    session['passport'] = 'YamiYami'
    return '''
    Welcome to HDCTF2023 <a href="/read?url=https://baidu.com">Read somethings</a>
    <br>
    Here is the challenge <a href="/upload">Upload file</a>
    <br>
    Enjoy it <a href="/pwd">pwd</a>
    '''
@app.route('/pwd')
def pwd():
    return str(pwdpath)
@app.route('/read')
def read():
    try:
        url = request.args.get('url')
        m = re.findall('app.*', url, re.IGNORECASE)
        n = re.findall('flag', url, re.IGNORECASE)
        if m:
            return "re.findall('app.*', url, re.IGNORECASE)"
        if n:
            return "re.findall('flag', url, re.IGNORECASE)"
        res = urlopen(url)
        return res.read()
    except Exception as ex:
        print(str(ex))
    return 'no response'
 
def allowed_file(filename):
   for blackstr in BLACK_LIST:
       if blackstr in filename:
           return False
   return True
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            return "Empty file"
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            if not os.path.exists('./uploads/'):
                os.makedirs('./uploads/')
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return "upload successfully!"
    return render_template("index.html")
@app.route('/boogipop')
def load():
    if session.get("passport")=="Welcome To HDCTF2023":
        LoadedFile=request.args.get("file")
        if not os.path.exists(LoadedFile):
            return "file not exists"
        with open(LoadedFile) as f:
            yaml.full_load(f)
            f.close()
        return "van you see"
    else:
        return "No Auth bro"
if __name__=='__main__':
    pwdpath = os.popen("pwd").read()
    app.run(
        debug=False,
        host="0.0.0.0"
    )
    print(app.config['SECRET_KEY'])
 

需要做的事情就2件,因为提示在/boogipop做坏事,那么就需要伪造session,Yaml反序列化。

伪造session,需要知道secret_key,对secret_key的定义

app.config['SECRET_KEY'] = str(random.random()*233)

对于伪随机数,当seed固定时,生成的随机数是可以预测的,也就是顺序为固定的,所以只要知道seed的值即可。这里看到seed使用的uuid.getnode()函数,该函数用于获取Mac地址并将其转换为整数。所以我们还需要读一下Mac地址。

random.seed(uuid.getnode())  

前提知识:
在 python 中使用 uuid 模块生成 UUID(通用唯一识别码)。可以使用 uuid.getnode() 方法来获取计算机的硬件地址,这个地址将作为 UUID 的一部分。
那么/sys/class/net/eth0/address,这个就是网卡的位置,读取他进行伪造即可。 

读取到的mac地址,把他转换成10进制

2485376912964 

构造secret_key 74.93509459398877

他的session形式

 

 在进行伪造session,伪造好session之后就是进行反序列化了

eyJwYXNzcG9ydCI6IldlbGNvbWUgVG8gSERDVEYyMDIzIn0.ZTPnxA.HH4vFZIJQ3RCFrA5XkJcirW1oe4

PyYaml反序列化漏洞_snowlyzz的博客-CSDN博客

接下来就是构造并上传yml文件进行反序列化:

由于上传文件后缀设置了黑名单,所以直接采用.txt文件,那为什么.txt也能被当作.yaml来解析呢。猜测可能是:这里full_load调用了load函数,而load函数输入的是一个steam,也就是流,二进制文件,所以不管是什么后缀都无关紧要了。 

 

上传成功后通过源码可知文件访问路径为/boogipop?file=/uploads/expp.txt

 成功访问

接下来就是连接 然后进行查询,得到flag

改session

监听并连接成功 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值