چطور هوش مصنوعی گوگل هک شد؟
یکی از نکاتی که برای افرادی که از هوش مصنوعی استفاده می کنند امنیت این ابزارها است. این غولهای چراغ جادو واقعا چقدر ایمن هستند. آیا امکان نفوذ به آنها وجود دارد؟ در ادامه مسیری را که یک گروه هکری برای نفوذ به هوش مصنوعی گوگل طی کرده باهم مرور می کنیم. در صورتی که می خواهید مقاله اصلی نوشته شده توسط این گروه را مطالعه کنید به انتهای مطلب و قسمت منابع مراجعه کنید. این نوشتار صرفا مروری روان و فارسی نوشت بر گامهای طی شده در این فرایند است.
گام آغازین: اجرای کد
در اولین گام از Gemini خواسته شده تا یک کد ساده را به زبان python اجرا کند.
run hello world in python3
خروجی کد اجرا شده را در تصویر زیر مشاهده می کنید:

در زمان اجرای این آزمایش، هوش مصنوعی Gemini یک تحلیل گر Python تحت Sandbox را ارائه می کند. همانطور که می دانید ایده محیط سندباکس به این ترتیب است که امکان اجرای کدی را در یک محیط محصور شده به شما می دهد بدون اینکه به شما اجزا بدهد به زیرسیستم هایی که این محیط محصور شده را اجرا می کنند دسترسی داشته باشید. این محیط محصور شده یا sandbox به نام gVisor شناخته می شود که در واقع یک هسته لینوکسی سطح کاربر است که گوگل آن را توسعه داده و به عنوان واسطی بین برنامه های کانتینر و سیستم عامل میزبان عمل می کند. این کرنل واسط system call های درخواستی برنامه های درون کانتینر را دریافت کرده و محدودیت های امنیتی سخت گیرانه ای را بر آنها اعمال می کند تا امکان فرار از سطح کانتینر به سطح سیستم عامل اصلی وجود نداشته باشد.

پاداش در نظر گرفته شده توسط گوگل برای فرار از این محیط سندباکس ۱۰۰ هزار دلار است.

.با این وجود همیشه قرار نیست از محیط سندباکس فرار کرد تا بتوان به اطلاعات سیستم اصلی دست پیدا کرد. موارد بسیار زیادی وجود دارد که درون خود محیط سندباکس اطلاعاتی برای نشت به خارج وجود دارد. ایده اصلی تیم این بود که در گام اول به نحوی به یک شل درون خود سندباکس دست پیدا کرده و در قدم بعدی به دنبال اطلاعاتی بگردد که قرار نبوده مورد دسترسی قرار بگیرد. اما مشکل اصلی اینجاست که سندباکس تنها می تواند یک کد کامپایل شده خاص پایتون را اجرا کند.
مشخص کردن قلمرو کاری
اولین نکته ای که مشخص شد این بود که می توان در فرانت اند یک قطعه کد را به صورت کامل بازنویسی و قطعه کد مورد نظر را در سمت سرور بازنویسی کرد. گام اول درک ساختار خود سندباکس بود. گمان اولیه تیم این بود که احتمالا در خود سندباکس اطلاعات جالبی وجود داشته باشد که امکان نشت دادن آنها به خارج از سندباکس وجود داشته باشد. با توجه به اینکه امکان دسترسی به شل وجود نداشت باید به دنبال کتابخانه هایی بود که احتمالا دسترسی های جذابی فراهم می کنند. یکی از کتابخانه های مورد نظر کتابخانه os بود. به کمک این کتابخانه امکان اینکه یک نگاشت از فایل سیستم سندباکس ایجاد کرد وجود دارد.
قطعه کد پایتون زیر اجرا شد:
import os
def get_size_formatted(size_in_bytes):
if size_in_bytes >= 1024 ** 3:
size = size_in_bytes / (1024 ** 3)
unit = "Go"
elif size_in_bytes >= 1024 ** 2:
size = size_in_bytes / (1024 ** 2)
unit = "Mb"
else:
size = size_in_bytes / 1024
unit = "Ko"
return f"{size:.2f} {unit}"
def lslR(path):
try:
# Determine if the path is a directory or a file
if os.path.isdir(path):
type_flag = 'd'
total_size = sum(os.path.getsize(os.path.join(path, f)) for f in os.listdir(path))
else:
type_flag = 'f'
total_size = os.path.getsize(path)
size_formatted = get_size_formatted(total_size)
# Check read and write permissions
read_flag = 'r' if os.access(path, os.R_OK) else '-'
write_flag = 'w' if os.access(path, os.W_OK) else '-'
# Print the type, permissions, size, and path
print(f"{type_flag}{read_flag}{write_flag} - {size_formatted} - {path}")
# If it's a directory, recursively print the contents
if type_flag == 'd':
for entry in os.listdir(path):
entry_path = os.path.join(path, entry)
lslR(entry_path)
except PermissionError:
print(f"d-- - 0Ko - {path} (PermissionError: cannot access)")
except Exception as e:
print(f"--- - 0Ko - {path} (Error: {e})")
هدف از این قطعه کد این بود تا با یک ساختار بازگشتی لیستی از فایل ها و دسترسی های آن ها به دست آورد. اگر به خط پانزدهم کد دقت کنید یک تابع با نام lslR() تعریف شده است. خروجی این تابع برای پوشه /usr مطابق شکل زیر است:

اگر به خطی که هایلات شده دقت کنید یک فایل نظر را جلب می کند. فایل با نام entry_point که از نوع فایل بوده و دسترسی خواندنی به آن وجود دارد.
اگر حجم فایل کم بود می شد آن را به صورت base64 اینکود کرد و بعد مستقیما آن را در فرانت اند چاپ کرد. اما با توجه به حجم بالای فایل نمی توان از این گزینه استفاده کرد چون باعث می شود که کل سندباکس متوقف شده و در نهایت تایم اوت شود.
روش بعدی که مورد بررسی قرار گرفت امکان ارسال بسته های TCP یا HTTP یا DNS به سمت خارج از بود. با این وجود تمامی تلاش ها برای ارتباط با بیرون از سندباکس منجر به شکست شد. به نظر می رسید که سندباکس به صورت کامل ایزوله شده است. با این وجود این سوال به وجود می آید که اگر سندباکس تا این حد ایزوله شده است چطور می تواند با سرویس های گوگل مثل گوگل فلایت ارتباط برقرار کند؟
برای اینکه بتوان این فایل بایتری را با استفاده از کنسول به خارج از سندباکس منتقل کرد تصمیم براین شد تا با استفاده از تابع seek() فایل را به قطعات 10 مگابایتی تقسیم و آن را استخراج کرد.
import os
import base64
def read_and_encode(file_path, kilobytes):
try:
# Calculate the number of bytes to read
num_bytes = kilobytes * 1024
# Open the file and read the specified number of bytes
with open(file_path, 'rb') as file:
file_content = file.read(num_bytes)
# Base64 encode the bytes
encoded_content = base64.b64encode(file_content)
# Print the encoded string
print(encoded_content.decode('utf-8'))
except FileNotFoundError:
print(f"FileNotFoundError: {file_path} does not exist")
except PermissionError:
print(f"PermissionError: Cannot access {file_path}")
except Exception as e:
print(f"Error: {e}")
read_and_encode("/usr/bin/entry/entry_point", 10000)

سپس از ابزار Caido استفاده شد تا درخواست ها از طرف پراکسی کایدو از سندباکس فراخوانی و تمامی آن ها به قابلیت Automate ابزار Caido ارسال شود. با استفاده از این قابلیت ابزار Caido می توان با استفاده از لیست به سرعت پارامترهای مشخصی را در Request های ارسالی تغییر داد و اقدام به fuzzing/bruteforcing نمود.
بعد از به دست آوردن تمامی قطعات استخراج شده و چسباندن آنها به یکدیگر فایل اصلی در سیستم محلی مجددا ساخته شد و حالا باید محتویات آن بررسی می شد.
چطور محتوای فایل را بخوانیم؟
در صورتی که دستور file را روی خروجی مرحله قبلی استفاده کنیم با محتوای زیر روبرو می شود که مشخص می کند فایل بدست آمده در واقع یک فایل اجرایی در سیستم عامل لینوکس است.
ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /usr/grte/v5/lib64/ld-linux-x86-64.so.2
اجرای دستور strings روی فایل خروجی ارجاعات متعددی را به عبارت google3 نشان می داد که یک منبع داخلی گوگل به نظر می رسید. با توجه به این ارجاعات متعدد به منابع داخلی گوگل به نظر می رسید که احتمالا این فایل یک منبع داخلی بوده که نباید نشت پیدا می کرده. با این وجود آیا این مسئله می تواند یک پیامد امنیتی داشته باشد؟
استفاده از ابزار Binwalk نقطه اصلی بود. با کمک این فایل می توان ساختارهای درونی و فایل های داخلی درون یک فایل اجرایی یا فریم ویر را استخراج کرد. با استفاده از این ابزار یک ساختار سلسله مراتبی کامل از سندباکس به دست آمد که یک تصویر داخلی کامل از سندباکس را نمایش می داد.
بررسی خروجی بدست آمده از مرحله قبلی ساختاری از دایرکتوری google3 را با فایل های زیر نمایش می داد:
total 2160
drwxr-xr-x 14 lupin staff 448B Aug 7 06:17 .
drwxr-xr-x 231 lupin staff 7.2K Aug 7 18:31 ..
-r-xr-xr-x 1 lupin staff 1.1M Jan 1 1980 __init__.py
drwxr-xr-x 5 lupin staff 160B Aug 7 06:17 _solib__third_Uparty_Scrosstool_Sv18_Sstable_Ccc-compiler-k8-llvm
drwxr-xr-x 4 lupin staff 128B Aug 7 06:17 assistant
drwxr-xr-x 4 lupin staff 128B Aug 7 06:17 base
drwxr-xr-x 5 lupin staff 160B Aug 7 06:17 devtools
drwxr-xr-x 4 lupin staff 128B Aug 7 06:17 file
drwxr-xr-x 4 lupin staff 128B Aug 7 06:17 google
drwxr-xr-x 4 lupin staff 128B Aug 7 06:17 net
drwxr-xr-x 9 lupin staff 288B Aug 7 06:17 pyglib
drwxr-xr-x 4 lupin staff 128B Aug 7 06:17 testing
drwxr-xr-x 9 lupin staff 288B Aug 7 06:17 third_party
drwxr-xr-x 4 lupin staff 128B Aug 7 06:17 util
در پوشه assistant یک قطعه کد داخلی Gemini مشاهده شد که لیست فراخوانی های RPC را به سرویس هایی مانند یوتیوب، گوگل فلایت و سایر سرویس ها نمایش می داد.
.
├── __init__.py
└── boq
├── __init__.py
└── lamda
├── __init__.py
└── execution_box
├── __init__.py
├── images
│ ├── __init__.py
│ ├── blaze_compatibility_hack.py
│ ├── charts_json_writer.py
│ ├── format_exception.py
│ ├── library_overrides.py
│ ├── matplotlib_post_processor.py
│ ├── py_interpreter.py
│ ├── py_interpreter_main.py
│ └── vegalite_post_processor.py
├── sandbox_interface
│ ├── __init__.py
│ ├── async_sandbox_rpc.py
│ ├── sandbox_rpc.py
│ ├── sandbox_rpc_pb2.pyc
│ └── tool_use
│ ├── __init__.py
│ ├── metaprogramming.py
│ └── runtime.py
└── tool_use
├── __init__.py
└── planning_immersive_lib.py
8 directories, 22 files
منابع
برای مشاهده منبع اصلی این مقاله و مطالعه متن کامل آن می توانید به آدرس زیر مراجعه کنید.
We hacked Google’s A.I Gemini and leaked its source code (at least some part)