暇つぶし文@謎

無料アクセスカウンターofuda.cc「全世界カウント計画」

2017-12-19

[][] AbemaTVの仕様とHLSの暗号化の弱さAdd Star

AbemaTVの仕様について気になったので調べてみた (研究目的です念の為)。

AbemaTVはPCへの動画配信において、配信プロトコルにHLSを使用しているようだ。HLSはMPEG-DASHと異なりDRMが使えず (厳密にはMac環境のFairplayなどの例外もあるが) 、AbemaTVでは鍵の生成に若干工夫を行ってるのみのようだ。


まず、APIを使ってチャンネル一覧をダウンロード

$ curl https://api.abema.io/v1/channels
{"channels":[{"id":"abema-news","name":"AbemaNewsチャンネル","playback":{"hls":"https://linear-abematv.akamaized.net/channel/abema-news/playlist.m3u8"}},{"id":"abema-special","name":"AbemaSPECIALチャンネル","playback":{"hls":"https://linear-abematv.akamaized.net/channel/abema-special/playlist.m3u8"}},(後略)

次に画質一覧をダウンロード

$ curl https://linear-abematv.akamaized.net/channel/abema-news/playlist.m3u8
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=184000
180/playlist.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=300000
240/playlist.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=900000
360/playlist.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1400000
480/playlist.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2200000
720/playlist.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4200000
1080/playlist.m3u8

映像のフラグメント一覧をダウンロード

$ curl https://linear-abematv.akamaized.net/channel/abema-news/1080/playlist.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:951004
#EXT-X-DISCONTINUITY-SEQUENCE:16994
#EXT-X-KEY:METHOD=AES-128,URI="abematv-license://XXXXXXXXXXXXXXXXXXXXXX",IV=0x000000000000000000000000000000
#EXTINF:5.005000,
https://linear-abematv.akamaized.net/tsnews/abema-news/h264/1080/xxxxxxxxxxxxxxxxxxxxxx.ts
#EXTINF:5.005000,
https://linear-abematv.akamaized.net/tsnews/abema-news/h264/1080/xxxxxxxxxxxxxxxxxxxxxx.ts
#EXTINF:5.005000,
https://linear-abematv.akamaized.net/tsnews/abema-news/h264/1080/xxxxxxxxxxxxxxxxxxxxxx.ts
#EXTINF:5.005000,
https://linear-abematv.akamaized.net/tsnews/abema-news/h264/1080/xxxxxxxxxxxxxxxxxxxxxx.ts

さて、映像はAES-128方式で暗号化されているようだ。暗号の鍵には初期化ベクトル(IV)とURIが指定されているが、URIに使われているabematv-licenseスキーマとは何だろう。仕組みは良く分からないが、Chrome通信ログを見ると、スキーマの後ろの部分 (XXXXXXXXXXXXXXXXXXXXXX) と何処かにあるトークンを使って、とあるURLにアクセスしているようだ。

トークンはローカルストレージにあるものと同じようなので、Chromeのコンソールからwindow.localStorage["abm_mediaToken"]と打つと手に入る。このトークンスキーマの後ろの部分を使って、ライセンスキーの種を手に入れる。

$ curl https://license.abema.io/abematv-hls?t=トークン --data '{"lt":"スキーマの後ろの部分","kv":"wd","kg":166}'
{"cid":"abema-news","k":"XXXXXXXXXXXXXXXXXXXXXXX"}

さて、どうやってライセンスキーの種 (k) をキーに変換するのだろう? 調べた所、遅延ロードされた以下のJavascriptがこの変換を処理しているようだ。

https://abema.tv/xhrp.js

若干難読化されているけれども、肝心の部分はそのままだし、コードインジェクションもし放題なので割と何とかなる。

キー計算の表面部分のロジックはこんな感じ。

function _0x569113(cid, uid, k){
  var _k = k.substring(0,k.length-1);
  var c = k.charAt(k.length-1);
  return c=='5'?_0x1e2ccc(cid, uid, _k):
         c=='4'?_0xa25b8f(cid, uid, _k):
                _0x2782e2(cid, uid, _k);
}
var _0x5ee3af=_0x569113(cid, window.localStorage["abm_userId"], k)

キー計算の中心部分は解読していないけれど、alert(_0x5ee3af);をインジェクションしてコードを実行するだけでキーが手に入る。

手に入ったキーは、バイナリ化してkey.binとして保存しておく。あとはそのキーを使って再生するだけ。

$ wget -N https://linear-abematv.akamaized.net/channel/abema-news/1080/playlist.m3u8 \
&& sed -i 's/URI=.*\,/URI=\"key.bin\",/g' playlist.m3u8 \
&& ffplay playlist.m3u8 -protocol_whitelist file,http,https,tcp,tls,crypto

フラグメント毎にしか再生できないので実用性には欠けるけれども、何にせよHLSが弱いことは証明できたので良いかな。

今後、AbemaTVでも強固なDRM付きのMPEG-DASHが導入されていくらしいので期待。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/nazodane/20171219/1513672025