本文主要分析vdoo发现的一些RTL8195A WIFI模块的漏洞。
下载最新的SDK
解压后在下面目录里面有一堆.a文件,漏洞就存在与这些.a里面
为了分析的方便,首先将.a链接成.so
然后就可以用IDA加载so进行分析了
本节基于最新的SDK和ameba-2.0.4-build20180817有漏洞版本SDK进行分析,同时对补丁和漏洞进行分析
ClientEAPOLKeyRecvd函数会调用CheckMIC来处理数据
EAPOLMsgRecvd为外部数据
Octet为数据地址,Length为数据长度,这里没有检查Length,从而导致栈溢出。
最新版本的CheckMIC函数如下
在最新版的SDK里面会检查length不能超过0x200
调用点
EAPOLMsgRecvd为外部数据,Octet为数据地址,Length为数据长度
问题还是位于CheckMIC函数
问题逻辑是,首先从数据包里面取出了2个字节作为长度存放到v8,然后没有检查v8是否会大于Length,就传给rt_md5_hmac去算一个hash,在rt_md5_hmac里面会越界读。
补丁版本
增加了长度检查
漏洞应该是位于ClientEAPOLKeyRecvd,函数会调用DecWPA2KeyData
EapolKeyMsg为外部数据,这里3个参数表示长度,直接从外部数据中取出,然后在DecWPA2KeyData里面会解密数据
解密结果会存放在tmp2,tmp2是栈数组,大小为257,如果keylen比较大就会导致栈溢出。
补丁,在调用ClientEAPOLKeyRecvd时会检查取出的keylen.
这个漏洞位于 AES_UnWRAP 函数,由于函数的二进制代码位于rom,这里直接分析原文提供的代码
主要问题是AES_UnWRAP循环解密时会不断把结果拷贝到栈数组R中,如果cipher_len过大,就会溢出数组R。
R的定义
漏洞位于ClientEAPOLKeyRecvd,函数会调用DecWPA2KeyData
EapolKeyMsg为外部数据,这里3个参数表示长度,直接从外部数据中取出,然后在DecWPA2KeyData里面会解密数据
DecWPA2KeyData解密完数据后会把keylen长度的数据拷贝到 kout,即decrypted_data 其大小为 128字节,所以可能导致栈溢出。
修复方案
额外增加了一个参数,表示Kout的大小,然后在DecWPA2KeyData里面会去校验
漏洞位于ClientEAPOLKeyRecvd
其中 v23 指向外部数据,然后从v23里面取出2字节的数据作为长度,调用rtl_memcpy将数据拷贝到栈上,decrypted_data大小为128字节,栈溢出。
该漏洞在最新版本中依然存在
https://www.vdoo.com/blog/realtek-rtl8195a-vulnerabilities-discovered
my blog
https://www.cnblogs.com/hac425/p/14375707.html
https:
/
/
github.com
/
ambiot
/
amb1_arduino
/
blob
/
master
/
Arduino_package
/
release
/
ameba_1
-
2.0
.
10
-
build20210203.tar.gz
https:
/
/
github.com
/
ambiot
/
amb1_arduino
/
blob
/
master
/
Arduino_package
/
release
/
ameba_1
-
2.0
.
10
-
build20210203.tar.gz
ameba_1
-
2.0
.
10
-
build20210203\hardware\variants\rtl8195a
ameba_1
-
2.0
.
10
-
build20210203\hardware\variants\rtl8195a
ar
-
x lib_ameba.a
ar
-
x lib_codec.a
ar
-
x lib_hs_uart_redirect.a
ar
-
x lib_mdns.a
ar
-
x lib_p2p.a
ar
-
x lib_rtlstd.a
ar
-
x lib_sdcard.a
ar
-
x lib_usbh.a
ar
-
x lib_wlan.a
ar
-
x lib_xmodem.a
ar
-
x lib_arduino_alexa.a
ar
-
x lib_google_cloud_iot.a
ar
-
x lib_i2c_redirect.a
ar
-
x lib_mmf.a
ar
-
x lib_platform.a
ar
-
x lib_rtsp.a
ar
-
x lib_usbd.a
ar
-
x lib_websocket.a
ar
-
x lib_wps.a
rm console_i2c.o
rm alexa_mem.o
arm
-
none
-
eabi
-
gcc
-
w
-
shared
*
.o
-
o liball.so
ar
-
x lib_ameba.a
ar
-
x lib_codec.a
ar
-
x lib_hs_uart_redirect.a
ar
-
x lib_mdns.a
ar
-
x lib_p2p.a
ar
-
x lib_rtlstd.a
ar
-
x lib_sdcard.a
ar
-
x lib_usbh.a
ar
-
x lib_wlan.a
ar
-
x lib_xmodem.a
ar
-
x lib_arduino_alexa.a
ar
-
x lib_google_cloud_iot.a
ar
-
x lib_i2c_redirect.a
ar
-
x lib_mmf.a
ar
-
x lib_platform.a
ar
-
x lib_rtsp.a
ar
-
x lib_usbd.a
ar
-
x lib_websocket.a
ar
-
x lib_wps.a
rm console_i2c.o
rm alexa_mem.o
arm
-
none
-
eabi
-
gcc
-
w
-
shared
*
.o
-
o liball.so
CheckMIC(v5
-
>EAPOLMsgRecvd, v5
-
>PTK, &v5
-
>EAPOLMsgRecvd)
CheckMIC(v5
-
>EAPOLMsgRecvd, v5
-
>PTK, &v5
-
>EAPOLMsgRecvd)
bool
__fastcall CheckMIC(OCTET_STRING EAPOLMsgRecvd, unsigned __int8
*
key,
int
keylen)
{
v3
=
EAPOLMsgRecvd.Octet;
v4
=
EAPOLMsgRecvd.Octet[
20
];
v6
=
&tmpbuf[
95
];
rtl_memcpy_0(tmpbuf, EAPOLMsgRecvd.Octet, EAPOLMsgRecvd.Length);
bool
__fastcall CheckMIC(OCTET_STRING EAPOLMsgRecvd, unsigned __int8
*
key,
int
keylen)
{
v3
=
EAPOLMsgRecvd.Octet;
v4
=
EAPOLMsgRecvd.Octet[
20
];
v6
=
&tmpbuf[
95
];
rtl_memcpy_0(tmpbuf, EAPOLMsgRecvd.Octet, EAPOLMsgRecvd.Length);
bool
__fastcall CheckMIC_constprop_14(
int
data, unsigned
int
length,
int
a3)
{
v6
=
*
(data
+
20
);
if
( length >
0x200
)
/
/
新增length的检查
return
0
;
v8
=
&stack[
95
];
freertos_memcpy_0(stack, data, length);
/
/
freertos_memset_0(&stack[
95
],
0
,
16
);
bool
__fastcall CheckMIC_constprop_14(
int
data, unsigned
int
length,
int
a3)
{
v6
=
*
(data
+
20
);
if
( length >
0x200
)
/
/
新增length的检查
return
0
;
v8
=
&stack[
95
];
freertos_memcpy_0(stack, data, length);
/
/
freertos_memset_0(&stack[
95
],
0
,
16
);
CheckMIC_constprop_14(sta
-
>EAPOLMsgRecvd.Octet, sta
-
>EAPOLMsgRecvd.Length, sta
-
>PTK) )
CheckMIC_constprop_14(sta
-
>EAPOLMsgRecvd.Octet, sta
-
>EAPOLMsgRecvd.Length, sta
-
>PTK) )
bool
__fastcall CheckMIC(OCTET_STRING EAPOLMsgRecvd, unsigned __int8
*
key,
int
keylen)
{
v3
=
EAPOLMsgRecvd.Octet;
v4
=
EAPOLMsgRecvd.Octet[
20
];
v6
=
&tmpbuf[
95
];
rtl_memcpy_0(tmpbuf, EAPOLMsgRecvd.Octet, EAPOLMsgRecvd.Length);
flag
=
v4 &
7
;
v8
=
(ntohs_0(
*
&tmpbuf[
16
])
+
4
);
/
/
从外部数据取出长度 v8
if
( flag
=
=
1
)
{
rt_md5_hmac_0(&tmpbuf[
14
], v8, key,
16
, &tmpbuf[
95
]);
/
/
作为 rt_md5_hmac参数
bool
__fastcall CheckMIC(OCTET_STRING EAPOLMsgRecvd, unsigned __int8
*
key,
int
keylen)
{
v3
=
EAPOLMsgRecvd.Octet;
v4
=
EAPOLMsgRecvd.Octet[
20
];
v6
=
&tmpbuf[
95
];
rtl_memcpy_0(tmpbuf, EAPOLMsgRecvd.Octet, EAPOLMsgRecvd.Length);
flag
=
v4 &
7
;
v8
=
(ntohs_0(
*
&tmpbuf[
16
])
+
4
);
/
/
从外部数据取出长度 v8
if
( flag
=
=
1
)
{
rt_md5_hmac_0(&tmpbuf[
14
], v8, key,
16
, &tmpbuf[
95
]);
/
/
作为 rt_md5_hmac参数
v9
=
(ntohs_0(
*
&stack[
16
])
+
4
);
if
( (length
-
13
) <
=
v9 )
/
/
检查长度
return
0
;
if
( (v6 &
7
) !
=
1
)
{
if
( (v6 &
7
)
=
=
2
)
{
v8
=
digest;
rt_hmac_sha1_0(&stack[
14
], v9, a3,
16
, digest);
return
rtl_memcmp_0(v8, data
+
95
,
16
)
=
=
0
;
}
v9
=
(ntohs_0(
*
&stack[
16
])
+
4
);
if
( (length
-
13
) <
=
v9 )
/
/
检查长度
return
0
;
if
( (v6 &
7
) !
=
1
)
{
if
( (v6 &
7
)
=
=
2
)
{
v8
=
digest;
rt_hmac_sha1_0(&stack[
14
], v9, a3,
16
, digest);
return
rtl_memcmp_0(v8, data
+
95
,
16
)
=
=
0
;
}
if
( !DecWPA2KeyData_0(
v5,
EapolKeyMsg
+
95
,
(EapolKeyMsg[
94
]
+
(EapolKeyMsg[
93
] <<
8
)),
&v5
-
>PTK[
16
],
16
,
decrypted_data) )
if
( !DecWPA2KeyData_0(
v5,
EapolKeyMsg
+
95
,
(EapolKeyMsg[
94
]
+
(EapolKeyMsg[
93
] <<
8
)),
&v5
-
>PTK[
16
],
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2021-2-6 22:30
被暗香沉浮编辑
,原因: