Wednesday, February 21, 2024

Asset Inventory for Security Teams

    The identification of all assets in any organisation is critical for several reasons. From a security point of view, this is essential for implementing proper protection. It enables organisations to establish appropriate security controls, access management policies, and incident response procedures to safeguard assets.
    I have created scripts that simplify the tasks associated with managing GCP Asset Inventory. I used Resource Manager and Cloud Asset APIs in order to create a central database. The choice of a spreadsheet interface was deliberate, driven by its simplicity. But it’s easy to switch to storing data in a database like big query or cloud sql. It’s also easy to use Looker Studio to present the results.
    I created 3 scripts at my GitHub project [1]. - main script which setup asset inventory. - script used to manage information about compute engines and - script used to manage information about GKE clusters and workloads.

Setup steps:
  1. Prepare the following information:
    1. GCP ORG ID
    2. ID of spreadsheet for cache database (just create new spreadsheet)
    3. ID of spreadsheet for inventory database (just create a new spreadsheet)
  2. Create a new project in Google Apps Script and place 3 files from my Github project. It is also required to create a Service Account in GCP with a role which can collect information from the GCP Resource Manager. The full setup is more complex and it can be a topic for a separate article). 
  3. Provide information from point 1 to
  4. Configure config_scope in At the moment supported features are: Compute Engines (COMPUTE_ENGINES) and GKE Clusters (GKE_CLUSTERS) including Pods and Deployments.
  5. Run setup_cache_db() - in this step a temporary database of assets is created.
  6. OPTIONAL STEP: set priorities for GKE clusters (it is important when you have a prod and non-prod environment, non-prod must have lower priority). You can set priorities in cache.db.
  7. Run function run_asset_inventory from file - in this step script collects information about all assets and stores it in cache.db.
  8. Run setup_inventory_db function - in this step final asset inventory db is created. 
  9. Run run_scheduled_scan_vm_asset_inventory function from and run_scheduled_scan_gke_asset_inventory function from Both scripts copy information from cache.db to main inventory.
  10. The final step is creation triggers in the App Script console.


Sunday, January 15, 2023

Monitoring of operating system versions in Google Workspace

Let’s continue the presentation of examples of use event logs from Google Workspace. Today I’ll describe how to use event logs to check and notify users about outdated versions of the operating system. The idea is to inform users via email that newer versions of the operating systems are available to install. Described methods work for all popular operating systems - e.g. MacOS, Windows, Linux, iOS or Android. 

Keep in mind that this method only notify users and/or administrators. The next step is to enforce installation of the new version. MDM systems can enforce such installation or we can use Google Workspace Context-Aware Access to prohibit older versions. 

Described use case: User just after login to Google Workspace receives notification via email that newer version of the operating system is available.

Source code described here is available at github repository:

The main function is main_version_monitor(). The first function is read_dates(). The function is using a spreadsheet to store the date of the last execution of the script. The main function should be executed at least every 5-10 minutes in order to notify users as soon as possible. We use the last execution date because in the next function read_events() is calling AdminReports.Activities.list() GSuite API which retrieves a list of activities. The read_events() collect 6 types of data from Google Workspace events: DEVICE_TYPE, DEVICE_MODEL, OS_VERSION, SERIAL_NUMBER, date and email of user. 

try {
 response = AdminReports.Activities.list(
 userKeyA, //”all”
 applicationNameA, //”mobile”

catch (error) {

if (params_event[zm4].name == "DEVICE_TYPE")
 device_type_vod = params_event[zm4].value;
if (params_event[zm4].name == "DEVICE_MODEL")
 device_model_vod = params_event[zm4].value;
if (params_event[zm4].name == "OS_VERSION")
 os_version_vod = params_event[zm4].value;
if (params_event[zm4].name == "SERIAL_NUMBER”
 serial_id_vod = params_event[zm4].value;


The next important function is compare_version_v2(). As you can see we are able to collect from the Device Action event information about the version of the operating system. Now, we have to inform the function which operating systems are approved. We are using a spreadsheet as a database of approved versions. An example is below:

Function is quite simple:

function compare_version_v2(version_to_check){

var handler_to_file = open_spreadsheet_file("", "supported versions");

for(var zmx = 1; zmx<handler_to_file[10].length;zmx++ )


 if(handler_to_file[10][zmx] == version_to_check)

   return true


 return false;


Finally, we have to prepare a message which will be sent via email.

Sunday, November 06, 2022

Using IP geolocation to detect suspicious logins to GSuite

Today I will describe how to detect suspicious login activities to Google Workspace.

I am using AdminReports.Activities.list API ( from my Apps Script script ( To limit results I will filter only login applications ( According to documentation the Login application’s activity reports return information about different types of Login activity events. The most important events are: login_failure and login_success.

Below function returns 4 fields (email of user, event name, event time and source IP address). we have to provide two parameters to our function - start date and end date. It is important to store end date in order to provide this value during next call.

function Logins(starts, ends) {

    var pageToken, responseX;

    var userKey = "all";

    var applicationName = "login";

    var table = [];

    do {

        var optionalArgs = {

            maxResults: 20,

            startTime: starts,

            endTime: ends,

            pageToken: pageToken,


        responseX = AdminReports.Activities.list(





        var activities = responseX.items;

        if (activities && activities.length > 0) {

            for (i = 0; i < activities.length; i++) {

                var activity = activities[i];

                if (

          [0].name == "login_failure" ||

          [0].name == "login_success"









        } else {

            Logger.log("No logins found.");


        pageToken = responseX.nextPageToken;

    } while (pageToken);

    return table;


I also had to create function responsible for retrieving GEO IP values (City, Country and continent). I decided to us database via API but you can choose any other geo ip database.

function example_function(){

var result_from_logins = Logins(“2022-10-06T19:23:13.280Z”, “2022-10-07T19:23:13.280Z”);

var geo_ip_data = getIpGeolocationData(result_from_logins[counter][3],'CITY, COUNTRY');



A part of function getIpGeolocationData is presented below:

ipData = isBlank(ip)? getResponseJsonData('') : getResponseJsonData('' + ip);

Result is returned as JSON. In Apps Script fetch method is used from UrlFetchApp class to call ipbase API.

function getResponseJsonData(url) {

    if (isBlank(url)) return;

    let response = UrlFetchApp.fetch(url, {

        headers: {

            apikey: APIKEY,



    let json = response.getContentText();

    return JSON.parse(json);


Results can be written to spreadsheet or send directly to the SOC team. I am writing data to spreadsheet where each tab contain suspicious activities from one day. It is also possible to filter countries and email address to limit false alarms then SOC team can focus only on admin accounts and logon events from some countries.




Cloud Security

I come back after a quite long break in publishing posts. During last 4 years I was engaged in building a bank in the cloud. SSDLC, security of CI/CD, workspace security including mobile devices, cloud security, k8s security, security monitoring, access control or identity protection are in area on my responsibility. I am going to publish at this site posts related to listed topics. Source code used by me is stored at this repo:

As you can see I’ve also changed domain name to the .cloud as I will mostly focus on cloud security topics. 

Tuesday, December 28, 2010

Breaking PIN for software tokens

Software tokens usually use PIN for accessing token functions. Some vendors avoid implementing methods of validating PIN within an application. PIN is validated implicitly by validating dynamic password or response value generated by the application. It is possible because PIN is hashed and then the result (key) is used to decrypt a main key. Next, the main key is used by the application to generate OTP. So when the wrong PIN is provided, the application will decrypt incorrect key and will generate not valid OTP.

But under some conditions it is possible to find out the right PIN code. First of all, we have to obtain at least one valid OTP. For time based tokens we have to know the time when the valid OTP was generated. For counter based tokens we have to find out the counter value. It can be a problem so the attack is more effective when we know an approximate value of the counter for corresponding OTP. The counter is stored in local database of the application and usually we are able to modify the content.

The last step is to perform brute force attack and to compare the values of two dynamic passwords. After every try we have to recover the previous value of the counter (for counter based tokens) or set the right time (for time based tokens).

The attack is very difficult to perform against mobile devices with offline software tokens. We have to have an access to local database of mobile device and capture valid OPT which is send via network.

Tuesday, June 15, 2010

Two-Factor Transaction Authentication

More and more banks to mitigate banking frauds implement new methods of authenticating electronic transactions. Few methods rely on the customer's mobile phone. It looks that today the most popular are SMS messages and software challenge response tokens. Both methods can help in detecting the Man in the Browser attack. And in both cases the customer is able to verify details of transaction during making a payment.

A discussion about which method is "better" seems to be quite interesting. One of such discussion takes place on the OWASP-POLAND mailing list. What "the better" mean? It is tricky to justify which method is "better" because banks must consider several factors. Security is important but system has to be customer-friendly and inexpensive.

I am not going to write here about attack vectors and all pros & cons but in my opinion method which is based on SMS messages has more advantages.

The customer can receive SMS message with transaction details including full destination account number, an amount and an authentication code (valid only for particular transaction). The code is used by the customer to confirm the transaction. When the customer submits authentication code to online banking system then the bank will consider that the customer has just verified transaction details and accepted the payment.

The second method is not customer-friendly enough and can have security issues. I have to emphasize here that I do not have knowledge about all solutions which are available on the market and it is possible that some solutions work in different way and offer different level of security.

As I mentioned, the second method is based on software challenge response tokens. An application (software token) is installed on the customer's mobile phone. Bank and the customer shares the same secret key which is used to generate and verify challenge and response codes.

When the customer makes a payment, the bank's application generates the challenge by using destination account number, an algorithm and a secret key. Only few digits from destination account number are used to create the challenge. Of course all destination account number can be used but then the challenge will be too long. The customer submits the challenge to the mobile phone and after acceptance, details about transaction are displayed on the screen (but only selected digits from destination account number) - the challenge, the algorithm and the secret key are used to calculate and display such information. Sometimes bank requires from the customer to submit additional information like the amount of payment. And then this value is used to calculate the response. In next step, the customer submits the response code to internet banking application. When everything is fine, the bank will accept the transaction. It is a little bit complicated, isn’t it?

I'm going to write more about algorithms in next article. Here let's just focus on numbers.
So why such system can have more secure issues than SMS messages? All because of the challenge code length. Limitation of challenge code length does not allow to display all numbers of destination account. For example, in 6-digit challenge it is possible to “hide” only 4 digits from destination account number.

We can imagine an attack vector where an intruder will use different account numbers which contain the same 4 digits like original destination account number. It is important to mention about the length of IBAN notation of destination account number. The IBAN consists of the Country Code, a 2-digit checksum, a Bank code and the account number. The account number in Poland has 16 digits.

Now, let’s try to calculate the probability of above attack vector. I will use the formula for classical probability P(A) = n (A) / n (S).
Below calculations are performed for the attack where victim and mule accounts have the same Bank code. It is very popular scenario used by frauders. Calculation are done for 4, 5 and 6 digits. Also, I checked if showing first 2-digit checksum from destination account number decreases the risk of the attack.

In addition to the formula I created the Python script to compare results. The script generates the valid account numbers.

Variant 1A – last 4 digits are extracted from the challenge and displayed on mobile phone. Probability is 1:10000. It means that we have to have 10000 accounts to perform a successful attack. Few valid account numbers:


Variant 1B – first 2 and last 2 digits are extracted from the challenge and displayed on mobile phone. It is important to emphasize that the checksum is only used to verify if an account number is correct. It is not related to security and we can notice that probability of attack is the same 1:10000. The result received from my script is presented below:

Variant 2A – last 5 digits. Probability is 1: 100000. Few examples of valid account numbers:


Variant 2B – first 2 and last 3 digits. Probability is 1: 1:100000. The same is for Variant 2A.


Variant 3A – last 6 digits. Probability is 1:1000000.


Variant 3B – first 2 digits and last 4 digits. Probability is 1:1000000.


Above examples show that the risk of attack is very low but the situation can change when we consider that destination account is in different bank and/or that few last digits have value 0 (what sometimes can be true).

Thursday, June 03, 2010

Internet Banking Security

Last few months I was engaged in projects related to internet banking security. I was performing analysis of various variants of malicious software called “banking Trojans” and spent a lot of time playing with fraud detection systems. Currently I am involved in another project related to new methods of transaction authentication. In the meantime I was invited to workshops for the police officers and prosecutors.
I would like to share some materials (in Polish) that I prepared for these workshops. I hope that it can be useful for some of you. First document is available at