The specified module ‘MSAL.PS’ was not loaded because no valid module file was found in any module directory.

Recently when I used Dynamics 365 Finance and Operation tools plugin for Azure Devops I faced an issue with a missing Powershell module.

Error message:

##[error]The specified module 'MSAL.PS' was not loaded because no valid module file was found in any module directory.

In order to bypass this issue, add a PowerShell step with the below commands:

Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module MSAL.PS
Import-Module MSAL.PS

Your final pipeline should look like the one below.

An additional issue you may face, could relate with the service connection authentication endpoint. The error indicates that the common endpoint cannot be used and the specific tenant-endpoint should be used instead.

##[error]AADSTS9001023: The grant type is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.

Go and edit your service connection details

Endpoint URL:

https://login.microsoftonline.com/organizations

Be sure that your user has sufficient privileges and that prerequisites are met as documented from Microsoft.

LCS doesn’t support service-to-service authentication. Therefore, only regular user credentials (that is, a user name and password) can be used. Because the pipelines don’t run interactively, multifactor authentication must not be set up for the account that you use. We recommend that you set up a separate user account that has limited access and strong credentials that can regularly be rotated for security purposes.

Create an LCS connection in Azure Pipelines

https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-tools/pipeline-lcs-connection

Export Github Organization Dependencies as text

Github has introduced a powerful feature to get complete view on your project dependencies. This feature is available per project but also for a whole organization which could contain hundred of projects.

You can get all your dependencies for your organization using the below link (ORG should be replaced with your GitHub organization name)

https://github.com/orgs/ORG/insights/dependencies

I was searching a method to get massively these dependencies exported as a file. I could obtain this information using the below code with the inspect element section of Chrome browser.

elements = document.getElementsByClassName("js-navigation-open");
for (var i=0; i <elements.length; i++ ){
    var singleElement = elements[i];
    console.log(singleElement.outerText);

The result is a list with the names of the dependencies.

Unfortunately this method will only get the dependencies that are present on each page that you are currently browsing.

Trigger Azure Devops build pipelines using REST API

In some cases you may need to schedule pipelines execution on nights but the schedules yaml feature cannot accomplish your needs. This could could happen if you have to provide parameters as inputs on the pipelines for a specific project export/import. In this case you could trigger your pipelines with REST APIs using ansible or another scripting tool.

In this article I will explain how you could trigger pipelines execution using the REST API of Azure Devops.

First things first you should create a personal access Token (PAT) in order to get the access required to run the pipelines on your organization. You can accomplish that by pressing your profile icon and selecting the sub-menu shown below.

You can specify the expiration of the token along with the access permissions. For the simplicity of deployment I gave it full access. You will need to copy the token somewhere as it will not be accessible after the creation.

In order to trigger a new build we would have to use the POST HTTP verb. Along with that we will need the repository name, the project name and the build pipeline ID. The below URL uses build API of version 6.1-preview.6 with the parameters

Organization: GeralexGR
Project: test-project

https://dev.azure.com/GeralexGR/test-project/_apis/build/builds?api-version=6.1-preview.6

Using CURL we can get information of runs for a specific pipeline. For example in order to get the latest runs for pipeline with ID:11. In the below example you should replace PAT with your provisioned personal access token.

curl  --user '':'PAT' --header "Content-Type: application/json" --header "Accept:application/json" https://dev.azure.com/GeralexGR/test-project/_apis/pipelines/11/runs?api-version=6.1-preview.1

In order to implement a run of a build pipeline using REST APIs I will use Postman.

The selected verb is POST and the URL is the one mentioned above. By giving the URL on the input field, POSTMAN will automatically enumerate Query parameters.

In Authorization tab you should select Basic Auth. The username can be empty and the password will be your PAT.

On Headers tab, add Content-Type as application/json

In the body, you should specify the build pipeline ID in the JSON format that is shown in the picture. If you press Send, you will successful trigger your build pipeline with ID 11.

The next step is to edit the pipeline to include also input parameters.

In order to do that, I will use the latest version of the REST API that uses the runs URL instead of builds.

As shown in the picture the request URL will be pipelines/buildID/runs

https://dev.azure.com/GeralexGR/test-project/_apis/pipelines/11/runs?&api-version=6.1-preview.1

The logic of the pipeline will only print the parameters that has been provided as input on the REST API.

trigger:
- none

pr: none 

pool:
  vmImage: ubuntu-latest

parameters:
  - name: name
    displayName: Tell me your name.
    type: string
    
steps:
- script: echo ${{parameters.name}} "succesfully triggered this build from a REST API call"
  displayName: 'print message from automatically created pipeline'

You can see in the result that my name is printed.

Azure Devops Rest API documentation:

https://docs.microsoft.com/en-us/rest/api/azure/devops/pipelines/runs/run-pipeline?view=azure-devops-rest-6.0

Email spoofing using Postfix – How I hacked my own email for testing purposes

It was a nice morning when I woke up and started surfing before going to work. Little did I know for what will happen that day. Outlook sent me a notification email, the one you can see below. At first I got shocked. I understood immediately that it was a spam email asking for money through crypto payments, but how did the sent it from my email address? The sender was me and the recipient was also me.

If you check carefully the email originator is the same email as the recipient. Did I got hacked? I instantly went to change my passwords and enable MFA option (yes you should do that before you get p0wned).

After contacting my host provider for logs (I wanted to make sure that the mail server was not affected) I started investigating the email. At first it seems like a normal one. By investigating further, I checked the headers.

Oups something seems strange here. The received from headers point an unknown host, the one that tried to trick me. Mister I could send you back the same email from your own address.

Return-Path: <support@brightdirectories.com>
X-Original-To: webmaster@geralexgr.com
Delivered-To: webmaster@geralexgr.com
Received: from cloudvpsserver.host.brightdirectories.com (unknown [64.91.244.139])

spf=pass (sender IP is 64.91.244.139) smtp.mailfrom=support@brightdirectories.com smtp.helo=cloudvpsserver.host.brightdirectories.com

This method of attack is called spoofing and you can read more details from the below article.

https://www.proofpoint.com/us/threat-reference/email-spoofing

Lets try to implement the same attack now, to understand how difficult this could be. The only thing that you will need is a linux machine running postfix and sendmail package. As simple as that and you become a spoofing hacker.

First things first, install and start postfix service.

yum install postfix sendmail; systemctl start postfix

Edit postfix configuration to allow all inet_interfaces.

vi /etc/postfix/main.cf

Then we will try the first spoofing attempt.

[root@centos-lab ~]# sendmail -v webmaster@blablabla.com < mail.txt

The attempt failed. What happened though? By checking the logs, I could find that mail server blocks some incoming messages based on spamhaus service.

Is that hard to bypass? Totally not. You have to go on spamhaus link and whitelist your IP address. The next time the service is updated, your email will be received from the mail server. I have to say that more advanced mail services like google, outlook provide much more sophisticated services to block spam than spamhaus.

By trying to send again my email, I successfully spammed my own mailbox. Lets try a google account this time. I will try to send an email from my personal domain account email to my gmail account. However this would be a spam email as the origin will be a local postfix service that tries to impersonate the real owner.

sendmail -v my_Gmail < mail.txt

You can find my mail.txt contents below.

From: webmaster@blablabla.com
Subject: spoofing email attack this email was sent from an unknown sender using postfix 

Voila. I received a spam email from a sender that is not the original one.

If you check more carefully, google adds a question mark and informs you that it could not verify the owner of the email. However the spam went directly to my mailbox and did not arrive on spam.

If you check the headers again, you will verify that the originator is fake

Original Message
Message ID	<202111202159.1AKLxI8x016745@geralexgr.com>
Created at:	Sat, Nov 20, 2021 at 11:59 PM (Delivered after 2 seconds)
From:	webmaster@blablabla.com
To:	
Subject:	spoofing email attack this email was sent from an unknown sender using postfix
SPF:	FAIL with IP 2.84.53.88 Learn more


Download Original
Copy to clipboard

Delivered-To: 
Received: by 2
Received: from geralexgr.com (IP_address. 
Received-SPF: fail (google.com: domain of root@geralexgr.com does not designate IP as permitted sender) client-ip=xxxxxx;
Authentication-Results: mx.google.com;
       spf=fail (google.com: domain of root@geralexgr.com does not designate 2.84.53.88 as permitted sender) smtp.mailfrom=root@geralexgr.com
Received: from geralexgr.com (localhost [127.0.0.1]) by geralexgr.com (Postfix) with ESMTPS id 88E031099F6B for <xxxxxx>; Sat, 20 Nov 2021 23:59:18 +0200 (EET)
Received: (from root@localhost) by geralexgr.com (8.15.2/8.15.2/Submit) Sat, 20 Nov 2021 23:59:18 +0200
Date: Sat, 20 Nov 2021 23:59:18 +0200
Message-Id: <202111202159.1AKLxI8x016745@geralexgr.com>
From: webmaster@geralexgr.com
Subject: spoofing email attack this email was sent from an unknown sender using postfix

As you can see from headers, the real sender is root@localhost and not the sender that is shown on gmail. You can also locate the incoming IP address.

To conclude we examined how one could spoof your email account and impersonate your self. Be very careful on the emails you receive and double check the originator. It is very easy to get hacked with this technique.