All posts by moh10ly

Get Report of Active Directory Locked Accounts and Machine they logged in from

Story:

I got some clients  that have reported some of their users being locked out and not able to discover how is this happening or which device its getting locked on.

Symptoms:

The user lock happens after you setup your GPO policy to get user locked after failing to login for X times with the correct password.

When user gets locked, they either can’t login or get prompted to re-enter their password in Outlook for example not knowing they have been locked. 

Hard to Find Out:

There’s no easy way to figure out what’s really happening and why the user got locked out specially if the account is being used on multiple devices e.g. (Phone, iPad, Desktop ..etc). Unless you have an auditing or an AD monitoring software that will log all auditing attempts to an external party and tell you where exactly the user is coming from, it’s a not an easy task to find out where is this taking place.  

Solution: 

1- Enabling Relevant Logs

In order for this to work, you’ll need to enable some Auditing logs on the Default Domain Controller Group Policy

Go to  >> Computer Configuration >> Windows Settings >> Security Settings >> Advanced Audit Policy Configuration >> Audit Policies >> Account Management >> Double Click on Audit User Account and enable both Success and Failure.

Once you applied this policy, you’ll need to force update your DCs , Sign out and back in and you’ll start noticing that in Event Viewer / Security the event 4740 and 4625 will start appearing .

The event 4740 will show you the locked user and the machine it tried to login from. 

The event 4625 will show you the path to the process/application that tried to login with your account. 

So to make this more benefitial I ended up writing a script that will get triggered by Task Scheduler in the case of Event 4740 being reported.

The script will search AD for any locked account. will scan the Logs for the user’s event and find the machine the user tried to login from and generate a report with all these details then send it to a target email in Excel forma after converting it using ImportExcel module.

Note that you must have a local SMTP Server for the email to be sent. If not you can just get the CSV and send it manually. 

 

2- Finding the relevant event

3- Finally The script

The script is simple so feel free to modify it, improve it or share it with others. 

Almost done
Script below 80%

#Report NTLM Authentication Failure for users
$ReportTime = ([datetime]::Today).ToString(“MM-dd-yyyy”)

#Generate report
$Report = [System.Collections.Generic.List[Object]]::new()

$LockedAccount = (Search-ADAccount -LockedOut -UsersOnly)
$i = 0
foreach ($User in $LockedAccount){

$i ++
Write-Progress -Activity “Gathering Logon info” -Status “Checking Login info for: $($User.Name)” -PercentComplete (($i / ($LockedAccount | Measure-Object).Count) * 100)
if($User.LockedOut){

$Event = Get-WinEvent -FilterHashtable @{ logname = ‘Security’; id = 4740 } -MaxEvents 500 | Select-Object TimeCreated,
@{ Name=’TargetUserName’; Expression={$_.Properties[0].value}},
@{ Name=’LogonMachine’; Expression={$_.Properties[1].value}} | Where {$_.TargetUserName -eq $User.SamAccountName}
}

$ReportLine = [PSCustomObject][Ordered]@{
Count = $i
ReportedUser = $User.Name
UPN = $User.UserPrincipalName
UserIsLocked = $User.LockedOut
LastLogonDate = $user.Lastlogondate
MachineName = $Event.LogonMachine -join ‘,’
‘Access Failure Time’ = $Event.TimeCreated -join ‘,’
‘Report Date’ = $ReportTime
}
$Report.Add($ReportLine)
}

$MailBody = “
<html><body>
<font color=’006400′> Dear Team, `
Please find attached a report of all locked out users including machine used for the login … `
If any issue you can report it via the ticketing system.</font>
<body><html>

#Eexport in CSV
$Report | Export-csv “C:\Reports\LockOutReport_$ReportTime.cscv” -NoTypeInformation

#Eexport in Excel Format
$Report | Export-Excel “C:\Reports\LockOutReport_$ReportTime.xlsx” -WorksheetName LogonFailure -TableName LogonFailure -AutoSize

$Exported = “C:\Reports\LockOutReport_$ReportTime.xlsx”

$CC = @(‘User2@domain.com’)
#
Get-ChildItem $Exported | send-mailmessage -from “system@domain.com” -to “user1@domain.com” -cc $cc -subject “Users LockOut Report $ReportTime” -body “$MailBody” -Priority High -smtpServer relay.domain.com -BodyAsHtml

Link to Github:

 

https://github.com/moh30ly/powershell/blob/main/ActiveDirectoryLockOutNotification

4- Attach Task to an Event

5- Get The Report

Checking and Providing Full and SendAs delegate access on O365 Exchange Online

Delegate Permissions

This is a code that I have wrote recently to check if an account have Full and SendAs access on target mailboxes in CSV and give the option to choose whether to provide this access or not.

Checking First:

You’ll need to provide two things to get this code working, First the Source account that will need access to the mailboxes. in this case referred to as “ServiceAccount”.

CSV List of Mailbxoes:

You’ll need to provide list of Mailboxes of the users you’d like to provide access to, the List must be user’s Identity either UPN or SMTP would be fine.

The Service account’s Identity must be the UPN attribute.

If you would like to improve this code please do comment or get in touch directly

Thanks

#Connect to Exchange
#Connect & Login to ExchangeOnline (MFA)

try
{
    Get-Clutter -Identity user@domain.com -ErrorAction Stop > $null
}
catch 
{
Connect-ExchangeOnline
}

    $Users = import-csv 'C:\CSV\MailboxListIsHere.csv'
    $ServiceAccount = 'Your Account that will access other Mailboxes' #// Please change the SVC account before running the code
    

        foreach ($User in $users)
        {
            $Mailbox = $User.Identity
            
            #Checking Full Access
            $Full = Get-MailboxPermission -Identity $Mailbox -User $ServiceAccount
            If ($Full.AccessRights -eq "FullAccess")
            {
                Write-Host -f Green $($ServiceAccount) "Already has Full access to $Mailbox."}
            
                    Else
                    {
                        $Answer1 = Read-Host "Do you want to assign $($ServiceAccount) Full access to $Mailbox (Yes or No)"
                        If ($Answer1 -eq "Yes")
                            {
                                Do{
                                    Add-MailboxPermission -Identity $Mailbox -User $ServiceAccount -AccessRights FullAccess
                                    Write-Host -f DarkGreen $($ServiceAccount) "Send-as access has been added to $Mailbox"
                                    }
                           
                            Until ($Full.AccessRights -eq "FullAccess")
                            
                        }
                        
                    }
                
                $SendAs = Get-RecipientPermission -Identity $Mailbox -Trustee $ServiceAccount -AccessRights SendAs
                if($SendAs.AccessRights -eq "SendAs") {
                    Write-Host -f Green $($ServiceAccount) "Already has SendAs access to $Mailbox."
                    }
                    Else
                    {
                        $Answer2 = Read-Host "Do you want to assign $($ServiceAccount) Send-as access to $Mailbox (Yes or No)"
                        If ($Answer2 -eq "Yes")
                            {
                                Do{
                                    Add-RecipientPermission -Identity $Mailbox -AccessRights SendAs -Trustee $ServiceAccount
                                    Write-Host -f Green $($ServiceAccount) "has Send-as access on $Mailbox"
                                }
                            Until ($SendAs.AccessRights -eq "Sendas") {Exit}
                            else{Exit}
                        }
                    }
        }
            
        

Retrieving attachments from Exchange mailbox using python

Story:

I got a request from a client who constantly gets CVs and have to download them for the hiring managers to review them and wanted to get some way an automated mechanism of downloading all those emails.

Googling lead me to the exchangelib project which is a great python source for such a purpose. I built my local lab of the following servers to test it

  1. AD 2016 moh10ly.local
  2. Exchange 2016 = exch01.moh10ly.local
  3. AAD = Another 2016 server to test from

I built my local Certification authority and made sure that all servers has the CA installed to avoid any issues on python.

If you are going to use this on your production environment you can basically install Python anywhere even on your own computer and it should work if EWS is exposed and Autodiscover is configured propely and have a valid and trusted 3rd party Certificate.

However, If you would like to schedule this to work on a daily basis and let it download attachments from mailbox then you’ll need a server or at least a computer to rely on that it would be on when the scheduled task works.

Prerequisites :

Windows Server 2016:

  • Download and install latest version of Python 3.10
  • From CMD run the following cmd
    • Pip install exchangelib
    • Pip install exchangelib[kerberos]
    • Pip install exchangelib[sspi]
  • Download and install MIT Kerberos MSI from https://web.mit.edu/KERBEROS/dist 64bit version
  • If you’re doing this on a local Lab without a trusted 3rd certificate you’ll need to make sure to export your certificatation Authority Certificate in CER format, copy the cert and add it to the end of Python root PEM.

Testing Scenario

  • I created two mailboxes on my local Exchange server lab
  • I have sent myself an email to info@moh10ly.com with 3 attachments in it as you can see.
  • Setup a server to use to download all attachments from the mailbox.

Prepare your Python Script

  • Import Packages in order to use them.

from exchangelib import DELEGATE, IMPERSONATION, Account, Credentials, EWSDateTime, EWSTimeZone, Configuration, NTLM, GSSAPI, CalendarItem, Message, Mailbox, Attendee, Q, ExtendedProperty, FileAttachment, ItemAttachment, HTMLBody, Build, Version, FolderCollection
  • Prepare Credentials of the user you would like to retrieve the attachments from.
credentials = Credentials(username='moh10ly\info', password='Bc12345$')
  • Enter your Exchange server configuration. Since autodiscover didn’t work for me as I don’t have a public certifiate so I went ahead and placed the server configuration.
ews_url = 'https://mail.moh10ly.com/EWS/exchange.asmx'
ews_auth_type = 'NTLM'
primary_smtp_address = 'info@moh10ly.com'
config = Configuration(service_endpoint=ews_url, credentials=credentials, auth_type=ews_auth_type)
  • Place the account type and configuration
account = Account(
primary_smtp_address=primary_smtp_address,
config=config, autodiscover=False,
access_type=DELEGATE)
  • Configure the local path of where you want to save attachments to on the server where this code is going to be launched from. in my code example I have created a folder called “Temp” on the C root drive and that’s what I will use.
  • You can pickup a different local path by changing the /temp path in the line “local_path = os.path.join(‘/temp‘, attachment.name)”
import os.path
from exchangelib import Account, FileAttachment, ItemAttachment, Message

some_folder = account.inbox 
for item in some_folder.all():
    for attachment in item.attachments:
        if isinstance(attachment, FileAttachment):
            local_path = os.path.join('/temp', attachment.name)
            with open(local_path, 'wb') as f:
                f.write(attachment.content)

This by now should be working fine and you should see that it is saving all your mailbox attachments to the folder that you have configured in the path section of the code.

Complete code to run

Working config


from exchangelib import DELEGATE, IMPERSONATION, Account, Credentials, EWSDateTime, EWSTimeZone, Configuration, NTLM, GSSAPI, CalendarItem, Message, Mailbox, Attendee, Q, ExtendedProperty, FileAttachment, ItemAttachment, HTMLBody, Build, Version, FolderCollection


credentials = Credentials(username='moh10ly\info', password='Bc12345$')

ews_url = 'https://mail.moh10ly.com/EWS/exchange.asmx'
ews_auth_type = 'NTLM'
primary_smtp_address = 'info@moh10ly.com'
config = Configuration(service_endpoint=ews_url, credentials=credentials, auth_type=ews_auth_type)


account = Account(
primary_smtp_address=primary_smtp_address,
config=config, autodiscover=False,
access_type=DELEGATE)

import os.path
from exchangelib import Account, FileAttachment, ItemAttachment, Message

some_folder = account.inbox 
for item in some_folder.all():
    for attachment in item.attachments:
        if isinstance(attachment, FileAttachment):
            local_path = os.path.join('/temp', attachment.name)
            with open(local_path, 'wb') as f:
                f.write(attachment.content)


-----------------

#To download all attachments in the inbox:

for item in account.inbox.all():
    for attachment in item.attachments:
        if isinstance(attachment, FileAttachment):
            local_path = os.path.join('/sky', attachment.name)
            with open(local_path, 'wb') as f, attachment.fp as fp:
                buffer = fp.read(1024)
                while buffer:
                    f.write(buffer)
                    buffer = fp.read(1024)
            print('Saved attachment to', local_path)

Hope this have helped you

References:

https://towardsdatascience.com/download-email-attachment-from-microsoft-exchange-web-services-automatically-9e20770f90ea

Check under attachments:

https://ecederstrand.github.io/exchangelib/

https://pypi.org/project/exchangelib/

Troubleshoot cert issue

https://stackoverflow.com/questions/51925384/unable-to-get-local-issuer-certificate-when-using-requests-in-python

With graph

https://techcommunity.microsoft.com/t5/identity-authentication/what-oauth-permissions-needed-for-exchangelib/m-p/2858179

550 relay not permitted distribution group contact

550 relay not permitted distribution group contact

Symptoms

When trying to add an external contact inside a Distribution group. A failure delivery mail with the following NDR is returned.

Delivery has failed to these recipients or groups:

Externalcontact@domain.com

Your message couldn’t be delivered and there was no valid enhanced status code being issued by the remote mail system to determine the exact cause, status: ‘550 relay not permitted’.

The following organization rejected your message: mxserver

Header

Diagnostic information for administrators:

Generating server: server
Externalcontact@domain.com

Remote Server returned '550 relay not permitted'

Original message headers:

Resent-From: <inboundemail@Exchangedomain.com>
Received: from 
with Microsoft SMTP Server (version=TLS1_2,
 cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521) id 15.1.2375.17; Wed, 15
 Dec 2021 11:53:30 -0500
Received: from mail-ot1-f41.google.com (209.85.210.41) by
 with Microsoft SMTP Server (version=TLS1_2,
 cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384) id 15.1.2375.17 via Frontend
 Transport; Wed, 15 Dec 2021 11:53:30 -0500
Received: by mail-ot1-f41.google.com with SMTP id a23-20020a9d4717000000b0056c15d6d0caso25610296otf.12
        for <inboundemail@Exchangedomain.com>; Wed, 15 Dec 2021 08:53:01 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20210112;
        h=mime-version:references:in-reply-to:from:date:message-id:subject:to;
        bh=rR2IMeF7H4JDA9rxaP9qe9SS4+k1fEFk6/Y7HUCR5us=;
        b=NV4VaI1l4JibchEYURu8Z0pAkxU2Km1s5xNxC3pE+vHL/7vd77ut2ri0zUvBqMRcLr
         kOSnRYnDeMnc7EAbsOJRP2oSx6afnHB1yN8WjMijDE/Va/0jOp7Ni4K0PTXIyz2X0W5i
         VPQuoTgOsyKkjN+HZqVpXgxHy8RyRNkiTnUsutwRIZZWevIoHC/p0cwad8yN6tIdCVif
         IMkACRMkA0HeAzBR/v0ctAChdUpkbcBXA+85hbuO2O8CQdXBCBCf4EzpjqiI97QK24yf
         oedS61hmS2qb2zFQ6f8qxmYBgxdK4lQWdI9TdurXmpnQHBKZFIqW56US0cMQ3jCpSF9q
         Se2A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20210112;
        h=x-gm-message-state:mime-version:references:in-reply-to:from:date
         :message-id:subject:to;
        bh=rR2IMeF7H4JDA9rxaP9qe9SS4+k1fEFk6/Y7HUCR5us=;
        b=qVj/PXzNyVqwff+McPc2WmcrhKnU1KzHFugZOqxTRB+v+IKASjxOXzq4oernUflv1P
         ApDShejS2jAO6czxgamOrV4i4E7MUlqM1ZOAORM1+ZZiicTPhLk4ybx88t6Ex6xWG8x1
         CayHD9LjorI/UGhs60fFXpfxREnRvz1mMXk4RQlUVGn7oQvlJZaApknskvs/KDaxB3K4
         l1HvunANu25x9/zmf6OuJEkNuhUQWPnh5TESf52pLknaUmeHBA9Ff4LhEFLoyuj2KwxX
         jDfyvQ3RRs8kN3S+IQntHrukyU6cIy4xskUiSzOUa4wb/b6SfSu7sVb5wy/3MzUcPfwQ
         NJuA==
X-Gm-Message-State: AOAM532yV7/oLUbulh/fnSKX/dvcwEJRrBUakKGRB2AAjJBFmHgQ1juk
	htSdNKTpkhrpu4K0SDKv8LbcseSolYSLvjbVKAFNgKmI1m/3Fg==
X-Google-Smtp-Source: ABdhPJyCyLPmOHEOsFfrUD36h6e5hI9mquwq0Sr3Q+d/MecZbT33ghjh5xXztarpHRBZm944nU8Zrrg/gk50FxN5cxk=
X-Received: by 2002:a9d:7b51:: with SMTP id f17mr9431931oto.88.1639587180247;
 Wed, 15 Dec 2021 08:53:00 -0800 (PST)
MIME-Version: 1.0
References: <cad49hozzrxa94krz4t+3pdqre=npiq+vv8svw3hbcnyzbca_dg@mail.gmail.com>
In-Reply-To: <cad49hozzrxa94krz4t+3pdqre=npiq+vv8svw3hbcnyzbca_dg@mail.gmail.com>
From: External Sender <Sender@gmail.com>
Date: Wed, 15 Dec 2021 22:22:47 +0530
Message-ID: <cad49hoym7ryqqfrzm++=xse4yh-g6pzy10xfo_bqnpyffhc=9g@mail.gmail.com>
Subject: Fwd: test email to Exchange DG
To: <inboundemail@Exchangedomain.com>
Content-Type: multipart/alternative; boundary="00000000000074fd9b05d33223fa"
Return-Path: Sender@gmail.com
X-Auto-Response-Suppress: DR, OOF, AutoReply

Cause:

By default, the ReportToManagerEnabled parameter is set to False and the ReportToOriginatorEnabled parameter is set to True when a distribution group is created in Exchange Online. When the parameters are both set to False, the Return-Path field in the header of the message is <> (blank). This means that the remote messaging system will not send delivery reports to the user who sent the message to the distribution group.

Additionally, if spam filtering is enabled on the remote messaging system, the message is dropped, and delivery reports are suppressed. This occurs because some anti-spam devices might flag messages whose Return-Path field is blank and not let the messages be delivered.

Resolution:

Set-DistributionGroup -ReportToManagerEnabled $true -ReportToOriginatorEnabled $false -Identity distributiongroup@domain.com

REF:

https://docs.microsoft.com/en-US/exchange/troubleshoot/email-delivery/external-recipients-not-receiving-distribution-group-emails

Script to delete all DPM 2019 recovery points

The Story

I have DPM server deployed and I got couple of Exchange Servers and with about 2 TB of data.

I scheduled DPM to backup Exchange four days a week, then I used the deduplication command to make a use of non used space. however that didn’t give me enough space.

As an alternative I planned to delete the recovery points each start of every month.

The script provided by Microsoft’s article about DPM here doesn’t really provide anyhow on how to delete a protection group with multiple recovery points.

After spending lots of digging I tried to create my own script.

Caution:

Please use this script with caution as it delete every Protection Group’s Recovery Points.

If you need custom script to delete recovery points for a specific date please don’t hesitate to send me an email.

Script:

$pgList = Get-ProtectionGroup $env:COMPUTERNAME

ForEach($pg in $pgList) {

  $dsList = Get-Datasource -ProtectionGroup $pg

  ForEach($ds in $dsList) {

    $RP = Get-DPMRecoveryPoint -Datasource $ds; $RP
        foreach ($P in $RP){
           Remove-DPMRecoveryPoint -RecoveryPoint $p -Confirm:$false -forcedeletion
  } }

}

If you think this script has a mistake or can be improved please leave a comment or drop me an email.

References:

Testing Office 365 SMTP relay

In order to test Office 365 SMTP relay you will have to create a user with an Exchange online license. After the email is activated for this user you can test this user for relay with the following powershell.

First connect to Microsoft Online service with this user that you’ll be using for relaying.

$msolcred = Get-Credential

Next edit the following powershell with the user’s e-mail and the recipient’s too

Send-MailMessage -From Office365User@Domain.com -To info@moh10ly.com -Subject “Test Email” -Body “Test SMTP Relay Service” -SmtpServer smtp.office365.com -Credential $msolcred -UseSsl -Port 587

clip_image001
clip_image002

https://technet.microsoft.com/en-us/library/dn554323(v=exchg.150).aspx

This test is known as Client SMTP submission you can also use a different method for multiple devices where you can configure them all to point to a single server (IIS) in a method known as IIS for relay with Office 365 however, all the methods what involve office 365 (Only) for relay will require a user with Exchange online license assigned to it.

https://technet.microsoft.com/en-us/library/dn592151%28v=exchg.150%29.aspx

Note:

The use of this command is not recommended for security reasons in particular for not supporting the modern protocols. use it on your own risk and make sure the user assigned to this service has no privilege’s or not any Office 365 feature admin or power user.

Securing and Testing your Exchange Server with Pfsense HAProxy

– Using the CVE-2021-26855 Payload

After the recent vulnerabilities that hit Exchange Servers On-premises I found sometime to install KaliLinux and try to check what kind of information would I get from the patched servers.

I downloaded the payloads and tried to run it against couple of clients that I have patched the servers for luckily no authentication was made.

image

– Using Nikto scanner

By using Nikto command from Kali Linux I could see what  Information could Exchange expose using

The command line is nikto –h mail.domain.com and the result of the scan would be exposing the Server’s name, local IP address, OWA Version,  ASP Net platform and version.

image

Since I have my Exchange Server published via HAProxy 1.8 on Pfsense then I had to tweak HAProxy to strengthen the ciphers, make sure that HSTS is in place and deny the headers that expose the server’s sensitive information.

The result is pretty good as it also has affected the server’s score on ssllabs.com

Prior to the tweaking  my owa scan result on SSL Labs would get an A

image

– Pfsense’s HAProxy Settings before

Before upgrading Pfsense to the latest version HAProxy was on 1.6 and the ssl/tls settings were also different as they were setup through the Advanced SSL options on the frontend however, now this is no longer supported and you’ll have to remove that and set it up on the “Global Advanced pass thru” in the General setting page.

ssl-default-bind-options ssl-min-ver TLSv1.2

tune.ssl.default-dh-param 2048

ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK

image

Right after you save this, you will still need to change another settings on the Frontend to protect your server’s information from being exposed.

In the HAProxy settings Go to Frontend > Scroll down all the way to “Advanced pass thru” and paste the following:

image

# Remove headers that expose security-sensitive information.

rspadd X-Frame-Options:\ SAMEORIGIN
rspidel X-FeServer:.*$
rspidel ^Server:.*$
rspidel ^X-Powered-By:.*$
rspidel ^X-AspNet-Version:.*$
rspidel X-WsSecurity-Enabled:.*$
rspidel X-WsSecurity-For:.*$
rspidel X-OAuth-Enabled:.*$
rspadd X-Xss-Protection:\ 1;\ mode=block
rspadd Strict-Transport-Security:\ max-age=31536000;includeSubDomains;preload
rspadd Referrer-Policy:\ no-referrer-when-downgrade
rspidel Request-Id:.*$
rspidel X-RequestId:.*$
rspadd X-Content-Type-Options:\ nosniff


In the below result, I have got almost everything protected well except for the OWA version which can be a bit problematic. In the next article I am going to try and mitigate this so the server can be protected in the expected manner.

image

image

– The Result

Now the server is showing a totally different result and the Nikto scan is not revealing anything anymore.

SSLabs

image

https://securityheaders.com/

The reason why I got B on security headers is due to the fact that Content-Security-Policy header will malfunction the ECP and OWA Login pages. Permission Policy is new feature and I couldn’t find anything about it on HAProxy.

image

I hope this helps

Refences:

https://securityheaders.com/

https://www.ssllabs.com/

https://www.haproxy.com/documentation/aloha/12-0/traffic-management/lb-layer7/http-rewrite/

https://www.net7.be/blog/article/xss_csrf_http_security.html

Exchange Server backdoor investigation tools

The Story

After the disastrous exploit that was found in Microsoft Exchange Servers lots of corporations started immediately patching their servers with the latest Cumulative update and Security patches. The question is would those patches be enough if the server is already hacked or have a backdoor installed already?

image

What are those 0-day exploits ?

The vulnerabilities recently being exploited were CVE-2021-26855, CVE-2021-26857, CVE-2021-26858, and CVE-2021-27065 which are part of alleged “State-sponsored Chinese group” according to Microsoft.

Let’s get into details of those exploits one by one:

CVE-2021-26855 is a server-side request forgery (SSRF) vulnerability in Exchange which allowed the attacker to send arbitrary HTTP requests and authenticate as the Exchange server.

CVE-2021-26857 is an insecure deserialization vulnerability in the Unified Messaging service. Insecure deserialization is where untrusted user-controllable data is deserialized by a program. Exploiting this vulnerability gave HAFNIUM the ability to run code as SYSTEM on the Exchange server. This requires administrator permission or another vulnerability to exploit.

CVE-2021-26858 is a post-authentication arbitrary file write vulnerability in Exchange. If HAFNIUM could authenticate with the Exchange server then they could use this vulnerability to write a file to any path on the server. They could authenticate by exploiting the CVE-2021-26855 SSRF vulnerability or by compromising a legitimate admin’s credentials.

CVE-2021-27065 is a post-authentication arbitrary file write vulnerability in Exchange. If HAFNIUM could authenticate with the Exchange server then they could use this vulnerability to write a file to any path on the server. They could authenticate by exploiting the CVE-2021-26855 SSRF vulnerability or by compromising a legitimate admin’s credentials.

How to proceed ?

Microsoft released couple of tools that could diagnose your servers and check if you already have been infected with a backdoor or any of these nasty malware and also remove those infected files or clean them and ask you for a restart if it’s required.

Tools:

  1. MSERT (Microsoft Safety Scanner) detects web shells, Download here .
  2. Health Checker (Scans your server for any vulnerabilities and whether you have updated Server CU and installed patches). Download here
  3. Exchange WebShell Detection (A simple PowerShell that is fast and checks if your IIS or Exchange directory has been exploited). Download here
  4. Scan your exchange server for proxy logon:
    https://github.com/microsoft/CSS-Exchange/tree/main/Security
  5. Microsoft very recently created a mitigation tool for Exchange on-premises that would rewrite url for the infected servers and recover the files that were changed. You can download the tools from this github link.

    https://github.com/microsoft/CSS-Exchange/tree/main/Security

    Copy the Test-ProxyLogon code into Notepad
    Save As “Test-ProxyLogon.ps1” with the quotes in your C:\Temp folder
    Run in Exchange Management Shell: .\Test-ProxyLogon.ps1 -OutPath C:\Temp

Scan Result

Scan result should show you the following if your servers has been exploited already.

This will remove the infections and asks for a restart.

clip_image001

References:

https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/

https://www.bleepingcomputer.com/news/security/microsoft-exchange-updates-can-install-without-fixing-vulnerabilities/

https://github.com/dpaulson45/HealthChecker?mkt_tok=eyJpIjoiTURRMk5HRTFaV1V6TkRrMCIsInQiOiJcL3ZOTkRUVzdXdkJmTm5ibUIzTExKTDVxXC9ObFAxTmZLanFRZ0xpcDkxMW5raVE0dlRwV2FhVFFmWlVUVFZaZUdFM1NlcEFNTEZ6dTh5aWlqcVBpV3J2R2IxbGJxMmNUZ1ppYjJyZklnMjZFZngrM2tBUnNsM1JKcHJsSU1ib3BTIn0%3D#download

Zammad throws error csrf token verification failed! Apache 2.4.41 Ubuntu 20.4

Symptoms:

Right after a fresh installation of Zammad you implement Let’s Encrypt and you are unable to login to your Zammad portal due to the following error.

CSRF token verification failed!

Cause:

When you install Zammad, it’ll automatically create a zammad.conf file under the path /etc/apache2/sites-enabled.

Until this moment your web page should be functioning normal, the problem starts when you implement the Let’s Encrypt certificate which creates another .conf file that would corrupt the web server and cause the error you’re having.

Solution:

To solve this problem simply, change the extension of the zammad-le-ssl.conf file into something else other than .conf and restart apache or nginx.

Solution 2:

You need to uncomment the “ServerTokens Prod” part in your configuration file if the solution 1 doesn’t work.

Solution 3:

Beneath the SSO Setup you need to make sure to change the RequestHeader set X_FORWARDED_PROTO ‘http’ to https as in the below line.

After you apply all those, you need to restart both apache and zammad services.

Here’s a working configuration of Zammad


# security - prevent information disclosure about server version
ServerTokens Prod

&lt;VirtualHost *:80>
    ServerName support.cloud-net.tech
    Redirect permanent / https://support.cloud-net.tech
&lt;/VirtualHost>

&lt;VirtualHost *:443>
    SSLEngine on
    SSLProtocol all -SSLv2 -SSLv3
    SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

    SSLCertificateFile /etc/letsencrypt/live/support.cloud-net.tech/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/support.cloud-net.tech/privkey.pem
    SSLOpenSSLConfCmd DHParameters /etc/ssl/dhparam.pem

    ## don't loose time with IP address lookups
    HostnameLookups Off

    ## needed for named virtual hosts
    UseCanonicalName Off

    ## configures the footer on server-generated documents
    ServerSignature Off

    ProxyRequests Off
    ProxyPreserveHost On

    &lt;Proxy 127.0.0.1:3000>
      Require local
    &lt;/Proxy>

    ProxyPass /assets !
    ProxyPass /favicon.ico !
    ProxyPass /apple-touch-icon.png !
    ProxyPass /robots.txt !
    ProxyPass /ws ws://127.0.0.1:6042/
    ProxyPass / http://127.0.0.1:3000/

    # change this line in an SSO setup
    RequestHeader unset X-Forwarded-User
    RequestHeader set X_FORWARDED_PROTO 'https'

    # Use settings below if proxying does not work and you receive HTTP-Errror 404
    # if you use the settings below, make sure to comment out the above two options
    # This may not apply to all systems, applies to openSuse
    #ProxyPass /ws ws://127.0.0.1:6042/ "retry=1 acque=3000 timeout=600 keepalive=On"
    #ProxyPass / http://127.0.0.1:3000/ "retry=1 acque=3000 timeout=600 keepalive=On"

    DocumentRoot "/opt/zammad/public"

    &lt;Directory />
        Options FollowSymLinks
        AllowOverride None
    &lt;/Directory>

    &lt;Directory "/opt/zammad/public">
        Options FollowSymLinks
              Require all granted
    &lt;/Directory>
&lt;/VirtualHost>
# security - prevent information disclosure about server version
ServerTokens Prod

&lt;VirtualHost *:80>
    ServerName support.cloud-net.tech
    Redirect permanent / https://support.cloud-net.tech
&lt;/VirtualHost>

&lt;VirtualHost *:443>
    SSLEngine on
    SSLProtocol all -SSLv2 -SSLv3
    SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

    SSLCertificateFile /etc/letsencrypt/live/support.cloud-net.tech/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/support.cloud-net.tech/privkey.pem
    SSLOpenSSLConfCmd DHParameters /etc/ssl/dhparam.pem

    ## don't loose time with IP address lookups
    HostnameLookups Off

    ## needed for named virtual hosts
    UseCanonicalName Off

    ## configures the footer on server-generated documents
    ServerSignature Off

    ProxyRequests Off
    ProxyPreserveHost On

    &lt;Proxy 127.0.0.1:3000>
      Require local
    &lt;/Proxy>

    ProxyPass /assets !
    ProxyPass /favicon.ico !
    ProxyPass /apple-touch-icon.png !
    ProxyPass /robots.txt !
    ProxyPass /ws ws://127.0.0.1:6042/
    ProxyPass / http://127.0.0.1:3000/

    # change this line in an SSO setup
    RequestHeader unset X-Forwarded-User
    RequestHeader set X_FORWARDED_PROTO 'https'

    # Use settings below if proxying does not work and you receive HTTP-Errror 404
    # if you use the settings below, make sure to comment out the above two options
    # This may not apply to all systems, applies to openSuse
    #ProxyPass /ws ws://127.0.0.1:6042/ "retry=1 acque=3000 timeout=600 keepalive=On"
    #ProxyPass / http://127.0.0.1:3000/ "retry=1 acque=3000 timeout=600 keepalive=On"

    DocumentRoot "/opt/zammad/public"

    &lt;Directory />
        Options FollowSymLinks
        AllowOverride None
    &lt;/Directory>

    &lt;Directory "/opt/zammad/public">
        Options FollowSymLinks
              Require all granted
    &lt;/Directory>
&lt;/VirtualHost>
# security - prevent information disclosure about server version
ServerTokens Prod

&lt;VirtualHost *:80>
    ServerName support.cloud-net.tech
    Redirect permanent / https://support.cloud-net.tech
&lt;/VirtualHost>

&lt;VirtualHost *:443>
    SSLEngine on
    SSLProtocol all -SSLv2 -SSLv3
    SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

    SSLCertificateFile /etc/letsencrypt/live/support.cloud-net.tech/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/support.cloud-net.tech/privkey.pem
    SSLOpenSSLConfCmd DHParameters /etc/ssl/dhparam.pem

    ## don't loose time with IP address lookups
    HostnameLookups Off

    ## needed for named virtual hosts
    UseCanonicalName Off

    ## configures the footer on server-generated documents
    ServerSignature Off

    ProxyRequests Off
    ProxyPreserveHost On

    &lt;Proxy 127.0.0.1:3000>
      Require local
    &lt;/Proxy>

    ProxyPass /assets !
    ProxyPass /favicon.ico !
    ProxyPass /apple-touch-icon.png !
    ProxyPass /robots.txt !
    ProxyPass /ws ws://127.0.0.1:6042/
    ProxyPass / http://127.0.0.1:3000/

    # change this line in an SSO setup
    RequestHeader unset X-Forwarded-User
    RequestHeader set X_FORWARDED_PROTO 'https'

    # Use settings below if proxying does not work and you receive HTTP-Errror 404
    # if you use the settings below, make sure to comment out the above two options
    # This may not apply to all systems, applies to openSuse
    #ProxyPass /ws ws://127.0.0.1:6042/ "retry=1 acque=3000 timeout=600 keepalive=On"
    #ProxyPass / http://127.0.0.1:3000/ "retry=1 acque=3000 timeout=600 keepalive=On"

    DocumentRoot "/opt/zammad/public"

    &lt;Directory />
        Options FollowSymLinks
        AllowOverride None
    &lt;/Directory>

    &lt;Directory "/opt/zammad/public">
        Options FollowSymLinks
              Require all granted
    &lt;/Directory>
&lt;/VirtualHost>

Hope this helps

Secure Zammad with LetsEncrypt Certıfıcate on Ubuntu 20.4 Apache

The Story

after installing Zammad ticketing system I tried to implement Let’sEncrypt certificate to secure the system but there was nothing available on the internet except an old article about implementing this on Ubuntu 16 with Nginx (see article here).

In my case I was using apache and no Nginx in place, and after installing Zammad it was using pretty fine on Http but needed to redirect http to HTTPS after implementing the certificate.

Zammad: Intuitive Service Desk with connection to i-doit | i-doit

Solution:

I first Installed Certbot for apache and then I took a backup of all my Zammad configuration and made sure not to alter the default Zammad directory.

So I created a dummy folder called /var/www/support and a file called /var/www/support/index.html within that folder and provided them the appropriate permissions.

sudo apt install certbot python3-certbot-apache

 sudo mkdir /var/www/support

sudo chown -R $USER:$USER /var/www/support

sudo chmod -R 755 /var/www/support

sudo nano /var/www/support/index.html


Edit the index.html file with the following to make sure that it works

<html>
             <head>
                         <title>Welcome to Your_domain!</title>
             </head>
             <body>
                       <h1>Success! The your_domain virtual host is working!</h1>
           </body>
</html>

image

image

Edit Zammad’s Default Config File

Please make sure you take a move the original copy of Zammad file to another location using the following command

sudo mv /etc/apache2/sites-enabled/zammad.conf /etc/apache2/sites-enabled/zammad.bak

Then we’ll replace the file with this configuration but since we moved the original file to .bak then we’ll have to recreate it with our intended configuration.

Edit a new zammad.conf file and copy the configuration below

sudo vi /etc/apache2/sites-enabled/zammad.conf

Configuration starts below this:

#

# this is the apache config for zammad

#

# security – prevent information disclosure about server version

#ServerTokens Prod

<VirtualHost *:8080> # I changed the default port of Zammad to 8080 to allow Letsencrypt to connect on 80 and create the certificate

# replace ‘localhost’ with your fqdn if you want to use zammad from remote

ServerName localhost:8080

## don’t loose time with IP address lookups

HostnameLookups Off

## needed for named virtual hosts

UseCanonicalName Off

## configures the footer on server-generated documents

ServerSignature Off

ProxyRequests Off

ProxyPreserveHost On

<Proxy 127.0.0.1:3000>

Require local

</Proxy>

ProxyPass /assets !

ProxyPass /favicon.ico !

ProxyPass /apple-touch-icon.png !

ProxyPass /robots.txt !

ProxyPass /ws ws://127.0.0.1:6042/

ProxyPass / http://127.0.0.1:3000/

— INSERT — 10,38 Top

DocumentRoot “/opt/zammad/public”

<Directory />

Options FollowSymLinks

AllowOverride None

</Directory>

<Directory “/opt/zammad/public”>

Options FollowSymLinks

Require all granted

</Directory>

</VirtualHost>

<VirtualHost *:80>

ServerName support.cloud-net.tech

DocumentRoot /var/www/support

ErrorLog ${APACHE_LOG_DIR}/error.log

CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

– ————————-

In the above configuration we did two things:

1- Replacing the original Zammad listening port instead of 80 to 8080

2- Created a new virtual host that points to our dummy folder /var/www/support

Save the file and exit from vi

Make sure you restart Apache after this

sudo systemctl restart apache2

Enable the new site configuration

sudo a2ensite zammad.conf

Lets create the certificate

In the below commands , the first one will drive you through the process of getting the certificate.

The second checks the status of the configuration of the auto renewal script certbot and third command tests the renewal of the certificate.

1- sudo certbot –apache

2- sudo systemctl status certbot.timer

3- sudo certbot renew –dry-run

As you can see in the below screenshot the command also asks you if you’d like to redirect all http traffic to HTTPS. You should want to say Y to that.

clip_image001

clip_image001[4]

When you accept creating Redirection rule from HTTP to HTTPs the main Zammad config will get that configuration which wont work in that case because we already changed the default zammad port to 8080.

So you’ll need to get into that zammad.conf that you created again and enter the redirection portion

image

# this is the apache config for zammad
#


# security – prevent information disclosure about server version
#ServerTokens Prod


<VirtualHost *:8080>
     # replace ‘localhost’ with your fqdn if you want to use zammad from remote
     ServerName support.cloud-net.tech:8080


    ## don’t loose time with IP address lookups
     HostnameLookups Off


    ## needed for named virtual hosts
     UseCanonicalName Off


    ## configures the footer on server-generated documents
     ServerSignature Off


    ProxyRequests Off
     ProxyPreserveHost On


    <Proxy 127.0.0.1:3000>
         Require local
     </Proxy>


    ProxyPass /assets !
     ProxyPass /favicon.ico !
     ProxyPass /apple-touch-icon.png !
     ProxyPass /robots.txt !
     ProxyPass /ws ws://127.0.0.1:6042/
     ProxyPass /
http://127.0.0.1:3000/


    # change this line in an SSO setup
     RequestHeader unset X-Forwarded-User


     DocumentRoot “/opt/zammad/public”


    <Directory />
         Options FollowSymLinks
         AllowOverride None
     </Directory>


    <Directory “/opt/zammad/public”>
         Options FollowSymLinks
         Require all granted
     </Directory>


RewriteEngine on
RewriteCond %{SERVER_NAME} =support.cloud-net.tech
RewriteRule ^
https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

<VirtualHost *:80>
     ServerName support.cloud-net.tech
RewriteEngine on
RewriteCond %{SERVER_NAME} =support.cloud-net.tech
RewriteRule ^
https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

image

Note:

You need to make sure that you have enabled port 443 on your Firewall and changed the main protocol of Zammad to HTTPs

To do so you’ll need to get into the Zammad portal > Settings > System > Http Type and change that to HTTPS.

image

That’s it, my example here worked as expected and now my traffic is automatically getting redirected to https.

image

Hope this helps anyone looking for such configuration.

Please consider donating to this Bitcoin account if you like this article or website.

image