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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
Magento-CVE-2016-4010 — Magento تنفيذ أكواد عن بعد غير مصرح به (CVE-2016-4010) | Kitploit
أدوات/GitHubGitHub/brianwrf/magento-cve-2016-4010
تحليل الثغرات الأمنيةتحليل الكودالاستغلالاستغلال تطبيقات الويباختبار الاختراقالتعلم والتعليممختبرات وتدريب عملي
GitHubbrianwrf/magento-cve-2016-4010

Magento-CVE-2016-4010

Magento تنفيذ أكواد عن بعد غير مصرح به (CVE-2016-4010)

عرض المستودع
63منذ 10 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

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

تحليل واستغلال ثغرة تنفيذ التعليمات البرمجية عن بُعد غير المصرح بها في Magento (CVE-2016-4010)


0x00 مقدمة

في 17 مايو، كشف باحث الأمن الأجنبي Netanel Rubin عن ثغرة تنفيذ تعليمات برمجية عن بُعد غير مصرح بها في Magento (CVE-2016-4010). تحتوي هذه الثغرة في الواقع على عدة ثغرات صغيرة وتسمح للمهاجم بتنفيذ كود PHP غير مصرح به على خادم Magento المعرض للخطر. Magento هي منصة تجارة إلكترونية شائعة جدًا، استحوذت عليها eBay في عام 2011. تستخدمها بعض الشركات المعروفة، مثل: Samsung و Nikon و Lenovo، بالإضافة إلى العديد من المتاجر الإلكترونية الصغيرة. يُذكر أن Magento يُستخدم من قبل 250,000 متجر عبر الإنترنت، وتتعلق مبالغ سنوية تصل إلى 60 مليار دولار أمريكي.

0x01 التحليل

شروط استغلال الثغرة:

  • تمكين RPCs في Magento (REST أو SOAP)، وهي ممكّنة افتراضيًا في معظم الحالات.
  • إصدارات CE & EE من Magento < 2.0.6.

تسمح واجهة برمجة تطبيقات الويب في Magento بنوعين مختلفين من RPCs: REST RPC و SOAP API. يوفر كلا النوعين نفس الوظائف، والفرق الوحيد هو أن الأول يستخدم JSON وطلبات HTTP لنقل الإدخال، بينما يستخدم الثاني XML.

لإتاحة واجهة برمجة تطبيقات بعض الوحدات فقط، يوفر Magento للمطورين طريقة ملائمة: إعلان واجهات API للوحدات التي يريدون الوصول إليها فقط في ملف "webapi.xml". يحتوي ملف webapi.xml على جميع فئات وطرق Web API التي يجب إتاحتها، وتحدد كل طريقة الأذونات المحددة التي تحتاجها. تتضمن هذه الأذونات:

  • anonymous - يسمح لأي شخص بالوصول إلى الطريقة.
  • self - يسمح فقط للمستخدمين المسجلين وأذونات إدارية محددة، مثل: صلاحية "Magento_Backend::admin" تسمح فقط للمسؤولين الذين يمكنهم تعديل تكوين الخادم بالوصول.

بالطبع، هذه الطريقة التي تسمح للمطورين باستخدام ملف webapi.xml للاتصال بين الواجهة الأمامية للنظام والواجهة الخلفية (Web API) تفتح في الواقع بابًا خلفيًا مباشرًا إلى نواة الوحدة.

علاوة على ذلك، حتى لو كان لدينا صلاحية "anonymous"، ما زلنا بحاجة إلى طريقة لتمرير القيم ديناميكيًا. يشير هذا إلى الكائنات المختلفة التي يمكن استخدامها في النظام، على سبيل المثال: تسمح وظيفة API "CustomerRepositoryInterface::save()" باستخدام كائن "CustomerInterface" في متغير "$customer"، النموذج الأولي للكود كما يلي:

root@kitploit:~
interface CustomerRepositoryInterface
{
/**
 * Create customer.
 */
public function save(\Magento\Customer\Api\Data\CustomerInterface $customer);
}

فكيف نستخدم واجهة RPC لإنشاء كائنات؟ في الواقع، تكمن إجابة هذا السؤال في كيفية تكوين Magento لخادم SOAP.

يستخدم Magento خادم SOAP المضمن مع PHP "SoapServer" افتراضيًا. لكي يتم تكوينه بشكل صحيح، يحتاج "SoapServer" إلى ملف WSDL، الذي يحدد جميع الطرق والمعلمات والأنواع المخصصة المستخدمة في طلبات RPC الفعلية. ينشئ Magento ملفات WSDL مختلفة لكل وحدة تدعم وظائف XMLRPC، ويضبط القيم مباشرة من ملف webapi.xml الخاص بالوحدة.

عندما يتم تحليل طلب RPC بواسطة الخادم، يستخدم الخادم البيانات الموجودة في ملف WSDL لتحديد ما إذا كان الطلب صالحًا، والتحقق من طريقة الطلب والمعلمات والأنواع. إذا كان الطلب صالحًا، يتم تمرير كائن الطلب الذي تم تحليله إلى Magento لمزيد من التحليل. نقطة مهمة جدًا هي أن "SoapServer" لا يتفاعل مع Magento بأي شكل من الأشكال، فجميع المعلومات حول طرق ومعلمات الوحدة تأتي من ملف WSDL. في هذه المرحلة، لا يزال الطلب المرسل يتكون من مصفوفات متداخلة، ولا يتم إنشاء أي كائنات خلال مرحلة تحليل SoapServer. لإنشاء الكائنات المطلوبة، يواصل Magento معالجة الإدخال بنفسه.

لاستخراج أسماء المعلمات وأنواع البيانات، يحصل Magento على النموذج الأولي من طريقة الطلب (راجع الكود السابق). بالنسبة لبعض أنواع البيانات الأساسية، مثل السلاسل والمصفوفات والقيم المنطقية وما إلى ذلك، سيقوم النظام بتعيين الإدخال إلى النوع المقابل. ولكن بالنسبة لأنواع الكائنات، تكون طريقة الحل أكثر تعقيدًا.

إذا كان نوع بيانات المعلمة هو مثيل لفئة، سيحاول Magento إنشاء مثيل باستخدام الإدخال المقدم. تذكر، الإدخال في هذه المرحلة هو مجرد قاموس، مفاتيحه هي أسماء الخصائص وقيمه هي قيم الخصائص.

أولاً، سيقوم Magento بإنشاء مثيل جديد للفئة المطلوبة. بعد ذلك، سيحاول ملؤه باستخدام الطريقة التالية:

  1. الحصول على اسم الخاصية (من مفتاح القاموس المدخل)
  2. البحث عن طريقة عامة تسمى "Set[Name]"، حيث [Name] هو اسم الخاصية
  3. إذا كانت هناك مثل هذه الطريقة، قم بتنفيذها باستخدام قيمة الخاصية كمعامل
  4. إذا لم تكن هناك مثل هذه الطريقة، تجاهل الخاصية واستمر في عرض الخاصية التالية

سيتعامل Magento بهذه الطريقة مع كل خاصية يحاول المستخدم تعيينها. عندما يتم فحص جميع الخصائص، سيعتبر Magento أن المثيل قد تم تعيينه وسيعالج المعامل التالي. عندما تتم معالجة جميع المعاملات بهذه الطريقة، سيقوم Magento في النهاية بتنفيذ طريقة API هذه.

باختصار، يسمح لك Magento بإنشاء كائن، وتعيين خصائصه العامة، وأخيرًا تنفيذ أي طريقة تبدأ بـ "Set" عبر RPC الخاص به. وهذا السلوك هو الذي أدى إلى ظهور الثغرة في Magento.

أظهرت الأبحاث أن بعض استدعاءات API تسمح بتعيين معلومات محددة في عربة التسوق، يمكن أن تكون عنوان بريدنا أو سلعنا أو حتى طريقة الدفع لدينا.

عندما يقوم Magento بتعيين معلوماتنا في مثيل عربة التسوق، يستخدم طريقة "save" الخاصة بالمثيل لتخزين البيانات المضافة حديثًا في قاعدة البيانات.

دعنا نلقي نظرة على كيفية عمل طريقة "save"!

root@kitploit:~
/**
* Save object data
*/
public function save(\Magento\Framework\Model\AbstractModel $object)
{
...
// If the object is valid and can be saved
if ($object->isSaveAllowed()) {
    // Serialize whatever fields need serializing
    $this->_serializeFields($object);
    ...
    // If the object already exists in the DB, update it
    if ($this->isObjectNotNew($object)) {
        $this->updateObject($object);
    // Otherwise, create a new record
    } else {
        $this->saveNewObject($object);
    }
     
    // Unserialize the fields we serialized
    $this->unserializeFields($object);
}
...
return $this;
}
// AbstractDb::save()

يضمن Magento أن كائناتنا صالحة، ثم يقوم بتسلسل (Serialize) جميع الأجزاء التي يجب تسلسلها وتخزينها في قاعدة البيانات، ثم يقوم بإلغاء تسلسل (Unserialize) الأجزاء التي تم تسلسلها سابقًا.

يبدو الأمر بسيطًا، أليس كذلك؟ في الواقع ليس كذلك، دعنا نستمر في رؤية كيف يحدد Magento الأجزاء التي يجب تسلسلها.

root@kitploit:~
/**
* Serialize serializable fields of the object
*/
protected function _serializeFields(\Magento\Framework\Model\AbstractModel $object)
{
// Loops through the '_serializableFields' property
// (containing hardcoded fields that should be serialized)
foreach ($this->_serializableFields as $field => $parameters) {
    // Get the field's value
    $value = $object->getData($field);
     
    // If it's an array or an object, serialize it
    if (is_array($value) || is_object($value)) {
        $object->setData($field, serialize($value));
    }
}
}
// AbstractDb::_serializeFields()

كما نرى، فقط تلك الحقول الموجودة في القاموس المشفر " _serializableFields" هي التي يمكن تسلسلها. الأهم من ذلك، أن هذه الطريقة تستمر في التسلسل فقط بعد التأكد من أن قيمة الحقل هي مصفوفة أو كائن.

الآن، دعنا نرى كيف يحدد Magento الأجزاء التي يجب إلغاء تسلسلها.

root@kitploit:~
/**
* Unserialize serializeable object fields
*/
public function unserializeFields(\Magento\Framework\Model\AbstractModel $object)
{
// Loops through the '_serializableFields' property
// (containing hardcoded fields that should be serialized)
foreach ($this->_serializableFields as $field => $parameters) {
    // Get the field's value
    $value = $object->getData($field);
     
    // If it's not an array or an object, unserialize it
    if (!is_array($value) && !is_object($value)) {
        $object->setData($field, unserialize($value));
    }
}
}
// AbstractDb::unserializeFields ()

حسنًا، يبدو مشابهًا جدًا. الاختلاف الوحيد هو أن Magento يحتاج هذه المرة إلى التأكد من أن قيمة الحقل ليست مصفوفة أو كائنًا. بسبب هذين الفحصين، يجب أن نكون قادرين على تنفيذ هجوم حقن كائن (Object Injection)، ببساطة عن طريق تعيين سلسلة ذات نمط معين في حقل قابل للتسلسل. عندما نفعل ذلك، لن يقوم النظام بتسلسل هذا الحقل قبل تخزين الكائن في قاعدة البيانات، لأنه ليس كائنًا أو مصفوفة. ولكن عندما يحاول النظام إلغاء تسلسله، بعد تنفيذ استعلام قاعدة البيانات، سيتم إلغاء تسلسله، لأنه ليس كائنًا أو مصفوفة.

ولكن هذا الشرط الصغير جدًا الذي يكاد لا يُرى هو الذي تسبب في الثغرة. المشكلة المتبقية هي النظر في أي الحقول تعتبر "قابلة للتسلسل"، وكيف يمكننا تعيينها.

بالطبع، السؤال الأول بسيط، أحتاج فقط إلى البحث عن الفئة التي تحتوي على الخاصية "_serializableFields". سرعان ما تم العثور على طريقة API في فئة "Payment"، ولكن ليس كمعامل، لذلك لا يمكن إنشاء أو التحكم في خصائص مثيلها. والأهم من ذلك، أن حقلها القابل للتسلسل "additional_information" لا يمكن تعيينه إلا كمصفوفة، باستخدام تقنية "Set[PROPERTY_NAME]" كإجراء أمني إضافي، لذلك لا يمكن إنشاؤه فحسب، بل حتى لو استطعنا، لا يمكننا تعيينه كسلسلة.

لكن من المثير للاهتمام، يمكن تعيينه بطريقة "غريبة" أخرى. عندما يقوم Magento بتعيين خصائص مثيل المعامل، في الواقع لا يقوم بتعيين الخصائص، بل يحفظها في قاموس يسمى "_data". عندما يتم استخدام خاصية مثيل، يتم استخدام هذا القاموس. هذا يعني بالنسبة لنا، أن حقلنا القابل للتسلسل - "additional_information" - يتم حفظه بالفعل في قاموس داخلي بدلاً من خاصية عادية.

لذا، إذا تمكنا من التحكم الكامل في قاموس "_data"، فيمكننا بسهولة تجاوز القيد المفروض على حقل "additional_information" كونه مصفوفة، لأنه يمكننا تعيينه يدويًا بدلاً من استدعاء "Set[PROPERTY_NAME]".

ولكن كيف نتحكم في هذا القاموس الحساس؟

قبل حفظ مثيل "Payment" الخاص بنا، أحد الأشياء التي يقوم بها Magento هو تحرير خصائصه. يعامل Magento إدخال API الخاص بنا كمعلومات دفع يجب تخزينها في مثيل "Payment"، كما يلي:

root@kitploit:~
/**
* Adds a specified payment method to a specified shopping cart.
*/
public function set($cartId, \Magento\Quote\Api\Data\PaymentInterface $method)
{
 
$quote = $this->quoteRepository->get($cartId); // Get the cart instance
$payment = $quote->getPayment(); // Get the payment instance
// Get the data from the user input
$data = $method->getData();
// Check for additional data
if (isset($data['additional_data'])) {
    $data = array_merge($data, (array)$data['additional_data']);
    unset($data['additional_data']);
}
// Import the user input to the Payment instance
$payment->importData($data);
 
...
}
// PaymentMethodManagement::set()

كما نرى، يتم الحصول على بيانات "Payment" من معامل "$method" عن طريق استدعاء "$method->getData()" الذي يعيد خاصية "_data". تذكر، لأن "$method" هو معامل في طريقة API، يمكننا التحكم فيه.

عندما يقوم Magento باستدعاء "getData()" في معاملنا "$method"، سيتم إعادة خاصية "_data" الخاصة بالمعامل، والتي تحتوي على جميع معلومات الدفع التي أدخلناها. بعد ذلك، يستدعي "importData()" مع خاصية "_data" كمدخل، ليحل محل خاصية "_data" في مثيل "Payment" بخاصية "_data" الخاصة بنا.至此، يمكننا الآن استخدام خاصية "_data" التي يمكننا التحكم فيها لاستبدال خاصية "_data" الحساسة في مثيل "Payment"، مما يعني أنه يمكننا الآن تعيين حقل "addition_information".

لكي يعمل unserialize()، نحتاج إلى أن يكون الحقل قابلاً للتعيين كسلسلة، لكن طريقة "Set[PROPERTY_NAME]" تسمح فقط بالمصفوفات. الحل هو وضع سطرين من التعليمات البرمجية قبل استدعاء "importData()". يسمح Magento للمطورين بإضافة طرق الدفع الخاصة بهم، وتوفير بياناتهم ومعلوماتهم الخاصة. لتحقيق ذلك، يستخدم Magento حقل "addition_data". وهذا الحقل هو قاموس يحتوي على المزيد من البيانات الخاصة بطريقة الدفع ويمكن للمستخدم التحكم فيه بالكامل. لكي يصبح المحتوى المخصص جزءًا من البيانات الأصلية، يقوم Magento بدمج قاموس "additional_data" مع قاموس "data" الأصلي، مما يسمح فعليًا لقاموس "additional_data" بتجاوز جميع القيم في قاموس "data"، أي يمكنه الكتابة فوقه بالكامل. هذا يعني أنه بعد دمج القاموسين، يصبح قاموس "additional_data" الذي يتحكم فيه المستخدم الآن هو قاموس "_data" الخاص بالمعامل، وبسبب "importData()"، يصبح أيضًا خاصية "_data" الحساسة في مثيل "Payment". بعبارة أخرى، أصبحنا الآن نتحكم بالكامل في الحقل القابل للتسلسل "additional_information" ويمكننا تنفيذ هجوم حقن كائن.

بما أنه يمكننا إلغاء تسلسل أي سلسلة نريدها، فقد حان الوقت لتنفيذ هجوم حقن كائن.

أولاً، نحتاج إلى كائن بطريقة "__wakeup()" أو "__destruct()" بحيث يتم استدعاؤها تلقائيًا عند إلغاء تسلسل الكائن أو تدميره. وذلك لأنه على الرغم من أننا نستطيع التحكم في خصائص الكائن، إلا أننا لا نستطيع استدعاء طرقه. لهذا السبب يجب أن نعتمد على الطرق السحرية (magical methods) في PHP، التي يتم استدعاؤها تلقائيًا عند حدوث حدث معين.

أول كائن سنستخدمه هو مثيل لفئة "Credis_Client"، والتي تحتوي على الطريقة التالية:

root@kitploit:~
/*
* Called automaticlly when the object is destrotyed.
*/
public function __destruct()
{
if ($this->closeOnDestruct) {
    $this->close();
}
}
/*
* Closes the redis stream.
*/
public function close()
{
if ($this->connected && ! $this->persistent) {
        ...
        $result = $this->redis->close();
}
...
}
// Credis_Client::__destruct(), close()

يمكننا أن نرى أن هذه الفئة تحتوي على طريقة "__destruct" بسيطة (سيتم استدعاؤها تلقائيًا بواسطة PHP عند تدمير الكائن) تستدعي طريقة "close()". المثير للاهتمام أن طريقة "close()" إذا وجدت اتصالاً نشطًا بخادم Redis، فإنها تستدعي "close()" في خاصية "redis" لإغلاقه.

نظرًا لأن " unserialize()" تسمح لنا بالتحكم في جميع خصائص الكائن، يمكننا أيضًا التحكم في خاصية "redis". يمكننا تعيين أي كائن نريده في الخاصية (ليس فقط Redis)، واستدعاء أي طريقة "close()" في أي فئة في النظام. هذا يوسع بشكل كبير سطح الهجوم لدينا. في Magento، هناك بعض طرق "close()" ونظرًا لأن هذه الطرق تُستخدم عادةً لإنهاء التدفقات، وإغلاق مقابض الملفات، وتخزين بيانات الكائن، يجب أن نتمكن من العثور على بعض الاستدعاءات المثيرة للاهتمام.

كما توقعنا، وجدنا طريقة "close()" التالية في فئة "Transaction":

root@kitploit:~
/**
* Close this transaction
*/
public function close($shouldSave = true)
{
...
if ($shouldSave) {
    $this->save();
}
...
}
/**
* Save object data
*/
public function save()
{
$this->_getResource()->save($this);
return $this;
}
// Magento\Sales\Model\Order\Payment\Transaction::__destruct(), close()

يبدو الأمر بسيطًا، طريقة "close()" تستدعي "save()" التي تستدعي بدورها طريقة "save()" في خاصية "_resource". بنفس الفكرة، لأننا نتحكم في خاصية "_resource"، يمكننا أيضًا التحكم في فئتها، وبالتالي يمكننا استدعاء طريقة "save()" لأي فئة نريدها.

لقد خطونا خطوة كبيرة إلى الأمام. كما توقعنا، تُستخدم طريقة "save()" عادةً لحفظ البيانات في وسائط تخزين متنوعة (مثل: نظام الملفات، قاعدة البيانات، إلخ). ما نحتاج إلى فعله الآن هو العثور على طريقة "save()" تستخدم نظام الملفات كوسيط تخزين.

سرعان ما وجدت واحدة:

root@kitploit:~
/**
* Try to save configuration cache to file
*/
public function save()
{
...
// save stats
file_put_contents($this->getStatFileName(), $this->getComponents());
...
}
// Magento\Framework\Simplexml\Config\Cache\File::save()

تقوم هذه الطريقة بحفظ البيانات الموجودة في حقل "components" في ملف. نظرًا لأن مسار الملف يتم الحصول عليه من حقل "stat_file_name"، وبما أننا نتحكم في هذين المعاملين، فإننا نتحكم فعليًا في مسار الملف ومحتواه، مما يؤدي إلى ثغرة كتابة ملف عشوائي.

الآن نحتاج فقط إلى العثور على مسار صالح قابل للكتابة ويمكن لخادم الويب الوصول إليه لكتابة الملف. في جميع أدلة تثبيت Magento، يوجد دليل "/pub" يُستخدم لتخزين الصور أو الملفات التي رفعها المسؤول، وهو مسار قابل للاستغلال بشكل فعال.

أخيرًا، نحتاج فقط إلى كتابة ملف ويب شيل (webshell) PHP على الخادم، ويمكننا تنفيذ أي كود PHP غير مصرح به على خادم Magento.

0x02 الاستغلال

إعداد بيئة الاختبار

  1. قم بتنزيل حزمة التثبيت المعرضة للخطر (هنا نستخدم الإصدار 2.0.0) رابط التحميل: https://github.com/magento/magento2/archive/2.0.0.zip
  2. تثبيت Magento خطوات التثبيت: https://github.com/magento/magento2/tree/2.0.0

ملاحظة: قد تواجه بعض المشكلات هنا، يمكنك الاطلاع على:

  • http://magento2king.com/magento2-insta-be-downloaded/
  • https://github.com/magento/magento2/issues/2419

استغلال الثغرة

رابط تحميل الـ exploit المنشور على exploit-db: https://www.exploit-db.com/exploits/39838/

طريقة الاستغلال كالتالي:

  1. ابحث عن موقع Magento معرض للخطر التحقق من إصدار Magento عبر الإنترنت: http://magentoversion.com/

  2. أضف منتجًا إلى عربة التسوق وصف الصورة هنا

  3. ادخل إلى عربة التسوق وانقر على "إتمام الشراء" وصف الصورة هنا

  4. املأ عنوان الشحن واعرض طلب POST /rest/default/V1/guest-carts/[guestCartId]/shipping-information واحصل على [guestCartID] وصف الصورة هنا وصف الصورة هنا

  5. احفظ الـ exploit أعلاه كـ magento_exp.php وقم بتنفيذه: php magento_exp.php [Magento_URL] [guestCartID] ([مسار كتابة webshell]) وصف الصورة هنا

الفحص الجماعي

بعد دراسة الـ exploit أعلاه، وجد أن الاستغلال يحتاج إلى استيفاء الشروط التالية:

  1. يجب أن يكون إصدار Magento للموقع الهدف أقل من 2.0.6 وأن يكون REST API ممكّنًا
  2. يجب أن توجد مقتطفات JS التالية في الصفحة الرئيسية للموقع الهدف وصف الصورة هنا

لذلك، تم كتابة سكربت تحقق جماعي بسيط لاستخدامه مع الـ exploit أعلاه:

root@kitploit:~
#!/usr/bin/env python
import urllib
import sys
import socket
timeout = 5
socket.setdefaulttimeout(timeout)

input = sys.argv[1]  # ملف يحتوي على عناوين URL لمواقع Magento
output = sys.argv[2] # ملف حفظ النتائج، يمكن أن يكون: output.txt

def logFile(str):
    f = open(output,'a')
    f.write(str+"\n")
    f.close()

def checkVul(url):
    try:
	    html = urllib.urlopen(url).read()
	    if "guest-carts" in html:
		    print url,"is vulnerable!"
		    logFile(url)
	    else:
		    print url,"is not vulnerable!"
    except Exception:
	    pass

if __name__ == '__main__':
    inp = open(input,'r')
    for i in inp:
	    url=i.strip()
	    #print url
	    checkVul(url)
    print "All Done!"

نتيجة التنفيذ: وصف الصورة هنا

0x03 الدفاع

قم بترقية Magento إلى أحدث إصدار (2.0.6)، رابط التحميل: https://www.magentocommerce.com/download

المراجع

  • http://netanelrub.in/2016/05/17/magento-unauthenticated-remote-code-execution/

  • https://www.exploit-db.com/exploits/39838/

تنزيل الأداة