Tuesday, December 23, 2014

ShmooCon Ticket Contest Writeup

We have a winner @bacnstrips! With a very close second place to @Nheafer! Congrats!
@bacnstrips was nice enough to do a write up on exactly how he solved the challenge:


This challenge covers a few different areas, including binary analysis, password cracking, stenography, and encryption. None of steps required in-depth knowledge of any particular area.

For this challenge I used Kali Linux. I found that almost the entire challenge could be solved with the programs contained in Kali Linux. The only required program Kali did not include was Open Stego. .

Once set up, I downloaded the evil.exe and looked at it's properties. Evil.exe is a Windows executable. What do we do with this file? I am pretty sure running a file called “evil.exe” is not something we are inclined to do. I started by using the Linux strings tool to look for clues and useful bits of information.

To make the results a little more manageable I set the -n flag to control the size of null terminated strings that are returned:

strings –n10 evil.exe

In the results I noticed:

Administrator
EXPLOITS.LOCAL
<<<<<<<<< IT IS BETWEEN THE NULL BYTES!!+2
Administrator
EXPLOITS.LOCAL
<<<<<<<<< IT IS BETWEEN THE NULL BYTES!!c?
YT1CTy*=tS
104.236.163.121


Strings just revealed a user name, domain name, IPv4 address and a clue. A hex dump of the file might give us more information. This can be done either with:

hexeditor evil.exe

Or

xxd evil.exe > evil_hexdump

Searching for the string “BETWEEN THE NULL BYTES” to quickly find a useful section of the dump.

NewImage

Looking at this portion the string “hash:” can be seen, and since the clue is “IT IS BETWEEN THE NULL BYTES!!” try looking for the null bytes (x00) in the hex.

Administrator, EXPLOITS.LOCAL can be seen a few lines above “hash:” and 5F 69 62 58 DC E9 FF 60 6B F3 FB 3D 1A 3B 86 F9 (which follows “hash:”) are all nicely wrapped null bytes.

The hash is probably a password, so that should be cracked but what type of hash is it?. Hash-identifier might shed light on possible hashing algorithms and hash-identifier returned:

NewImage

Because there is a user name and domain name, Domain Cached Credentials seemed like a good place to start This hash can be cracked using hashcat:

NewImage

Or you could use John the Ripper:

NewImage

Both tools quickly revealed that the password was “welcome1”. Now I needed to find out what I could do with the password.

Opening up a web browser and going to http://104.236.163.121 shows a seemingly default web page. However the page does say that “somethings have been changed”.

NewImage

Although it is hard to see in the screenshot, viewing the source revealed a commented out image tag for “shmoo_opensteg.png”. Manually browsing the image shows:

NewImage

The filename says that stego is involved, which means we will have to extract something from the picture. Scalpel can extract hidden files, but in this case it did not recover anything useful.

Most stego tools usually have their own particular method of hiding data, searching Google for “OpenSteg” shows that there is an open source tool called “Open Stego”.

After downloading and installing Open Stego and providing the password “welcome1” a hidden file called “README” is extracted.

The README file was for pyFTPd a python FTP server, except with a couple lines added to the top. These couple of lines indicated that pyFTPd had been installed with default accounts enabled.

It didn’t say where the FTP server was but running nmap against 104.236.163.121 with a banner grabbing does.

nmap -sS -sV -v -n -Pn --script banner 104.236.163.121
Here are the results:
Starting Nmap 6.47 ( http://nmap.org ) at 2014-12-12 18:55 EST
NSE: Loaded 30 scripts for scanning.
NSE: Script Pre-scanning.
Initiating SYN Stealth Scan at 18:55
Scanning 104.236.163.121 [1000 ports]
Discovered open port 80/tcp on 104.236.163.121
Discovered open port 22/tcp on 104.236.163.121
Discovered open port 2121/tcp on 104.236.163.121
Completed SYN Stealth Scan at 18:56, 7.45s elapsed (1000 total ports)
Initiating Service scan at 18:56
Scanning 3 services on 104.236.163.121
Completed Service scan at 18:56, 6.22s elapsed (3 services on 1 host)
NSE: Script scanning 104.236.163.121.
Initiating NSE at 18:56
Completed NSE at 18:56, 5.48s elapsed
Nmap scan report for 104.236.163.121
Host is up (0.099s latency).
Not shown: 993 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.0p1 Debian 4+deb7u2 (protocol 2.0)
|_banner: SSH-2.0-OpenSSH_6.0p1 Debian-4+deb7u2
25/tcp filtered smtp
80/tcp open http Apache httpd 2.2.22 ((Debian))
135/tcp filtered msrpc
139/tcp filtered netbios-ssn
445/tcp filtered microsoft-ds
2121/tcp open ftp pyftpd
|_banner: 220 Welcome to pyftpd. Happy downloading.
Service Info: Host: Welcome; OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.29 seconds
Raw packets sent: 1048 (46.112KB) | Rcvd: 1045 (42.316KB)


There it is, running on port 2121, pyftpd! Just needed the default account credentials to log into it.

Searching Google for pyFTPd, returns references to CVE-2010-2073 (http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2073) where pyFTPd had an issue with default credentials. Additionally Google helps find the pyFTPd source code.

Some of the disclosures contained the following excerpt from auth_db_config.py:

passwd = [('test', 'test', 'CY9rzUYh03PK3k6DJie09g=='),
('user', 'users', '7hHLsZBS5AsHqsDKBgwj7g=='),
('roxon', 'users', 'ItZ2pB7rPmzFV6hrtdnZ7A==')]


However there are no references to the plaintext version of these passwords. Time to crack some more hashes… A quick peek at the source code for pyFTPd to determine what hashing algorythm was being used revealed that MD5 was used.

After crafting another hash file and running it through hashcat or John the Ripper we get the following user names and passwords back:

test : test
user : user
roxon : noxor


Since test and user seem pretty uninteresting I started with the roxon account.

NewImage

It Worked! The only file available was "Acrobatics Earthliest Subinfeudatorys Enchanted Creative Broad.data". Downloading it and opening it in a hexeditor gives us no useful information.
The file is not readable, it is probably encrypted. Looking closely at filename, the first letter of each word spells out “AESECB”. That is our next hint. While we don't know whether it is 128, 192 or 256 bit, there aren't that many to try.

First I tried using openssl to decrypt the file using:

openssl aes-128-ecb –d –in <encrypted file>

When prompted for the password “welcome1”, results in an error… “Bad Magic Number” I tried a few other strengths of AES ECB but still no luck!

NewImage

Searching Google for AES ECB Decryption tools, will lead to a few sites that will decrypt files . NEVER use a website to decrypt sensitive files! One off the sites (http://aes.online-domain-tools.com/) would accept the key in either plaintext or hex, but it automatically converted plain-text to hex in order to decrypt. This can be done using the –K flag and the hex equivalent of “welcome1”.
Attempting to decrypt results in the plain-text message when openssl throws an error, to eliminate the error, add the -nopad flag. With all of the flags, openssl gives the plain-text without any errors:

NewImage

This returned:

Congrats you have reached the end! Send a PGP encrypted email answers@projectmentor.net with this public key 33A45714258D9AC8

That's the final flag! The only thing left to do was send the PGP encrypted email.

===========

Thanks a ton to @bacnstrips again for the great walk through. One other option to solving the AES encryption without needing to know the bits was with a short bit of python:

#!/usr/bin/env python

import binascii
from Crypto.Cipher import AES

skey = 'welcome1'
key = bytes(skey)
blocksize = 16
padding_required = blocksize - (len(key) % blocksize)
padChar = b'\x00'
data = key.encode('utf-8') + padding_required * padChar
cipherhex = "9c733b26742bd75854f7e60384d0cae120f115e14fa2f2a197068bb8f77588315c6ef33f3617a49732c15117321b14e7f80dac6850cc67e84ac827b23ccc9ffea9da5c8133c85fff1a83d8fa0e64676c1535bfba29550d6fa232aa829413450a9f53c900102ace043a9721e5c8c77339d32c44002cd8dd7025ef387146aa4a7f"
ciphertext = binascii.unhexlify(cipherhex)
decobj = AES.new(data, AES.MODE_ECB)
plaintext = decobj.decrypt(ciphertext)

print plaintext


Which results in the exact same result as with OpenSSL