/nmap-sap

Nmap custom probes for better detecting SAP services

Primary LanguagePython

SAP Services detection via nmap probes

This article aims at showing how to improve the capability of the nmap network scanner to detect SAP services. This is by no mean a complete and 100% exact way of doing service detection as a lot of corner cases exist that are not covered in this text. If you want a more comprehensive way to do SAP services detection and even much more, the ERPScan Monitoring Suite is a good starting point with its port scanner feature.

How nmap can help us

Our goal is to detect every network service exposed by SAP servers. Those servers are complex beasts with numerous components exposed to the network by default and each of these components potentially has vulnerabilities. So we want to send specific network probes to detect the presence of these services and then better assess if a service is vulnerable or not.

Nmap is an open source network port scanner that can do many things and especially service detection via fingerprints. We will explain how one could implement a SAP-aware port scanner with this tool.

SAP existing support in nmap

First, if you look closely at the official nmap release you will notice that there are some traces of SAP support. It is actually very sparse and can be confirmed by scanning a real SAP server:

Nmap scan report for 172.16.30.29
Host is up (0.00018s latency).
Not shown: 65508 closed ports
PORT      STATE SERVICE         VERSION
1128/tcp  open  soap            gSOAP 2.7
3201/tcp  open  cpq-tasksmart?
3299/tcp  open  saprouter?
3301/tcp  open  unknown
3901/tcp  open  nimsh?
4901/tcp  open  sybase-adaptive Sybase Adaptive Server
4902/tcp  open  sybase-backup   Sybase Backup Server
4903/tcp  open  unknown
8101/tcp  open  http            SAP Message Server httpd release 745
30101/tcp open  unknown
30102/tcp open  unknown
30103/tcp open  unknown
30104/tcp open  unknown
30107/tcp open  unknown
30108/tcp open  unknown
30111/tcp open  http            BaseHTTPServer 0.3 (Python 2.7.10)
30116/tcp open  unknown
40000/tcp open  safetynetp?
40001/tcp open  unknown
40002/tcp open  unknown
40080/tcp open  http            SAP Internet Graphics Server httpd
46287/tcp open  status          1 (RPC #100024)
50000/tcp open  http            SAP WebDispatcher
50001/tcp open  ssl/http        SAP WebDispatcher
50004/tcp open  unknown
50007/tcp open  unknown
50013/tcp open  soap            gSOAP 2.7
50014/tcp open  ssl/soap        gSOAP 2.7
50020/tcp open  unknown
50113/tcp open  soap            gSOAP 2.7
50114/tcp open  ssl/soap        gSOAP 2.7

The columns SERVICE and VERSION shows us plenty of unknown or improperly named fields. This situation can be improved if we analyze each unknown port/protocol.

If you dig a bit more you'll find that Core Security researcher Martin Gallo wrote much more improved support for SAP proprietary protocol (available at corelabs-nmap-service-probes.txt) that does smarter stuff like extracting technical server information from answers. That is a very good starting point and as we included some of these probes we enlarged the support a bit more.

Version and service detection

Nmap key file for service detection is nmap-service-probes (stored in /usr/share/nmap/ for Linux installation).

The format is quite self-explanatory for its main features. Let us consider one of the simplest example:

Probe TCP NULL q||
match sajpoin m|SAP_Cluster_Manager| p/SAP Java Cluster Join Service/

The Probe line describes the TCP payload that we send to the server. In this case, we connect to the TCP port without sending any TCP payload after the 3-way handshake.

The next line beginning with match describes what we want to check from the server's answer. A match is final, the parser won't check another match for the given probe (as long as we don't use softmatch). In this example, we look for the ASCII string SAP_Clutser_Manager via a regular expression. If the expression is matched, then nmap tags the matching port with the product name "SAP Java Cluster Join Service".

That probe can be used many times for all those protocols that are based on the first message sent by the server to the client (SSH, FTP, mail protocols, for example). We just add other match lines after the Probe.

Full documentation of this file format can be found at https://nmap.org/book/vscan-fileformat.html

How to generate and test probes

So now, we need a way to know which packets need to be sent and what specific piece of information inside an answer can allow us to identify with a good assurance what protocol is being used and from that determine what is the service using this protocol. In order to illustrate the difference about service and protocol, you can look at the HTTP protocol and all the different services that will make use of it.

SAP services implement many different binary protocols that does not ease our task.

Let's have a look at a simple probe for a service using a binary protocol: SAP Router.

Probe TCP SAProuter q|\x00\x00\x00\x00|
ports 3299
match saprouter m|SAProuter ([\d.]+) on '(\w+)'| p/SAProuter/ v/$1/ h/$2/
match saprouter m|SAProuter| p/SAProuter/

Per official documentation SAP router service should be listening to the port tcp/3299.

When sending the binary request \x00\x00\x00\x00 to a SAP Router we can get several answers depending on the router version/configuration.

Sometime the SAP Router can leak information like version + hostname, so we try to match this specific answer first and then we try to match the more generic answer without the information disclosure.

The additional information we gather in the first match can be propagated and printed nicely by nmap using the version field and the hostname. That is what we accomplish with help of regular expression groups (using parenthesis inside the expression) and by referencing them via their position in the v// and h// statement ('v' standing for version, and 'h' for hostname).

How to handle scan port range

Usually with nmap, if we do not specify -p option it will scan the 1000 most used port (from Internet statistics). Unfortunately, many SAP ports will be missed by doing so. Therefore, we need to scan all 65535 ports at a big scan time cost or we look a bit closer at how to generate these SAP ports. For efficiency, we decide to choose the second option.

If we look at SAP documentation, we see their rules to define potential ports for each services. So by using these rules, we can expand the full list of potential SAP ports.

SAP services have the notion of instance number, this is a number that can vary from 00 to 99 and the port of the service will depend on it.

SAP official documentation on all SAP TCP ports used by their services can be accessed at https://cp.hana.ondemand.com/dps/d/preview/47673f06bd494db680ff6150c0b08108/2.0/en-US/frameset.htm

For example the web ports for ICM HTTP service are noted 80NN, with NN being this instance number. It means they can cover the range 8000-8099.

If we look at another example the SAP TREX nameserver service will listen on ports 3NN01. So our potential port range will be from 30001, 30101, 30201,...,39901.

You can find port collision with two (and more) different services/protocols using theoretically the same port. Some examples: 32NN used on the Netweaver Java platform by the Enqueue service and on the Netweaver ABAP platform by the Dispatcher service. Another one is the previous example with port 3NN01 being used by SAP TREX nameserver and SAP HANA TREXNet internal nameserver port.

Nmap handle all of that nicely with its service detection algorithm given a proper nmap-service-probe file: we can have the same port used in a Probe rule, and several match on a single port.

Port generation tool

The following python tool sap_ports.py takes care of port generation and prints out a comma-separated list of ports that can be used as the nmap -p parameter as following:

$ nmap -p $(sap_ports.py) $TARGETS

The main idea of sap_ports.py is to use a statically defined dictionary with information gathered from SAP on-line documentation to generate the list of ports with possibility to generate a subset of the ports depending on several criteria.

What about port customization by the admin?

During our security audit we saw rarely cases of port customization. One example case lead to wrong assumption on the instance number of a service by analyzing the port number. For instance: using 3617 for the message server service on the instance number 32... In this case it is necessary to inspect the protocol and use information disclosures to be able to disambiguate this situation.

There is no generic answer to this problem if we do not want to scan the 64k TCP ports. We accept in this article the low risk that some port customization could be out of our static port range from our experience of seeing it very rarely.

How a scan looks like with custom SAP probes

Nmap scan report for 172.16.30.29
Host is up (0.00018s latency).
Not shown: 6563 closed ports
PORT      STATE SERVICE             VERSION
22/tcp    open  ssh                 OpenSSH 6.2 (protocol 2.0)
111/tcp   open  rpcbind             2-4 (RPC #100000)
1128/tcp  open  sapstartservice     SAP Management Console (SID SAP, NR 99)
3201/tcp  open  sapjavaenq          SAP Enqueue Server
3299/tcp  open  saprouter           SAProuter 40.4
3301/tcp  open  sapgateway          SAP Gateway
3901/tcp  open  sapms               SAP Message Server
4901/tcp  open  sapase              SAP ASE Database
4902/tcp  open  sybase-backup       Sybase Backup Server
4903/tcp  open  unknown
8101/tcp  open  sapmshttp           SAP Message Server httpd release 745 (SID J45)
30201/tcp open  saptrex             SAP TREX Name server
30202/tcp open  saptrex             SAP TREX Preprocessor
30203/tcp open  saptrex             SAP TREX Index server
30204/tcp open  saptrex             SAP TREX Queue server
30207/tcp open  saptrex             SAP TREX RFC server
30208/tcp open  saptrex             SAP TREX Cruise server
30211/tcp open  saptrex             SAP TREX AlertServer (BaseHTTP/0.3 Python/2.7.10)
30216/tcp open  saptrex             SAP TREX Index server
40080/tcp open  sapigs              SAP Internet Graphics Server
50000/tcp open  sapjavaweb          SAP NetWeaver Application Server (Kernel version 7.45, Java version 7.50)
50001/tcp open  ssl/sapjavaweb      SAP NetWeaver Application Server (Kernel version 7.45, Java version 7.50)
50004/tcp open  sapjavap4           SAP JAVA P4 (Potential internal IP 172.16.30.29)
50007/tcp open  sapp4iiop           (Internel IP 172.16.30.29)
50013/tcp open  sapstartservice     SAP Management Console (SID J45, NR 00)
50014/tcp open  ssl/sapstartservice SAP Management Console (SID J45, NR 00)
50020/tcp open  sapjoin             SAP Java Cluster Join Service
50113/tcp open  sapstartservice     SAP Management Console (SID J45, NR 01)
50114/tcp open  ssl/sapstartservice SAP Management Console (SID J45, NR 01)
50213/tcp open  sapstartservice     SAP Management Console (SID TRX, NR 02)
Service Info: Host: java745;

Issues encountered: SSL

In theory there is the keyword sslports in the service-probe file that may indicate on which port a specific probe should be checked upon the SSL layer. In practice these specified ports were not properly validated as SSL ones without ripping the whole probes related to SSL in the original nmap-service-probe file (begins in our custom probe file at the Probe TCP SSLSessionReq).

What can be improved

Code exploits / port information disclosure in NSE Lua scripts tagged by categories:

  • version, discovery, exploit, auth, dos
  • safe, intrusive

What to do next with that information?

If you are a pentester, you probably have a bag full of exploits for specific SAP services, so you want to automatically link open ports to exploits attempts. That can be easily done by storing the nmap scan into an XML file (-oX option) and then writing a parser that will generate exploit command-line to be executed on the specific open ports.

On the other hand, if you are a security analyst or doing operational security you probably want to store those results and be able afterwards to search them to detect change in the landscape or be able to pinpoint vulnerable services by their version. For this mean, we use the IVRE framework that can import our XML nmap scans and provides a nice web interface to query scan results and allows doing basic statistics/reporting tasks.

The attached screenshots shows a scan in IVRE with filtering OFFICE (internal lab) scan source and looking for P4 service (present on Java NetWeaver application servers) detected on the network. The right column shows the top ports histogram computed from those specific scan results.

Conclusion

We hope that this will help you better understand what is hidden behind those cryptic SAP servers and show you that only with network level probes we can go deep in this knowledge of what is behind an SAP server.

This blog post is a way to remind that SAP servers have a huge exposition surface and that enforcing a strict networking policy including them is part of a good security hygiene.

This article and the associated Nmap files are available at github.com. A web-only version is available at https://erpscan.com/press-center/blog/sap-services-detection-via-nmap-probes/

Authors

Name Mail Involvement
Mathieu Geli mathieu.geli@gmail.com Main author/maintainer of those files
Michael Medvedev m.medvedev@erpscan.com Second author
Martin Gallo mgallo@coresecurity.com Initial support on Diag/RFC/MS/Enqueue protocols
Joris van de Vis jvdvis@erp-sec.com Improvements over RFC probes