Wannabe Security Researcher!?!?

Wannabe Security Researcher!?!?

This is the very first article that I am publishing on this blog, I wanted to share this experience with folks that are passionate like myself about Security at 360 degrees and also share my thought process to actually produce the correct solution. The assignment received has been pretty interesting and at the same time challenging given that I consider myself a wannabe Security Researcher :D. Without further ado, let’s get into it!

Assignment background

Implement a passive RDP data extractor whose goal is giving an IP & port the script will try to initiate an RDP connection to the service in order to extract as much data as possible about the service without being blocked/blacklisted.

Tasks

  1. Write a python script name rdp_extractor.py that take the following argument: a. ip_address - the ip address to be scan b. port - the scanning port c. output_file - output_file path The script will try to initiate a RDP handshake against the RDP service at the given ip-port and extract as much data as possible about the service (such as banner, SSL data & NTLM) and save all the data in the output file.
  2. Is there a way to find out the operating system (Windows, Linux etc) and the OS version of the service?
  3. We want to capture a screenshot of the RDP login screen - can you come up with a plan how we can achieve that?
  4. [Bonus Question] Create a list of CVE that are related to the RDP service vulnerabilities and suggest ways to assign them based on your script result.

Note

  1. For developing the script you can run linux RDP on docker using the following instruction and you can try to find an open service online.
  2. You can only use any python package for the script.
  3. You are only allowed to do passive calls, Do not try to log in using active methods.
  4. You have a maximum of 2 days to submit the assignment. (Don’t worry if you didn’t finish all the tasks - that’s OK).

Ok ok!!! That’s interesting!!! Very interesting, considering that at the time I got this I hadn’t touched Windows in ages and RDP. Remote Desktop Protocol is a proprietary protocol developed by Microsoft Corporation… not really something I have spent time on in the last decade. After giving the very first read to the whole doc I started to think to the steps I should take to have the faster solution in the shortest amount of time, after all these type of assignments want to assess critical thinking, speed and thought process (not necessarily the A solution, right?).

First thing first on an exercise like this you want to have quickly a functioning testing environment, hence I boostrapped the Docker container that would provide me a running local RDP service:

alessandro@xps:~/Development/blog$ docker run -it \
>     --rm \
>     --hostname="$(hostname)" \
>     --publish="3389:3389/tcp" \
>     --name="remote-desktop" \
>     scottyhardy/docker-remote-desktop:latest /bin/bash
xrdp-sesman[30]: (30)(139881464239680)[DEBUG] libscp initialized

xrdp-sesman[30]: (30)(139881464239680)[DEBUG] Testing if xrdp-sesman can listen on 127.0.0.1 port 3350.

xrdp-sesman[30]: (30)(139881464239680)[DEBUG] Closed socket 4 (AF_INET6 ::ffff:127.0.0.1 port 3350)

xrdp-sesman[31]: (31)(139881464239680)[INFO ] starting xrdp-sesman with pid 31

xrdp-sesman[31]: (31)(139881464239680)[INFO ] listening to port 3350 on 127.0.0.1

xrdp[32]: (32)(140630472390464)[INFO ] address [0.0.0.0] port [3389] mode 1

[20240223-14:15:39] [INFO ] address [0.0.0.0] port [3389] mode 1
xrdp[32]: (32)(140630472390464)[INFO ] listening to port 3389 on 0.0.0.0

[20240223-14:15:39] [INFO ] listening to port 3389 on 0.0.0.0
xrdp[32]: (32)(140630472390464)[INFO ] xrdp_listen_pp done

[20240223-14:15:39] [INFO ] xrdp_listen_pp done
xrdp[32]: (32)(140630472390464)[DEBUG] Closed socket 6 (AF_INET6 :: port 3389)

[20240223-14:15:39] [DEBUG] Closed socket 6 (AF_INET6 :: port 3389)
root@xps:/# xrdp[33]: (33)(140630472390464)[INFO ] starting xrdp with pid 33

xrdp[33]: (33)(140630472390464)[INFO ] address [0.0.0.0] port [3389] mode 1

xrdp[33]: (33)(140630472390464)[INFO ] listening to port 3389 on 0.0.0.0

xrdp[33]: (33)(140630472390464)[INFO ] xrdp_listen_pp done

Wowwow that worked first try!!! For 3 seconds I felt confident, so now what’s next? Well you need a client to connect to the service right? Luckily on Ubuntu Remmina is pretty straightforward to install and use. Alright I can finally connect to the service. I RDP on localhost and surprise surprise (⊙ _ ⊙ ).

alt

Well well wouldn’t have been better to have a Windows machine when trying to learn about RDP and NTLM? At the best of my knowledge I believe that the answer is a yes.

I didn’t give up though, because straight after taking the few actions above, took me about 30 mins altogheter, I thought that I needed to figure out the story of the Windows machine (but that’s easy enough right?) Go to shodan.io, do a search for 3389 et voilà:

alt

No big deal… next I started to get a little bit deeper into the protocol analysis, I fired wireshark and applied a simple bpf rule ip.addr = <ip_target>, I opened an RDP session agaisnt a random host pulled from shodan DB, after a little bit of looking at the TLS handshake packets bingoooo!!! I found out that the server discloses hostname so I was hoping to find more, happy because I felt I had a clue, I started to dig deeper I checked every single packet, but I found nothing else than what is shown below:

alt

At this stage I had some basic information, but the issue was to try disable encryption to be able to view the packets in clear and attempt to figure things out that way… but unfortunately I didn’t have the time and also I really didn’t feel like looking into how to achieve that, I had the feel it would waste me too much of precious time.

After a little bit of head scratching I thought about looking into nmap, after all the purpose of the exercise was about writing an RDP scanner that would pull information from the handshake or something… I opened github and started to dig into some very interesting part of the nmap repo /scripts the Nmap Scripting Engine (NSE) is a very powerfull feature of the scanner that allows executing scripts in LUA, there is a huge amount of interesting things in that folder, I had the feeling that I could find the answer in there and in fact I did it!!! The command below executes rdp-ntml-info.nse LUA script.

alessandro@xps:~$ sudo nmap -p 3389 --script rdp-ntlm-info 207.81.231.54
[sudo] password for alessandro: 
Starting Nmap 7.80 ( https://nmap.org ) at 2024-02-23 20:40 CET
Nmap scan report for d207-81-231-54.bchsia.telus.net (207.81.231.54)
Host is up (0.31s latency).

PORT     STATE SERVICE
3389/tcp open  ms-wbt-server
| rdp-ntlm-info: 
|   Target_Name: OFFICE
|   NetBIOS_Domain_Name: OFFICE
|   NetBIOS_Computer_Name: SERVER2020-RDP
|   DNS_Domain_Name: office.local
|   DNS_Computer_Name: server2020-rdp.office.local
|   DNS_Tree_Name: office.local
|   Product_Version: 10.0.17763
|_  System_Time: 2024-02-23T19:40:54+00:00

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

Bingooo!!! I had the answer and yet I didn’t write a line of Python after about an hour or so of frenetic typing. My aim was actually to figure a fast solution, I have learnt over the years that business wants speed not elegance :P … I decided so to produce my first attempt brutally wrapping nmap command into a simple Python script rdp_extractor.py I wasn’t proud of what I produced but after all was the solution of tasks 1 and 2 right?

Side note: the famous Docket container if tested with the same command won’t work! Sorry what instructions should I follow to test this? Tip or trick?

alessandro@xps:~$ sudo nmap -p 3389 --script rdp-ntlm-info localhost
[sudo] password for alessandro: 
Starting Nmap 7.80 ( https://nmap.org ) at 2024-02-23 20:57 CET
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00051s latency).

PORT     STATE SERVICE
3389/tcp open  ms-wbt-server

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

Lesson learnt, never trust pdf attached to an email :D !!!

I was happy I had a solution, but I had the feeling that was not what they actually wanted, I decided to provide something after a short time rather than keep going, I put together a report of my results and I send it over. After like 5 minutes I received an answer asking me to try with scapy (failed attempt number 1) (¬_¬")

After a few attempts I managed to have a script that would trigger the RDP TLS handshake and grab some data but nothing around OS versions rdp_extractorv2.py (failed attempt number 2) (¬_¬")

At this stage was hours that I was trying to produce something, time was running out I so started to research code written in other languages that could replicate the nmap LUA script and I found this repo NTLM_Info I pulled the package I ported it to Python and job done!!! In between I tried a bunch of Python libraries like rdpy and others without success.

alessandro@xps:~/Development/NTLM_Info$ python3 ntmlinfo.py 
+-------------------+-----------------------------------------------+
|       Server Name | SERVER2020-RDP                                |
|       Domain Name | OFFICE                                        |
|       Server FQDN | server2020-rdp.office.local                   |
|       Domain FQDN | office.local                                  |
|     Parent Domain | office.local                                  |
| OS Version Number | 10.0.17763                                    |
|        OS Version | Windows 10/Server 2019 (Build 17763)          |
+-------------------+-----------------------------------------------+

So, end of the headache I figured!!! The simplest explanation of this I found HTTP NTLM Information Disclosure

The ntlm_info script explained

The ntlm_info initiates an RDP connection to the specified IP address. It sends an NTLMSSP message requesting a challenge. The server responds with an NTLMSSP challenge message containing information such as server name, domain name, OS version, etc. The script receives this challenge, decodes it, and prints out the relevant information. Comparing the above with the nmap LUA script it is easy to understand that the answer was exactly in that script and specifically in:

-- NTLMSSP Negotiate request mimicking a Windows 10 client
    local NTLM_NEGOTIATE_BLOB = stdnse.fromhex(
      "30 37 A0 03 02 01 60 A1 30 30 2E 30 2C A0 2A 04 28" ..
      "4e 54 4c 4d 53 53 50 00" .. -- Identifier - NTLMSSP
      "01 00 00 00" ..  -- Type: NTLMSSP Negotiate - 01
      "B7 82 08 E2 " .. -- Flags (NEGOTIATE_SIGN_ALWAYS | NEGOTIATE_NTLM | NEGOTIATE_SIGN | REQUEST_TARGET | NEGOTIATE_UNICODE)
      "00 00 " ..       -- DomainNameLen
      "00 00" ..        -- DomainNameMaxLen
      "00 00 00 00" ..  -- DomainNameBufferOffset
      "00 00 " ..       -- WorkstationLen
      "00 00" ..        -- WorkstationMaxLen
      "00 00 00 00" ..  -- WorkstationBufferOffset
      "0A" ..           -- ProductMajorVersion = 10
      "00 " ..          -- ProductMinorVersion = 0
      "63 45 " ..       -- ProductBuild = 0x4563 = 17763
      "00 00 00" ..     -- Reserved
      "0F"              -- NTLMRevision = 5 = NTLMSSP_REVISION_W2K3
    )

Lessons learnt

Do not trust what you read 100%, think first if that makes sense and be critical! In this assignment a lot of details were left to the reader interpretation. Starting from the Docker container mimicking RDP, is it actually possible to enable NTLM on an RDP installed on a Linux machine? C’mon I would not even try to enable that! Also I am still scratching my head, what is exactly a passive RDP data extractor? The solution is not really passive when to trigger the information disclosure from the Server is required a full handshake. Despite the struggle I learnt a lot of things over the couple of days I dedicated to this, I really enjoyed the moment I figured the solution, that was super satisfying… Feel free to comment on the approach, what you think? How you would have approached this? Thanks for reading! Ciao

comments powered by Disqus