源码
- 两道题分别泄露
.index.php.swp
和www.zip
.index.php.swp
<?php
$flag = $_GET['flag'];
if ($flag != '15562') {
if (strstr($flag, 'zctf')) {
if (substr(md5($flag),8,16) == substr(md5('15562'),8,16)) {
die('ZCTF{#########}');
}
}
}
die('ha?')
?>
www.zip中admin.php (解密:混淆phpjm, 3元)
<?php
require_once("db.php");
$auth = 0;
if (isset($_COOKIE["auth"])) {
$auth = $_COOKIE["auth"];
$hsh = $_COOKIE["hsh"];
if ($auth == $hsh) {
$auth = 0;
} else if (sha1((string)$hsh) == md5((string)$auth)) {
$auth = 1;
} else {
$auth = 0;
}
} else {
$auth = 0;
$s = $auth;
setcookie("auth", $s);
setcookie("hsh", sha1((string)$s));
}
if ($auth) {
if (isset($_GET['query'])) {
$db = new SQLite3($SQL_DATABASE, SQLITE3_OPEN_READONLY);
$qstr = SQLITE3::escapeString($_GET['query']);
$query = "SELECT amount FROM my_wallets WHERE id=$qstr";
$result = $db->querySingle($query);
if (!$result === NULL) {
echo "Error - invalid query";
} else {
echo "Wallet contains: $result";
}
} else {
echo "<html><head><title>Admin Page</title></head><body>Welcome to the admin panel!<br /><br /><form name='input' action='admin.php' method='get'>Wallet ID: <input type='text' name='query'><input type='submit' value='Submit Query'></form></body></html>";
}
} else echo "Sorry, not authorized.";
分析
关键部分1
if (strstr($flag, 'zctf')) {
if (substr(md5($flag),8,16) == substr(md5('15562'),8,16)) {
die('ZCTF{#########}');
}
}
- 分析可知由于==为php弱类型相等,flag的MD5的8-16位为开头0e的全数字,且flag中包含zctf子串
关键部分2
else if (sha1((string)$hsh) == md5((string)$auth)) {
$auth = 1;
- 分析可知由于==为php弱类型相等,$hsh的sha1值为0e开头的全数字,并且$auth的MD5值也为0e开头的全数字
爆破
- 爆破脚本的构造方式有如下分类思路
- 出口判断
- 0e数字
- 题设相等
- payload设置
- 数值递增
- 字符递归
- 出口判断
第一题的题设相等,数值递增的PHP脚本
<?php
for ($a = 1; $a <= 999999; $a++) {
$flag = "zctf".$a;
if (substr(md5($flag),8,16) == substr(md5('15562'),8,16)){
echo $flag.":";
echo substr(md5($flag),8,16)."\n";
}
}
echo $flag;
?>
第一题的0e数字,数值递增的Python脚本
import hashlib
for i in range(10000000):
s = 'zctf' + str(i)
md5 = hashlib.md5(s).hexdigest()
h = md5[8:24]
flag = 1
if md5[8:10] == '0e':
for j in md5[10:24]:
if j.isalpha():
flag = 0
break
if flag == 1:
print s
break
第二题的0e数字,字符递归的php爆破脚本,其中sha1(40位)和MD5(32位)函数可互相更改
<?php
function find($a)
{
$s='asdfghjklpoiuytrewqzxcvbnm1234567890ZXCVBNMLKJHGFDSAQWERTYUIOP{}._';
$ss=substr(sha1($a), 0,2);
if($ss=='0e') //判断前两位是否为0e
{
$flag = 0;
for($i=2;$i<40;$i++) // 40为摘要位数
{
if(sha1($a)[$i]>'9') //判断后38位是否为数字
{
$flag=1;
break;
}
}
if($flag==0)
{
echo $a."的sha1:".sha1($a)."\n";
}
}
if(strlen($a)>7) //递归字符串长度
return;
else
{
for($j=0;$j<strlen($s);$j++)
{
find($a.$s[$j]); // 递归调用
}
}
}
$p='';
find($p);
?>
知识小结
- 花式源码泄露
- php弱类型相等
- 密码爆破脚本的构造