
SolarWinds ARM CVE-2026-28326 के लिए गैर-विनाशकारी पैच-स्थिति जाँचकर्ता जो TCP 55555 पर gRPC लिसनर की जाँच करके VULNERABLE, PATCHED, या INCONCLUSIVE रिपोर्ट करता है।
CVE-2026-28326 के लिए एक अनधिकृत पैच-स्थिति जाँच, जो SolarWinds Access Rights Manager (ARM) में अनधिकृत रिमोट कोड
निष्पादन भेद्यता है, जिसे 2026-09-17 को
ARM 2026.2.1
में ठीक किया गया। CWE-798, CVSS 8.8 High
(CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)। SolarWinds को Armadin के Kai Huang द्वारा रिपोर्ट किया गया।
उस वेक्टर में AV:A यह मानता है कि TCP 55555 केवल एक निकटवर्ती नेटवर्क से पहुँच योग्य है, जो वह
स्थिति है जिसके लिए ARM का अपना फ़ायरवॉल टूलिंग बनाया गया है; जहाँ पोर्ट को अधिक व्यापक रूप से खोला गया है वहाँ
स्कोर उस वातावरण के लिए जोखिम को कम आँकता है।
TCP 55555 पर ARM का gRPC रिमोटिंग लिसनर पीयर को क्लाइंट प्रमाणपत्र से प्रमाणित करता है। अनपैच्ड
बिल्ड एक फ़ॉलबैक क्रेडेंशियल भी स्वीकार करते हैं जो एक हार्डकोडेड कुंजी से व्युत्पन्न होता है जो हर
इंस्टॉलेशन पर समान होती है, जो उस प्रमाणीकरण को बायपास करती है और एक असुरक्षित डीसेरिएलाइज़ेशन पथ को उजागर करती है। परिणाम
ARM सेवा खाते के रूप में कोड निष्पादन है, जो डिफ़ॉल्ट रूप से LocalSystem के रूप में चलता है।
स्क्रिप्ट रिपोर्ट करती है कि प्रत्येक लक्ष्य पर फ़िक्स मौजूद है या नहीं। यह प्रमाणीकरण इंटरसेप्टर द्वारा लौटाए गए
स्टेटस कोड पढ़ती है और कुंजी का उपयोग नहीं करती, प्रमाणित नहीं करती, या डीसेरिएलाइज़ेशन पथ पर डेटा नहीं भेजती। VULNERABLE के अलावा कोई परिणाम
अपने आप में यह नहीं दर्शाता कि कोई लक्ष्य पैच किया गया है; देखें गैर-भेद्य परिणामों की व्याख्या।
# single target (port defaults to 55555)
./cve_2026_28326_check.py arm.example.com
# explicit port
./cve_2026_28326_check.py arm.example.com:55555
# several targets
./cve_2026_28326_check.py arm-a.example.com arm-b.example.com
# scan a list, one target per line ('#' comments allowed), compact output
./cve_2026_28326_check.py -f targets.txt --brief
# machine-readable output for pipelines
./cve_2026_28326_check.py -f targets.txt --json > results.json
Python 3.8+, केवल मानक लाइब्रेरी — कोई तृतीय-पक्ष पैकेज नहीं।
टूल को कलेक्टर के बजाय ARM सर्वर के विरुद्ध चलाएँ। दोनों भूमिकाएँ 55555 पर सुनती हैं, लेकिन एक
कलेक्टर फ़िक्स से पहले और बाद में बाहरी अनुरोधों को उसी तरह अस्वीकार करता है, इसलिए टूल इसे
INCONCLUSIVE के रूप में रिपोर्ट करता है।
| Flag | Description |
|---|---|
TARGET | One or more HOST[:PORT] targets; the port defaults to 55555 |
-f, --targets-file FILE | Read targets from a file (one per line; # comments) |
-p, --port PORT | Default port when a target omits one (default: 55555) |
--timeout SECS | Per-probe timeout (default: 12) |
--workers N | Concurrent targets (default: 16); output stays in input order |
-b, --brief | Single aligned line per target, for scanning many hosts |
--json | Emit structured JSON, including both probes per target |
--no-color | Disable coloured output (also honours NO_COLOR and non-TTY) |
भेद्य सर्वर (डिफ़ॉल्ट आउटपुट; [!] मार्कर और VULNERABLE एक TTY पर लाल रंग में दिखाए जाते हैं):
$ ./cve_2026_28326_check.py arm.example.com
[!] arm.example.com:55555: VULNERABLE [unavailable-on-server-role]
Remoting/Send returned 14 UNAVAILABLE on a listener answering as the server role, the pre-patch rejection path (<= 2026.2.0.42)
पैच किया गया सर्वर। फ़िक्स किया गया बिल्ड एक grpc-message लौटाता है, जिसे टूल निर्णय के साथ
प्रिंट करता है:
$ ./cve_2026_28326_check.py arm-dr.example.com
[+] arm-dr.example.com:55555: PATCHED [unauthenticated-gate]
Remoting/Send returned 16 UNAUTHENTICATED, the localhost and per-process-token gate introduced by the fix (>= 2026.2.1.7)
grpc-message: Client certificate not found. Please register your application first.
वह लिसनर जिसे वर्गीकृत नहीं किया जा सकता। एक कलेक्टर, या एक सर्वर जो बाहरी अनुरोधों को अस्वीकार करता है, दोनों बिल्ड पर दोनों प्रोब का उत्तर एक ही तरह देता है:
$ ./cve_2026_28326_check.py collector.example.com
[?] collector.example.com:55555: INCONCLUSIVE [external-requests-refused]
the listener refuses external requests, which a collector role and a restricted server both do identically on either build; scan the ARM server itself
--brief के साथ कई लक्ष्य:
$ ./cve_2026_28326_check.py -f targets.txt --brief; echo "exit: $?"
VULNERABLE arm.example.com:55555 unavailable-on-server-role
PATCHED arm-dr.example.com:55555 unauthenticated-gate
INCONCLUSIVE collector.example.com:55555 external-requests-refused
UNAFFECTED db.example.com:55555 not-arm
ERROR offline.example.com:55555 unreachable
exit: 1
--json के साथ JSON आउटपुट। दोनों प्रोब परिणाम शामिल हैं ताकि निर्णय को कच्ची प्रतिक्रियाओं के विरुद्ध
जाँचा जा सके:
$ ./cve_2026_28326_check.py arm.example.com --json
[
{
"target": "arm.example.com:55555",
"verdict": "VULNERABLE",
"reason": "unavailable-on-server-role",
"detail": "Remoting/Send returned 14 UNAVAILABLE on a listener answering as the server role, the pre-patch rejection path (<= 2026.2.0.42)",
"grpc_message": "",
"probes": [
{
"path": "/SolarWinds_ARM_GRPC_ConnectionAuthrization.ConnectionAuthorization/GetCertificate",
"status": 0,
"message": "",
"alpn": "h2",
"note": ""
},
{
"path": "/SolarWinds_ARM_Remoting.Remoting/Send",
"status": 14,
"message": "",
"alpn": "h2",
"note": ""
}
]
}
]
यह जाँच उत्पादन प्रणालियों के विरुद्ध उपयोग के लिए है:
Remoting/Send संदेश बॉडी में एक सीरिएलाइज़्ड
ऑब्जेक्ट द्वारा ट्रिगर होती है। दोनों प्रोब शून्य-लंबाई बॉडी वाला एक gRPC संदेश भेजते हैं,
और इंटरसेप्टर किसी भी संदेश बॉडी को डिस्पैच किए जाने से पहले कॉल को अस्वीकार कर देता है।GetCertificate प्रोब
एक खाली नामांकन कोड भेजता है, जिसे सर्वर किसी भी लंबित कोड को खोजने या हटाने से पहले अस्वीकार कर देता है, इसलिए प्रोब
उस क्लाइंट के लिए नामांकन कोड का उपभोग नहीं करता जो पंजीकरण के बीच में है।| # | Call | Purpose |
|---|---|---|
| 1 | ConnectionAuthorization/GetCertificate | Confirms the endpoint is ARM and is in the server role |
| 2 | Remoting/Send | The patch-state probe |
एक अनपैच्ड सर्वर पर एक अस्वीकृत अनाम अनुरोध डिबग स्तर पर लॉग होता है
(Unable to validate remote request token) और पीयर का नाम बताने वाली एक सूचनात्मक पंक्ति। पैच किए गए
बिल्ड पीयर का नाम बताने वाली एक अस्वीकृति और ऊपर grpc-message में उद्धृत पंजीकरण संकेत लॉग करते हैं।
कोई भी बिल्ड सत्र रिकॉर्ड नहीं करता।
जोखिम के बजाय शोषण की तलाश करने के लिए, ARM के NetworkConnectionEntry रिकॉर्ड की समीक्षा करें। IsAuthenticated=false और
एक भरे हुए ClientCertThumbPrint वाली प्रविष्टि प्रमाणीकरण बायपास के अनुरूप है और सामान्य ट्रैफ़िक में
नहीं होती।
फ़िक्स ने बदल दिया कि प्रमाणीकरण इंटरसेप्टर उस पीयर को कौन-सा स्टेटस लौटाता है जो कोई क्लाइंट
प्रमाणपत्र प्रस्तुत नहीं करता। पैच से पहले, क्लाइंट-प्रमाणपत्र जाँच में प्रत्येक अस्वीकृति पथ Unavailable सेट करता था।
पैच के बाद, localhost-plus-token जाँच एक विशिष्ट संदेश के साथ Unauthenticated सेट करती है, और
उस पथ पर और कुछ भी 16 नहीं लौटाता। दो अनाम कॉल बिल्ड को अलग करती हैं: