DEV Community


Posted on • Updated on


Security Information and Event Management (SIEM) using Microsoft Sentinel.

What's a SIEM

SIEM stands for security information and event management and provides organizations with next-generation detection, analytics and response. SIEM software combines security information management (SIM) and security event management (SEM) to provide real-time analysis of security alerts generated by applications and network hardware. SIEM software matches events against rules and analytics engines and indexes them for sub-second search to detect and analyze advanced threats using globally gathered intelligence. This gives security teams both insight into and a track record of the activities within their IT environment by providing data analysis, event correlation, aggregation, reporting and log management.
SIEM software can have a number of features and benefits, including:

  • Consolidation of multiple data points
  • Custom dashboards and alert workflow management
  • Integration with other products

How does a SIEM work ?

SIEM software works by collecting log and event data generated by an organizations applications, security devices and host systems and bringing it together into a single centralized platform. SIEM gathers data from antivirus events, firewall logs and other locations; it sorts this data into categories, for example: malware activity and failed and successful logins. When SIEM identifies a threat through network security monitoring, it generates an alert and defines a threat level based on predetermined rules. For example, someone trying to log into an account 10 times in 10 minutes is ok, while 100 times in 10 minutes might be flagged as an attempted attack. In this way it detects threats and creates security alerts. SIEM's custom dashboards and event management system improves investigative efficiency and reduces time wasted on false-positives.

Preview of technical steps

We're going to create a windows 10 virtual machine inside Azure and set it up as a honeypot (A honeypot is a network-attached system set up as a decoy to lure cyberattackers and to detect, deflect or study hacking attempts in order to gain unauthorized access to information systems. The same goes vice versa, in which a hacker tries to distract a, e.G. , Company with a mock-up hack, to proceed to the main hack, of which the, e.G. , company doesn’t know about.)
In order to do that, we will turn the external firewall off for the VM and we're going to turn the windows firewall off as well so our machine will be exposed to the internet and anyone can ping it from any country. Next we're going to create a log repository in azure called a "log analytics workspace" which will be used to ingest our logs from the virtual machine and then we're going to set up azure sentinel (Microsoft's cloud native SIEM) within azure which we're going to use to create a map that maps all the different attacker data so we can see from which country are the attacks coming.
We're also going to use PowerShell in this lab in order to get the country's latitude and longitude, we'll extract the IP addresses from the VM's windows event security log and send it to a third-party API which will derive the latitude and longitude send back the state and province of the incoming attacks to our virtual machine which we'll then use to create a custom log with geographic data in it to display it in a map inside azure.
One of the main features of a SIEM is to be able to create triggers and alerts when incidents occur, but this post will not cover that, I'll let you figure that out by yourself.
What we will do is extract failed logon data and ingest it into sentinel and map it on a world map so we can visualize where the attacks are coming from.

Create an A virtual machine in Azure

Before you start the lab, DO NOT FORGET or SKIP the VERY IMPORTANT NOTE at the end of the lab

To create the windows 10 VM in Azure, you'll have to sign up for an Azure subscription, it's free and you get 200 dollars worth of free credits, but you'll have to provide some credit card info.
After that, when you're on your account's homepage, search for "virtual machine" and click it, on the left you'll see a plus sign with "Create" written next to it, click it.

Under "Resource group" click "New", a resource group is basically a logical grouping of resources in azure that share the same lifespan, you can name it "honeypot" or something memorable like that, for the name of the vm, do the same, and set the image as Windows 10 pro. Other settings are fine, just enter a username and password and make sure to remember them, check the licensing checkbox and move to the networking tab.

Allow all in firewall

Under "NIC security group" which you can think of it as the equivalent of a firewall, choose Advanced and create a new one, under inbound rules you'll find a default rule, remove it and click "Add an inbound rule" which we will configure to allow all incoming connections into the VM. For "Destination port ranges" put a star(*), "Protocol" as Any, "Action" allow, "Priority" 100 and set the name whatever you want.
And like this, our VM is discoverable by any mean; SYN scans, TCP pings, ICMP pings and other techniques can now find the machine. Hit OK and then "Review + Create", it'll take some time so open another tab with azure in it.

Create analytics workspace

Next search for "Log Analytics Workspaces", here we will setup ingesting logs from the vm, ingest windows event logs and create our own custom log that contain geographic data.
Click "Create log analytics workspace", for the ressource group, select the one we just created, name it, and click "Review + Create" then "Create"

Enable gathering VM logs in Security center

Next, search for "Security center", this is where we enable the ability to gather logs from the virtual machine into the logs analytics workspace. On the left side panel, click "pricing and security" and then the log analytics workspace we just made, turn on "Servers" and turn of "SQL servers on machines" because we won't need them in this lab, hit save.
Next in the left panel click "Data Collection" and select "all events" and save.

Connect log analytics to VM

Go back to log analytics, select the workspace from the left side panel, under "workspace data sources" click "virtual machines" and simply click "connect".

Setup Azure Sentinel

Search for "Azure Sentinel" and hit create, here you can pick the analytics workspace you want to connect to, right click the one we just created and hit add.

Log into VM with remote access

In order to log in to your virtual machine, search for virtual machines, and click it. In the essentials section you can find the machine's IP address, copy it so that we can connect toit using remote desktop. Depending on the OS you're using, you should find a native software that allows you to connect remotely to a machine. If you're on windows 10, open the start menu and search for Remote Desktop, if not, i'll let you figure out a way to do it for practice. Enter the IP address you just copied and connect using the machine's credentials

Observing event viewer logs in analytics

Once on the VM, open up the event viewer by searching it in the start menu, on the left side panel select "Windows logs" and then "Security" and you'll be faced with all the security event on the VM. What we're interested in here is event ID 4625, which is the audit failure security event. If you go back to your computer and try to log in again into the VM only this time using incorrect credentials, it'll show up in the security logs and you can see the details of the failed logon, among them the IP address from which the person tried to connect to the VM, in this case your IP. We will use it later to determine the country this happened from.

Turn off windows firewall in VM

In order for our machine to be discoverable in the internet, let's turn off the firewall. For that, in the windows 10 virtual machine go to start and type "wf.msc", this will open windows defender firewall settings, click on "windows defender firewall properties" then turn everything off in "domain profile", "private profile" and "public profile".
You can try to ping the VM from your computer and it'll work.

Powershell script

This is a script that will export logs to a text file which will be used to map the incoming attacks, go ahead and copy it in Powershell ISE by going to the start menu and searching for it, hit save and name the .ps1 file.

# Get API key from here:
$API_KEY      = "d4600b4efdef42b39828f5155041a457"
$LOGFILE_NAME = "failed_rdp.log"

# This filter will be used to filter failed RDP events from Windows Event Viewer
$XMLFilter = @'
   <Query Id="0" Path="Security">
         <Select Path="Security">

    This function creates a bunch of sample log files that will be used to train the
    Extract feature in Log Analytics workspace. If you don't have enough log files to
    "train" it, it will fail to extract certain fields for some reason -_-.
    We can avoid including these fake records on our map by filtering out all logs with
    a destination host of "samplehost"
Function write-Sample-Log() {
    "latitude:47.91542,longitude:-120.60306,destinationhost:samplehost,username:fakeuser,sourcehost:,state:Washington,country:United States,label:United States -,timestamp:2021-10-26 03:28:29" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:-22.90906,longitude:-47.06455,destinationhost:samplehost,username:lnwbaq,sourcehost:,state:Sao Paulo,country:Brazil,label:Brazil -,timestamp:2021-10-26 05:46:20" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:52.37022,longitude:4.89517,destinationhost:samplehost,username:CSNYDER,sourcehost:,state:North Holland,country:Netherlands,label:Netherlands -,timestamp:2021-10-26 06:12:56" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:40.71455,longitude:-74.00714,destinationhost:samplehost,username:ADMINISTRATOR,sourcehost:,state:New York,country:United States,label:United States -,timestamp:2021-10-26 10:44:07" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:33.99762,longitude:-6.84737,destinationhost:samplehost,username:AZUREUSER,sourcehost:,state:Rabat-Salé-Kénitra,country:Morocco,label:Morocco -,timestamp:2021-10-26 11:03:13" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:-5.32558,longitude:100.28595,destinationhost:samplehost,username:Test,sourcehost:,state:Penang,country:Malaysia,label:Malaysia -,timestamp:2021-10-26 11:04:45" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:41.05722,longitude:28.84926,destinationhost:samplehost,username:AZUREUSER,sourcehost:,state:Istanbul,country:Turkey,label:Turkey -,timestamp:2021-10-26 11:50:47" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:55.87925,longitude:37.54691,destinationhost:samplehost,username:Test,sourcehost:,state:null,country:Russia,label:Russia -,timestamp:2021-10-26 12:13:45" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:52.37018,longitude:4.87324,destinationhost:samplehost,username:AZUREUSER,sourcehost:,state:North Holland,country:Netherlands,label:Netherlands -,timestamp:2021-10-26 12:33:46" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:17.49163,longitude:-88.18704,destinationhost:samplehost,username:Test,sourcehost:,state:null,country:Belize,label:Belize -,timestamp:2021-10-26 13:13:25" | Out-File $LOGFILE_PATH -Append -Encoding utf8
    "latitude:-55.88802,longitude:37.65136,destinationhost:samplehost,username:Test,sourcehost:,state:Central Federal District,country:Russia,label:Russia -,timestamp:2021-10-26 14:25:33" | Out-File $LOGFILE_PATH -Append -Encoding utf8

# This block of code will create the log file if it doesn't already exist
if ((Test-Path $LOGFILE_PATH) -eq $false) {
    New-Item -ItemType File -Path $LOGFILE_PATH

# Infinite Loop that keeps checking the Event Viewer logs.
while ($true)

    Start-Sleep -Seconds 1
    # This retrieves events from Windows EVent Viewer based on the filter
    $events = Get-WinEvent -FilterXml $XMLFilter -ErrorAction SilentlyContinue
    if ($Error) {
        #Write-Host "No Failed Logons found. Re-run script when a login has failed."

    # Step through each event collected, get geolocation
    #    for the IP Address, and add new events to the custom log
    foreach ($event in $events) {

        # $[19] is the source IP address of the failed logon
        # This if-statement will proceed if the IP address exists (>= 5 is arbitrary, just saying if it's not empty)
        if ($[19].Value.Length -ge 5) {

            # Pick out fields from the event. These will be inserted into our new custom log
            $timestamp = $event.TimeCreated
            $year = $event.TimeCreated.Year

            $month = $event.TimeCreated.Month
            if ("$($event.TimeCreated.Month)".Length -eq 1) {
                $month = "0$($event.TimeCreated.Month)"

            $day = $event.TimeCreated.Day
            if ("$($event.TimeCreated.Day)".Length -eq 1) {
                $day = "0$($event.TimeCreated.Day)"

            $hour = $event.TimeCreated.Hour
            if ("$($event.TimeCreated.Hour)".Length -eq 1) {
                $hour = "0$($event.TimeCreated.Hour)"

            $minute = $event.TimeCreated.Minute
            if ("$($event.TimeCreated.Minute)".Length -eq 1) {
                $minute = "0$($event.TimeCreated.Minute)"

            $second = $event.TimeCreated.Second
            if ("$($event.TimeCreated.Second)".Length -eq 1) {
                $second = "0$($event.TimeCreated.Second)"

            $timestamp = "$($year)-$($month)-$($day) $($hour):$($minute):$($second)"
            $eventId = $event.Id
            $destinationHost = $event.MachineName# Workstation Name (Destination)
            $username = $[5].Value # Account Name (Attempted Logon)
            $sourceHost = $[11].Value # Workstation Name (Source)
            $sourceIp = $[19].Value # IP Address

            # Get the current contents of the Log file!
            $log_contents = Get-Content -Path $LOGFILE_PATH

            # Do not write to the log file if the log already exists.
            if (-Not ($log_contents -match "$($timestamp)") -or ($log_contents.Length -eq 0)) {

                # Announce the gathering of geolocation data and pause for a second as to not rate-limit the API
                #Write-Host "Getting Latitude and Longitude from IP Address and writing to log" -ForegroundColor Yellow -BackgroundColor Black
                Start-Sleep -Seconds 1

                # Make web request to the geolocation API
                # For more info:
                $API_ENDPOINT = "$($API_KEY)&ip=$($sourceIp)"
                $response = Invoke-WebRequest -UseBasicParsing -Uri $API_ENDPOINT

                # Pull Data from the API response, and store them in variables
                $responseData = $response.Content | ConvertFrom-Json
                $latitude = $responseData.latitude
                $longitude = $responseData.longitude
                $state_prov = $responseData.state_prov
                if ($state_prov -eq "") { $state_prov = "null" }
                $country = $responseData.country_name
                if ($country -eq "") {$country -eq "null"}

                # Write all gathered data to the custom log file. It will look something like this:
                "latitude:$($latitude),longitude:$($longitude),destinationhost:$($destinationHost),username:$($username),sourcehost:$($sourceIp),state:$($state_prov), country:$($country),label:$($country) - $($sourceIp),timestamp:$($timestamp)" | Out-File $LOGFILE_PATH -Append -Encoding utf8

                Write-Host -BackgroundColor Black -ForegroundColor Magenta "latitude:$($latitude),longitude:$($longitude),destinationhost:$($destinationHost),username:$($username),sourcehost:$($sourceIp),state:$($state_prov),label:$($country) - $($sourceIp),timestamp:$($timestamp)"
            else {
                # Entry already exists in custom log file. Do nothing, optionally, remove the # from the line below for output
                # Write-Host "Event already exists in the custom log. Skipping." -ForegroundColor Gray -BackgroundColor Black
Enter fullscreen mode Exit fullscreen mode

I won't explain the script in detail but you should definitely learn more about scripting languages such as powershell or bash because you'll often use them to automate tasks. What this script does is it basically runs in a loop and looks through the event log we visited earlier, grabs all the failed login events and specifically gets their IP and store it in the directory specified in the $LOGFILE_PATH variable. One thing you need to do in order for the script to work is go to and get your own API key, you'll need to sign up to get one. Go back to the script and paste your own key $API_KEY value

Run script to get geo data from attackers

You can start the script, and notice down in the command line some text has popped up if you actually retried to connect with incorrect credentials, you can even go and take a look at the log file to see what's inside, you'll find some sample data followed by your failed login data

Create custom log in LAW to bring in our custom log

Next thing we're going to do is we're going to create a custom log inside of our log analytics workspace to bring our custom log with the geo data in it into our workspace.
Back to your machine, in azure look for "log analytics" click your workspace and then "custom logs" and the "add custom log", you'll see it's asking for a log file, but ours is in the virtual machine, there's a lot of ways you can send it to our machine but for now we will just copy it from the file directly. Go back to your VM and navigate to the folder where the log is, in the script it's in "C:\ProgramData\", you might have to toggle on "show hidden folders" in the windows file viewer because that directory is hidden. After copying it paste it in a notepad on your host machine and save it. Now you can add the file in azure, click next. On collection path write the path of the file "C:\ProgramData\failed_rdp.log" as we named it in the script and hit next, in details you can name the log and give it a description if you want, next and create.
To see if it's working, go back to your Log analytics workspace in azure and click "Logs", on the right you can write whatever you named the log and see if it gives you results under the request, if you get nothing, you might want to leave some time in order for the two machines to sync, but you can try and request other logs for example "SecurityEvent" and see the results coming in from the VM. After sometime, the failedrdp logs should should up when you ask to see them, you'll see the sample ones followed by your own failed login attempts, we will have to take the raw data column and extract the latitude and longitude and make them in their own columns.

Create custom fields/extract fields from raw custom

To do that, expand one of the logs, click the three dots above and click "Extract fields from 'what_you_named_the_log'". In raw data highlight the latitude value, you'll be prompted with a small panel where you can name it latitude and show numeric as field type, hit extract and you'll see some search results on the right, make sure the search is accurate and only the latitude values are highlighted. Hit save extraction and do the same for longitude, if you find that in the search results there something else highlighted other than the longitude, click on the pencil looking icon in the not accurate search result and hit "Modify this highlight" and highlight the longitude. Repeat this process because the extract algorithm is not always as accurate and needs help to identify the right values we want to extract. By now you know how to extract data from a raw data string, do the same for the destination host with the field type : text. Finish all the others until you find yourself with processed data instead of raw data, meaning all the fields are known to us and are well categorized and can be used in our analytics.

Testing extracts

Going back to the custom logs panel you can click the "custom fields" tab to see what we extracted. you can run the failed_rdp query again in the logs panel and see your data all neatly organized in columns. If not, go ahead and try another failed log, this tile it should work

Setup map in Sentinel with latitude longitude (or...

Go to azure sentinel, click on the one we setup earlier, if you go to overview, you can see some data about the incidents that occurred on our VM, feel free to analyze it. Go to "Workbooks" under "Threat manager" in the left panel of sentinel and hit "Add workbook". Click edit and remove the default widgets you'll find in this workbook by clicking the three dots beside each one, we'll need the space to setup our map. Next add a query, and type this one in :

FAILED_RDP_WITH_GEO_CL | summarize event_count=count() by sourcehost_CF, latitude_CF, longitude_CF, country_CF, label_CF, destinationhost_CF | where destinationhost_CF != "samplehost" | where sourcehost_CF != ""
Enter fullscreen mode Exit fullscreen mode

Providing that you named the columns the same way when we formatted that raw data earlier, if not, make it just like yours. What this query does it it asks for the failed login attempts from the custom log we created excluding the sample ones we used to train the extract algorithm because they don't make sense to us. Now in "Visualization" choose "Map".
On the right side you'll find the settings for the map, for the location info we'll be using Latitude/Longitude, under it select the fields that correspond to both of them and size by the event_count.
Click apply and you should see your location popup on the map, we can further tweaks the settings to make the map more readable. Under metric settings, put "Metric label" as label_CF and "Metric value" as event_count. You can change the plot data to whatever suits you as this is just a suggestion. When you're done hit save and close and save your workbook and click "Done editing".

Witnessing the attacks

Note that you must leave the script in the VM under execution, since it's an infinite while loop it won't stop until you do it manually and if you do, the log file won't be updated and azure won't get new data.
You can leave your computer and the virutual machine for an hour or two and come back later to discover who's been trying to log into the vm from around the world. Analyze the data, see the different techniques the hackers used.


After finishing the lab, you should shutdown COMPLETELY the virtual machine in azure, do that by going to the machine's page in azure and click "Stop", verify the machine is deallocated by checking the "status : Stopped (deallocated)" under the Essentials menu. If you miss this, your 200 dollars will be depleted and you can't use them for future labs concerning azure.

Final thoughts

As soon as a machine is vulnerable on the internet, it's bound to get attacked. Hackers don't care if you're worth hacking or not, if you're a business or just an individual with unexploitable data in your machine like personal data in the form of bank account credentials, family photos or work documents they can encrypt and request money for, what tried to login to your vm are probably bots scouring the internet for vulnerable machine. If they can do it, they will. So if your login credentials are admin admin or similarly guessable words, consider improving your password policy. Read up on how to secure your systems and on layered security.
There are much better ways to do what we did here, but this basically is the gist of what a SIEM does; it aggregates log data, security alerts, and events into a centralized platform to provide real-time analysis for security monitoring. We didn't cover the alerts part, but you should definitely read up on it and try to implement it. Also, it's even better to understand what's happening behind the scene when it comes to which protocols were used to achieve this.
There are still a lot more features to Azure Sentinel, we only scratched the surface here, so head on to the official
documentation and experiment with this tool.

Credit where credit's due,

  • This post was inspired by Josh Madakor's youtube video, check out his youtube channel for cyber security related content.
  • Some lines from this article about the definition of a SIEM and how it works.

Top comments (0)

Create an Account!
Now it's your turn!
🗒 Share a tutorial
🤔 Reflect on your coding journey
❓ Ask a question

Create an account to join hundreds of thousands of DEV members on their journey.