Nội dung
Đây là câu chuyện thực tế về việc một subdomain của cá nhân Thạch Phạm – Founder & CEO của AZDIGI bị chiếm quyền kiểm soát thông qua kỹ thuật tái sử dụng địa chỉ IP của các dịch vụ Cloud công cộng lớn, và cách mình sử dụng Python kết hợp Google Search Console API để xử lý hơn 1000 sitemap spam trong thời gian ngắn nhất.
Mở đầu: Một email bất thường từ Google
Mọi chuyện bắt đầu vào một buổi sáng bình thường, khi mình nhận được thông báo từ Google Search Console:
Chủ sở hữu mới cho https://www.sub.domain

Đây là một subdomain mà mình đã ngừng sử dụng từ lâu, trước đó được tạo và trỏ về một địa chỉ IP dịch vụ Cloud của DigitalOcean. Droplet trên DigitalOcean đã được xóa, nhưng bản ghi DNS vẫn còn nguyên. Một sai lầm tưởng chừng như vô hại nhưng lại rất quan trọng.
Với kinh nghiệm tiếp xúc với SEO từ năm 2008, mình kiểm tra Google Search Console ngay để tìm điều bất thường, và hiện điều khủng khiếp: hơn 1000 sitemap XML đã được submit, tất cả đều chứa nội dung đồi trụy và spam SEO, hơn một nửa trong số đó đã có trạng thái xanh như lá chuối trên GSC.
Đây là Dangling DNS Attack — một kỹ thuật tấn công tinh vi đang ngày càng phổ biến khi nhu cầu sử dụng máy chủ ảo/cloud ngày càng phổ biến.
Phần 1: Hiểu Về Dangling DNS Attack

1.1. Dangling DNS là gì?
Dangling DNS (hay còn gọi là “DNS treo”) là tình trạng bản ghi DNS vẫn trỏ đến một tài nguyên không còn tồn tại hoặc không còn nằm dưới quyền kiểm soát của chủ sở hữu domain.
Theo định nghĩa từ Palo Alto Networks:
“When a subdomain is set as an alias… and the company moves away from that service but forgets the DNS record is still pointed to the expiring domain or external hostname/IP, attackers can use this Dangling DNS technique for phishing and other social engineering attacks.”
Microsoft cũng cảnh báo rõ ràng về mối nguy hiểm này:
“Dangling DNS records can pose significant security risks because they point to domains or services that no longer valid or under the domain owner’s control. Attackers can exploit these records by registering expired domains, gaining control over subdomains.”
1.2. Chuỗi tấn công xảy ra với mình
Chuỗi quá tình mình bị “diss” như sau, nhờ AI tạo hình cho trực quan nhé 😉.

Nếu không phát hiện ra kịp, chắc chắn không chỉ dừng lại việc submit 1000+ sitemap mà sẽ có những ảnh hưởng lớn hơn.
Phần 2: Tái sử dụng địa chỉ IP – Kỹ Thuật Tấn Công Cốt Lõi
2.1. Cơ chế cấp địa chỉ IP của các dịch vụ Cloud/VPS
Khi bạn thuê một server từ các nhà cung cấp cloud như AZDIGI, AWS, DigitalOcean, hay Azure, server được gán một địa chỉ IP công cộng từ IP pool của họ. Khi bạn xóa server, IP đó được trả về pool và có thể được cấp cho bất kỳ khách hàng nào khác.
Đây là cơ chế hoàn toàn bình thường để tối ưu hóa tài nguyên. Nhưng nó tạo ra một lỗ hổng nghiêm trọng khi kết hợp với Dangling DNS. Đặc biệt nguy hiểm với các dịch vụ mà người dùng có quyền linh hoạt tạo và xoá các máy chủ liên tục trong thời gian ngắn như DigitalOcean, AWS, Vultr, Linode,…
2.2. Nghiên cứu học thuật: Cloud Squatting
Vào năm 2022, một nhóm nghiên cứu từ Pennsylvania State University đã công bố nghiên cứu đột phá về vấn đề này. Họ gọi kỹ thuật tấn công này là “Cloud Squatting”:
“In a cloud squatting attack, an adversary allocates resources in the cloud (e.g., IP addresses) and thereafter leverages latent configuration to exploit prior tenants.”
— Nguồn: Pauley et al. – Measuring and Mitigating the Risk of IP Reuse on Public Clouds
Quy mô nghiên cứu thực sự đáng kinh ngạc:
| Metric | Số liệu |
|---|---|
| Số EC2 servers triển khai | 3,000,000+ |
| Số địa chỉ IP nhận được | 1,500,000 |
| Tỷ lệ pool được cover | 56% |
| Thời gian nghiên cứu | 101 ngày |
| Số tổ chức bị ảnh hưởng | 5,400+ |
| Bao gồm top-1000 websites | 23 |
“Our study of a small fraction of IP addresses on Amazon Web Services showed over 5,400 organizations potentially affected, including 23 of the top-1000 websites.”
2.3. Kỹ thuật Passive Subdomain Takeover
Kẻ tấn công không cần nhắm mục tiêu cụ thể vào mình mà sẽ đi scan hàng loạt, ai xui thì dính. Họ sử dụng kỹ thuật Passive Takeover — liên tục tạo ra VPS/Cloud với IP mới và kiểm tra xem có domain nào đang trỏ về IP đó không.
Theo phân tích từ kmsec:
“A much smarter approach: when you request an IP from cloud provider, it just assigns you a random IP. Check if the IP has a valid A record pointing to it. If a valid A record is found: spin up the malicious landing page, else: abort.”
— Nguồn: kmsec – Passive Takeover
Công cụ của attacker thường sử dụng Passive DNS data từ các nguồn như:
- SecurityTrails
- Shodan
- Censys
2.4. Vấn đề đặc thù với DigitalOcean
Nghiên cứu từ Smaran Chand (tháng 7/2025) chỉ ra rằng DigitalOcean có những điểm yếu đặc biệt:
“DigitalOcean Cloud DNS does not appear to have any protection mechanisms or safeguards in place to prevent this… An attacker who notices that a domain still points to DigitalOcean nameservers could simply add that domain to their own DigitalOcean account. Once added, they would have full control of the domain’s DNS records.”
Một nghiên cứu trước đó từ The Hacker Blog đã chiếm được hơn 20,000 domains trên DigitalOcean:
“If you delete the domain from your account anyone can immediately re-add it to their own account without any verification of ownership and take it over.”
— Nguồn: The Hacker Blog – Floating Domains
Phần 3: Google Search Console Abuse — Mục Đích Thực Sự
3.1. Tại sao attacker muốn chiếm GSC?
Khi đã kiểm soát được subdomain, việc xác minh ownership trên Google Search Console trở nên rất đơn giản, attacker chỉ cần upload file HTML verification hoặc thêm meta tag.

Theo phân tích từ Sucuri, mục đích của việc chiếm GSC bao gồm:
“Submit sitemaps of their spammy pages to have Google quickly discover them all, meaning they don’t have to wait for Google to discover the pages via links on other sites. Hackers might even think that Google will treat their spam pages as legitimate when they are submitted as part of a sitemap directly from a verified site owner.”
— Nguồn: Sucuri – Malicious Google Search Console Verifications
Lợi ích cho attacker:
| Mục đích | Giải thích |
|---|---|
| Indexing nhanh | Sitemap được submit từ verified owner sẽ được crawl ưu tiên |
| Tận dụng ưu thế của tên miền | Tên miền của nạn nhân có độ uy tín cao, thứ hạng tốt là con mồi béo bở |
3.2. Quy mô tấn công trong case của mình
Khi kiểm tra GSC, mình phát hiện:
- Số lượng sitemap: 1000+ files
- Nội dung: Nội dung người lớn, cá cược, bán hàng giả
- Thời gian submit: Chỉ trong khoảng 10 phút
Thực tế thời điểm nhận mail thông báo mình đã xử lý ngay chỉ trong 5-10 phút nhưng trong lúc đó attacker đã submit được 1000 file sitemap rồi, đáng sợ thật sự.
Đây là pattern phổ biến được Sucuri mô tả:
“In our experience, verifying site ownership is currently mainly used in attacks that create tons of spammy doorway pages in Japanese… They work in a niche of ‘cheap/fake brand goods’ so you can normally detect them if you search your site for keywords like ‘louboutin’, ‘gucci’, ‘louis vuitton’, ‘moncler’, ‘ray ban’, etc.”
Phần 4: Xử Lý Sự Cố — Sử Dụng Python và Search Console API
4.1. Vấn đề: Không thể xóa thủ công 1000 sitemap
Giao diện Google Search Console không thiết kế để có thể xoá nhiều sitemap trên mỗi trang, muốn xoá sitemap bạn phải nhấp vào từng file và chọn nút xoá ở góc phải phía trên, bất đắc dĩ làm thủ công vẫn được nhưng dĩ nhiên mình phải tìm ra cách nào đó xử lý nhanh hơn.
Dĩ nhiên là có rồi, đó là sử dụng Search Console API của Google, kết hợp nhờ AI viết một vài đoạn code để xoá sitemap là được. Và dưới đây là chi tiết quá trình setup để chạy script xoá sitemap hàng loạt trên Google Search Console với API.
4.2. Thiết lập môi trường
Bước 1: Tạo Service Account trên Google Cloud Console
Đầu tiên là cần tạo một project tại Google Cloud Console hoặc sử dụng một project đang có. Bật Google Search Console API lên.

Sau đó tìm mục Service Account và tạo một service account mới, chỉ cần nhập tên các tuỳ chọn khác giữ nguyên mặc định.

Tạo xong thì tải thông tin service account về với dạng JSON.
Bước 2: Cấp quyền cho Service Account trong GSC
Truy cập Google Search Console, vào mục cài đặt và thêm một người dùng mới là địa chỉ email của service account vừa tạo với toàn quyền quản lý. Email của service account có dạng xxx@project-id.iam.gserviceaccount.com.
Bước 3: Khởi tạo môi trường Python ảo và cài package
mkdir -p ~/gsc-sitemap-remove
cd ~/gsc-sitemap-remove
python -m venv venv
source venv/bin/activate
pip install google-api-python-client google-auth google-auth-httplib2 google-auth-oauthlib
4.3. Script xóa hàng loạt sitemap
Bạn copy file .json của service account vừa tải về vào thư mục của code này và đổi tên thành service-account.json.
Tạo một file .py tên bất kỳ và sử dụng code bên dưới.
Nhớ sửa lại domain ABC.com hoặc sử dụng sc-domain:ABC.com nếu GSC của bạn sử dụng property dạng tên miền (thay vì chỉ theo tiền tố URL).
from urllib.parse import quote
from google.oauth2 import service_account
from googleapiclient.discovery import build
# 1) Chọn đúng property
SITE_URL = "sc-domain:ABC.com" # hoặc "https://ABC.com/"
# 2) Subdomain bị spam sitemap
SPAM_HOST = "www.SUB.ABC.com"
# 3) Service Account JSON (đã add email SA vào GSC property)
SERVICE_ACCOUNT_FILE = "./service-account.json"
SCOPES = ["https://www.googleapis.com/auth/webmasters"]
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
# Lưu ý: API sitemaps nằm dưới webmasters v3
svc = build("webmasters", "v3", credentials=creds)
# List sitemaps
resp = svc.sitemaps().list(siteUrl=SITE_URL).execute()
sitemaps = resp.get("sitemap", [])
targets = []
for sm in sitemaps:
# field "path" là URL sitemap đã submit
path = sm.get("path", "")
if f"://{SPAM_HOST}/" in path or path.startswith(f"https://{SPAM_HOST}/") or path.startswith(f"http://{SPAM_HOST}/"):
targets.append(path)
print(f"Found {len(targets)} spam sitemaps to delete")
# Delete từng sitemap
for feedpath in targets:
try:
svc.sitemaps().delete(siteUrl=SITE_URL, feedpath=feedpath).execute()
print("Deleted:", feedpath)
except Exception as e:
print("Failed:", feedpath, "=>", e)
Bạn có thể thử kiểm tra trên Google theo cú pháp site:domain-bị-tấn-công xem có link nào bị index không, nếu có thì nhờ ChatGPT viết đoạn code Python sử dụng Search Console API để gửi yêu cầu xoá index số lượng lớn nhé.
Tạo xong thì chạy script thôi, ví dụ:
python remove.py
Quan trọng nè, dùng xong nhớ revoke cái service account vừa tạo đi nhé.
4.4. Kết quả thực thi
Sau khi chạy script:

Tổng thời gian xử lý: ~15 phút (với rate limiting 0.5s/request)
Phần 5: Hậu Quả Nếu Không Kịp Xử Lý
5.1. SEO Penalties và Manual Actions
Nếu không xử lý kịp thời, domain có thể bị Google áp dụng Manual Action vì vi phạm:
Theo Google Spam Policies:
“Doorway abuse is when sites or pages are created to rank for specific, similar search queries. They lead users to intermediate pages that are not as useful as the final destination.”
“Using existing or creating new subdomains, subdirectories, or sites with the intention of continuing to violate our policies.”
Các loại penalty có thể:
| Loại | Mô tả | Thời gian phục hồi |
|---|---|---|
| Algorithmic | Tự động bởi spam detection | Vài tuần – vài tháng |
| Manual Action | Review bởi Google team | Vài tháng – vĩnh viễn |
| Domain-wide | Ảnh hưởng toàn bộ domain | Cực kỳ khó phục hồi |
5.2. Reputation Damage
REN-ISAC cảnh báo về hậu quả lâu dài:
“Sites fronted by subdomain takeover are often used for SEO purposes and may contain sensitive, adult, and/or malicious content… It may take months for your site’s entries to disappear from Google searches and caches.”
5.3. Rủi ro pháp lý
Nếu nội dung spam bao gồm:
- Nội dung vi phạm bản quyền
- Nội dung người lớn/đồi trụy
- Phishing/Scam content
- Malware distribution
Chủ sở hữu domain có thể phải chịu trách nhiệm pháp lý, đặc biệt nếu không chứng minh được đã thực hiện các biện pháp xử lý kịp thời.
Phần 6: Các Biện Pháp Phòng Ngừa
6.1. Quy trình xử lý đúng cách
Theo kiểu tấn công thế này, theo quan điểm của mình thì đầu tiên là hãy xoá bản ghi DNS trước để IP của attacker không còn liên kết với bất kỳ tài sản nào của mình, sau đó rà soát lại bao gồm:
- Kiểm tra Google Search Console
- Kiểm tra các hoạt động liên quan đến địa chỉ IP này trước đây
- Kiểm tra các email để tìm thông báo liên quan nếu có
6.2. DNS Audit định kỳ
Thường xuyên kiểm tra lại các bản ghi DNS và xoá đi những bản ghi không còn dùng đến. Nếu có ngưng triển khai dự án nào mà trước đây dùng IP của các dịch vụ cloud/vps thì xoá ngay tại lúc đó.
Có thể tham khảo ý tưởng chạy script tự động audit DNS như bên dưới thử.
#!/usr/bin/env python3
"""
DNS Audit Script - Phát hiện Dangling DNS records
"""
import dns.resolver
import socket
import ipaddress
import logging
# Cloud provider IP ranges (simplified)
CLOUD_RANGES = {
'digitalocean': [
'104.131.0.0/16',
'134.209.0.0/16',
'138.68.0.0/16',
'139.59.0.0/16',
'142.93.0.0/16',
'146.190.0.0/16',
'157.245.0.0/16',
'159.65.0.0/16',
'159.89.0.0/16',
'161.35.0.0/16',
'164.90.0.0/16',
'165.22.0.0/16',
'167.71.0.0/16',
'167.172.0.0/16',
'178.128.0.0/16',
'188.166.0.0/16',
'206.189.0.0/16',
'209.97.0.0/16',
],
'aws': [
# AWS ranges - lấy từ https://ip-ranges.amazonaws.com/ip-ranges.json
],
'azure': [
# Azure ranges
]
}
def is_cloud_ip(ip, provider='digitalocean'):
"""Kiểm tra IP có thuộc cloud provider không"""
try:
ip_obj = ipaddress.ip_address(ip)
for cidr in CLOUD_RANGES.get(provider, []):
if ip_obj in ipaddress.ip_network(cidr):
return True
except:
pass
return False
def check_subdomain(subdomain):
"""
Kiểm tra subdomain có đang trỏ về IP không còn kiểm soát
"""
result = {
'subdomain': subdomain,
'status': 'unknown',
'ip': None,
'is_cloud': False,
'is_reachable': False,
'risk': 'low'
}
try:
# Resolve DNS
answers = dns.resolver.resolve(subdomain, 'A')
ip = answers[0].to_text()
result['ip'] = ip
# Check if cloud IP
for provider in CLOUD_RANGES.keys():
if is_cloud_ip(ip, provider):
result['is_cloud'] = True
result['cloud_provider'] = provider
break
# Check if reachable
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
sock.connect((ip, 80))
sock.close()
result['is_reachable'] = True
result['status'] = 'active'
except:
result['is_reachable'] = False
result['status'] = 'unreachable'
# Cloud IP + unreachable = HIGH RISK
if result['is_cloud']:
result['risk'] = 'HIGH'
result['warning'] = 'Dangling DNS - Cloud IP unreachable!'
except dns.resolver.NXDOMAIN:
result['status'] = 'nxdomain'
except dns.resolver.NoAnswer:
result['status'] = 'no_answer'
except Exception as e:
result['status'] = f'error: {e}'
return result
def audit_dns(subdomains):
"""Audit danh sách subdomains"""
results = []
high_risk = []
for subdomain in subdomains:
result = check_subdomain(subdomain)
results.append(result)
if result.get('risk') == 'HIGH':
high_risk.append(result)
return results, high_risk
# Example usage
if __name__ == "__main__":
# Danh sách subdomains cần audit
subdomains = [
'chat.example.com',
'api.example.com',
'staging.example.com',
'dev.example.com',
'test.example.com',
]
results, high_risk = audit_dns(subdomains)
if high_risk:
print("\n⚠️ HIGH RISK - Dangling DNS Detected!")
for r in high_risk:
print(f" - {r['subdomain']} → {r['ip']} ({r.get('cloud_provider', 'unknown')})")
6.3. Giám sát GSC chủ động
REN-ISAC khuyến nghị:
“Consider claiming your top-level domain (TLD) in the Google Search Console which will facilitate Google notifying you directly when Google crawlers find spam on sites within your domain.”
Thiết lập alerts:
- Thiết lập Google Search Console ở cấp độ domain property (sc-domain:yourdomain.com) thay vì chỉ URL
- Bật thông báo qua email tại đây.
- Kiểm tra GSC thường xuyên hơn.
Lời kết
Sự cố lần này là một bài học thực sự đắt giá, nhưng rất may đã được phát hiện sớm và xử lý kịp thời trước khi gây ra những hậu quả nghiêm trọng hơn về SEO, uy tín thương hiệu và rủi ro pháp lý. Thực tế cho thấy, chỉ một bản ghi DNS bị bỏ quên cũng có thể trở thành điểm xâm nhập nguy hiểm, bị kẻ xấu lợi dụng để triển khai spam, lừa đảo hoặc nội dung độc hại trên chính domain của bạn mà không cần xâm nhập hệ thống.
Trong bối cảnh cloud computing và hạ tầng linh hoạt ngày càng phổ biến, các cuộc tấn công dạng Dangling DNS hay Subdomain Takeover sẽ không còn là tình huống hiếm gặp, mà dần trở thành rủi ro “thường trực” đối với bất kỳ cá nhân hay doanh nghiệp nào vận hành website ở quy mô vừa và lớn. Vì vậy, việc quản lý DNS chặt chẽ, kiểm tra định kỳ, kết hợp giám sát chủ động thông qua Google Search Console và các công cụ tự động, không còn là khuyến nghị mang tính tham khảo, mà nên được xem là một phần bắt buộc trong quy trình vận hành và bảo mật hạ tầng web hiện đại.
Tài Liệu Tham Khảo
Nghiên cứu học thuật
- Pauley, E., et al. (2022). “Measuring and Mitigating the Risk of IP Reuse on Public Clouds”. IEEE S&P. https://arxiv.org/abs/2204.05122
Vendor Documentation
- Microsoft Learn. “Prevent dangling DNS entries and avoid subdomain takeover”. https://learn.microsoft.com/en-us/azure/security/fundamentals/subdomain-takeover
- Google Search Central. “Spam Policies for Google Web Search”. https://developers.google.com/search/docs/essentials/spam-policies
Security Research
- Bishop Fox. “Fishing the AWS IP Pool for Dangling Domains”. https://bishopfox.com/blog/fishing-the-aws-ip-pool-for-dangling-domains
- The Hacker Blog. “Floating Domains – Taking Over 20K DigitalOcean Domains”. https://thehackerblog.com/floating-domains-taking-over-20k-digitalocean-domains-via-a-lax-domain-import-system/
- kmsec. “Passive Takeover – uncovering an expensive subdomain takeover campaign”. https://kmsec.uk/blog/passive-takeover/
- Smaran Chand. “You Forgot, I Remembered: Mass DNS Takeovers on DigitalOcean”. https://smaranchand.com.np/2025/07/you-forgot-i-remembered-mass-dns-takeovers-on-digitalocean/
Industry Advisories
- Sucuri. “Malicious Google Search Console Verifications”. https://blog.sucuri.net/2015/09/malicious-google-search-console-verifications.html
- REN-ISAC. “Subdomain Takeover Advisory”. https://www.ren-isac.net/services/publications/alerts/Subdomain_Takeover_Advisory.html
- Palo Alto Networks. “What Is Dangling DNS?”. https://www.paloaltonetworks.com/cyberpedia/what-is-a-dangling-dns
- CSO Online. “Cloud squatting: How attackers can use deleted cloud assets against you”. https://www.csoonline.com/article/1261461/cloud-squatting-how-attackers-can-use-deleted-cloud-assets-against-you.html