
استغلال ثغرة حقن الأوامر الموجودة في ملف uhttpd الثنائي من كاميرا IP TP-Link Tapo c200
CVE-2021-4045 هي ثغرة حقن أوامر (Command Injection) تسمح بتنفيذ الكود عن بُعد (Remote Code Execution) في كاميرا TP-Link Tapo c200 IP. تؤثر على جميع إصدارات البرامج الثابتة قبل 1.1.16 Build 211209 Rel. 37726N بسبب عدم كفاية الفحوصات على مدخلات المستخدم في uhttpd، وهو أحد الثنائيات الرئيسية للجهاز. يمكن العثور على الشرح الكامل هنا.
هذه نسخة موسعة من إثبات المفهوم (PoC) التي تم إنشاؤها لعرض الثغرة في CryptoParty Madrid 2022. لها وضعان:
shell: يفتح شل جذر (root shell) على الهدف

rtsp: يمنح الوصول إلى بث الفيديو المباشر عبر RTSP

الدالة exec_and_read_json تستخدم popen لتنفيذ الأوامر:

exec_and_read_json تُستخدم من قبل دالتين غير مسمّيتين، أسميتهما set_language و wifi_connect. تتعاملان على التوالي مع إعدادات اللغة وواي فاي (بشكل واضح). يبدو أن wifi_connect تقوم بتحليل الاقتباسات المفردة (')، لكن set_language لا تفعل ذلك. هذا يعني أنه إذا تمكنا من التحكم في مدخلات دالة set_language، يمكننا حقن أوامرنا بنجاح.

الدالة set_language تُستخدم بواسطة uh_slp_proto_request، الدالة التي ذكرتها سابقاً، والتي تمرر كمدخل بعض البيانات المُحلّلة التي تم تلقيها من المستخدم.

لتحليل بيانات المستخدم، تتحقق uh_slp_proto_request مما إذا كانت كائن JSON صالحاً. ثم تحصل على قيمة نصية يُحددها المفتاح "method" وقيمة قاموس يُحددها "params" (على الأقل هذا ما أعتقده، حيث لم يُحل استدعاء الدالة بواسطة Ghidra ولكن بدا أنه يعمل بهذه الطريقة). اعتماداً على الطريقة المحددة، تختار uh_slp_proto_request الدالة التي سيتم استدعاؤها.
لذا، عن طريق إرسال {"method": "setLanguage", "params":{}} نستدعي بنجاح دالة set_language ونمرر {} كمعامل language_json. ثم، داخل set_language، يتم تحويل كائن language_json إلى نص وإدراجه مباشرة في "ubus call system_state_audio set_language \'%s\'" ليتم تنفيذه.
عن طريق إرسال {"method": "setLanguage", "params": {"payload": "'; touch poc;'"}}، سيتم تنفيذ ubus call system_state_audio set_language '{"payload": "'; touch poc;'"}' الذي يحتوي فعلياً على 3 أوامر: ubus call system_state_audio set_language '{"payload": "'، touch poc، و '"}'. الثاني يعطينا تنفيذ كود كامل.
الآن، uh_slp_proto_request تُستخدم بواسطة دالة أخرى غير مسمّاة تدير جميع الطلبات، أسميتها main_server_function. إذا كان الطلب صحيحاً (لا يتجاوز الحد الأقصى للطول، يستخدم http أو https اعتماداً على تكوين الخادم، إلخ)، تتحقق main_server_function مما إذا كان عنوان URL يحتوي على /cgi-bin/luci أو /web-static. إذا لم يكن كذلك، يتم استدعاء uh_slp_proto_request.

بتخمين وإرسال بضعة طلبات إلى الكاميرا، يمكننا التحقق من أن البيانات المستخدمة بواسطة uh_slp_proto_request هي بيانات POST عادية. لذا، إذا أرسلنا طلب POST إلى / مع الحمولة السابقة، ستقوم uh_slp_proto_request بمعالجة هذه البيانات، واستدعاء set_language وسيتم حقن حمولتنا في الأمر الذي ينفذه exec_and_get_result.
كما ترون، لم أذكر أي شيء عن المصادقة، نظراً لأن طريقة setLanguage يمكن استدعاؤها دون تسجيل الدخول. هذا يسمح لأي مستخدم بالسيطرة الكاملة على الكاميرا بطلب واحد غير مصادق.