Skip to content

Isolated Storage is no guarantee of security

During code reviews and the analysis of partner apps, I have often noticed that centralized "Isolated Storage Management” codeunits are created which have getter and setter procedures. This is certainly nice from a code structuring point of view, but from a security point of view it's a nightmare.

The AppSourceCop gives an indication of the security problem:

AppSourceCop Warning AS0081 - InternalsVisibleTo should not be used as a security feature.

The InternalsVisibleTo setting will expose your internal objects to any extension with the given name, publisher, and ID. Access modifiers are not designed to be used as a security boundary, but for API development.

Source

This message is unfortunately ignored far too often, but it is really important!

Analyze your target

The following procedure is realistic. All code samples are real and have been shortened and anonymized. Before you read on, always remember: don't be evil!

This procedure was carried out in a Business Central SaaS environment. Before begin, however, it is important to put on a black hacker hoody 😉

  1. First, I install the app I want to attack from AppSource in my SaaS sandbox.
  2. I establish a connection via VS Code, add a dependency on the app and download the symbols.
  3. I unzip the downloaded symbol file via 7zip.
  4. Two files are important here:

    • SymbolReference.json - this file describes the complete signature of the app. All objects, fields, procedures, ... are listed here In this file I search for the classic procedure names: GetPassword, GetSecret, ... You will quickly find a definition like this:

      {
        "Methods": [
          {
            "ReturnTypeDefinition": {
              "Name": "Text"
            },
            "IsInternal": true,
            "Parameters": [],
            "Attributes": [
              {
                "Arguments": [],
                "Name": "NonDebuggable"
              }
            ],
            "Id": -123,
            "Name": "GetPassword"
          }
        ]
        "Id": 5000000,
        "Name": "ABC IsolatedStorageMgmt"
      }
      

      We recognize that there is a procedure GetPassword in the ABC IsolatedStorageMgmt Codeunit which has the access modifier internal and is not debuggable. At first glance this is safe, but let's look further.

    • NavxManifest.xml - This file contains all the settings of the original app.json. Here we are particularly interested in who is allowed to see the internals. Open the file in your prefered Text Editor and look for the InternalsVisibleTo node.

Stealing the secret

We now have all the information we need to steal the secret. To do this, we simply give our app the id from the InternalsVisibleTo node of NavxManifest.xml. The app name and publisher are not important here (there were a few buggy releases where these also had to be matched). Then we write a method that calls the GetPassword procedure of the app to be attacked and returns us a message:

trigger OnOpenPage()
var
    IsolatedStorageMgmt: Codeunit "ABC IsolatedStorageMgmt";
begin
    Message(IsolatedStorageMgmt.GetPassword());
end;

Scary observation

The partner from whom i copied the code had also defined the following in the manifest:

<SuppressWarnings>
  <SuppressWarning Name="AS0081" />
</SuppressWarnings>

Unfortunately, the partner did not understand what it was about and ignored every warning.

How to secure your App

Securing your own app against attacks of this kind is simple: The secret must be loaded from the isolated storage where it is to be used. A GetPassword procedure must be local.