تحليل الثغرات في خط Airdrop

يجب على المطورين الذين يعتمدون على IBC ومهندسي الأمن الذين يراجعون عمليات تكامل IBC مراجعة سطح الهجوم المعرض لعملاء أو قنوات IBC الضارة بعناية.

** بقلم: ويل **

** مقدمة: ** تصف هذه المقالة الثغرة الأمنية التي اكتشفها Jump Crypto في برنامج Stride airdrop: Stride عبارة عن سلسلة كوزموس تُستخدم لتخزين السوائل في النظام البيئي Cosmos. قد تسمح هذه المشكلة للمهاجم بسرقة جميع عمليات الإنزال الجوي التي لم تتم المطالبة بها على Stride. في وقت الاكتشاف ، كان أكثر من 1.6 مليون STRD (ما يعادل حوالي 4 ملايين دولار) في خطر. أبلغ Jump بشكل خاص عن الثغرة الأمنية للمساهمين في Stride ، وتم إصلاح المشكلة منذ ذلك الحين ، مع عدم حدوث عمليات استغلال ضارة نتيجة لجهودنا. عنوان الارتباط الأصلي [1]

Airdrop on Stride

تجري Stride بانتظام عمليات إنزال جوي كبيرة لرمزها الأصلي [STRD] لتحفيز نشاط الشبكة ولامركزية الحوكمة عبر مجموعة واسعة من الأطراف. رمز التخصيص والمطالبة بإنزال الهواء في x / claim [2] نفذت في الوحدة. يتم تخصيص Airdrop من خلال LoadAllocationData [3] تحددها وظيفة تقوم بتحميل ملف تخصيص يحتوي على العناوين وتخصيصات الإنزال الجوي. بالنسبة لمعظم عمليات الإسقاط الجوي ، تصف العناوين التي تم تحميلها المستخدمين في سلاسل Cosmos الأخرى ، مثل Osmosis أو Juno ، لذلك يقوم الكود أولاً بتحويلهم إلى عناوين Stride باستخدام وظيفة uses.ConvertAddressToStrideAddress.

لكل حساب في الإنزال الجوي ، تقوم الوحدة بإنشاء سجل مطالبة [4] ، والذي يحتوي على معرف الإسقاط الجوي لإسقاط جوي معين ، والعنوان المحول ، ومقدار الرموز المميزة المخصصة للمستخدم. بعد إنشاء ClaimRecord ، يمكن للمستخدم الذي لديه عنوان Stride المقابل إرسال MsgClaimFreeAmount إلى السلسلة [5] تعال وطالب بإنزالهم الجوي.

ومع ذلك ، لم ينجح هذا التطبيق أثناء الإنزال الجوي الأخير من EVMOS لأن وظيفة الاستخدامات KonvertAddressToStrideAddress ترسم عناوين Evmos إلى عناوين Stride التي لا يمكن الوصول إليها. وذلك لأن عناوين EVMOS مشتقة باستخدام نوع العملة 60 ، بينما يتم اشتقاق عناوين Stride باستخدام نوع العملة 118.

من أجل أن يظل المستخدمون المتأثرون قادرين على المطالبة بالإسقاط الجوي ، أضاف الفريق القدرة على تحديث العنوان المستهدف لسجل مطالبة لم تتم المطالبة به عبر رسالة IBC عبر سلسلة من حساب EVMOS المقابل. يتم تنفيذ آلية التحديث هذه كجزء من وحدة x / الطيار الآلي. س / الطيار الآلي [6] اعترض إرسال IBC ICS-20 الوارد وحاول استخراج تعليمات خاصة بـ Stride من المذكرة أو حقل المستقبل (يتضاعف حقل المستقبل كحقل المذكرة في إصدارات IBC السابقة للإصدار الخامس):

func (imibcmodule) OnRecvPacket (

ctxsdk.Context ،

packetchanneltypes.

relayersdk.AccAddress ،

) ibcexported. شكر وتقدير {

// ملاحظة: الإقرار سيتم كتابته بشكل متزامن أثناء معالجة IIB.

تحويل البيانات

iferr: = transfertypes.ModuleCdc.UnmarshalJSON (packet.GetData ()، & data)؛ err! = لا شيء {

returnchanneltypes.NewErrorAcknowledgement (يخطئ)

}

[..]

// ibc-gov5hasaMemofieldthat canstoreforwardinginfo

// Forolderversionofibc-go ، يجب أن يكون الأفضل في مجال الاستقبال

metadatastring

ifdata.Memo! = "{// ibc-gov5 +

الميتاداتا = البيانات

} else {// beforeibc-gov5

الميتاداتا = البيانات. المتلقي

}

[..]

// parseoutanyforwardinginfo

packetForwardMetadata ، err: = types.ParsePacketMetadata (بيانات التعريف)

iferr! = لا شيء {

returnchanneltypes.NewErrorAcknowledgement (يخطئ)

}

// Iftheparsedmetadataisnil ، فهذا يعني أنه لا يوجد منطق إعادة توجيه

// Passthepacketdowntothenextmiddleware

ifpacketForwardMetadata == لا شيء {

returnim.app.OnRecvPacket (ctx ، packet ، relayer)

}

// ModifythepacketdatabyreplacingtheJSON metadatafieldwithareceiver العنوان

// toallowthepackettocontinuedownthestack

newData: = البيانات

newData.Receiver = packetForwardMetadata.Receiver

bz ، يخطئ: = transfertypes.ModuleCdc.MarshalJSON (& newData)

iferr! = لا شيء {

returnchanneltypes.NewErrorAcknowledgement (يخطئ)

}

newPacket: = حزمة

newPacket.Data = bz

// عبوة جديدة

ack: = im.app.OnRecvPacket (ctx ، newPacket ، relayer)

if! ack.Success () {

العودة

}

الطيار الآلي: = im.keeper.GetParams (ctx)

// إذا كان النقل ناجحًا ، ثم خُطط للوحدة المقابلة ، إذا كان ذلك ممكنًا

switchroutingInfo: = packetForwardMetadata.RoutingInfo. (النوع) {

أنواع الكاسيت.

[...]

casetypes.ClaimPacket البيانات الوصفية:

// Ifclaimroutingisinactive (butthepackethadroutinginfointhemo) إرجاع الخطأ الخطأ

[..]

im.keeper.Logger (ctx) .Info (fmt.Sprintf ("Forwaringpacketfrom٪ stoclaim"، newData.Sender))

iferr: = im.keeper.TryUpdateAirdropClaim (ctx ، newData ، routingInfo) ؛ يخطئ! = لا شيء {

im.keeper.Logger (ctx). خطأ (fmt.Sprintf ("Errorupdatingairdropclaimfromautopilot for٪ s:٪ s"، newData.Sender، err.Error ()))

returnchanneltypes.NewErrorAcknowledgement (يخطئ)

}

العودة

تقصير:

returnchanneltypes.NewErrorAcknowledgement (errorsmod.Wrapf (types.ErrUnsupportedAutopilotRoute ، "٪ T" ، routingInfo))

}

}

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

func (kKeeper) TryUpdateAirdropClaim (

ctxsdk.Context ،

تحويل البيانات.

packetMetadatatypes.ClaimPacketMetadata ،

)خطأ{

[..]

// grabrelevantaddresses

senderStrideAddress: = utils.ConvertAddressToStrideAddress (data.Sender)

ifsenderStrideAddress == "" {

returnerrorsmod.Wrapf (sdkerrors.ErrInvalidAddress، fmt.Sprintf ("عنوان invalidsender (٪ s)"، data.Sender))

}

newStrideAddress: = packetMetadata.StrideAddress

// updatetheairdrop

airdropId: = packetMetadata.AirdropId

k.Logger (ctx) .Info (fmt.Sprintf ("تحديث العنوان٪ s (الأصل٪ s) إلى٪ s forairdrop٪ s" ،

senderStrideAddress ، data.Sender ، newStrideAddress ، airdropId))

returnk.claimKeeper.UpdateAirdropAddress (ctx ، senderStrideAddress ، newStrideAddress ، airdropId)

}

تقوم الوظيفة بتحويل عنوان حزمة IBC المرسل إلى عنوان Stride المسمى senderStrideAddress ، وتستخرج airdropId وعنوان airdrop الجديد newStrideAddress من بيانات تعريف الحزمة. ثم يستدعي UpdateAirdropAddress لتحديث سجل Claim مفتوح يطابق مجموعة senderStrideAddress و airdropId إلى العنوان الجديد.

مع تحديث ClaimRecord ، يمكن الآن لـ newStrideAddress المطالبة بالإسقاط الجوي. من المهم ملاحظة أن آلية التحديث هذه محمية فقط بعنوان المرسل المحدد في حزمة IBC. لا يقوم Stride بإجراء أي تحقق آخر للتأكد من أن المستلمين الحقيقيين قد أطلقوا تحديثات عمليات الإنزال الجوي.

لفهم سبب كون هذه ثغرة خطيرة ، نحتاج إلى إلقاء نظرة فاحصة على IBC ، بروتوكول الاتصال بين blockchain.

أمان IBC

IBC هي آلية اتصال عبر سلسلة خفيفة تعتمد على العميل. على غرار بروتوكولات الشبكة الكلاسيكية ، تلخص ** وحدة IBC الأساسية ** العديد من التفاصيل منخفضة المستوى ، مما يسمح للمطورين ببناء عمليات التكامل الخاصة بهم بسهولة فوقها. يبدو توصيل سلسلة واحدة ممكّنة لـ IBC (السلسلة A) بسلسلة أخرى ممكّنة لـ IBC (السلسلة B) قليلاً مثل هذا:

CreatedsolomachineclientonIBCenabledchain [ClientID = 06-solomachine-6]

Createdtendermintclientonsolomachine [ClientID = 07-totermint-M48f]

InitializedconnectiononIBCenabledchain [ConnectionID = connection-4]

Initializedconnectiononsolomachine [ConnectionID = Connection-Kinb]

ConfirmedconnectiononIBCenabledchain [ConnectionID = connection-4]

Confirmedconnectiononsolomachine [ConnectionID = Connection-Kinb]

InitializedchannelonIBCenabledchain [ChannelID = channel-0]

Initializedchannelonsolomachine [ChannelID = channel-wwl6]

ConfirmedchannelonIBCenabledchain [ChannelID = channel-0]

تم تأكيد القناة [ChannelID = channel-wwl6]

تأسيس الاتصال!

في الخطوة الأولى ، يتم إنشاء عميل IBC الخفيف للسلسلة A على السلسلة B ، والعكس صحيح. يتم تحديد عميل IBC بشكل فريد من خلال معرف العميل الخاص به ، والذي يستخدم لتتبع حالة السلسلة البعيدة والتحقق منها. بعد إنشاء العملاء ، يمكنهم الاتصال عبر اتصال ، والذي يبدأ بمصافحة رباعية. يؤدي هذا إلى إنشاء ConnectionEnd على السلسلة A مع عملاء خفيفين للسلسلة B على A ، وآخر في السلسلة B مع عملاء خفيفين للسلسلة A على B. الاتصالات ، بمجرد إنشائها ، تكون مستمرة ومشفرة بواسطة عميلين خفيفين.

ينقسم الاتصال عبر الاتصالات أيضًا إلى قنوات مختلفة. يتم تحديد القنوات من خلال الاتصال الأساسي ومنافذ المصدر والوجهة. يحدد كل منفذ وحدة نمطية على السلسلة المقابلة المتصلة عبر IBC. يتم إنشاء ChannelEnd المرتبطة بالاتصال على كلا السلاسل ويتم تحديدها بواسطة معرف القناة. يمكن الآن نقل البيانات بين السلسلتين من خلال القناة المحددة.

من المهم أن تتذكر أن IBC هو بروتوكول غير إذن افتراضيًا. هذا يعني أنه يمكن لأي شخص توصيل أي سلسلتين ممكّنتين لـ IBC دون إذن أو موافقة مسبقة. في الواقع ، تدعم IBC ما يسمى بـ Solo Machines [7] قياسي ، لا يمثل العميل سلسلة بلوكشين ، ولكنه يمثل مضيفًا أو جهازًا واحدًا. نظرًا لأن محتوى حزمة IBC يتحكم فيه المرسل بالكامل (عادةً ما يكون الوحدة المصدر في سلسلة المصدر) ، فإن الوحدات النمطية التي تؤدي عمليات مميزة على حزم IBC الواردة تحتاج دائمًا إلى التحقق من أن الرسالة جاءت من قناة موثوقة.

نقاط الضعف

ومع ذلك ، بقدر ما يتعلق الأمر Stride ، فإن فحص القناة مفقود في وحدة x / الطيار الآلي. يفترض الكود أنه لا يمكن إرسال حزم ICS-20 IBC التي لها عنوان مرسل معين إلا من قبل شخص يتحكم في هذا العنوان. هذا صحيح إذا أخذنا في الاعتبار وحدات النقل على سلاسل شركاء موثوق بهم مثل EVMOS ، ولكن يمكن للمهاجم ببساطة إرسال بيانات حزم IBC الخاضعة للرقابة الكاملة لاستخدام عميل IBC ضار تحت سيطرته. استغلال هذه الثغرة الأمنية بسيط نسبيًا:

  1. إنشاء عميل IBC ضار
  2. استخدام العميل الخبيث Craft لإنشاء قناة IBC إلى وحدة النقل Stride IBC ،
  3. وإرسال تحويل IBC ضار باستخدام عنوان سجلات المطالبة غير المطالب بها باعتباره الحقل "من". استخدم حقل مذكرة ClaimMetadata لتشغيل الطيار الآلي وتحديث عنوان الإنزال الجوي إلى حساب Stride يتحكم فيه المهاجم.
  4. سرقة الإنزال عن طريق إرسال MsgClaimFreeAmount إلى وحدة x / claim

اصلاحات الشوائب

عند تلقي تقريرنا السريع ، قام المساهم في Stride بسرعة بسحب جميع الأموال من محفظة Airdrop لإعادة البيع لضمان عدم تعرض الأموال للخطر. تم تنفيذ إصلاح طويل الأجل لضمان وصول حزم تحديث عنوان IBC airdrop عبر قناة IBC الصحيحة الموثوقة.

ختاماً

يعد الدعم القوي للتواصل عبر السلاسل من خلال IBC ميزة فريدة لنظام Cosmos البيئي. في حين أن IBC مبنية على أسس تشفير متينة ، فإن التكامل معها يتطلب فهماً جيداً لنموذج الثقة الأساسي. يجب على المطورين الذين يعتمدون على IBC ومهندسي الأمن الذين يراجعون عمليات تكامل IBC أن يراجعوا بعناية سطح الهجوم المعرض لعملاء أو قنوات IBC الضارة. نود أن نشكر مساهمي Stride على تعاملهم المهني واستجابتهم السريعة لهذه المشكلة.

** رابط WeChat الخارجي **

[1] عنوان الارتباط الأصلي:

[2] x / مطالبة:

[3] بيانات LoadAllocation:

[4] سجل المطالبة:

[5] MsgClaimFreeAmount:

[6] س / الطيار الآلي:

[7] آلات منفردة:

شاهد النسخة الأصلية
المحتوى هو للمرجعية فقط، وليس دعوة أو عرضًا. لا يتم تقديم أي مشورة استثمارية أو ضريبية أو قانونية. للمزيد من الإفصاحات حول المخاطر، يُرجى الاطلاع على إخلاء المسؤولية.
  • أعجبني
  • تعليق
  • مشاركة
تعليق
0/400
لا توجد تعليقات
  • تثبيت