考试周结束,有时间来复现了。。。然鹅好像有题目崩了,java又没学过。。。只能复现一部分了。
web 签到题 点击,扫描,发现除了index.php 之外其他都需要登陆,抓包发现有发送Auth.php请求,其中有didictf_username字段,尝试添加成为didictf_username: admin。成功登陆。
然后在返回包中显示出了一个php文件,尝试访问看到了Session.php的源代码如下:
<?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);// ....//config/flag.php if(strlen($path) !== 18) {//../config/flag.php exit(); } $this->response($data=file_get_contents($path),'Congratulations'); } exit(); } } ?> <?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() {//target1: 绕过所有false if(empty($_COOKIE)) { return FALSE; }//cookie not empty $session = $_COOKIE[$this->cookie_name]; if(!isset($session)) { parent::response("session not found",'error'); return FALSE; }//ddctf_id 不能为空 $hash = substr($session,strlen($session)-32);//长度要大于32? 32位之后的内容 $session = substr($session,0,strlen($session)-32);//一直截断到倒数第32位 if($hash !== md5($this->eancrykey.$session)) {//key.txt 内容和 ddctf_id 内容片段拼接 再md5 等于ddctf_id32位之后的内容 parent::response("the cookie data not match",'error'); return FALSE; } $session = unserialize($session);//ddctf_id 反序列化 if(!is_array($session) OR !isset($session['session_id']) OR !isset($session['ip_address']) OR !isset($session['user_agent'])){ return FALSE; }//ddctf_id 反序列化之后的内容要有 session_id ip_address user_agent 再来个path?? 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"); }//sprint格式化打印函数利用,通过传递进参数nickname = %S 让它可以读取key。 if($session['ip_address'] != $_SERVER['REMOTE_ADDR']) { parent::response('the ip addree not match'.'error'); return FALSE; }//ip_address 要写自己的ip if($session['user_agent'] != $_SERVER['HTTP_USER_AGENT']) { parent::response('the user agent not match','error'); return FALSE; }//user_agent 内容要和 http_user_agent的匹配 return TRUE; }//看起来可以动手脚的只有session_id? 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($ ); $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(); ?> 得到key之后构造ddctfid:
...