85 - iOS 0days, Apache Dubbo RCEs, and NPM bugs
A malicious inetloc
file can be used to execute arbitrary applications that already exist on the system. Normally inetloc
files are usually shortcuts to an internet location. So MacOS will execute these files by opening the requested url. The problem is that the file://
protocol is supported, which will trigger the targeted file into being opened which can be an application.
The AWS WorkSpaces desktop application registers a custom URI on the host system and does not properly sanitize the parameters leading to argument injection. As the WorkSpaces client is based on Chromium Embeded Framework the debugging argument --gpu-launcher
can be used to issue arbitrary commands.
Four vulnerabilities related to XPC services either not sufficiently checking application entitlements leading to disclosure of sensitive information
Gamed
The com.apple.gamed
XPC service does not properly check for the calling app to have the com.apple.developer.game-center
entitlement. This allows any app installed to retrieve several XPC proxy objects from the service that can be used to disclose sensitive information. If Game Center is enabled on the device then they will have access to information sensitive information such as the First and Last name of the Apple ID account, and an authentication token for interacting with gc.apple.com
. Even if Game Center is disabled, it is still possible to read files from outside the sandbox like the Speed Dial and Address Book databases, and CoreDuet database containing contact information.
Nehelper - Enumerate Installed Apps
The Nehelper XPC service can be used to retrieve cached information about applications. This is done by providing a cache-signing-identifier
which is the bundle id of the application, and cache-command
set to 3
. Any app can invoke this method and use it to determine if an application is installed based on whether or not it exists in the cache.
Nehelper - Wifi Information
The com.apple.nehelper
XPC service will skip the com.apple.developer.networking.wifi-info
entitlement check if the user-supplied sdk-version
is less than or equal to 524288
. Allowing any “qualified” app to retrieve Wifi information without the required entitlement. This is slightly mitigated by the presence of some authorization checking where the calling app must meet one of the following requirements (source: https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo)
- The app uses Core Location, and has the user’s authorization to use location information.
- The app uses the NEHotspotConfiguration API to configure the current Wi-Fi network.
- The app has an active VPN configuration installed.
- The app has an active NEDNSSettingsManager configuration installed.
Analyticsd
The com.apple.analyticsd
XPC service has a log-dump
command that can be invoked by any user installed app and will provide analytics logs in response. This potentially includes fairly sensitive medical information along side device usage, screen time, crashes, and other information.
These are five issues that enabled file writes outside of the expected directory when NPM was unpacking an archive using the node-tar
library.
First, node-tar
would try to guarentee that archives wouldn’t write outside of the expected directory. It did this by checking if the target path was an absolute path, if so it stripped the absolute path root off and proceeded. The problem was that stripping this path could still leave you with an absolute path. ///some/path
for example would become //some/path
, //some/path
would not work because that is a root path on windows.
Patching this issue resulted in a change in parsing the root and using an iterative solution that will continue stripping paths until the path is no longer absolute.
The second issue as reported is kinda two issues. First, when calling something like fs.writeFileSync
to write a file it will attempt to resolve()
the arguments given. This resolution is a bit more forgiving regarding absolute paths than the node-tar
parser was and also has a bit of a gotcha we’ve seen before with path joining. If you try to join one path to an absolute path, the absolute path takes precedence. This means that providing a filename
that resolve
thinks is an absolute path will overwrite the overrule the provided directory to write to. D:different/root
will write to D:\different\root
.
The second half of that bug was in node-tar
’s attempt to prevent relative paths by stripping ..
. The problem was that it would look for ..
to exist between path separators or at the start/end of the path. c:../example
would not get stripping, but when used with a resolve
would be treated like a relative path.
Next Up are three issues had to deal with the handling of symlinks and hardlinks in an archive. It will attempt to ensure that the folders it iterates into are not symlinks. As an optimization it would also maintain a cache of directories created, if it created the directory it wouldn’t check if it was a symlink.
The first problem with this cache was that if a directory was overwritten by a symlink (or anything really) the cache entry wouldn’t be removed. So a symbolic link that had the same name as the folder would bypass the check. The path was to remove the cache entry when its changed.
Once this was believed to be patched, the bug still remained due to a difference in how paths were normalized when being added to the cache vs when being removed. When creating the directories it would split the path on \
and /
and rejoin the path using /
. When removing cache entries its looking it up path.win32.resolve
which normalizes the path using the system path separator. So the directory cache might contain C:\packages\here\example-package/example-dir
while the deletion will be looking for C:\packages\here\example-package\example-dir
. A similar issue existed on Unix filesystem, where a path name a\\x
will look for a
and a/x
but not the actual file a\\x
.
This was patched by moving all the cache code into using helpers that do the normalization. Though this time there was a problem with unicode normalization, where MacOS will do NFD normalization on unicode in the path.
Thirteen distinct vulnerabilities in Apache Dubbo related to insecure deserialization, and an excellent look at using CodeQL to assist manual vulnerability research and attack surface discovery. A lot of the interesting points in this post are more about the discovery of new attack surface rather than in the vulnerabilities themselves.
Bypass Hessian2 allowlist via alternative protocols - Deserialization issues were previously found, leading to the introduction of an allowlist to control allowable types that can be deserialized. The allow list protects the obvious routes to an RPC invocation object, but Dubbo supports other protocols and message types that can lead to deserialization. In particular the TelnetCodec which is used when the message doesn’t start with 0xADBB
provided several requests and responses that could be sent and lead to deserialization.
Pre-auth RCE via Java native deserialization in the Generic filter - When using the GenericFilter, which is a default-installed filter extension it will use reflection to determine the user-specified service to invoke. This puts the attack in control of the RPC attachment which specifies how the arguments should be parsed, nativejava
being an option.
Pre-auth RCE via arbitrary bean manipulation in the Generic filter - Using the GenericFilter there are other options for deserialization and code execution beyond nativejava
. true
and raw.return
will use the builtin PojoUtils.realize()
method. This reads the class to instantiate out of a dictionary with a class
key, the rest of the entries are used to set or invoke the setter for other fields. If there is an RCE setter gadget in the classpath than an attacker could obtain RCE through this. The bean
option can be used similarly but also allows for invoking the default constructors on the classes.
Pre-auth RCE via arbitrary bean manipulation in the Telnet handler - Using CodeQL the author finds other places the decoders used in the previously vulnerability are used. This results in a deserialization attack by causing the Telnet protocol to perform and RPC invocation.
RCEs via unsafe YAML unmarshalling - Moving away from the RPC invocation code, the author looks for other dangerous APIs being used and found some configuration classes were insecurely unmarshalling YAML. These enabled remote code execution should an attacker be able to modify one of the target configurations. While this might appear to be a larger ask, most of the configuration managers run without any authentication or authorization enabled.
RCE on customers via script route poisoning (Nashorn script injection) - Routing rules can provide a script in any of the scripting languages available in the JDK. An attacker with access to a non-authenticated registry can register a new scripted route, this route will be downloaded and evaluated on the consumers.
Pre-auth unsafe Java deserialization (bypass of checkSerialization control - This is the most interesting issue in my opinion. In DecodeableRpcInvocation.decode
there is a call to CodecSupport.checkSerialization
which enforces the type that gets deserialized. Both the decode
method and the checkSerialization
methods will attempt to look up the class/service path to obtain an object representing the service. checkSerialization
does this using lookupExportedServiceWithoutGroup
, and if it fails it leaves the function without throwing an exception. Later when decode
is using the service, it uses lookupService
. These two methods work slightly differently, the former will lookup an exported service using its path and its version, whereas the later simply uses the class path. This allows an attacker to craft a request that will get through the checkSerialization
method by including a non-existent version, but when used later will be found bypassing the check.