Overview
The Flipper Zero recently came out with a JavaScript system built off of MJS that exposes some of the functionality of the Flipper Zero. Using this new JavaScript system, users can now create small JavaScript programs in .js files, as opposed to writing them and compiling them in C. These new scripts can then be run from the SD card under the /ext/apps/Scripts/ folder. This lowers the barrier to entry for some simpler applications and can allow you to quickly throw together a proof of concept. Having recently seen that this was released, I wanted to take a stab at creating a small program I’ve had in mind for a while.
Firmware Differences
While the JavaScript system exists in the factory firmware, there are many different firmware options out there. The factory firmware is probably one of the most limited for exposed functionality in JavaScript. I personally have been using the Momentum Firmware as of late, and this one has a lot more functionality in the JavaScript API.
Derek Jamison put together an amazing write-up on Flipper Zero JavaScript over on his GitHub page which highlights several of the differences between firmware choices and what is supported with each one.He also included a nice table to summarize a bunch of info and several examples to fill the void in the documentation for the JavaScript API. Derek Jamison also has an amazing YouTube channel where he covers a lot of topics about the Flipper Zero including C development. If you are interested in learning more about the Flipper Zero, I would highly recommend watching his videos.
The Project: UART Injector
So I wanted to try my hand at the JavaScript functionality on the Flipper Zero and decided, ”Why not make a project I’ve had in mind for a while.” The project was to make it so the Flipper Zero could connect to a UART interface on a PCB and inject command payloads that I would want to run without the use of a computer. While the Flipper Zero does have a USB-to-UART Bridge, it would be nice if common tasks could be performed in a standalone manner without needing the computer.
I figured this scope would give me enough of a project to dive into, see how viable it is, and if there were limitations that would still cause a fallback to C programming or if they could be worked around.
So What Can it Do?
When designing this project, I had a few goals in mind:
1. Simple to use:
a. I want to just wire it, select the baud rate and the payload and fire away
2. The ability to inject a command
3. Sometimes, the ability to inject a command and capture the output
That last requirement was the more difficult one. Since the Flipper Zero has a small screen, it’s not ideal to read on. However, the Flipper Zero does have a SD card, and the mobile application can allow you to read files from the Flipper Zero in the field. This would be a lot more ergonomic.
Optionally, I wanted the following:
• Sanity check that this is a Linux root shell
• Ability to easily add payloads in the future without technical debt
Turns out, these were both fairly easy to add to the JavaScript application thanks to the serial.expect() function.
With the application built, I decided to wire it up to the UART port of an old PogoPlug Mobile device I had laying around and give the application its maiden flight.
Command Injection without Capture:
The first payload I tested was the Bindsh 4444 - Telnetd payload. This creates a persistent (until reboot) passwordless bind shell on TCP port 4444 on the device using BusyBox’s telnetd applet. Busybox’s version of telnetd has a -l switch which is shown in the help menu as:
-1 LOGIN Exec LOGIN on connect
This is to allow a custom binary to handle the login process. If you set this to /bin/sh, then the authentication check is bypassed and you are just dropped into a shell. Effectively, we just want to run:
telnetd -1 /bin/sh -p 4444
I added this as a payload in the script. Since this one does not return an output, there is nothing to capture and the script is finished once it sends the payload. The graphic below shows an attempt to connect to the PogoPlug Mobile on port 4444 before running the script, at which point the script is executed and the port is now open for as many connections as we want.
This payload can make life a lot simpler if telnetd is present on the device since it allows you shell access to a device on the network without having to be tethered to the device’s UART interface. This also makes it easier to extract flash from the system by reading the MTD devices over the network.
Other examples of these types of payloads are rebooting the device or even triggering a kernel panic, which put the device in an unusable state and it didn’t automatically reboot to self heal.
Run Commands and Extract Output to SD Card:
The other requirement I had was being able to execute a command or series of commands and save the output to the SD card on the Flipper Zero. I figured this could make initial reconnaissance efforts easier if the device has an exposed UART port with a linux shell on it. I had created a few payloads to test out on this device. The graphic below shows the payloads to gather MTD information and general system information, which was then saved to a file.
Once this was completed, we had the files. A sample of the Get MTD file is shown below:
MTD.txt contents |
/ # > ---===[ /dev/mtd0 - u-boot ]===--- |
And the Sysinfo.txt is shown in the table below. One of my favorite things with this payload was executing /bin/\busybox so it provided a list of applets the developer provided in it. This can help you see what is available to you for exfiltration and help with crafting command injection exploit payloads later if any are discovered on the device.
Sysinfo.txt contents |
/ # > > > > > > > > > > > > > > > > > |
Final Thoughts
This was a fun project and shows how powerful the JavaScript system in the Flipper Zero can be. While it took little time to slap this project together, it is one I can use in my hardware projects.
Even though I managed to run through this project, there were some limitations I encountered that I had to work around.
No class Keyword
The keyword class is not recognized in MJS. Originally, I wanted to make the Payload a data class. However, while classes aren’t supported, objects are. So instead of a class, it’s a function that returns an object the way I had in mind with the data class.
Dialog Module has a File Picker, but no Save File:
Honestly, the Dialog module is really nice and allows any JavaScript you write to feel very close to a real application. However, even though it has a function to pick a file, it does not have one for saving a new file. As a result I needed to build my own. Which brings us to my final limitation.
MJS Does Not Provide a Date Object:
Since I had to build my own Save File dialog, I figured a default name like uart_log_YYYYMMDD_HHMMSS would have been a nice default. However, I was unable to find a workaround for this and don’t see any way in JavaScript on the Flipper Zero that you can get the current date and time. Perhaps a future API version can provide something, even if it’s just a unix timestamp from the Flipper Zero.
Conclusion
I hope you’ve enjoyed this article on using JavaScript on Flipper Zero. If you want to download my script and give it a go, you can find it in my Github repo.It’s a wonderful addition to the Flipper Zero that makes it quicker and easier to make simple applications or draft a quick proof of concept on the fly. If you are interested in learning more about using the Flipper Zero as a hardware hacking tool, check out some of our past Professionally Evil Webcasts on YouTube where we’ve presented on that and several other exciting topics, or check out our upcoming Webcast.