BROADCOM WI-FI芯片漏洞分析三


文章目录
  1. 1. 切入点
  2. 2. Wlan知识普及
  3. 3. wifi驱动发送管理帧数据包流程
  4. 4. Wifi固件接收到管理帧的处理过程
  5. 5. 总结
  6. 6. 参考

切入点

从解析wme信标帧开始
参考:freebuf博客:完整解析博通WiFi芯片Broadpwn漏洞
先找到固件中的漏洞位置,如下代码所示,有几个关键的数据帧标志类型。根据管理帧的类型在 VMG-1312 的源代码定位到处理这部分管理帧数据包的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
frame_type = *(unsigned __int16 *)(arg + 8); // arg->frame_type
cfg = *(_DWORD *)(arg + 4); // arg->bsscfg
v4 = wlc;
ie = *(_DWORD *)(arg + 0xC); // arg->ie
current_wmm_ie = *(_BYTE **)(cfg + 0x354); // cfg->current_wmm_ie
if ( frame_type == 0x20 ) // FC_REASSOC_REQ = 0x20 重新关联请求帧
goto LABEL_9;
if ( frame_type <= 0x20 )
{
if ( *(_WORD *)(arg + 8) )
{
if ( frame_type != 0x10 ) // FC_ASSOC_RESP = 0x10 //关联帧
return 0;
goto LABEL_15;
}
...
...
...
if ( frame_type != 0x30 ) // FC_REASSOC_RESP = 0x30 重新关联响应帧
{
if ( frame_type == 0x80 ) // FC_BEACON = 0x80 信标帧
{
v16 = **(_DWORD **)(*(_DWORD *)arg + 0x1C);
if ( *(_DWORD *)(*(_DWORD *)wlc + 0x34) )
...
...
...

Wlan知识普及

1)802.11数据包类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. 数据: 数据数据包的作用是用来携带更高层次的数据(如IP数据包,ISO7层协议)。
它负责在工作站之间传输数据
2. 管理: 管理数据包控制网络的管理功能
1) 信标帧(Beacons): 在无线设备中,定时依次按指定间隔发送的有规律的无线信号(类似心跳包),主要用于定位和同步使用
2) 解除认证(Deauthentication)数据包
3) Probe(request and response)探测包
4) Authenticate(request and response)身份认证
5) Associate(request and response)关联
6) Reassociate(request and response)重新关联
7) Dissassociate(notify) 解除关联
管理帧负责监督,主要用来加入或退出无线网络,以及处理接入点之间连接的转移事宜
3. 控制: 控制数据包得名于术语"媒体接入控制(Media Access Control, MAC)",是用来控制对共享媒体(即物理媒介,如光缆)的访问
1) 请求发送(Request To Send,RTS)数据包
2) 清除发送(Clear To Send,CTS)数据包
3) ACK确认(RTS/CTS)
4) PS-Poll: 当一部移动工作站从省电模式中苏醒,便会发送一个 PS-Poll 帧给基站,以取得任何暂存帧
控制帧通常与数据帧搭配使用,负责区域的清空、信道的取得以及载波监听的维护,并于收到数据时予以正面的应答,借此促进工作站间数据传输的可靠性

wifi驱动发送管理帧数据包流程

总共定位到一处位置:

是在kernel中发送数据包的过程
在\VMG1312-B-master\VMG1312-B-master\kernel\linux\drivers\staging\otus\80211core\cmm.c 中的函数 void zfSendMmFrame(zdev_t dev, u8_t frameType, u16_t dst,
u32_t p1, u32_t p2, u32_t p3)中实现
wlan连接过程:
STA (工作站)启动初始化、开始正式使用、AP 传送数据幀之前,要经过三个阶段才能接入:
(1) 扫描(SCAN)
(2) 认证(Authentication)
(3) 关联(Association)

1)探测帧

1
2
3
case ZM_WLAN_FRAME_TYPE_PROBEREQ ://构造探测帧
offset = zfSendProbeReq(dev, buf, offset, (u8_t) p1);//探测请求
break;

2)探测响应帧

构造探测响应帧时有WME参数部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
case ZM_WLAN_FRAME_TYPE_PROBERSP : //探测响应帧
zm_msg0_mm(ZM_LV_3, "probe rsp");
/* 24-31 Time Stamp : hardware WON'T fill this field */
zmw_tx_buf_writeh(dev, buf, offset, 0);
zmw_tx_buf_writeh(dev, buf, offset+2, 0);
zmw_tx_buf_writeh(dev, buf, offset+4, 0);
zmw_tx_buf_writeh(dev, buf, offset+6, 0);
offset+=8;
...
...
..
/* WME Parameters */
if (wd->wlanMode == ZM_MODE_AP)
{
if (wd->ap.qosMode == 1)
{
offset = zfApAddIeWmePara(dev, buf, offset, vap);
}
}
if ( wd->wlanMode != ZM_MODE_IBSS )
{
// jhlee HT 0
//CWYang(+)
/* TODO : Need to check if it is ok */
/* HT Capabilities Info */
offset = zfMmAddHTCapability(dev, buf, offset);
//CWYang(+)
/* Extended HT Capabilities Info */
offset = zfMmAddExtendedHTCapability(dev, buf, offset);
}
if ( wd->sta.ibssAdditionalIESize )
offset = zfStaAddIbssAdditionalIE(dev, buf, offset);
break;

3)身份认证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
case ZM_WLAN_FRAME_TYPE_AUTH ://身份认证
if (p1 == 0x30001)
{
hlen += 4;
offset += 4; // for reserving wep header
encrypt = 1;
}
/* Algotrithm Number */
zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p1&0xffff));
offset+=2;
/* Transaction Number */
zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p1>>16));
offset+=2;
...
..
..
else if (p1 == 0x30001)
{
/* share-3 : STA return challenge Text */
zfCopyToIntTxBuffer(dev, buf, wd->sta.challengeText, offset, wd->sta.challengeText[1]+2);
offset += (wd->sta.challengeText[1]+2);
}
break;

4)关联请求/重新关联请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
case ZM_WLAN_FRAME_TYPE_ASOCREQ ://关联请求帧
case ZM_WLAN_FRAME_TYPE_REASOCREQ : // FC_REASSOC_REQ = 0x20 重新关联请求帧
/* Capability */
zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[0]);
zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[1]);
/* Listen Interval */ //监听间隔
zmw_tx_buf_writeh(dev, buf, offset, 0x0005);
offset+=2;
/* Reassocaited Request : Current AP address */
if (frameType == ZM_WLAN_FRAME_TYPE_REASOCREQ)// FC_REASSOC_REQ = 0x20 重新关联请求帧
{
zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[0]);
offset+=2;
zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[1]);
offset+=2;
zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[2]);
offset+=2;
}
...
...
//Store asoc request frame body, for VISTA only
wd->sta.asocReqFrameBodySize = ((offset - hlen) >
ZM_CACHED_FRAMEBODY_SIZE)?
ZM_CACHED_FRAMEBODY_SIZE:(offset - hlen);
for (i=0; i<wd->sta.asocReqFrameBodySize; i++)
{
wd->sta.asocReqFrameBody[i] = zmw_tx_buf_readb(dev, buf, i + hlen);
}
break;

5)关联响应/重新关联响应

这部分也有WME的相关参数构造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
case ZM_WLAN_FRAME_TYPE_ASOCRSP ://关联响应帧
case ZM_WLAN_FRAME_TYPE_REASOCRSP :// 重新关联响应帧
vap = (u16_t) p3;
/* Capability */
zmw_tx_buf_writeh(dev, buf, offset, wd->ap.capab[vap]);
offset+=2;
/* Status Code */
zmw_tx_buf_writeh(dev, buf, offset, (u16_t)p1);
offset+=2;
/* AID */
zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p2|0xc000));
offset+=2;
...
...
...
/* WME Parameters */
if (wd->wlanMode == ZM_MODE_AP)
{
/* TODO : if WME STA then send WME parameter element */
if (wd->ap.qosMode == 1)
{
offset = zfApAddIeWmePara(dev, buf, offset, vap);
}
}
// jhlee HT 0
//CWYang(+)
/* HT Capabilities Info */
offset = zfMmAddHTCapability(dev, buf, offset);
//CWYang(+)
/* Extended HT Capabilities Info */
offset = zfMmAddExtendedHTCapability(dev, buf, offset);
break;

6)通知传输指示信息

1
2
3
4
5
case ZM_WLAN_FRAME_TYPE_ATIM ://通知传输指示消息
/* NULL frame */
/* TODO : add two dumb bytes temporarily */
offset += 2;
break;

7)QoS帧/数据帧

1
2
3
4
5
6
7
case ZM_WLAN_FRAME_TYPE_QOS_NULL :
zmw_buf_writeh(dev, buf, offset, 0x0010);
offset += 2;
break;
case ZM_WLAN_DATA_FRAME :
break;

8)解除关联/解除认证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
case ZM_WLAN_FRAME_TYPE_DISASOC ://解除关联
case ZM_WLAN_FRAME_TYPE_DEAUTH ://解除认证
if (wd->wlanMode == ZM_MODE_AP)
{
vap = (u16_t) p3;
if ((aid = zfApFindSta(dev, dst)) != 0xffff)
{
zmw_enter_critical_section(dev);
/* Clear STA table */
wd->ap.staTable[aid].valid = 0;
zmw_leave_critical_section(dev);
if (wd->zfcbDisAsocNotify != NULL)
{
wd->zfcbDisAsocNotify(dev, (u8_t*)dst, vap);
}
}
}
/* Reason Code */
zmw_tx_buf_writeh(dev, buf, offset, (u16_t)p1);
offset+=2;
break;

在wifi连接过程中主要有这些数据包种类

9)发送数据包

1
2
3
4
5
6
zfwBufSetSize(dev, buf, offset);//拷贝构造好的数据包到dev
zm_msg2_mm(ZM_LV_2, "management frame body size=", offset-hlen);
//Copy wlan header
zfTxGenMmHeader(dev, frameType, dst, header, offset-hlen, buf, vap, encrypt);//发送数据包过程

Wifi固件接收到管理帧的处理过程

我们关注的还是漏洞触发位置的重新关联响应帧

1)解析重新关联响应帧时造成溢出的过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void wlc_bss_parse_wme_ie(wlc_info *wlc, ie_parser_arg *arg) {
unsigned int frame_type;
wlc_bsscfg *cfg;
bcm_tlv *ie;
unsigned char *current_wmm_ie;
int flags;
frame_type = arg->frame_type;
cfg = arg->bsscfg;
ie = arg->ie;
current_wmm_ie = cfg->current_wmm_ie;
if ( frame_type == FC_REASSOC_REQ ) {
...
<handle reassociation requests>
... }
if ( frame_type == FC_ASSOC_RESP ) {
...
if ( wlc->pub->_wme ) {
if ( !(flags & 2) ) {
...
if ( ie ) {
...
cfg->flags |= 0x100u;
memcpy(current_wmm_ie, ie->data, ie->len);

2)溢出的位置确定

溢出的位置是current_wmm_ie的下一个结构体wlc->pm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
wlc_bsscfg *wlc_bsscfg_malloc(wlc_info *wlc) {
wlc_info *wlc;
wlc_bss_info *current_bss;
wlc_bss_info *target_bss;
wlc_pm_st *pm;
wmm_ie *current_wmm_ie;
...
current_bss = wlc_calloc(0x124);
wlc->current_bss = current_bss;
if ( !current_bss ) {
goto fail; }
target_bss = wlc_calloc(0x124);
wlc->target_bss = target_bss;
if ( !target_bss ) {
goto fail; }
pm = wlc_calloc(0x78);
wlc->pm = pm;
if ( !pm ) {
goto fail; }
current_wmm_ie = wlc_calloc(0x2C);
wlc->current_wmm_ie = current_wmm_ie;
if ( !current_wmm_ie ) {
goto fail; }

3)溢出结构体类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
typedef struct wlc_pm_st {
uint8 PM; bool PM_override;
mbool PMenabledModuleId;
bool PMenabled;
bool PMawakebcn;
bool PMpending;
bool priorPMstate;
bool PSpoll;
bool check_for_unaligned_tbtt;
uint16 pspoll_prd;
struct wl_timer *pspoll_timer;
uint16 apsd_trigger_timeout;
struct wl_timer *apsd_trigger_timer;
bool apsd_sta_usp;
bool WME_PM_blocked;
uint16 pm2_rcv_percent;
pm2rd_state_t pm2_rcv_state;
uint16 pm2_rcv_time;
uint pm2_sleep_ret_time;
uint pm2_sleep_ret_time_left;
uint pm2_last_wake_time;
bool pm2_refresh_badiv;
bool adv_ps_poll;
bool send_pspoll_after_tx;
wlc_hwtimer_to_t *pm2_rcv_timer;
wlc_hwtimer_to_t *pm2_ret_timer;
} wlc_pm_st_t;

4)漏洞利用方式

struct wlc_pm_st结构体中 wl_timer 类型的pspoll_timer、 apsd_trigger_timer,和wlc_hwtimer_to_t 类型的pm2_rcv_timer、 pm2_ret_timer。
wl_timer的 pspoll_timer 成员。这个结构体能在相关过程中定期触发的回调函数进行处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int timer_func(struct wl_timer *t) {
prev_cpsr = j_disable_irqs();
v3 = t->field_20;
...
if ( v3 ) {
v7 = t->field_18;
v8 = &t->field_8;
if ( &t->field_8 == v7 ) {
...
} else {
v9 = t->field_1c;
v7->field_14 = v9;
*(v9 + 16) = v7;
if ( *v3 == v8 ) {
v7->field_18 = v3;
}
}
t->field_20 = 0;
}
j_restore_cpsr(prev_cpsr);
return 0;
}

总结

这部分代码是在linux内核里,初步分析是wifi驱动管理帧数据包发送过程,结合研究固件的源码中解析数据包的过程一起看,差不多整个wifi连接过程数据包的处理流程就出来了。接下来的工作,一个是固件地址爆破,还有一个是写exp利用漏洞。

参考

802.11协议帧格式 :http://blog.csdn.net/u012570105/article/details/51785452

相关代码参考

cmm.c :主要是wifi驱动发送管理帧数据包流程

wl_linux.h : wl_timer结构体参考

wlan.h:

/* Frame Subtype */
#define ZM_WLAN_FRAME_TYPE_ASOCREQ          0x00
#define ZM_WLAN_FRAME_TYPE_ASOCRSP          0x10
#define ZM_WLAN_FRAME_TYPE_REASOCREQ        0x20
#define ZM_WLAN_FRAME_TYPE_REASOCRSP        0x30
#define ZM_WLAN_FRAME_TYPE_PROBEREQ         0x40
#define ZM_WLAN_FRAME_TYPE_PROBERSP         0x50

wlc_alloc.c :wlc_bsscfg_malloc结构体

wlc_bsscfg.h : wlc_pm_st 结构体参考

wlc.c:部分解析管理帧可以根据关键字FC_ASSOC_RESP来定位看