Skip to main content

Overview

 

Welcome back to our series on Actionable Threat Hunting with Google Threat Intelligence! This time, we're going to talk about a huge phishing scam that's just happened in the last few months. It's connected to Booking, which is one of the most popular websites for booking hotels.

Our main goal here is to show you how just one email we got helped us figure out how big this scam really was. We also found some interesting files that seem connected to Telegram messages the threat actors used. And don't worry, we'll share some of our code from Google Colab so you can try this yourself!

One clever thing about this scam is that the threat actors sent messages directly to victims through Booking's official website. They even used the message chats from bookings people had already made. This strongly suggests that the threat actors were somehow able to access this information through a method that is currently unknown.

 

‘Your reservation is at risk’

 

If you've recently received an email that appears to be from Booking.com, or even a message in the message thread of the Booking application for a reservation you had saying “your reservation is at risk”, don't worry, you're not alone.

For several weeks now, several users have reported a massive Booking phishing campaign where the actors behind the phishing sites are attempting to steal information such as credit cards. Pictured in Figure 1 is an example of a message sent through the Booking chat, using a real reservation thread.

Figure 1: Example of message discovered in a phishing website related to booking.com

 

According to our analysis, the phishing message is sent using two different ways:

  1. Through the Booking.com website or mobile application, within the conversation thread with the hotel reservation. 
  2. Through email from a legitimate Booking message.

For example, if you have a reservation at a hotel in Los Angeles made via Booking, the attackers will send you a message in that reservation's chat, stating that your booking is at risk and you must update your card details, otherwise it will be canceled.

Due to Booking.com's functionality, all messages sent via chat are also delivered to the user by email, which means the user receives the same message twice through two different channels.

In this campaign, the message the user receives contains a supposed URL that they must click to enter their card details and prevent their reservation from being canceled. Based on our observations, these URLs serve only as redirectors to the sites that actually host the fraudulent content.

Therefore, the actors registered Tier 1 domains that simply act as redirectors to the Tier 2 domains. The Tier 2 domains contain the content for stealing the victims' credit card details. Additionally, these domains were registered with names similar to "Booking" to make the user think it is the legitimate domain.

AD_4nXcgY2g20_qq53u9qC5ITt3rkwjhkDCe11PRmPxLiLWG5Baaw6gyL01K3LCqtHbWUeIsrMoFvb10_75OTdRAHi1IkO5cNDoxpjIS9STHNILc5vGI7XnLSZbBJkdXnO4SCe-aVPzmGvY?key=fkCb0wiTLWAGZ9qqI8EbUA

Figure 2: How this phishing is usually distributed

Discovering Tier 1 infra

 

The email we received had a domain setup that looked like ohotel_name]. 3_letters]-]2_letters].com (for example: hostelmandarinkauxeh.eto-lan.]com). What's important here is that the first part of this domain name was actually the name of a real hotel from a current booking.

After you clicked the link from the Booking chat, it redirects you to a different URL. This new domain name tried to look like a real Booking domain, and its name often looked like booking.confirmation-ido5_numbers].com.

Knowing how redirects work, and the patterns of both domains, we can make different searches to help us find possible URLs related to the campaign.

The first query is to find Tier 1 URLs that redirect to Tier 2 URLs. To do this, we want to avoid getting results that are Tier 2 URLs. We can use the redirects_to modifier to set the pattern found in the Tier 2 URLs, which is the typical behavior. We will also use the hostname modifier to only show results for URLs that might be Tier 1.

entity:url redirects_to:"https://booking.confirmation-*" and not 
hostname:"booking.confirmation-"

 

The results we expect from this search are URLs related to Tier 1 domains. Some example URLs we find will match the patterns we described earlier:

AD_4nXcbpHne4q4ZLmVSsdOlo8wAcCsDga1-8atJVlDLfQ33t0fpha879PCGiVLNJ-qsqUBS6hJJBYqcDEtXmhhoE78XzLy8oJD06tDtJzK3ZkD4Znps7zhpWIbONIiDxTPiEJfwNC0aIQ?key=fkCb0wiTLWAGZ9qqI8EbUAFigure 3: Results obtained from the query used looking for Tier 1 URLs

 

With the results we have, we now want to find certain patterns that all these URLs share. This way, we can widen our search to find new possible URLs related to both Tier 1 and Tier 2 infra. Let’s focus on the HTML information from these URLs obtained in the first query.

For the following code examples we are going to use vt-py, we recommend you read the documentation and the examples that we have available in our GitHub repository to get familiar. The next code snippet is the base to build the rest of the code snippets that we have to obtain different kinds of data.

<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#FFFFFF"><path d="M480-120q-33 0-56.5-23.5T400-200q0-33 23.5-56.5T480-280q33 0 56.5 23.5T560-200q0 33-23.5 56.5T480-120Zm-80-240v-480h160v480H400Z"/></svg>

DISCLAIMER: Please note that this code is for educational purposes only. It is not intended to be run directly in production. This is provided on a best effort basis. Please make sure the code you run does what you expect it to do.

 

# Base code

# Before running the code, make sure you have enough quota to do so. This query can consume a lot of quota.

import vt

cli = vt.Client(getpass.getpass('Introduce your VirusTotal API key: '))

query = "entity:url redirects_to:\"https://booking.confirmation-*\" and not hostname:\"booking.confirmation-\"" # @param {type: "string"}

# Look for the samples

query_results_t1 = q]

async for itemobj in cli.iterator('/intelligence/search',params={'query': "%s"%(query)},limit=0): # Set the limit you want

    query_results_t1.append(itemobj.to_dict())

all_results_t1 = list(json.loads(json.dumps(query_results_t1, default=lambda o: getattr(o, '__dict__', str(o)))))

 

From the initial query that we ran, let’s get the HTML titles and group them to identify the most observed. We can achieve this by running the following snippet in our Google Colab.

# Get URL Titles

df = pd.DataFrame(columns=d'title', 'url'])


for item in all_results_t1:

    # Get the 'attributes' dictionary from the current item, defaulting to an empty dictionary if not present
    attributes = item.get('attributes', {})
    # Get the 'title' and 'url' values from the attributes dictionary
    title = attributes.get('title')
    url = attributes.get('url')
    # Check if both title and url are present (not None or empty)
    if title and url:
        # If both are present, create a new DataFrame with the title and url
        # and concatenate it to the main DataFrame. ignore_index=True resets the index.
        df = pd.concat(rdf, pd.DataFrame({'title': ttitle], 'url': url]})], ignore_index=True)

# Group by title and count the number of URLs
title_counts = df.groupby('title') 'url'].count().reset_index(name='url_count')

# Sort by url_count in descending order
title_counts = title_counts.sort_values(by='url_count', ascending=False).reset_index(drop=True)

# Display the resulting DataFrame
display(title_counts)

 

Running the last code snippet, the TOP 5 titles we obtained were the following:

Title

Count

One moment...

779

One moment…

67

AD not found (captcha2)

46

Suspected phishing site | Cloudflare

5

booking.confirmation-id83974.com | 521: Web se...

5

 

The first two results might look the same, but they are not. The difference is the dots used after One moment. In this case, it seems the first three results are the most common, so we can save this information to build a search later. Please note that these values can be used with the title modifier for URLs.

Another interesting piece of information that could help find new URLs is the <meta> tags from the URLs we've identified. To do this, we will run a search like before, but this time, instead of titles, we will look at the values of any <meta> tag. These values can be used with the meta modifier.

# Get meta values

from collections import Counter

all_meta_values = t]

# Iterate through each item in dsaaaa (assuming this contains the relevant data)
for item in all_results_t1:
    attributes = item.get('attributes', {})
    html_meta = attributes.get('html_meta', {})
    # Iterate through the values of the html_meta dictionary
    for meta_values_list in html_meta.values():
        # Extend the all_meta_values list with the items from the current list
        all_meta_values.extend(meta_values_list)

# Count the occurrences of each unique meta value
meta_value_counts = Counter(all_meta_values)

# Convert the counts to a pandas DataFrame
df_meta_counts = pd.DataFrame(list(meta_value_counts.items()), columns=v'Meta Value', 'Count'])

# Sort by count in descending order
df_meta_counts = df_meta_counts.sort_values(by='Count', ascending=False).reset_index(drop=True)

# Display the resulting DataFrame
display(df_meta_counts)

 

The results we got from the <meta> tags were very interesting, and there were over 750 possible results. First, we found many meta values that actually were URLs storing images. Some of these images were icons used on fake websites, and others were from hotels hosted in a legitimate Booking domain.

  • URL identified in the <meta> tags 126 times: hxxps://ltdfotom.]ru/images/2025/06/04/photo_2025-06-02_11-23-22.md.jpg
  • URL identified in the <meta> tags 14 times: hxxps://cf.bstatic6.]com/xdata/images/hotel/max300/619949340.jpg?k=971fb717a1df5b8d7ae0b077411493921f7f041a8992a9deb4d11b8aef870571&o= 

Bstatic.com is a legitimate domain owned by Booking. Multiple images hosted in that domain were discovered in the <meta> tags of the phishing websites.

We also found many strings in the <meta> tag values that started with Booking - >hotel_name]. This finding is interesting because there were up to 400 possible results that started this way. Some examples were the following:

Meta string

Count

Booking - HEIMALEIGA - Your Icelandic home awa...

24

Booking - Grand Hotel Duomo

9

Booking - FOUND Hotel Carlton Nob Hill

7

Booking - La Castellana

7

Booking - Payment verification

7


Booking - Villa Preselle Country Resort

1

Booking - Hotel Hagemann

1

Booking - Tahiti Airport Motel

1

Booking - Hotel Aldea Berlin

1

Booking - Fasthôtel Clermont-Ferrand Gerzat

1

 

Basically, with these results, we can now add more filters to our first search or even create a new one. The following query can help us to expand the results and get new URLs that could be related to some Booking campaigns, even before this one.

entity:url fs:2024-09-01+ (title:"One moment" or title:"AD not found 
(captcha2)") and (meta:"Booking -" or
meta:"https://ltdfoto.ru/images/2025/06/04/photo_2025-06-02_11-23-22.md.jpg" or
meta:"https://cf.bstatic.com/xdata/images/hotel/") and not
(hostname:"booking.confirmation-" or hostname:"booking.com")

AD_4nXdu4Lx7D2iJwfIkQbFmyKQBGUt1LOTU2mtzuL8mD7tFvcEPmNkis-BmIsAwUwsxEbS_WLVAKdh-lpI7665yl1byM_JnGMaL6txWUa-O8g0pbVv18h7nTo7eO7DyOJlxbB56zc6qQoA?key=fkCb0wiTLWAGZ9qqI8EbUA

Figure 4: Ways to do hunting in the Tier 1 infra (download format)
 

Discovering Tier 2 infra

 

We have enough information to also find Tier 2 infrastructure set up by the actors. The first thing we will do is look for domains that match the patterns we found earlier, with the following search. The next search gives us over 100 recently registered domain results.

entity:domain domain_regex:"^booking\.confirmation-idc0-9]{5}\.com$"

AD_4nXfo_ZAHz5w2ba4r4Lgm38WWcNdvkR0L40Y8VEtZ37vk6spZDmN4kQiOFRjE1TXSD7ohFuyuqYbqSo2dTf320bIeW7_s_jAcmBhjVVTom0_2Jpmr6Oe-2b66Ijq_loutqZX9kFKhTvk?key=fkCb0wiTLWAGZ9qqI8EbUA

Figure 5: Tier 2 domains matching the query regex

 

The next step is to find URLs that have that pattern in their hostname. One of the best queries that we can run in this case is the following.

entity:url hostname:"booking.confirmation-id*"

Around 1,500 URLs match the hostname criteria, and all of them are related to Booking campaigns. In fact, the oldest URL was uploaded to the platform in November 2023.

To follow the same idea we used with the Tier 1 URLs, it would now be good to look for titles and patterns in the <meta> tags for all these new URLs discovered with the last query. This could help us find new possible phishing sites. For the titles we obtained the following results.

Title

count

AD not found (captcha2)

492

One moment...

300

Booking.com | Official website | Best hotels and accommodation

43

One moment…

33

403 Forbidden

23

Booking.com | Official site | The best hotels & accommodation

17

Suspected phishing site | Cloudflare

16

404 Not Found

16

Just a moment...

14

Booking.com | Official site | The best hotels, flights, car rentals & accommodations

8

 

Strings like One moment or AD not found (captcha2) were seen before in the Tier 1 infrastructure. However, in this case, we also see another title pattern that could be interesting to find other URLs, like Booking.com | Official.

For patterns found in the <meta> tags, we saw similar results. However, there are also values that start with Booking.com followed by the hotel's name, similar to the pattern identified in infra Tier 1 Booking - followed by the hotel's name. 

 

Meta String

Count

httpst:]//ltdfotos.]ru/images/2025/06/04/photo_2025-06-02_11-23-22.md.jpg

68

light dark

40

Booking.com

34

company

34

https3:]//www.booking>.]com

26

Booking.com Hotel Reservations

16

com.booking

16

Booking.com: The largest selection of hotels, homes, and vacation rentals

16

@bookingcom

16

Booking - Wind Hotel

3

Booking: Barcelona City North Hostal

2

 

Based on the results, if we want to create a new query and make sure we only get URLs related to the Tier 2 infrastructure, the next search will definitely give us that information.

entity:url (title:"One moment" or title:"AD not found (captcha2)" or 
title:"Booking.com | Official") and (meta:"Booking -" or
meta:"https://ltdfoto.ru/images/2025/06/04/photo_2025-06-02_11-23-22.md.jpg" or
meta:"https://cf.bstatic.com/xdata/images/hotel/") and
hostname:"booking.confirmation-*"

AD_4nXeFuZ_JcbHEycZluyhzmHn2f9XiHWgy2ervvC-wAhz3uzAs9MuSjNadLha3tXzMi8pOh8va3EW0Mp7BeRG3CbTPy72VNLM9Ah54vUT03kCOkD1Oj2Cpx4XeeAxb9vVlr5GHkhvDL4w?key=fkCb0wiTLWAGZ9qqI8EbUA

Figure 6: Tier 2 URLs matching the query

 

With this, we'll now have access to URLs that have been distributed by the threat actors for Tier 2. Next, we will put together all the URLs from both Tiers to better understand this campaign and get more details.

AD_4nXfrJx4w9mHVg4qmCwBS5udI0yvpyaoPQsXiG-moKK3wkNKh5PTn-ussd5pVZ96vzuW_UxzHKN7aHE8wNEXReVPg794YoRn0vZEh8z2poQ78fcrDo-HkuOl77-EOvkZ7Y4kkEFxWfQs?key=fkCb0wiTLWAGZ9qqI8EbUA

Figure 7: Ways to do hunting in the Tier 2 infra (download format)

We've uncovered the intricate layers of this massive phishing operation. Now, Part 2 reveals how we leveraged these discoveries to track the threat actors, uncover their tools, and empower actionable defenses.

This is interesting as there have been many malicious or suspicious activities by several actors on booking.com websites  and or their booking app by which they redirect you to telegram page. Then the actors would introduce you to daily tasks, asking you to complete a task by reposting or liking  some TikTok videos to get paid. When the tasks are completed, the actor will paid you in your residential currency and then the actors will ask to pay another actors to get more yields from your payment. Meanwhile the actor are waiting for you to send large amounts of money another actor before executing their attacks.  The management of Booking.com need to be alerted to be aware of several malicious activities carried out with their websites and app. Thank you.


Reply