A tale of two mainframes

Today, I acquired a copy of a report on anakata’s alleged hacking of Logica. You, too, can find a copy of it in PDF form here.
There’s a number of interesting things in this report, and I figured I would take the time to disassemble them and give a little bit of analysis on each.

The first interesting thing, which starts on the bottom of page 36, is the vast number of IPs from which the attackers came from. Out of curiosity, I did a little investigation on the boxes involved in the attacks, the jumpboxes, if you will.
Now, one of these is pretty interesting.
124.248.187.225 and 27.109.118.33 are located in Cambodia. This implies that, if it WAS anakata, he presumably just compromised wireless routers in his area and used those to launch the attacks, or else was too lazy to protect himself.
93.186.170.54 belongs to a VPS company.
The others, bar one, are all residential ranges. I took a look at them, and nothing particularly struck my fancy about them, however, they did possess dreamboxes and/or some rather esoteric webservers, so my guess would be either default credentials or really, really bad code led to their compromises.
Now, what grabs my attention is 202.120.189.223, and here is why:
This was a z/OS mainframe belonging to Tongji University in China, one of the most respected universities in the country (although it is now offline). So, this brings the total number of hacked mainframes up to 3.

I’m just speculating here, but I would imagine that owing to the difficulty in transferring and working with files from UNIX to z/OS (even with Unix System Services and FTP), that Chinese mainframe probably existed as both storage for the tools used in the Logica hack, and as a development environment. I’m frankly very curious as to how, exactly, these mainframes were so easily broken into, but I have some suspicions.
RACF, which is one of two competing “user management systems” for z/OS (the other being ACF2), has a number of interesting… quirks, including a limit on password length (8 characters), and the fact that the superuser account shipped by default cannot be completely removed; trying to attempt so may seem successful, but will result in it being quietly restored later. I have a few other theories, including the possibility of credential reuse and easily enumerated accounts (RACF conveniently tells you if a username doesn’t exist on the system), but unfortunately most of these aren’t concrete. Additionally, the main methods of egress seem to have been FTP and SSH, with little to no login failures reported, in which case it is worth assuming that the credentials may have been gathered from elsewhere, ie a compromised webserver.
Anyway, as I said, this is just conjecture, and not solid facts.

Another interesting thing that is worth pointing out is the nature of the majority of the backdoor tools. Take a look at the following code:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
setuid(0);
setgid(0);
setgroups(0, NULL);
execl("/bin/sh", "sh", NULL);
}

That’s incredibly, incredibly simple C. I’m not a C programmer, and even I could write that. But there’s a wonderful elegance about it. Why waste time with a tremendously technical backdoor tool when the simplest thing, a setuid wrapper for a shell, works just as well?
That said, there are also far more technical and clever tools deployed, including one written in Z/arch HLasm. Dabbling in C, assembly, and other languages seems rather adventurous, so, with the warning that it’s just speculation, I’d imagine that this was a group of people familiar with mainframe development, not just one developer.
The other tools, go.rx and kurwa, are interesting, too. Based on the strings shown from them, they’re probably rexx scripts (rexx is the equivalent of Perl on UNIX). If the giant /* REXX */ didn’t inform you. What is interesting is that they are apparently exploiting a previously unknown privilege escalation vulnerability, as well as adding yet another language to the list used.
There are also less technical backdoors, for example, changing SSH keys to ensure access later, and altering inetd.conf to accomplish the same thing.

So, now that we’ve taken a look at this, I’d like to comment on what seems, to me, to be paradoxical and/or stupid.
There are only two mainframes, yet a fairly bewildering range of techniques was deployed, with tools written in at least three different programming languages. This right here is terrible opsec, and a terrible waste. Adding multiple backdoors is risky, because you can’t gain MORE access; once you’ve got a backdoor in place you’ve got a backdoor, but you’re leaving more things around that a curious system administrator might stumble upon. As well as that, the more varied the tools and techniques, the more obvious it’s a large and diverse group. It would have been wiser to agree on a list of public tools and simple code that could have been easily ported to z/OS. It just seems weird that everyone was deploying their own toolkit; if these were made specifically for this attack, that’s quite an amount of time to spend.

Still, it’s a fascinating story. Mainframe security doesn’t get nearly enough coverage, and IBM’s z/OS has survived through a lack of scrutiny; security through obscurity.

Password Algorithms: Windows System Key (SYSKEY)

I stumbled upon some forum posts related to System Key recently and read something about 1 of the authentication modes available to Administrators that made me wonder if true or not.

Just to note, there are 3 modes.

  1. Generated by passphrase
  2. Stored in registry
  3. Stored on removable storage device

2 is enabled by default, but you can change this with the syskey.exe utility.

The claim was that if you forgot the passphrase or “startup password” there’s no reliable method of recovery. The “only way” to get back into the system is to restore a backup if one is available or disable completely using something like ntpasswd

In most cases, either way is probably sufficient enough, but there are situations where you would need to know the original passphrase and don’t have a backup available or perhaps you can’t even use a backup which could erase some critical information required.

There are a number of ways to recover the passphrase but I’ll just suggest one for now.
Found this short video which shows someone enabling the startup password

One of the the comments is “BOSS HOW WE HACK SYSKEY!!!” :-)

History of SYSKEY

SYSKEY was Microsoft’s response to pwdump and L0phtCrack.
It was provided as an optional security enhancement with Windows NT SP3 and enabled by default since the release of Windows 2000.

The purpose of this feature was to prevent pwdump working without modifications. Open source offline decryption tools didn’t surface until the release of samdump2 by Nicola Cuomo.

What follows is a short timeline of events related to SYSKEY.

March 1997 Samba developer Jeremy Allison publishes pwdump which enables Administrators to dump LM and NTLM hashes stored in the SAM database.
April 1997 L0pht publishes L0phtcrack which allows Administrators to audit password hashes. It had been in development since the release of pwdump.
May 1997 Microsoft publishes Service Pack 3 for Windows NT which added SYSKEY as an optional feature to prevent pwdump working properly.
December 1999 Todd Sabin documents flaw with SYSKEY. Anyone with access to the SAM database can reveal password hashes without the System key.
April 2000 Todd Sabin releases pwdump2 which dumps password hashes with the obfuscation removed. This also dumps hashes from a domain controller.
February 2004 Nicola Cuomo documents SYSKEY, Releases Samdump2 which enables offline decryption of password hashes stored in SAM database.

Password Generation

When the system boots and auth mode 1 is enabled, windows will display a dialog box waiting for you to enter the password. The following text is displayed on an XP system.

“This computer is configured to require a password in order to start up. Please enter the Startup Password below.”

Blank passwords are acceptable so whether you enter something or not, it gets processed with MD5 and authenticated once you hit OK.

#define MAX_SYSKEY_PWD 260

void pwd2key(wchar_t pwd[], uint8_t syskey[]) {
  MD5_CTX ctx;
  size_t pwd_len = wcslen(pwd);
  pwd_len = (pwd_len > MAX_SYSKEY_PWD) ? MAX_SYSKEY_PWD : pwd_len;
 
  MD5_Init(&ctx);
  MD5_Update(&ctx, pwd, pwd_len);
  MD5_Final(syskey, &ctx);
}

Enter the wrong password 3 times and you’ll receive the following error.

“System error: Lsass.exe”
“When trying to update a password the return status indicates that the value provided as the current password is not correct.”

This message appears because the LSA database key fails to decrypt but I wanted to know how exactly this password was authenticated.

Between XP and Vista, the LSA database got a major upgrade so you may see something else on post-XP systems.

If you were to attempt recovery through the LSA database, it would not only be much slower, it’s more complicated and because there’s a simpler way, I’m not going to cover it.

SAM Database

The SAM database is stored in %SystemRoot%\System32\config\SAM which as you probably know contains local user and group information, including encrypted NTLM/LM hashes.

Windows reads the value of F under SAM\Domains\Account and using the System key, decrypts the Sam key.

The structure of the F value isn’t documented but I’ve put together what I *think* is close enough to the original based on some MSDN documentation and analyzing code in SAMSRV.DLL which is where the decryption occurs.

#define SYSTEM_KEY_LEN   16
 
#define QWERTY "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"
#define DIGITS "0123456789012345678901234567890123456789"

#define SAM_KEY_LEN      16
#define SAM_SALT_LEN     16
#define SAM_CHECKSUM_LEN 16

typedef struct _SAM_KEY_DATA {
  uint32_t Revision;
  uint32_t Length;
  uint8_t Salt[SAM_SALT_LEN];
  uint8_t Key[SAM_KEY_LEN];
  uint8_t CheckSum[SAM_CHECKSUM_LEN];
  uint32_t Reserved[2];
} SAM_KEY_DATA, *PSAM_KEY_DATA;

typedef enum _DOMAIN_SERVER_ENABLE_STATE {
  DomainServerEnabled = 1,
  DomainServerDisabled
} DOMAIN_SERVER_ENABLE_STATE, *PDOMAIN_SERVER_ENABLE_STATE;

typedef enum _DOMAIN_SERVER_ROLE {
  DomainServerRoleBackup  = 2,
  DomainServerRolePrimary = 3
} DOMAIN_SERVER_ROLE, *PDOMAIN_SERVER_ROLE;

typedef struct _OLD_LARGE_INTEGER {
  unsigned long LowPart;
  long HighPart;
} OLD_LARGE_INTEGER, *POLD_LARGE_INTEGER;

#pragma pack(4)
typedef struct _DOMAIN_ACCOUNT_F {
  uint32_t Revision;
  uint32_t unknown1;
  
  OLD_LARGE_INTEGER CreationTime;
  OLD_LARGE_INTEGER DomainModifiedCount;
  OLD_LARGE_INTEGER MaxPasswordAge;
  OLD_LARGE_INTEGER MinPasswordAge;
  OLD_LARGE_INTEGER ForceLogoff;
  OLD_LARGE_INTEGER LockoutDuration;
  OLD_LARGE_INTEGER LockoutObservationWindow;
  OLD_LARGE_INTEGER ModifiedCountAtLastPromotion;
  
  uint32_t NextRid;
  uint32_t PasswordProperties;
  uint16_t MinPasswordLength;
  uint16_t PasswordHistoryLength;
  uint16_t LockoutThreshold;
  uint16_t unknown2;
  
  DOMAIN_SERVER_ENABLE_STATE ServerState;
  DOMAIN_SERVER_ROLE ServerRole;
  
  uint8_t UasCompatibilityRequired;
  uint32_t unknown3[2]; 
  
  SAM_KEY_DATA keys[2];
  uint32_t unknown4;
} DOMAIN_ACCOUNT_F, *PDOMAIN_ACCOUNT_F;
#pragma pack()

NTSTATUS DecryptSamKey(PSAM_KEY_DATA key_data, uint8_t syskey[]) {
  MD5_CTX ctx;
  RC4_KEY key;
  uint8_t dgst[MD5_DIGEST_LEN];
  
  // create key with salt and decrypt data
  MD5_Init(&ctx);
  MD5_Update(&ctx, key_data->Salt, SAM_SALT_LEN);
  MD5_Update(&ctx, QWERTY, strlen(QWERTY) + 1);
  MD5_Update(&ctx, syskey, SYSTEM_KEY_LEN);
  MD5_Update(&ctx, DIGITS, strlen(DIGITS) + 1);
  MD5_Final(dgst, &ctx);
  
  RC4_set_key(&key, MD5_DIGEST_LEN, dgst);
  RC4(&key, SAM_CHECKSUM_LEN + SAM_KEY_LEN, 
      key_data->Key, key_data->Key);
  
  // verify decryption was successful by generating checksum
  MD5_Init(&ctx);
  MD5_Update(&ctx, key_data->Key, SAM_KEY_LEN);
  MD5_Update(&ctx, DIGITS, strlen(DIGITS) + 1);
  MD5_Update(&ctx, key_data->Key, SAM_KEY_LEN);
  MD5_Update(&ctx, QWERTY, strlen(QWERTY) + 1);
  MD5_Final(dgst, &ctx);
  
  // compare with checksum and return status
  if (memcmp(dgst, key_data->CheckSum, SAM_CHECKSUM_LEN) == 0) {
    return STATUS_SUCCESS;
  }
  return STATUS_WRONG_PASSWORD;
}

NOTE: The strings didn’t format well for the blog but if you plan on using, let me know.

As you can see above, the Sam key is decrypted using System key and then a checksum is generated and compared with that stored in SAM_KEY_DATA
If they match, authentication succeeded, return STATUS_SUCCESS else STATUS_WRONG_PASSWORD

That’s pretty much how you can brute force the System Key when auth mode 1 is selected.

Recovery

Assuming you can read the F value from SAM hive, recovery is straight forward enough with the right libraries/code.

Following is just some pseudo code to demonstrate flow of recovery using dictionary attack.

    sam = openfile("offline_system\Windows\config\SAM");
   data = readreg(sam, "SAM\Domains\Account", "F")
 
  words = openfile("dictionary.txt")
 
  while (readfile(words, pwd)) {
    pwd2key(pwd, syskey)
    if (DecryptSamKey(data->keys[0], syskey) == STATUS_SUCCESS) {
      print "Found password: " + pwd
      break;
    }
  }
  closefile(words)
  closefile(sam)

LSA and NTDS algorithms call a hash function 1000 times during creation
of the encryption/decryption key while SAM algorithm doesn’t use any.

It’s not a vulnerability but could be useful to know some day.

Quick Post: Initial Analysis of “LuckyCat” APT Android Malware

First off, view I have not been writing as often as I like lately. Have a bunch of nice things half written, and no time at present to finish the damn things due to college. Anyway, online on with the show!

So I was browsing the Contagio Mobile Malware Dump and came across this: http://contagiominidump.blogspot.ie/2012/08/luckycata-android-apt-malware.html#more

I was intrigued. The “LuckyCat” APT people had come on my radar before for their elegant use of incredibly low-tech methods (old exploits, sickness very simplistic malware).

So, I decided to dissect this thing. Using Dex2Jar, Unzip and JD-GUI, I was able to quickly reduce the .apk to its source code (Java, ugh) and poke around.

Trend Micro had previously shown it seemed to have file manager functionality, remote command execution, and possibly phonebook theft features. So I decided to go look at its C&C.

I eventually found the following code in the “CMainControl.java” class:
private String strReIP = “greenfuns.3322.org”;
private String strRePort = “54321”;

Now, this lead me to think “So, it connects to that host on that port… Interesting”.

An nslookup shows this no longer seems to exist:
$ nslookup greenfuns.3322.org
Server:        192.168.1.254
Address:    192.168.1.254#53

Non-authoritative answer:
Name:    greenfuns.3322.org
Address: 10.0.0.101

3322.org is, unless I am mistaken, a dynamic DNS provider.  A whois shows it to be China based, as expected.

While going over the source, I noticed a few strings with Chinese characters in them, further giving me the opinion this is another Chinese APT type threat thingy.

I did not, unfortunately, have time for anymore screwing with this, so without further ado, here is the download link to the malware and decompiled source. Password for zip files is “infected”, where needed.

https://www.dropbox.com/s/bbj2y6w9zku10vw/LuckyCat-Android-Malware.zip

 

Forensics – HackEire .pcap challenge

I was awfully saddened to hear there was going to be no HackEire challenge in 2012, as I had always hoped I would get a chance to attend. However, seems the IRISS-CERT guys might be doing something, so that should be fun :D

Over at boards.ie in the Tech/Security section, the challenges are slowly appearing. So when I saw the “pcap challenge”, I HAD to have a look. Seeing as I am taking Forensic Science and Analysis starting in September, a major change from what I was studying – Biopharmaceutical Chemistry. Well, I hope to be taking it – I applied, and theoretically should get the place as I have more than enough CAO points. Forensic Science both allows me to use my knowledge of chemistry, and other “hard sciences”, but also provides me with opportunities to further study Digital Forensics and such, which has, er, become of GREAT interest to me as I wish to try help prevent online crime, rather than facilitate. ANYWAYS. Enough of that, lets get down to the fun stuff!

***infodox puts on his network forensics hat***

You may get the challenge files here – Dropbox and the thread is here – Boards.ie

Now, this post is going to be edited a lot as I progress through, and seeing as it is .pcap files I am analysing, I will be starting off by playing with Wireshark and Xplico, though any other tools I use will also be documented.

The pcap_questions.rtf file has “Questions” about each pcap that you must answer, and I will be keeping strictly to their requirements rather than digressing. However if I see anything funny or interesting I will note it.

So, I am going to start with c1.pcap and start with the first question…

“What was the complete URI of the original web request that led to the client being compromised?”

Well, lets see. The easiest way to filter this would be to use urlsnarf, part of Dug Songs dsniff toolkit. This comes as standard with most penetration testing distributions…

After a bit of parsing (using /dev/brain and gedit), I removed all references to legit sites (yes, even all the advertising ones) and found the following suspect URL’s.

10.20.0.165 – – [04/Jun/2012:04:42:04 +0100] “GET http://10.20.0.111:8080/banking.htm HTTP/1.1″ – – “-” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)”

10.20.0.165 – – [04/Jun/2012:04:42:04 +0100] “GET http://10.20.0.111:8080/banking.htm?UOjiXfyAbAISuH HTTP/1.1″ – – “-” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)”

10.20.0.165 – – [04/Jun/2012:04:42:04 +0100] “GET http://10.20.0.111:8080/banking.htmTysdAWdqQEBybyCGKQkGJyVuQsNWvmIFg.gif HTTP/1.1″ – – “http://10.20.0.111:8080/banking.htm?UOjiXfyAbAISuH” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)”

Now I had an IP address, so I opened the .pcap in Wireshark and proceeded to check what the hell was going to and from the “malicious” server.

I used the following filters:

ip.src == 10.20.0.111
and
ip.dst == 10.20.0.111

I then started peeking through the packet data to see could I find anything interesting…

The initial page (banking.htm) on the malicious server seems to serve a redirect to a second page, which serves up Javascript, and finally a .gif file, leading to remote code execution – once the GIF is served up, we see more traffic from the client to the server on port 4444 – pretty standard behavior for a Meterpreter reverse shell. So far, evidence suggests the “evil” machine was running some exploit from Metasploit.

1(a)
What was the complete URI of the original web request that led to the client being compromised?

> http://10.20.0.111:8080/banking.htm

1(b)
What file type was requested in the final web request to the malicious server? (Answer a, b, c ,d or e)

a. windows executable
b. javascript
c. pdf
d. worddocument
e. gif

> e, a .GIF file

1(c)
What is the sha1 hash of the afore-mentioned file?

> NOT FOUND YET, HAVE TO EXTRACT… Will look into extracting the file later :)

1(d)
What is the number of the first frame that indicates that the client has been compromised?

> 4722 in Wireshark seems to be the SYN packet in the reverse shell

1(e)
At one point, the malicious server sends a malicious file to the client. What type of file is ? (Answer a, b, c ,d or e)

a. windows executable
b. javascript
c. pdf
d. worddocument
e. gif

> NOT FOUND YET, HAVE TO EXTRACT!

1(f)
What is the sha1 hash of the malicious file?

> NOT FOUND YET, HAVE TO EXTRACT…

1(g)
What vulnerable software is exploited (in the following format, ff3.5, ff3.6, ff5, Word2010, ie7, Safari2, Chrome2, AdobeReader, ie6, ff4)?

> FF4 According to User Agent (Mozilla/4.0)

1(h)
When the capture ends, is the client still connected to the malicious attacker? Answer either “yes” or “no”.

> YES, the connection to port 4444 never has a FIN or RST so I can assume it is still ongoing.

1(i)
Can you give the corresponding CVE security bulletin that covers the vulnerability here that was exploited (answer in form of CVE-$year-$number).

> NOT FOUND (YET)

1(j)
From the capture, it is clear that the attacker gets a certain form of access (i.e. the interface), what (type of) access does the attacker “get” on the client?

> Shell access, based on the junk data, an encrypted reverse shell. Based on port data, Meterpreter. Further investigation into the payload used is necessary.

— Post Changelog —
1. The editor broke and pasted the first three paragraphs into the top like a million times. oops…