Microsoft Defender for Endpoint: The Latest Versions of Antivirus Engine & Signatures. In a previous episode on Microsoft Defender for Endpoint, I described how to get a list of antivirus engine and signatures versions for the hosts in your infrastructure using the Microsoft Graph API. But the problem remains. You know the versions that are currently installed on the hosts. But where can you get the latest versions that should be installed there?
I haven’t found any pretty solution for this. I parse public html pages on the Microsoft site I’ll show you how I do it. If you know something better, please write in the comments.
Antivirus engine versions
You can see the engine version on the defenderupdates page.
It can be obtained using a simple function:
import requests
import re
def get_defender_av_engine_version():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
}
response = requests.get('https://www.microsoft.com/en-us/wdsi/defenderupdates', headers=headers)
vers = re.findall("<li>Engine Version: <span>([^<]*)</span></li>", response.text)
version = ""
if vers:
version = vers[0]
return version
print(get_defender_av_engine_version())
Output:
1.1.18500.10
In fact, this is just one GET request and parsing of the html-page. As a result, we get the version of the Microsoft Defender for Endpoint antivirus engine, which can be compared with the versions of the engine installed on the hosts.
Antivirus signature versions
Now let’s look at the signature versions. There is such a page antimalware-definition-release-notes.
The one latest version may be enough for the Defender engine, because it doesn’t change very often. But this will not work for signatures. Signatures are updated several times a day, and requiring all hosts to have the latest version of signatures at any given time is simply impractical. What can be done? We can get a “signature version -> the release date” mapping and select the versions that work for us. The page has a drop-down list of all available versions.
With a GET request, I get a list of these versions and then make separate requests to get the dates for them.
import requests
import re
def get_top_20_signature_versions():
base_url = "https://www.microsoft.com/en-us/wdsi/definitions/antimalware-definition-release-notes"
r = requests.get(base_url)
signature_versions = list()
for line in r.text.split("\n"):
if "dropDownOption" in line:
signature_versions.append(re.sub("[ \r]","",re.sub("<[^>]*>","",line)))
return signature_versions[:20]
def get_release_date(signature_version):
base_url = "https://www.microsoft.com/en-us/wdsi/definitions/antimalware-definition-release-notes?" + \
"requestVersion=" + signature_version
r = requests.get(base_url)
release_date = ""
for line in r.text.split("\n"):
if "releaseDate_0" in line:
release_date = re.sub("\r","",re.sub("^ *","",re.sub("<[^>]*>","",line)))
return(release_date)
top_20_signature_versions = get_top_20_signature_versions()
for signature_version in top_20_signature_versions:
release_date = get_release_date(signature_version)
print(signature_version + " - " + release_date)
Output:
1.349.657.0 - 9/13/2021 12:59:12 PM
1.349.655.0 - 9/13/2021 10:45:47 AM
1.349.651.0 - 9/13/2021 8:35:52 AM
1.349.647.0 - 9/13/2021 6:25:58 AM
1.349.643.0 - 9/13/2021 4:09:46 AM
...
By analyzing this mapping, you can, for example, get the maximum version that was 2 days ago, and assume that all versions more than it are normal, and those that are less than it are outdated.
...
import time
import datetime
def release_date_to_ts(date_string):
return (time.mktime(datetime.datetime.strptime(str(date_string), '%m/%d/%Y %I:%M:%S %p').timetuple()))
def ts_to_human(ts):
return(
datetime.datetime.fromtimestamp(
int(ts)
).strftime('%Y-%m-%d %H:%M:%S')
)
def get_current_ts():
return(int(time.time()))
def get_max_2_days_ago_sifnature_version():
top_20_signature_versions = get_top_20_signature_versions()
for signature_version in top_20_signature_versions:
release_date = get_release_date(signature_version)
ts = release_date_to_ts(release_date)
if ts > get_current_ts() - 3*24*60*60 and ts < get_current_ts() - 2*24*60*60:
return signature_version
print(get_max_2_days_ago_sifnature_version())
Output:
1.349.554.0
The use of this information about the latest versions of the Defender for Endpoint engine and signatures depends on your corporate policy.
Hi! My name is Alexander and I am a Vulnerability Management specialist. You can read more about me here. Currently, the best way to follow me is my Telegram channel @avleonovcom. I update it more often than this site. If you haven’t used Telegram yet, give it a try. It’s great. You can discuss my posts or ask questions at @avleonovchat.
А всех русскоязычных я приглашаю в ещё один телеграмм канал @avleonovrus, первым делом теперь пишу туда.
hi there,
thanks for the scripts… I got it working last week, but somehow this week the definition script just stopped working altogether?
Dont worry… got it working again…
had to use useragent and headers in the second intelligence updates version query as well.
Thanks again for the effort.
Pingback: И тут было бы справедливо спросить: "А не ты ли, Александр, совсем недавно топил за эти самые облачные ИБ сервисы Microsoft, а теперь получаетс
Pingback: Vulnerability Management news and publications #2 | Alexander V. Leonov