Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
gosentry — سلسلة أدوات Go موجّهة نحو الأمن، تركّز على قدرات Fuzzing على أحدث مستوى. | Kitploit
أدوات/GitHubGitHub/trailofbits/gosentry
التحليل الثابتالتحليل الديناميكي (عزل)تحليل الثغرات الأمنيةتحليل الكودالاختبار العشوائيDevSecOpsتحليل الملفات الثنائيةالتعلم والتعليم
GitHubtrailofbits/gosentry

gosentry

سلسلة أدوات Go موجّهة نحو الأمن، تركّز على قدرات Fuzzing على أحدث مستوى.

عرض المستودع
1173منذ 9 أيامتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

gosentry

integration tests

gosentry هو فرع (fork) من سلسلة أدوات Go تركّز على الأمان، يدمج العديد من الميزات لحملات التضمين (fuzzing) المتطورة على قواعد أكواد Go. إذا كنت تستخدم go test -fuzz سابقًا، فينبغي أن تستخدم gosentry كبديل. يأتي هذا مع تحسينات متنوعة للتضمين وكاشفات أخطاء غير موجودة أصلاً في سلسلة أدوات Go. انظر TLDR; أدناه. يمكنك أيضًا قراءة المقالة المرتبطة بالمدونة هنا.

TLDR (الميزات والخيارات):

  • قم بتضمين مدخلات struct مباشرة (بدون الحاجة إلى محلل مخصص). أضف بذورًا باستخدام f.Add(Input{N: 7, S: "hi"}) ثم f.Fuzz(func(t *testing.T, in Input) { ... }).
  • التوقف (Panic) عند تجاوز سعة الأعداد الصحيحة واكتشاف مشاكل العمليات الحسابية
  • التضمين باستخدام LibAFL لتقنيات تضمين متطورة مثل حل قيود المسار
  • توليد/تحوير المدخلات من قواعد نحوية لتجنب التحويرات غير المفيدة. التحوير يولّد عملية رياضية صحيحة مثل X + Y - Z يمكن أن تصبح X / U + Z - 14 بدلاً من X + Yè - Z
  • التوقف (Panic) عند استدعاء دوال محددة (مثل مسجلات الأخطاء الحرجة) والانهيار عند استدعائها
  • تركيز المُضمِّن على الأسطر المعدّلة حديثًا وعلى التغطية الجديدة لاستهداف الالتزامات (commits) الجديدة بشكل أساسي
  • اكتشاف سباقات البيانات (data races) أثناء التضمين
  • اكتشاف تسريبات Go أثناء التضمين
  • اكتشاف التنفيذات العالقة عبر المهلات الزمنية أثناء التضمين
  • توليد تقرير تغطية HTML من مجموعة حملة تضمين بأمر CLI واحد

فهرس المحتويات

  • البناء
    • الميزة 1: التضمين المدرك للبنى (تضمين البنى كمدخلات)
    • الميزة 2: اكتشاف مشاكل تجاوز السعة والاقتطاع للأعداد الصحيحة
    • الميزة 3: التوقف عند دوال محددة
    • الميزة 4: التضمين المتطور باستخدام LibAFL
    • الميزة 5: التضمين الموجّه بـ Git-blame (تجريبي)
    • الميزة 6: اكتشاف حالات السباق وتسريبات goroutine والتعليق أثناء التضمين
    • الميزة 7: التضمين القائم على القواعد النحوية (Nautilus)
    • الميزة 8: توليد تقارير تغطية التضمين من الحملة
  • الاكتشافات
  • الاعتمادات

البناء```bash

cd src && ./make.bash # Produces ../bin/go. See GOFLAGS below.

root@kitploit:~
> [!TIP]
> وثائق المساهمين: اقرأ `docs/gosentry/index.md` للحصول على خريطة الكود، وحلقة التطوير الموصى بها، ونقاط دخول CI، وسكربتات القياس.
> يستخدم هذا الفرع تطبيق Pull GitHub لفتح ودمج PRs تلقائيًا من `golang/go:master` إلى `master`، مما يضمن ألا نتخلف أبدًا عن أحدث تحديثات سلسلة أدوات Go.

## الميزة 1: الاختبار التلقائي المبني على البنى (fuzz structs كمدخلات)

#### نظرة عامة

الاختبار التلقائي الأصلي في Go (`go test -fuzz=...`) يدعم فقط مجموعة صغيرة من الأنواع العددية كوسائط للاختبار التلقائي (`[]byte`, `string`, أرقام, ...). في gosentry، يمكنك أيضًا اختبار **الأنواع المركبة** المبنية من تلك الأنواع العددية: البنى (structs)، المصفوفات، الشرائح، والمؤشرات.
هذا مفيد عندما يتلقى الكود الخاص بك مدخلات منظمة بشكل طبيعي ولا تريد بناء مُرمِّز/مُفكِّك ترميز مخصص فقط لتزويد المجموعة (corpus) وتغييرها.
انظر `test/gosentry/examples/multiargs` و `test/gosentry/examples/composite` للحصول على أمثلة.

#### مثال بسيط```go
type Input struct {
	Data []byte
	S    string
	N    int
	OK   bool
}

func FuzzStructInput(f *testing.F) {
	// Seed the initial corpus with a Go struct (gosentry feature).
	f.Add(Input{Data: []byte("A"), S: "B", N: 7, OK: true})

	f.Fuzz(func(t *testing.T, in Input) {
		if in.OK && in.N == 1337 && in.S == "BOOMMOOB" && bytes.Equal(in.Data, []byte("A")) {
			t.Fatalf("boom")
		}
	})
}
كيف تعمل بذور البنى (f.Add) والتفزيز البنيوي (اللاصق المُصنَّع)

لا يمكن للمفزز الأصلي في Go تفزيز قيمة struct مباشرة (فهو يعرف فقط كيفية تحوير قائمة صغيرة من الأنواع العددية). يضيف gosentry طبقة لاصقة صغيرة: عندما يستهدف المفزز أنواعًا مركّبة (مثل Input)، يقوم gosentry بتفزيز []byte واحدة خلف الكواليس. في كل تنفيذ، يقوم بفك ترميز تلك البايتات إلى البنية الخاصة بك (حقلًا بحقل، وبشكل تكراري للمقاطع/المصفوفات/المؤشرات) ثم يستدعي رد اتصال f.Fuzz بالقيمة المفكوكة. يُستخدم نفس الترميز للبذور، لذا فإن f.Add(Input{...}) يصبح إدخال مجموعة بايتات مشفّرة يمكن للمفزز إعادة استخدامها وتحويرها مثل أي بذرة أخرى.

تقوم المفززات (بما فيها LibAFL) بتحوير البايتات الخام، لذلك نريد وحدة فك ترميز يمكنها تحويل أي شريحة بايتات إلى قيمة بنية "ما" والاستمرار. JSON/gob سترفض معظم المدخلات العشوائية (أمر سيء للتغطية)، كما أنها لا تملأ الحقول غير المُصدَّرة، بينما غالبًا ما يستفيد التفزيز من كسر القيود الثابتة. هذا التنسيق المخصص صغير وسريع وحتمي ومتسامح مع البيانات التالفة.

في الكواليس، يستخدم هذا تنسيق gosentry الثنائي البسيط الخاص (ليس gob وليس JSON). الكود موجود في src/testing/libafl.go:

  • الترميز: libaflMarshalInputs /

الميزة 2: كشف تجاوز الأعداد الصحيحة ومشاكل الاقتطاع

نظرة عامة

هذا العمل مستوحى من الأداة المطورة سابقًا go-panikint. يضيف كشفًا للتجاوز (overflow) والتجاوز السفلي (underflow) في العمليات الحسابية على الأعداد الصحيحة، و(اختياريًا) كشفًا لاقتطاع الأنواع في تحويلات الأعداد الصحيحة. عند اكتشاف تجاوز أو اقتطاع، يُطلق panic برسالة خطأ مفصلة، تشمل نوع العملية المحدد والأنواع الصحيحة المعنية.

العمليات الحسابية: تتعامل مع الجمع + والطرح - والضرب * والقسمة / لكل من الأنواع الصحيحة الموقّعة وغير الموقّعة. للأعداد الموقّعة، تشمل int8 وint16 وint32. للأعداد غير الموقّعة، تشمل uint8 وuint16 وuint32 وuint64. حالة القسمة تكشف تحديدًا حالة التجاوز MIN_INT / -1 للأعداد الموقّعة. int64 وuintptr لا يتم فحصهما في العمليات الحسابية.

كشف اقتطاع النوع: يكشف تحويلات الأنواع الصحيحة التي قد تسبب فقدانًا للبيانات. يشمل جميع الأنواع الصحيحة: int8 وint16 وint32 وint64 وuint8 وuint16 وuint32 وuint64. يستبعد uintptr بسبب استخدامه المعتمد على المنصة. هذا معطّل افتراضيًا.

كشف التجاوز مفعّل افتراضيًا. لتعطيله، أضف GOFLAGS='-gcflags=-overflowdetect=false' قبل تنفيذ ./make.bash. يمكنك أيضًا تفعيل فاحص الاقتطاع بإضافة: -gcflags=-truncationdetect=true

كيف يعمل

تقوم هذه الميزة بتعديل توليد SSA في المترجم بحيث تحصل العمليات الحسابية على الأعداد الصحيحة وتحويلات الأعداد الصحيحة على فحوصات إضافية في زمن التشغيل تستدعي بيئة التشغيل لإطلاق panic برسالة خطأ مفصلة عند اكتشاف خطأ. تُطبَّق الفحوصات باستخدام تصفية مبنية على موقع المصدر بحيث يتم تزويد كود المستخدم بالفاحصات بينما يتم تخطي ملفات المكتبة القياسية والتبعيات (ذاكرة الوحدات وvendor/).

يمكنك قراءة مقالة المدونة المرتبطة بهذا الموضوع هنا.

كبت النتائج الإيجابية الكاذبة

أضف علامة على نفس سطر العملية أو السطر الذي يسبقه مباشرة لكبت تقرير محدد:

  • تجاوز/تجاوز سفلي: overflow_false_positive
  • اقتطاع: truncation_false_positive

مثال:```go // overflow_false_positive intentionalOverflow := a + b // truncation_false_positive x := uint8(big) sum2 := a + b // overflow_false_positive x2 := uint8(big) // truncation_false_positive

root@kitploit:~
أحيانًا قد لا يعمل هذا، والسبب أن Go تقوم بتضمين الدالة (inlining). إذا لم يكن `// overflow_false_positive` كافيًا، أضف `//go:noinline` قبل توقيع الدالة الخاصة بك.

## الميزة 3: التسبب في panic عند استدعاء دوال محددة

عند فحص الأهداف باستخدام fuzzing، قد نكون مهتمين بتفعيل panic عند استدعاء دوال معينة. على سبيل المثال، قد تصدر بعض البرامج رسائل `log.error` بدلاً من التسبب في panic، على الرغم من أن هذه الحالات غالبًا ما تشير إلى حالات يريد باحثو الأمان اكتشافها أثناء fuzzing.
ومع ذلك، عادةً ما يتم التعامل مع هذه الأخطاء داخليًا (على سبيل المثال، عبر آليات إعادة المحاولة أو الإيقاف المؤقت، أو عبر طباعة الرسائل في السجلات)، مما يجعلها غير مرئية إلى حد كبير لأدوات fuzzing. الهدف من هذه الميزة هو معالجة هذه المشكلة.

#### طريقة الاستخدام

قم بتجميع gosentry، ثم استخدم الخيار `--panic-on`.```bash
./bin/go test -fuzz=FuzzHarness --use-libafl --focus-on-new-code=false --catch-races=false --catch-leaks=false --panic-on="test_go_panicon.(*Logger).Warning,test_go_panicon.(*Logger).Error"

المثال أعلاه سيُحدث panic عند استدعاء إما (*Logger).Warning أو (*Logger).Error (قائمة مفصولة بفواصل).

كيف تعمل ميزة panic على الدوال المحددة```text ┌───────────────────────────────────────────────────────────────────────────┐ │ 1) gosentry `go test` │ │ - parses + validates `-panic-on=...` against packages being built │ │ - forwards patterns to the compiler via `-panic-on-call=...` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) `cmd/compile` │ │ - prevents inlining of matching calls so the call stays visible │ │ - SSA pass inserts a call to `runtime.panicOnCall(...)` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) `runtime.panicOnCall` │ │ - panics with: "panic-on-call: func-name" │ └───────────────────────────────────────────────────────────────────────────┘ ``` عمليًا، يجعل هذا أي موقع استدعاء مطابق يتصرف كتعطل/ذعر لأدوات الفزّينغ (لاحظ: يمكن احتجاز مواقع الاستدعاء الثابتة فقط).

الميزة 4: فزّينغ متطور مع LibAFL

يقدم LibAFL أداءً أفضل بكثير من أداة فزّينغ Go التقليدية. عند الفزّينغ (go test -fuzz=...)، يستخدم gosentry LibAFL افتراضيًا (المشغل في golibafl/).

ملاحظة ثبات: في وضع LibAFL، يفرض gosentry GODEBUG=updatemaxprocs=0 (تعطيل تحديثات GOMAXPROCS التلقائية في وقت التشغيل) لتجنب تعطل متقطع في CI الخاص بنظام Linux ("sync: inconsistent mutex state"). التفاصيل في misc/gosentry/USE_LIBAFL.md.

عند استخدام LibAFL (الوضع الافتراضي)، يجب عليك أن تختار صراحةً ما إذا كنت تريد تفعيل الجدولة المدركة لـ git أم لا: --focus-on-new-code=true|false. مزيد من التوثيق في ملف Markdown هذا. يمكنك أيضًا تمرير ملف إعداد JSONC اختياري لـ LibAFL (بما في ذلك خيارات الفزّينغ القواعدي)، انظر هنا. مع "stop_all_fuzzers_on_panic": false، يحفظ LibAFL كل تعطل ويعيد تشغيل عميله لمواصلة الفزّينغ.```bash ./bin/go test -fuzz=FuzzHarness --focus-on-new-code=false --catch-races=false --catch-leaks=false --libafl-config=path/to/libafl.jsonc # optional --libafl-config

root@kitploit:~
استخدم `-fuzztime=1m` لإيقاف حملة LibAFL بعد دقيقة واحدة.

توليد تقرير التغطية من مجموعة حملة LibAFL موثق في [الميزة 8](#feature-8-generate-go-coverage-reports-from-fuzzing-campaign).

التضمين القائم على القواعد (Nautilus) موثق في [الميزة 7](#feature-7-grammar-based-fuzzing-nautilus).

<details>
<summary><strong>كيف يتم ربط Go مع LibAFL معًا</strong></summary>```text
┌───────────────────────────────────────────────────────────────────────────┐
│ 1) gosentry `go test`                                                      │
│    - captures  `testing.F.Fuzz(...)` callback                             │
│    - generates  extra source file: `_libaflmain.go`                       │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 2) Generated bridge: `_libaflmain.go`                                     │
│    - provides libFuzzer-style C ABI entrypoints:                          │
│        LLVMFuzzerInitialize                                               │
│        LLVMFuzzerTestOneInput                                             │
│    - adapts bytes -> Go types -> calls the captured fuzz callback         │
└───────────────┬───────────────────────────────────────────────────────────┘ 
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 3) `libharness.a` (static archive on disk) contains:                      │
│      - compiled objects for all test package (+ dependencies)             │
│      - generated `_testmain.go` + `_libaflmain.go`                        │
│      - LLVMFuzzerInitialize                                               │
│      - LLVMFuzzerTestOneInput                                             │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 4) `golibafl/` (Rust + LibAFL)                                            │
│    env: HARNESS_LIB=/path/to/libharness.a                                 │
│    fuzz loop: mutate input -> LLVMFuzzerTestOneInput(data) -> observe     │
└───────────────────────────────────────────────────────────────────────────┘

في وضع --use-libafl، يقوم gosentry ببناء libharness.a ويقوم مشغّل Rust golibafl بتشغيله داخل العملية عبر نقاط دخول libFuzzer. ملاحظة: يمكن أن يشير HARNESS_LIB إلى أي اسم أرشيف harness (على سبيل المثال libharness_race.a المستخدم من قبل --catch-races).

كيف تعمل آلية تتبع التغطية (LibAFL + هدف Go)

في وضع --use-libafl، يقوم gosentry بترجمة harness Go مع تفعيل آلية تتبع التغطية. يضيف هذا عدّادات صغيرة إلى الكود تتغير عند تنفيذ أجزاء مختلفة من برنامجك. عندما يبدأ harness داخل golibafl، يكشف وقت تشغيل Go عن هذه العدّادات إلى LibAFL. يقرأ LibAFL هذه العدّادات بعد كل إدخال لمعرفة أي كود تم تنفيذه، ويستخدم تلك التغطية لتوجيه الطفرات التالية.

القيود

لنتحدث عن الدافع وراء استخدام LibAFL. إن التضمين باستخدام go test -fuzz متخلف بكثير عن أحدث تقنيات التضمين. مثال جيد على ذلك هو CMPLOG/Redqueen الخاص بـ AFL++. تسمح هذه الميزات لأدوات التضمين بحل قيود معينة. لنفترض المقتطف التالي```go if input == "IMARANDOMSTRINGJUSTCMPLOGMEMAN" { panic("this string is illegal") }

root@kitploit:~
أدوات التضمين المتطورة (SOTA) مثل AFL++ أو LibAFL كانت ستكتشف الانهيار (panic) فورًا في تلك الحالة. لكن أداة التضمين الأصلية للغة Go لن تفعل ذلك. تلك فجوة هائلة تعيق استكشاف التغطية **بكثير**.

المعيار أدناه يُظهر هذه الحدود. لاحظ أن هذه المعايير يمكن **إعادة إنتاجها** وتحسينها عبر [مستودع gosentry-bench-libafl](https://github.com/kevin-valerio/gosentry-bench-libafl/tree/main).

##### المعيار 1:

الرسم البياني أدناه يوضح تطور عدد الأسطر المغطاة أثناء التضمين (Fuzzing) لمكتبة [UUID](https://github.com/google/uuid) الخاصة بجوجل باستخدام LibAFL مقابل أداة التضمين الأصلية للغة Go.
![BENCH1](https://assets.kitploit.com/production/public/readmes/41918/7b1ea005996846c9ee4d7c0d42fee26731050d10b6b21d59c551e4b1b956923e.png "BENCH1")

##### المعيار 2:

الرسم البياني أدناه يوضح تطور عدد الأسطر المغطاة أثناء التضمين (Fuzzing) لمشروع [go-ethereum](https://github.com/ethereum/go-ethereum) باستخدام LibAFL مقابل أداة التضمين الأصلية للغة Go.
![BENCH2](https://assets.kitploit.com/production/public/readmes/41918/61aab8540ab8d339307854de6737a405056c3c8ad83a822df40f74e362b93021.png "BENCH2")



#### مثال
يمكنك اختباره على بعض أحزمة التضمين (fuzzing harnesses) في المسار `test/gosentry/examples/`.```bash
cd test/gosentry/examples/reverse
../../../../bin/go test -fuzz=FuzzReverse --focus-on-new-code=false --catch-races=false --catch-leaks=false

أوقف حملة fuzz باستخدام Ctrl+C.

دليل مخرجات LibAFL (هوية الحملة / إعادة استخدام corpus)

يخزّن gosentry حالة حملة LibAFL (corpus، الأعطال، إلخ) تحت جذر ذاكرة التخزين المؤقت لـ fuzz في Go (تقريبًا $(go env GOCACHE)/fuzz)، في دليل حتمي مشتق من نفس الحزمة + نفس هدف fuzz (ونفس جذر المشروع).

هذا يعني أن إيقاف (Ctrl+C) وإعادة تشغيل نفس حملة fuzz سيؤدي، افتراضيًا، إلى المتابعة من corpus queue/ السابق لـ LibAFL.

يُطبع المسار في نهاية التشغيل:```text libafl output dir: /full/path/to/.../fuzz//libafl//

root@kitploit:~
ملاحظات:
- `<harness>` هو اسم هدف الـ fuzz عندما يكون `-fuzz` معرّفًا بسيطًا مثل `FuzzXxx` (أو `^FuzzXxx$`)، وإلا فإنه يكون `pattern-<hash>`.
- توليد التغطية (`--generate-coverage`) يستخدم نفس القاعدة للعثور على مجموعة `queue/` الصحيحة، لذا يجب تشغيله من نفس الحزمة مع نفس `-fuzz=...`.

## الميزة 5: التضمين الموجَّه بـ Git-blame (تجريبي)

#### نظرة عامة

التضمين الموجَّه بالتغطية ممتاز في استكشاف مسارات جديدة، لكنه يعامل جميع الأكواد المغطاة على أنها مثيرة للاهتمام بنفس القدر. عند تضمين قواعد أكواد كبيرة، قد ترغب في تحيز أداة التضمين نحو الأكواد المعدلة مؤخرًا، حيث من المرجح أن تُدخل الانحدارات والعلل. في وضع LibAFL، يمكن لـ gosentry استخدام `git blame` لتفضيل المدخلات التي تنفذ أسطرًا تغيرت مؤخرًا (مع الإبقاء على توجيه التغطية كإشارة أساسية).

يستند هذا العمل إلى عمل سابق من [LibAFL-git-aware](https://github.com/kevin-valerio/LibAFL-git-aware). جميع التفاصيل التقنية المعمقة موثقة هناك.

#### طريقة الاستخدام

فعّل الجدولة الموجَّهة بـ git باستخدام `--focus-on-new-code=true`:```bash
./bin/go test -fuzz=FuzzHarness --use-libafl --focus-on-new-code=true --catch-races=false --catch-leaks=false

يتطلب هذا الوضع git (لتشغيل git blame) وgo tool addr2line لتعيين عدادات التغطية مرة أخرى إلى المصدر file:line.

كيف يعمل fuzzing الموجَّه بـ git-blame```text ┌───────────────────────────────────────────────────────────────────────────┐ │ 1) gosentry `go test -fuzz` │ │ - builds `libharness.a` (contains `go.o` + `.go.fuzzcntrs`) │ │ - runs `golibafl` with `GOLIBAFL_FOCUS_ON_NEW_CODE=1` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) `golibafl` generates a cached "git recency map" │ │ - maps coverage counters -> (file:line) via `go tool addr2line` │ │ - runs `git blame` to get a timestamp per line │ │ - stores timestamps in `git_recency_map.bin` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) LibAFL scheduler uses the recency map │ │ - coverage decides what enters the corpus │ │ - among the corpus, prioritize inputs that hit newer lines │ └───────────────────────────────────────────────────────────────────────────┘ ```
كيف ينشئ gosentry ملف git_recency_map.bin

.go.fuzzcntrs هو قسم الرابط الذي يحمل عدادات التغطية 8-بت بنمط libFuzzer الخاصة بلغة Go (مفعّلة عبر -gcflags=all=-d=libfuzzer)؛ كل بايت يمثل "عدد المرات التي تم فيها الوصول إلى هذه النقطة المُجهزة". عند استخدام --focus-on-new-code=true، يقوم golibafl بإنشاء git_recency_map.bin عبر:

  1. استخراج go.o من libharness.a.
  2. قراءة حجم قسم .go.fuzzcntrs للحصول على عدد العدادات N.
  3. فحص عمليات إعادة التوطين في .text التي تشير إلى رموز .go.fuzzcntrs لاستعادة العنوان لكل فهرس عداد.
  4. تحويل كل عنوان إلى file:line باستخدام .
المعيار 1 (go-ethereum / geth): خط الأساس مقابل git-aware

تم التنفيذ باستخدام misc/gosentry/bench_focus_on_new_code_geth.sh --trials 5 --warmup 600 --timeout 200.

```text gitaware_5: crash (7122ms) baseline results: trial 1: crash (107747ms) trial 2: crash (146415ms) trial 3: crash (37902ms) trial 4: crash (154034ms) trial 5: timeout (200000ms) baseline crashes: 4/5 (timeouts=1, errors=0) baseline median (capped to timeout): 146.415s

git-aware results: trial 1: timeout (200000ms) trial 2: crash (87432ms) trial 3: crash (61733ms) trial 4: crash (157540ms) trial 5: crash (7122ms) git-aware crashes: 4/5 (timeouts=1, errors=0) git-aware median (capped to timeout): 87.432s

root@kitploit:~
</details>

## الميزة 6: اكتشاف حالات السباق، وتسريبات الغوروتين، والتعليق (انتهاء المهلة) أثناء وقت التضمين

##### اكتشاف التعليقات المؤكدة (انتهاء مهلة LibAFL)

عند التضمين باستخدام LibAFL، يمكن أن ينتهي تنفيذ الـ harness **بمهلة** (على سبيل المثال بسبب طريق مسدود / غوروتينات عالقة في الانتظار، أو مسار بطيء للغاية).

لتقليل النتائج الإيجابية الخاطئة، يتعامل gosentry مع انتهاء المهلة كمرشح للتعليق ويؤكده بإعادة تشغيل المدخلات التي انتهت مدتها عدة مرات مع مهلة أكبر. عند تأكيد التعليق، يكتب gosentry المدخلات إلى `<libafl output dir>/hangs/` ويوقف حملة التضمين (يتعامل معها كخلل/انهيار).

قبل الخروج، يحاول `golibafl` تصغير المدخلات المتسببة في الانهيار/التعليق (أفضل جهد؛ يتم تحديد التعليقات بحوالي 60 ثانية إجمالاً).

ملاحظة: يتم أيضًا تشغيل تأكيد التعليق أثناء استيراد/توليد المجموعة الأولية، لذا يمكن اكتشاف الأهداف التي تنتهي مهلتها على كل مدخل بشكل حتمي.

يتم تكوين هذا عبر `--libafl-config`:
- `catch_hangs` (الافتراضي: `true`)
- `hang_timeout_ms` (الافتراضي: `10000`)
- `hang_confirm_runs` (الافتراضي: `3`)

##### اكتشاف حالات السباق (`--catch-races`)

يمكن لـ gosentry تشغيل حلقة إعادة تشغيل منفصلة `-race` تراقب دليل LibAFL `queue/` وتعيد تشغيل البذور المكتشفة حديثًا مع `GORACE=halt_on_error=1`.

تقوم حلقة إعادة التشغيل ببناء أرشيف harness منفصل `-race` لإعادة التشغيل فقط (بدون أدوات قياس تغطية التضمين).

عند اكتشاف حالة سباق أثناء إعادة التشغيل، يطبع gosentry تقرير كاشف السباق الكامل قبل ملخص `catch-races:` وأمر إعادة الإنتاج.

ملاحظة: يكتشف كاشف السباق في Go حالات السباق **داخل تنفيذ harness واحد فقط** (سباقات بين غوروتينات في نفس العملية تصل إلى نفس الذاكرة دون مزامنة صحيحة). سيفوّت `--catch-races` السباقات إذا لم تؤدِ البذرة إلى تحفيز التزامن المتسابق، كما أنه لا يكتشف السباقات عبر العمليات.

<details>
<summary><strong>كيف تعمل وضعية كشف السباق</strong></summary>

يبدأ هذا الوضع مراقبًا صغيرًا داخل `go test` (نفس العملية الأب)، ويعمل طوال حملة التضمين بأكملها.

- متى: قبل بدء عملية التضمين الرئيسية في LibAFL، يبني gosentry أداة إعادة التشغيل + المُشغّل.
- المراقبة: قبل بدء التضمين، تلتقط gosentry لقطة للمحتويات الأولية لدليل `<libafl output dir>/queue/` في مجموعة `seen`. ثم يقوم غوروتين باستطلاع `<libafl output dir>/queue/` كل ~1 ثانية ويعيد فقط تشغيل البذور المنشأة حديثًا (يتخطى ملفات dotfiles و `*.metadata`).```text
Legend: output/... = <libafl output dir>/...

┌───────────────────────────────────────────────────────────────────────────┐
│ 1) Main LibAFL fuzzing run                                                 │
│    - `golibafl` writes new seeds to `output/queue/`                        │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 2) `--catch-races` sidecar setup                                           │
│    - builds replay harness: `libharness_race.a` (`go test -race ...`)      │
│    - builds replay runner: `golibafl-race` (linked against race harness)   │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 3) Replay loop                                                             │
│    - polls `output/queue/` for new seeds                                   │
│    - runs: `GORACE=halt_on_error=1 golibafl-race run --input <seed>`       │
│      (2 workers × 3 repeats per seed)                                      │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 4) On "DATA RACE"                                                          │
│    - prints the race detector report                                       │
│    - copies seed to `output/races/`                                        │
│    - stops the fuzz campaign (treat as bug/crash)                          │
└───────────────────────────────────────────────────────────────────────────┘
كشف تسريبات الـ goroutine (--catch-leaks)

يمكن لـ gosentry أيضًا تشغيل حلقة إعادة تشغيل goleak تراقب مجلد queue/ الخاص بـ LibAFL وتعيد تشغيل البذور المكتشفة حديثًا مع تفعيل go.uber.org/goleak.

عند اكتشاف تسريب goroutine، يطبع gosentry المسار الدقيق للبذرة وينسخه إلى <libafl output dir>/leaks/.

ملاحظة: goleak مخصص لتسريبات الـ goroutine، وليس تسريبات الذاكرة.

كيف يعمل وضع كشف تسريبات الـ goroutine

تبدأ هذه الوضعية أيضًا مراقبًا صغيرًا داخل go test (نفس العملية الأم)، ويعمل طوال حملة التضميد الكاملة.

  • المراقبة: تستقصي goroutine مجلد <libafl output dir>/queue/ كل ~1 ثانية وتعيد تشغيل كل بذرة جديدة مع GOSENTRY_LIBAFL_CATCH_LEAKS=1 (يفعّل go.uber.org/goleak بعد كل تنفيذ).```text Legend: output/... = /...

┌───────────────────────────────────────────────────────────────────────────┐ │ 1) Main LibAFL fuzzing run │ │ - golibafl writes new seeds to output/queue/ │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) --catch-leaks sidecar setup │ │ - builds replay runner: golibafl-leak (linked against the harness) │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) Replay loop │ │ - polls output/queue/ for new seeds │ │ - runs: │ │ (enables checks after each execution) │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 4) On "catch-leaks: detected goroutine leak" │ │ - copies seed to │ │ - stops the fuzz campaign (treat as bug/crash) │ └───────────────────────────────────────────────────────────────────────────┘

كيف يعمل التوليد العشوائي القائم على القواعد النحوية في gosentry```text Legend: output/... = /...

┌───────────────────────────────────────────────────────────────────────────┐ │ 0) gosentry go test -fuzz=FuzzXxx (LibAFL + --use-grammar) │ │ - captures your testing.F.Fuzz callback + its parameter types │ │ - builds libharness.a (libFuzzer-style entrypoints for LibAFL) │ │ - runs golibafl fuzz ... --use-grammar --grammar ... │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 1) golibafl (Rust + LibAFL) fuzzes the Go harness in-process │ │ - loads libharness.a via HARNESS_LIB=... │ │ - observers: edges + time (+ cmplog for comparisons) │ │ - feedback/objective: coverage/time/crash (and optional hang handling) │ │ - scheduler selects a corpus seed (coverage-guided) │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) Nautilus (in-process, per client) │ │ - loads the JSON grammar into a Nautilus context │ │ - fuzz loop stage: parse seed -> mutate tree -> unparse to bytes │ │ - if the seed is not parseable: fall back to generation-from-scratch │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) Grammar mode stages │ │ - initial corpus: if input dir empty, call N times │ │ - fuzz loop: corpus seed -> grammar mutate -> exec harness │ │ - new coverage inputs are added to the on-disk corpus () │ └───────────────────────────────────────────────────────────────────────────┘

تنزيل الأداة
libaflAppendValue
  • فك الترميز: libaflUnmarshalArgs / libaflDecodeValue
  • قواعد الترميز (بشكل عام):

    • bool: 1 بايت (0 أو 1)
    • الأعداد الصحيحة: بايتات بالترتيب القليل الأهمية أولاً (int/uint حجمها 8 بايتات)
    • الأعداد العشرية: بتات IEEE-754 بالترتيب القليل الأهمية أولاً (float32 = 4 بايتات، float64 = 8 بايتات)
    • string: uvarint(len) ثم بايتات السلسلة الخام
    • []byte: uvarint(len) ثم البايتات الخام
    • المقاطع الأخرى: uvarint(len) ثم ترميز كل عنصر
    • البنى: تُرمَّز الحقول بترتيب التصريح
    • المؤشرات: 1 بايت (0 = فارغ، 1 = موجود) ثم القيمة المُشار إليها
    go tool addr2line
  • تشغيل git blame --line-porcelain للحصول على committer-time لكل سطر.
  • كتابة git_recency_map.bin كـ u64 head_time + u64 N + N * u64 timestamps (بترتيب البايتات الأقل أهمية). الإدخالات غير المعيّنة تستخدم الطابع الزمني 0.
  • GOSENTRY_LIBAFL_CATCH_LEAKS=1 golibafl-leak run --input <seed>
    go.uber.org/goleak
    output/leaks/
    root@kitploit:~
    </details>
    
    
    #### كيفية الاستخدام
    
    فعّل اكتشاف تسرب الـ goroutine باستخدام `--catch-leaks=true` أو اكتشاف التسابق باستخدام `--catch-races=true````bash
    ./bin/go test -fuzz=FuzzHarness --use-libafl --focus-on-new-code=false --catch-races=true --catch-leaks=true
    

    الميزة 7: التوليد المعتمد على القواعد النحوية (Nautilus)

    نظرة عامة

    التوليد على مستوى البايت رائع، لكن المحلِّلات (parsers) وتنسيقات الملفات غالبًا ما تحتاج إلى مدخلات منظمة. مع --use-grammar، يستخدم gosentry مولّد القواعد النحوية Nautilus من LibAFL لتوليد وتحوير مدخلات تتوافق مع قواعد نحوية يقدمها المستخدم (بتنسيق JSON)، ويغذيها إلى أداة الاختبار التقليدية لـ Go (testing.F.Fuzz).

    في وضع القواعد النحوية، لا يزال LibAFL يشغّل حلقة التوجيه بالتغطية المعتادة (اختيار بذرة من المجموعة → تحوير → تنفيذ → الاحتفاظ بالمدخلات التي تزيد التغطية). يضيف المُشغّل (runner) تحوير Nautilus (بذرة → شجرة قواعد نحوية → تحوير → إلغاء البناء النحوي) بالإضافة إلى مرحلة (افتراضيًا) موجَّهة بـ CMPLOG على غرار I2S تعيد كتابة العُقد الطرفية في Nautilus بناءً على المقارنات أثناء التشغيل. وهذا يُبقي المدخلات صالحة نحويًا (فهو لا يشغّل مراحل الفوضى/الرموز الخام على مستوى البايت في وضع القواعد النحوية). يمكنك تعطيل مرحلة CMPLOG/I2S في --libafl-config عبر nautilus_cmplog_i2s=false (التوليد على مستوى البايت يُبقي CMPLOG/I2S مفعّلًا دائمًا).

    [!NOTE] وضع القواعد النحوية عادةً ما يكون أبطأ من التوليد على مستوى البايت. إنها مقايضة: بنية أكثر مقابل عدد أقل من عمليات التنفيذ في الثانية.

    للحصول على أفضل النتائج، استخدم دالة اختبار (fuzz callback) بوسيط واحد تأخذ إما شريحة بايت ([]byte) أو سلسلة نصية (string):```go f.Fuzz(func(t testing.T, data []byte) { / parse data */ }) // or: f.Fuzz(func(t testing.T, s string) { / parse s */ })

    root@kitploit:~
    يعمل وضع القواعد بشكل أفضل مع وسيط إدخال واحد (`[]byte` أو `string`). تؤدي استدعاءات fuzz متعددة الوسائط إلى جعل gosentry يفك ترميز المخزن المؤقت للبايتات الأساسي إلى قيم منفصلة، لذا لن يبقى النص الأصلي المُولَّد عبر القواعد سليماً.
    
    > [!NOTE]
    > وضع القواعد ما زال يولد **بايتات/سلاسل نصية**. إذا كنت تحتاج إلى مدخلات مهيكلة (أو تقوم بتشويش تفاضلي)، فإن الـ harness هو المكان الذي تحوّل فيه `data` إلى قيم المجال (parse/unmarshal). (خارج وضع القواعد، يمكن لـ gosentry أيضًا تشويش أنواع Go > المركبة عن طريق فك ترميزها من البايتات؛ انظر [الميزة 1](#feature-1-struct-aware-fuzzing-fuzz-structs-as-inputs).)
    
    يمكنك ضبط Nautilus عبر `--libafl-config` (يُستخدم فقط مع `--use-grammar`): `nautilus_max_len` و `nautilus_cmplog_i2s` (انظر `misc/gosentry/libafl.config.jsonc`).
    
    <details>
    <summary><strong>قياس الأداء: مرحلة Nautilus grammar CMPLOG/I2S (مفعّلة مقابل معطّلة)</strong></summary>
    
    نُفّذ في 17 فبراير 2026 باستخدام مثال JSON الخاص بالقواعد في المستودع (`test/gosentry/examples/grammar_json`, `FuzzGrammarJSON`, grammar `testdata/JSON.json`).
    
    النتائج (LibAFL `UserStats`):
    
    | الوضع | `nautilus_cmplog_i2s` | مدة التشغيل | عدد التنفيذات | تنفيذ/ثانية | الحواف |
    |---|---:|---:|---:|---:|---:|
    | مفعّل | `true` | 1m-5s | 103818 | 1.586k | 388/8008 (4%) |
    | معطّل | `false` | 1m-0s | 256659 | 4.251k | 388/8008 (4%) |
    
    ملاحظة: `edges` هي حواف خريطة التغطية في LibAFL، وليست أسطر مصدر Go.
    
    </details>
    
    عيّن `GOSENTRY_VERBOSE_AFL=1` لطباعة عدد قليل من المدخلات المولّدة. عيّن `GOSENTRY_VERBOSE_AFL_ALL_INPUTS=1` لطباعة **كل** تنفيذ في وضع القواعد بصيغة `GOLIBAFL_MUTATED_INPUT "..."` (ضجيج كبير جدًا).
    
    #### أدوات مساعدة لتأليف القواعد
    
    إذا كنت بحاجة إلى إنشاء قواعد Nautilus JSON جديدة لتنسيق/بروتوكول هدفك الخاص، فإن gosentry يتضمن:
    
    - موجه جاهز لـ LLM: [misc/gosentry/nautilus/prompt.md](https://github.com/trailofbits/gosentry/blob/HEAD/misc/gosentry/nautilus/prompt.md)
    - مجموعة صغيرة من أمثلة القواعد: [misc/gosentry/nautilus/examples/](https://github.com/trailofbits/gosentry/blob/HEAD/misc/gosentry/nautilus/examples/)
    
    <details>
    <summary><strong>مثال على harness اختبار Go (JSON)</strong></summary>```go
    func FuzzGrammarJSON(f *testing.F) {
    	f.Fuzz(func(t *testing.T, data []byte) {
    		dec := json.NewDecoder(bytes.NewReader(data))
    		dec.UseNumber()
    
    		var v any
    		if err := dec.Decode(&v); err != nil {
    			t.Fatalf("invalid JSON: %v", err)
    		}
    		if err := dec.Decode(&struct{}{}); err != io.EOF {
    			t.Fatalf("invalid JSON: trailing data")
    		}
    	})
    }
    

    مخطط منصة اختبار التشويش التفاضلي (محللان):```go f.Fuzz(func(t *testing.T, data []byte) { gotA, errA := ParseA(data) gotB, errB := ParseB(data) if (errA == nil) != (errB == nil) { t.Fatalf("parser disagreement: A=%v B=%v", errA, errB) } _ = gotA _ = gotB })

    root@kitploit:~
    </details>
    
    <details>
    <summary><strong>مثال: اختبار قواعد نحوية لِـ"لغة إدخال حقيقية" (بدون مُرمِّز مخصص)</strong></summary>
    
    يقوم هذا المثال باختبار مُقيِّم تعبيرات حسابية بسيطة من خلال توليد **تعبيرات صالحة** من قاعدة نحوية. لا يوجد ترميز مُخصص بصيغة "بنية إلى بايتات": المُختبر يُنتج نفس النوع من الإدخال الذي يحلّله الكود الخاص بك عادةً.
    
    كود الاختبار (إدخال `string` بوسيط واحد يعمل بشكل أفضل في وضع القواعد النحوية):```go
    func FuzzExprEval(f *testing.F) {
    	f.Add("1+2")
    	f.Add("(3*4)-5")
    
    	f.Fuzz(func(t *testing.T, expr string) {
    		// Parse+eval your language/protocol.
        // You can be **sure** that `expr` will always be a valid math operation. Just decode/parse/unmarshall it afterwards. 
    		_, _ = Eval(expr)
    	})
    }
    

    مخطط القواعد النحوية (صيغة Nautilus JSON):```json [ ["Expr", "{Term}"], ["Expr", "{Term}+{Expr}"], ["Expr", "{Term}-{Expr}"], ["Term", "{Factor}"], ["Term", "{Factor}*{Term}"], ["Factor", "{Num}"], ["Factor", "({Expr})"], ["Num", "0"], ["Num", "1"], ["Num", "2"], ["Num", "3"] ]

    root@kitploit:~
    </details>
    
    <details>
    <summary><strong>مثال لقواعد Nautilus JSON (مجموعة فرعية صغيرة من JSON)</strong></summary>
    
    هذا هو تنسيق الملف المتوقع بواسطة `--grammar=...`:
    - القواعد النحوية هي مصفوفة JSON من القواعد: `["NonTerm", "RHS"]`.
    - يجب أن تبدأ أسماء الرموز غير الطرفية بحرف كبير (`Value`, `Object`, ...).
    - استخدم `{NonTerm}` في RHS للإشارة إلى قاعدة أخرى.
    - الرمزان `{` و `}` محجوزان لمراجع الرموز غير الطرفية؛ لإصدار أقواس حرفية، استخدم `\\{` و `\\}` في سلسلة RHS.```json
    [
      ["Json", "{Value}"],
      ["Value", "null"],
      ["Value", "{String}"],
      ["String", "\"{Chars}\""],
      ["Chars", ""],
      ["Chars", "{Char}{Chars}"],
      ["Char", "a"],
      ["Char", "b"]
    ]
    
    generate
    output/queue/
    root@kitploit:~
    </details>
    
    القيود (الغراء الحالي):
    - وضع القواعد النحوية يعمل بشكل أفضل مع معامل إدخال واحد؛ أهداف التشويش متعددة المعاملات ستفك ترميز مخزن البايت الأساسي إلى قيم منفصلة.
    - لا يوجد إعادة تجميع/تقاطع قواعد بين بذور المجموعة حتى الآن (التحوير أحادي البذرة).
    
    ## الميزة 8: إنشاء تقارير تغطية Go من حملة التشويش
    
    بعد (أو أثناء) تشغيل حملة تشويش LibAFL، يمكن لـ gosentry إنشاء تقرير تغطية Go عن طريق إعادة تنفيذ **مجموعة الانتظار** الحالية في LibAFL (بدون تشويش).```bash
    # Same package + same fuzz target as your fuzz campaign:
    ./bin/go test -fuzz=FuzzHarness --generate-coverage .
    

    تقوم هذه الأداة بإعادة تشغيل المدخلات من <libafl output dir>/queue/ وتكتب cover.out و cover.html.

    الإنجازات

    تم اكتشاف هذه الأخطاء من خلال حملة تنقيح تفاضلي (differential-fuzzing) باستخدام ميزة التنقيح النحوي في gosentry.

    Optimism

    • يمكن أن يختلف Kona وop-node حول قنوات brotli
    • نوع دفعة غير معروف يسبب حالة panic ويؤدي إلى رفض الخدمة في kona-protocol
    • عدم تطابق تحليل إطارات Kona مع op-node ومواصفات OP Stack

    REVM

    • إيداع فاشل في op-revm يتوقف مع OutOfFunds لا يزيد قيمة nonce، مما يؤدي إلى عدم تطابق جذر الحالة مع العملاء الآخرين

    الاعتمادات

    • golibafl
    • Nautilus
    • LibAFL
    • goleak
    • go
    • go-panikint