Reverse Engineering Electron Apps to Discover APIs
2024-5-15 00:0:0 Author: securityboulevard.com(查看原文) 阅读量:4 收藏

I had a problem. 

When I was recently evaluating whether Bruno was any good for hacking APIs, my laptop’s network monitoring agent alerted me when it detected foreign requests from the application that I wasn’t expecting.

I had concerns. So I decided to look into it.

Since Bruno is a desktop application written in ElectronJS, I wanted to see if I could figure out what was going on. Even though I know the app is open-source and on GitHub, as I am pulling it from a cask with the brew package manager in macOS, I wanted to be sure I knew EXACTLY what was going on with the actual code that hit my machine.

Ya, I’m weird that way. Just seems like a fun challenge.  

AIE

Techstrong Podcasts

This article describes how I reverse engineered an Electron app to discover what APIs it was reaching out to and why.

Why do this? 

On any Mac I use, I always install Little Snitch in silent mode to detect unexpected network activity. When a recent update to Bruno occurred, the snitch notified me of several new network connections it had never seen before.

The first connection was to posthog.com, which I know is for app telemetry analytics and usage monitoring. Devs like to use it to understand how an app is being used. It makes sense that the developers of the Bruno project wanted to track that. 

The second connection was to a custom app on DigitalOcean. This one was more interesting to me.

I wanted to know why an app that prides itself on working offline is connecting to a server at DigitalOcean.

Let’s find out.

But first… what the hell is an Electron app?

Under a rock much? An Electron app is a cross-platform desktop application built using web technologies like JavaScript, HTML, and CSS, which runs on a simplified Chromium browser framework along with Node.JS under the hood.

It’s perfect for web devs who want to write desktop apps. 

You’d be surprised at some of the apps that use Electron: 1Password, Discord, Docker Desktop, Microsoft Teams, Visual Studio Code, Spotify, Postman, and yes… even Bruno.

The thing to note is that an Electron app includes a “main” process along with several other “renderer” processes. The main process manages the overall application lifecycle and creates web pages by creating renderer processes, which are responsible for running the web pages’ JavaScript in isolated environments.

OK, so with that explanation out of the way, let’s go about reverse engineering this puppy.

(Groan… ya… bad Bruno joke)

Reversing an Electron App

When software publishers wish to distribute an Electron app, they must follow certain Application Packaging constructs, which the ElectronJS’ Application Distribution documentation describes.

We care about the format of the app source code archive (ASAR) file. This archive file contains the app’s source code and is usually stored under the application’s “resources” directory.

Knowing that applications are usually dropped in /Application/ on macOS, we can do some command-line fu to find where this file might be.

find /Applications/Bruno.app -type f -iname "*.asar" 2>/dev/null

Excellent. Let’s pull a copy of it so we can play with it. 

Extracting source with ASAR

From the ElectronJS documentation, we are told that there is an npm package called @electron/asar that works like tar, concatenating all files together without compression, while having random access support.

Nothing says we can’t use it ourselves to extract all the source code. So let’s install that package and use it.

npm install -g @electron/asar
asar extract app.asar src

Nice. We have all the artifacts and source code of the Electron app. Let’s quickly extract all the API artifacts we can from it.

Extracting API endpoints

We first want to extract as many URLs from the Javascript code as we can find. I’ll move into the src directory, search for all Javascript files, and parse them using BishopFox’s jsluice tool.

I’ll sprinkle in some jq goodness and sort out all unique URLs to remove any dupes. The whole command might look something like this: 

find . -type f -name "*.js" | jsluice urls | jq -r '.url' | sort -u

Looking through the code

With our first pass of the code searched, it’s time to look a bit closer at it. In my case, I opened the src directory in Visual Studio Code and immediately found a dotenv sample file that defines two global environment variables. 

The first is named BRUNO_INFO_ENDPOINT. The second BRUNO_LICENSE_ENDPOINT

As both global variables refer to URLs, we should quickly scan the code to see what might be using them.

find . -type f -name "*.js" -exec grep -H "BRUNO_INFO_ENDPOINT" {} \;

Ahhhh. For the first time, we have stumbled upon actual API endpoints. We should scan the code for the predictable path of /api/ now that we know it exists.

find . -type f -name "*.js" -exec grep -H "/api/" {} \;

It doesn’t look like that returns anything new.

What about that call to the server at goldfish-app-xfxje-app.ondigitalocean.app? We haven’t seen that domain anywhere in the code or environment variables.

Let’s grep for it:     

find . -type f -name "*.js" -exec grep -H "goldfish" {} \;

Nothing. We need to dig deeper into the domain.

DNS recon on the strange server name

Whenever I encounter a strange domain name hosted on a cloud provider’s app domain like AWS, Azure, or DigitalOcean, I kind of expect that it might be a record with a CNAME mapping to it. Since we already extracted several domains during the initial endpoint extraction process, we could quickly do a DNS lookup to see if there are any matching CNAME records.

So let’s start with the first domain we extracted, which was appinfo.usebruno.com

dig appinfo.usebruno.com CNAME +noall +answer

Sure enough, we can see that appinfo.usebruno.com has a CNAME record to goldfish-app-xfxje-app.ondigitalocean.app. Looking through our initial greps for that in the global variables, we find that it was fetching it in notifications.js.

I think we have a better idea now of what is going on. Bruno is fetching some sort of data at appinfo.usebruno.com to use in the Electron app. 

I’d kinda like to know what that data is and what data is being sent to that server.

Let’s try to intercept the traffic and find out.

Intercepting Electron app traffic with Burp Suite

So… remember when I said that an Electron app is pretty much a Chromium environment with a Node backend? 

We can use that to our advantage.

If you know anything about Chromium, you can configure it to use a proxy server at runtime. 

Running an Electron App through Burp Proxy

If you read the documentation for Chromium, you will find you can configure the network settings using extra arguments during runtime execution. To make it route traffic through the Burp Proxy, we will need to set to args:

  1. --proxy-server :  Points to the local Burp proxy
  2. --ignore-certificate-errors : Tells Chromium to ignore cert errors for Burp’s self-signed cert.

So on my macOS, to route Bruno through Burp the command looks like this:

open /Applications/Bruno.app --args --proxy-server=127.0.0.1:8080 --ignore-certificate-errors

I immediately saw traffic being sent out to PostHog.

But where was the other traffic? Well, remember how I said that an Electron app is Chromium with a Node backend? We may need to configure Node/NPM to proxy too.

Setting up Node for proxying through Burp

For Node, you typically need to set up a transparent proxy by doing some DNS rerouting in /etc/hosts, or by configuring npm to use a proxy. I like the latter option as it’s easier to do at the command line without additional privileges. 

You typically want to set both the HTTP and HTTPS proxy. You should also instruct Node to ignore errors in certification resolution since it won’t understand Burp’s self-signed certificate (which you should have already installed in your Keyring or Cert store).

Here are the commands I use:  

npm config set proxy http://localhost:8080
npm config set https-proxy https://localhost:8080
export NODE_TLS_REJECT_UNAUTHORIZED=0

And with that, I am now able to capture all the traffic.

Side Note – To reverse these changes, use: 

npm config rm proxy
npm config rm https-proxy
export NODE_TLS_REJECT_UNAUTHORIZED=1

The results

So, I reverse engineered the Electron app, got access to the source code, and extracted all the URLs and API endpoints I wanted. I then proxied all the traffic through Burp Suite to see what Bruno was actually sending to an external server. 

And what I found out was that it was all OK.

Bruno sends some very basic telemetry data to posthog.com. And that weird call to the ondigitalocean.app server? It ended up pulling down data related to release notes. It seems like stale data, though, so it may not be used much anymore.

Conclusion

I hope this article has opened your eyes to how easy it is to reverse engineer an Electron app. 

But why show it?

Because there are MANY desktop apps written in ElectronJS that rely on APIs. It is a perfect thick client from which you can extract API artifacts, including source code, API endpoints, and JSON schemas. Take advantage of the wealth of information you can extract as part of your API recon methodology.

HTH. Hack hard!

One last thing…

API Hacker Inner Circle

Have you joined The API Hacker Inner Circle yet? It’s my FREE weekly newsletter where I share articles like this, along with pro tips, industry insights, and community news that I don’t tend to share publicly. If you haven’t, subscribe at https://apihacker.blog.

The post Reverse Engineering Electron Apps to Discover APIs appeared first on Dana Epp's Blog.

*** This is a Security Bloggers Network syndicated blog from Dana Epp's Blog authored by Dana Epp. Read the original post at: https://danaepp.com/reverse-engineering-electron-apps-to-discover-apis


文章来源: https://securityboulevard.com/2024/05/reverse-engineering-electron-apps-to-discover-apis/
如有侵权请联系:admin#unsafe.sh