-
-
[原创] 某设备CoAP协议漏洞挖掘实战
-
发表于: 2022-8-9 21:13 21414
-
发现看雪等国内安全论坛好像CoAP协议相关内容很少,以及CVE中基本也是CoAP协议库存在的漏洞,所以将最近对某设备CoAP漏洞挖掘的相关分析写一下。
CoAP可以简单的当做基于UDP协议的轻量化HTTP协议。
协议栈:
Constrained RESTful Environments (CoRE)
CoAP Resource Discovery 机制
例: CoAP server 提供了2个资源
安全机制
CoAP 有四种安全机制: NoSec, PreSharedKey ,RawPublicKey,Certificate, 但是只有NoSec和RawPublicKey是强制实现的。
CoAP 本身没有实现认证和授权机制,而是通过 communication security(IPsec,DTLS)和object security 来完成。
安全考虑
CoAP协议默认端口为5683或5684,端口为5683时的安全机制为NoSec, 5684则是开启了DTLS。看了下设备端口开启的5683。
如下,设备实现了基于CoRE 的 Well-Known URI
所以可以直接进行 Resourse Discovery 过程:
可以看到,CoAPserver 提供了以下资源
逆向对应二进制看到的代码实现,对应的函数名和URI也 可以推测下对应功能。
剩下的就是对这些函数进行进一步漏洞挖掘了。
挖掘成果:
coapsync_handler函数会将设备SSID,Pwd等参数返回给client,导致了信息泄露,比较鸡肋的一个洞。
Url
字段数据导致的命令注入。
recv_cmdfile_handler会调用到cmdupgrade_parse。
最终会调用函数do_upgrade
, 而Url
字段数据会拼接到system执行的命令中,达成未授权RCE.
cotopaxi
fd0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6e0j5h3#2K6N6h3&6Y4i4K6u0r3j5$3!0@1L8%4m8S2P5r3V1`.
libcoap,aiocoap等 coap 协议实现库
判断是否可以进行resource discovry 操作获取CoAP server 的资源
判断安全机制是哪种
判断是否实现了认证机制
对请求解析函数进行逆向分析
227K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1L8$3!0D9M7#2)9J5k6h3W2W2N6r3k6Q4x3X3g2G2M7X3N6Q4x3V1k6Z5N6r3#2D9i4K6u0r3M7X3k6U0z5o6j5I4y4b7`.`.
cf7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1j5i4c8S2N6s2u0S2j5$3E0W2M7W2)9J5k6h3W2W2N6r3k6Q4x3X3g2G2M7X3N6Q4x3V1k6V1L8$3y4Q4x3V1k6Z5N6r3#2D9i4K6u0r3M7X3k6U0y4U0j5&6x3l9`.`.
dc3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8W2)9J5k6i4N6A6K9$3W2H3k6h3c8A6j5g2)9J5k6h3!0J5k6#2)9J5c8Y4N6A6K9$3W2Q4x3V1k6o6L8$3&6K6N6s2u0S2K9h3&6W2k6q4)9#2k6V1q4H3M7r3I4A6j5$3q4@1K9h3!0F1i4K6g2X3f1s2u0G2N6r3!0U0L8$3H3`.
836K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1j5i4c8S2N6s2u0S2j5$3E0W2M7W2)9J5k6h3W2W2N6r3k6Q4x3X3g2G2M7X3N6Q4x3V1k6V1L8$3y4Q4x3V1k6Z5N6r3#2D9i4K6u0r3M7X3k6U0y4K6t1#2x3R3`.`.
050K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1j5i4c8S2N6s2u0S2j5$3E0W2M7W2)9J5k6h3W2W2N6r3k6Q4x3X3g2G2M7X3N6Q4x3V1k6V1L8$3y4Q4x3V1k6Z5N6r3#2D9i4K6u0r3M7X3k6U0y4e0M7^5y4b7`.`.
REQ: GET coap:
/
/
server:port
/
.well
-
known
/
core
RES:
2.05
Content
<
/
sensors
/
temp>;
if
=
"sensor"
,
<
/
sensors
/
light>;
if
=
"sensor"
REQ: GET coap:
/
/
server:port
/
.well
-
known
/
core
RES:
2.05
Content
<
/
sensors
/
temp>;
if
=
"sensor"
,
<
/
sensors
/
light>;
if
=
"sensor"
udp
0
0
0.0
.
0.0
:
5683
0.0
.
0.0
:
*
udp
0
0
0.0
.
0.0
:
5683
0.0
.
0.0
:
*
if
(
*
((_BYTE
*
)v21
-
>hdr
+
1
)
=
=
1
&& !memcmp(key, &unk_A0DC,
4u
) )
{
coap_log_impl(
7
,
"create default response for %s\n"
,
".well-known/core"
);
v22
=
wellknown_response(context, node
-
>pdu);
}
if
(
*
((_BYTE
*
)v21
-
>hdr
+
1
)
=
=
1
&& !memcmp(key, &unk_A0DC,
4u
) )
{
coap_log_impl(
7
,
"create default response for %s\n"
,
".well-known/core"
);
v22
=
wellknown_response(context, node
-
>pdu);
}
import
asyncio
from
aiocoap
import
*
async
def
main():
protocol
=
await Context.create_client_context()
msg
=
Message(code
=
GET, uri
=
"coap://192.168.1.1:5683/.well-known/core"
)
response
=
await protocol.request(msg).response
print
(response.payload)
asyncio.run(main())
import
asyncio
from
aiocoap
import
*
async
def
main():
protocol
=
await Context.create_client_context()
msg
=
Message(code
=
GET, uri
=
"coap://192.168.1.1:5683/.well-known/core"
)
response
=
await protocol.request(msg).response
print
(response.payload)
asyncio.run(main())
b'<
/
>;title
=
"General Info"
;ct
=
0
,
...
<
/
device
/
inform
/
boot>;title
=
device
/
inform
/
boot,<
/
device
/
inform
/
syncreq>;title
=
device
/
inform
/
syncreq,<
/
device
/
inform
/
off>;title
=
device
/
inform
/
off,<
/
device
/
inform
/
hb>;title
=
device
/
inform
/
hb,<
/
device
/
inform
/
data>;title
=
device
/
inform
/
data,
<
/
device
/
cmd
/
file
>;title
=
device
/
cmd
/
file
<
/
async>;ct
=
0
'
b'<
/
>;title
=
"General Info"
;ct
=
0
,
...
<
/
device
/
inform
/
boot>;title
=
device
/
inform
/
boot,<
/
device
/
inform
/
syncreq>;title
=
device
/
inform
/
syncreq,<
/
device
/
inform
/
off>;title
=
device
/
inform
/
off,<
/
device
/
inform
/
hb>;title
=
device
/
inform
/
hb,<
/
device
/
inform
/
data>;title
=
device
/
inform
/
data,
<
/
device
/
cmd
/
file
>;title
=
device
/
cmd
/
file
<
/
async>;ct
=
0
'
void
*
__fastcall start_coap_server_thread(void
*
a1)
{
pthread_t v1;
/
/
$v0
v1
=
pthread_self();
pthread_detach(v1);
...
registerCoapMethod(
"device/inform/boot"
, coapboot_handler)
registerCoapMethod(
"device/inform/syncreq"
, coapsync_handler)
registerCoapMethod(
"device/inform/off"
, coapoff_handler)
registerCoapMethod(
"device/inform/hb"
, coaphb_handler )
registerCoapMethod(
"device/inform/data"
, coapdata_handler)
registerCoadMethod(
"device/cmd/url"
, coapdata_url_handler)
...
startCoapService(
"0.0.0.0"
,
5683
);
return
0
;
}
void
*
__fastcall start_coap_server_thread(void
*
a1)
{
pthread_t v1;
/
/
$v0
v1
=
pthread_self();
pthread_detach(v1);
...
registerCoapMethod(
"device/inform/boot"
, coapboot_handler)
registerCoapMethod(
"device/inform/syncreq"
, coapsync_handler)
registerCoapMethod(
"device/inform/off"
, coapoff_handler)
registerCoapMethod(
"device/inform/hb"
, coaphb_handler )
registerCoapMethod(
"device/inform/data"
, coapdata_handler)
registerCoadMethod(
"device/cmd/url"
, coapdata_url_handler)
...
startCoapService(
"0.0.0.0"
,
5683
);
return
0
;
}
...
cJSON_AddItemToObject(v73,
"SSID"
, v13);
v14
=
cJSON_CreateString(&v83[
136
]);
cJSON_AddItemToObject(v73,
"SecurityMode"
, v14);
v15
=
cJSON_CreateString(&v83[
72
]);
cJSON_AddItemToObject(v73,
"Pwd"
, v15);
...
...
cJSON_AddItemToObject(v73,
"SSID"
, v13);
v14
=
cJSON_CreateString(&v83[
136
]);
cJSON_AddItemToObject(v73,
"SecurityMode"
, v14);
v15
=
cJSON_CreateString(&v83[
72
]);
cJSON_AddItemToObject(v73,
"Pwd"
, v15);