Meet Moss: The Helper

The word "MOSS" rendered in bright green rectangular blocks against a dark blue background, in a pixelated or digital font style.

Hello, meet Moss! Moss stands for nothing; it’s just a cool name from the British TV show The IT Crowd. You can check other versions or more about the project by visiting here.

This tool helps me at work. I decided to share some of it in the hope that it could make other people’s jobs easier as well.

It will take input and generate different queries that I can search on the Firewall. I will not disclose the name of the firewall we use for operational security (opsec) reasons.

After inputting an IP address, it will use the AD API to get all the groups that the user is in.

Often, I need to look up a site’s IP. We use nslookup very often. The code will take a site and perform a Nslookup request and take the IPs that are shown and put them in a format that allows me to easily search the firewall for requests made to that site. It will save the query to the clipboard buffer.

What It Looks Like

MOSS menu for querying data, managing groups, and performing lookups.

Nslookup

After it displays and copies the IP query into the clipboard, the code will go back to the main page of Moss.

MOSS system command-line menu for michaelmeade.org, including IP address lookup and options for Queries, Get Groups, and Nslookup.

If there are multiple IPs found when performing the nslookup query, it will create a query with the IPs nested like the snippet shown below.

( ( addr.dst in '13.107.213.40' ) or ( addr.dst in '13.107.246.40' )  )

Getting User’s Groups

The get groups is the same code that I mentioned in my other article, Using PowerShell: At Work. The script is a little different than the one given in that article because, for an unknown reason, my permissions or something were changed that caused this part of the script to not work anymore.

But during the summer, I found a new way of getting the user groups. I am not going to show it in action for privacy reasons. I don’t want to accidentally expose something that I am not supposed to.

A new feature will turn a user name into an email address. It will detect if a space is included in the input string.

If there is a space, it will ask to replace the space with a . and ask for the user’s agency. Then it will append the name with the @ and the agency name and create an email, which will then get the AD Groups and print them out.

Turning Data Into Queries

After inputting a site, the following menu will show which currently has 15 different ways to create queries that can be used to query the firewall. During work, I usually mostly use the url contains ( 4 ) option since it will rarely match the exact URL given.

Command-line interface showing a URL input for 'google.com' and a numbered menu of 15 options for filtering or querying data, including Referer, URL, Category, Email & DST address, App, User & URL, and destination address.

After picking an option, it will generate the query and copy it to the clipboard buffer, so all you have to do is paste it into the Firewall to search. It will also display the query it generates in yellow.

Below is an example of a query that was generated and copied to the clipboard.

( url contains 'Eduthings.com' )

The Log File

Before copying the generated query to the clipboard, the script will save the generated query in a log file.

This is so the user can have a record of the query that they can reuse at a later time.

The log file can be changed, but the output looks like this: query –> date & Time as seen in the image below.

Screenshot of terminal output showing logged URL and referrer matches with timestamps, including domains like souview.oagte c.net, zotero.org, and nasa.gov.

The Delimiter between the query and the date / time is -->.

The Code

$Host.UI.RawUI.ForegroundColor = 'green'

function Read-Host($prompt) {
    Write-Host "$prompt " -NoNewline -ForegroundColor Red
    Microsoft.PowerShell.Utility\Read-Host
}

function Log-Query {
param(
    [string] $q
)

    $filePath = "C:\Users\MMeade1\OneDrive - New York State Office of Information Technology Services\Desktop\fun\logs\logs.txt"
    $date = Get-Date -Format "MM-dd-yyyy HH:mm:ss"
    $write = $q + " --> " + $date
    Write-Output $write | Out-File $filePath -append

}


function Save-Query {
param(
    # Writes the query in console and also sets it in clipboard buffer
        [string] $query
    )
    Write-Host `n`n`n`n
    Write-Host $query -NoNewline -ForegroundColor yellow
    Set-Clipboard $query
    Log-Query $query


}

function Create-Email-By-Name {
param( 
[string] $name
)
    # turns name to email
    $email_host = $name.replace(" ", ".")
    $agency = Read-Host "Enter Agency>"
    $email = $email_host + "@" + $agency + ".ny.gov"
return $email 
}

function Get-Groups {
param(
    [string] $email
)
    # Gets a user AD groups
    $user_name = Get-aduser -Filter {UserPrincipalName -eq $email -and Enabled -eq $true } -Properties Enabled, UserPrincipalName, SamAccountName, mail | select SamAccountName
    $user = $user_name.SamAccountName;


    $user_groups = Get-ADUser -Identity $user -Properties MemberOf | Select -ExpandProperty MemberOf

    foreach ($group in $user_groups) {
        $name = $group.Split(',')[0].split("=")[1]
        Write-Host $name -ForegroundColor yellow
    }
    Write-Host `n`n`n
}

function Query-Menu {
    # Used to create query for palo

    Clear-Host
    
    $url = Read-Host "Enter URL>"


    Write-Host "`n`n`t`t1) Referer eq`n`t
    `t2) Refferer contains`n
    `t3) Url eq`n
    `t4) Url contains`n
    `t5) Category eq`n
    `t6) Email & DST address`n
    `t7) App`n
    `t8) User & URL`n
    `t9) URL contains & Not Equal Alert`n
    `t10) URL Contains ^ Not Equal & User`n
    `t11) App Id & User`n
    `t12) Source user & src IP`n
    `t13) URL eq & zone`n
    `t14) URL contains & zone`n
    `t15) dest address`n"

    Write-host `n`n`n
    $option = Read-Host "Enter Option>"
    Write-host `n`n
    if ($option -eq 1) {
        # Referer equals URL
        Save-Query "( referer eq '$url' )"
        Write-host `n`n
    }
    elseif ($option -eq 2) {
        # Referer contains URL
        Save-Query "( referer contains '$url' )"
        Write-host `n`n
    }
    elseif ($option -eq 3) {
        # URL is equal
        Save-Query "( url eq '$url' )"
        Write-host `n`n
    }
    elseif ($option -eq 4) {
        # URL contains
        Save-Query "( url contains '$url' )"
        Write-host `n`n
    }
    elseif ($option -eq 5) {
        # Category contains URL 
        Save-Query "( category contains '$url' )"
        Write-host `n`n

    }
    elseif ($option -eq 6) {
        # url & dest addr
        Write-Host `n`n`n`
        $email = Read-Host "Enter username>"
        Save-Query "( addr.dst in '$url' ) and ( user.src eq '$email' )"
        Write-host `n`n

    } 
    elseif ($option -eq 7) {
        # App equal URL
        Save-Query "( app eq '$url' )"
        Write-host `n`n

    }
    elseif ($option -eq 8) {
        # User and URL equal
        Write-Host `n`n`n`
        $email = Read-Host "Enter emails>"
        Save-Query "( user.src eq '$email' ) and ( url eq '$url' ) "
        Write-host `n`n

    }
    elseif ($option -eq 9){
        # URL contains & not equal alert
        Save-Query "( url contains '$url' ) and ( action neq 'alert' )"
        Write-host `n`n

    }
    elseif ($option -eq 10){
        # URL contains & not equal & user
        Write-Host `n`n`n`
        $email = Read-Host "Enter emails>"
        Save-Query "( url contains '$url' ) and ( action neq 'alert' ) and ( user.src eq '$user' )"
        Write-host `n`n

    }
    elseif ($option -eq 11) {
        # app id & user
        Write-Host `n`n`n`
        $email = Read-Host "Enter emails>"
        Save-Query "( app eq '$url' ) and ( user.src eq '$email' )"
        Write-host `n`n

    }
    elseif ($option -eq 12) {
        # Email & Source IP
        Write-Host `n`n`n`
        $email = Read-Host "Enter emails>"
        Save-Query " ( user.src eq '$email' ) and ( addr.src in '$url' )"
        Write-host `n`n
    }
    elseif ($option -eq 13) {
        # Search by zone & URL eq
        Write-Host `n`n`n`
        $zone = Read-Host "Enter zone>"
        Save-Query "( zone.src eq '$zone' ) and ( url eq '$url' )"
        Write-host `n`n
    }
    elseif ($option -eq 14) {
        # Search by zone & URL contains
        Write-Host `n`n`n`
        $zone = Read-Host "Enter zone>"
        Save-Query "( zone.src eq '$zone' ) and ( url contains '$url' )"
        Write-host `n`n
    }
    elseif ($option -eq 15) {
        #dest address
        Write-Host `n`n`n`
        Save-Query "( addr.dst in '$url' )"
        Write-host `n`n
    }
}


function Get-Ip-Query {
    param (
        $site
    )
    $ips   = [System.Net.Dns]::GetHostAddresses($site)
    $count = $ips.count
    $out = ""
    $i =0
    Foreach($item in $ips) {
        $i += 1
        If ($i -eq $count) {
            $out += "( addr.dst in '$item' ) "
        } 
        else {
            $out += "( addr.dst in '$item' ) or "
        }
    }

    Write-Host "(" $out ")" -ForegroundColor yellow
    $clip = "(" + $out + ")"
    Set-Clipboard -Value $clip
    Write-Host `n`n`n`n
}


$bye = "

    ########  ##    ## ########                 
    ##     ##  ##  ##  ##                       
    ##     ##   ####   ##                       
    ########     ##    ######                   
    ##     ##    ##    ##                       
    ##     ##    ##    ##       ### ### ### ### 
    ########     ##    ######## ### ### ### ### 
                                             

"

$banner = "`t`t
           `t`t         ███    ███  ██████  ███████ ███████ 
           `t`t         ████  ████ ██    ██ ██      ██      
           `t`t         ██ ████ ██ ██    ██ ███████ ███████ 
           `t`t         ██  ██  ██ ██    ██      ██      ██ 
           `t`t         ██      ██  ██████  ███████ ███████ 
                                    
                                                         
"

while ($true) {
    Write-Host `n`n
    Write-Host $banner
    Write-Host `n`n
    Write-Host "`t`t`t`t===================================================`n"
    Write-Host "`t`t`t`n`t`t`t`t`t`t`t`t1) Queries`n`t
    `t`t`t`n`t`t`t`t`t`t`t`t2) Get Groups`n`t
    `t`t`t`n`t`t`t`t`t`t`t`t3) Nslookup to Query`n`t
    `t`t`t`n`t`t`t`t`t`t`t`t4) Exit`n`t"
    Write-Host "`t`t`t`t`===================================================`n"
    Write-Host `n`n`n
    $options = Read-Host "menu> "
    if ($options -eq 1) {
        Query-Menu
    }
    elseif ($options -eq 2) {
        # get groups
        Clear-Host
        $input_email = Read-Host "email> " -NoNewline -ForegroundColor red
        if ($input_email -match " ") { 
            $input_email = Create-Email-By-Name $input_email
        }

        Write-Host `n`n`n`n 
        
        Get-Groups $input_email
    }
    elseif ($options -eq 3) {
        Clear-Host
     
        $site = Read-Host "site> "
        Write-Host `n`n`n
        Get-Ip-Query $site
        Write-Host `n`n
    }
    elseif ($options -eq 4) {
        Clear-Host
        Write-Host $bye
        exit
    }
}

Notes

Some of the file paths have been changed to protect my privacy and opsec at my job.

Another new feature that I added that is that after generating the query it will save the newly created query into a txt file.

This acts as a log where I can see the date and time, and the query that was generated at a later time.

A new feature I added recently is that when it creates the query, it will save the newly created query in a text file.

This is so that in the future you can look back and find the query to re-use or maybe even see the most common query you use during a period of time.