
مثال من Seal Security — تطبيق Maven معرّض للثغرات (SnakeYAML CVE-2022-1471) تمت معالجته إلى إصدارات مُحكمة؛ تكامل GitHub Actions + Jenkins
تطبيق Spring Boot بسيط وبه ثغرات مقصودة، يُستخدم للتوضيح، من البداية إلى النهاية، لكيفية معالجة Seal Security ثغرة CVE معروفة عن طريق استبدال تبعية ضعيفة بإصدار مُغلَق (backported، قابل للتبديل المباشر) — دون أي تغيير في الإحداثيات المُعلنة لديك أو في كودك.
صُمم ليكون اختبار دخان (smoke test) متكاملًا من الأمام إلى الخلف لـ Seal CLI في بيئات CI/CD: شغّل التطبيق، وأطلق استغلالًا حقيقيًا، وشغّل Seal، ولاحظ كيف يُحظر نفس الاستغلال.
| النظام البيئي | Java / Maven |
| التبعية الضعيفة | org.yaml:snakeyaml:1.33 |
| CVE | CVE‑2022‑1471 — إلغاء تسلسل Constructor في SnakeYAML → تنفيذ تعليمات برمجية عن بُعد (CVSS 9.8) |
| الإصدار المُغلَق (المُصحَّح) | snakeyaml 1.33+sp1 من مستودع Maven الخاص بـ Seal |
| التكامل | Seal CLI كخطوة بناء واحدة — موضَّح لكل من GitHub Actions وJenkins |
كما يصرّح المشروع بتبعيات ضعيفة معروفة أخرى (jackson-databind 2.13.1,
commons-text 1.9, spring-core/web 5.3.26, json-smart 2.4.8, commons-lang3 3.12.0,
spring-boot 2.7.18)، ويُخضعها Seal جميعًا أيضًا للمعالجة إلى بناء مُغلَق.
تأخذ صفحة الترحيب معامل name، وتحلّله عبر المُنشئ الافتراضي لـ SnakeYAML:
Yaml yaml = new Yaml();
Object parsed = yaml.load(name); // SnakeYAML 1.33 — CVE-2022-1471
سينشئ Constructor الافتراضي في SnakeYAML أنواع Java عشوائية مُسمّاة في YAML —
وهي بدائية حقن الكائنات الكامنة خلف CVE‑2022‑1471. يكفي حمولة تُسمّي javax.script.ScriptEngineManager
(نقطة الدخول لسلسلة أدوات (gadget chain) RCE الكلاسيكية) لإثبات أن المحلِّل سيبني أي
صنف يسميه المهاجم.
طلب عادي
/?name=alice → Welcome, alice!
طلب استغلال
/?name=!!javax.script.ScriptEngineManager []
يقوم SnakeYAML الضعيف بإنشاء الصنف الذي سمّاه المهاجم، ويعرض التطبيق صفحة
"لقد تم اختراقك"، ثم يُقتل الخادم (بعد بضع ثوانٍ، حتى تُعرض الصفحة
أولًا). أعد التحميل وسيختفي التطبيق — وعبر ngrok سترى صفحة "نقطة النهاية غير متصلة".
هذه هي بدائية حقن الكائنات؛ ويبني عليها الاستغلال الكامل سلسلة استغلال (عبر URLClassLoader)
لتحميل التعليمات البرمجية عن بُعد وتشغيلها.
.
├── pom.xml # declares the vulnerable dependencies
├── src/main/java/… # Spring Boot app (HelloController, DataService)
├── .seal-actions.yml # optional local fix-mode mapping (vulnerable → sealed)
├── Jenkinsfile # example Jenkins (Groovy) pipeline with the Seal stage
└── .github/workflows/
├── build-and-run.yml # build + expose the app for browser testing
└── seal-security.yml # run Seal remediation, then start the app
Seal هي SaaS تستضيفها Seal — لا يتم تثبيت أي شيء داخل بيئتك، وكل حركة المرور هي HTTPS صادرة على TCP 443 فقط. لتشغيل المعالجة تحتاج إلى:
| السر / بيانات الاعتماد | الغرض | المكان |
|---|
قم بتكوينها في Settings → Secrets and variables → Actions (في GitHub) أو Manage Jenkins → Credentials (في Jenkins). لا تضع الرموز في المستودع أبدًا.
أضف مضيفات Seal التالية إلى القائمة المسموح بها للاتصالات الصادرة على المنفذ 443:
app.sealsecurity.io, authorization.sealsecurity.io, cli.sealsecurity.io, و— بالنسبة
لقطع Maven المغلقة — maven.sealsecurity.io. يتم تنزيل ثنائي CLI من
github.com / objects.githubusercontent.com.
mvn clean package -DskipTests
java -jar target/java-example-1.0.0.jar # → http://localhost:8080
افتح http://localhost:8080/?name=alice (يعمل)، ثم
http://localhost:8080/?name=!!javax.script.ScriptEngineManager [] — يعرض التطبيق
"لقد تم اختراقك" ويُقتل الخادم بعد بضع ثوانٍ.
يعمل Seal CLI كـخطوة إضافية واحدة، بعد حل التبعيات وقبل التعبئة. يفحص التبعيات التي تم حلها ويعيد كتابة التبعيات الضعيفة إلى إصداراتها المغلقة، باستخدام وضع الإصلاح remote (تُدار السياسة مركزيًا في Seal UI).
يستخدم seal-community/cli-action:
- uses: seal-community/cli-action@latest
with:
mode: fix
fix_mode: remote
token: ${{ secrets.SEAL_TOKEN }}
target: pom.xml # the manifest for this ecosystem
شغّله عبر Actions → "Seal Security Remediation" → Run workflow. انظر
.github/workflows/seal-security.yml.
مرحلة واحدة مُضافة، بعد حل التبعيات وقبل التعبئة. انظر
Jenkinsfile:
stage('Seal') {
steps {
sh '''
curl -fsSL https://github.com/seal-community/cli/releases/download/latest/seal-linux-amd64-latest -o seal
chmod +x seal
./seal fix --mode remote "$SEAL_MANIFEST" # SEAL_MANIFEST=pom.xml
'''
}
}
يأتي SEAL_TOKEN من بيانات اعتماد Jenkins seal-token؛ واضبط SEAL_PROJECT على معرّف
مشروعك في Seal.
بعد seal fix، تُحل التبعيات الضعيفة إلى بناءات مغلقة من مستودع Maven الخاص بـ Seal —
نفس الإحداثيات، مع إصلاح أمني مُرتجع (backported):
الإصدار المُغلَق هو نفس القطعة (artifact) مع الإصلاح الأمني المُرتجع — بديل مباشر (drop-in)، دون تغييرات في الكود ودون ترقية للإصدار الرئيسي.
أعد تشغيل الاستغلال ضد التطبيق المُعالَج. يرفض snakeyaml المُغلَق إنشاء
الأنواع العامة الخبيثة، لذلك لم تعد الحمولة تُحمّل ملف JAR البعيد — يتم حظر تنفيذ
التعليمات البرمجية عن بُعد.
seal fix إلى ملف البيان (manifest) المحدد — pom.xml بالنسبة لـ Maven. بالنسبة للبناء متعدد الوحدات،
شغّل seal fix واحدًا لكل ملف بيان.هذا هو التكامل بأكمله — مرحلة واحدة، اتصالات صادرة فقط، دون أي تغييرات في كود التطبيق.
| رمز Seal | مصادقة Seal CLI | سر GitHub Actions SEAL_TOKEN / بيانات اعتماد Jenkins "Secret text" seal-token |
| رمز ngrok (اختياري) | عرض التطبيق قيد التشغيل لمتصفح للاختبار | سر GitHub Actions NGROK_TOKEN |
| التبعية | قبل | بعد (مُغلَق) |
|---|
| org.yaml:snakeyaml | 1.33 | 1.33+sp1 |
| com.fasterxml.jackson.core:jackson-databind | 2.13.1 | 2.13.1+sp1 |
| org.apache.commons:commons-text | 1.9 | 1.9+sp1 |
| org.springframework:spring-core / spring-web | 5.3.26 | 5.3.26+sp1 |
| net.minidev:json-smart | 2.4.8 | 2.4.8+sp1 |
| org.apache.commons:commons-lang3 | 3.12.0 | 3.12.0+sp1 |
| org.springframework.boot:spring-boot | 2.7.18 | 2.7.18+sp1 |