Anti-fraud: Difference between revisions
(Add note about detecting User-Agent changes (no built-in alert)) |
(Add 'Getting Passed Arguments' section with detailed argument structure and examples) |
||
| Line 158: | Line 158: | ||
| Local numbers are in || Country for classifying international-prefixed calls as local || your country | | Local numbers are in || Country for classifying international-prefixed calls as local || your country | ||
|} | |} | ||
=== Getting Passed Arguments === | |||
Custom scripts are invoked with command-line arguments containing alert information. The fourth argument (<code>$argv[4]</code> in PHP) contains a JSON-encoded object with detailed alert data. | |||
==== Argument Structure === | |||
The script receives the following arguments: | |||
{| class="wikitable" | |||
|- | |||
! Argument Index !! Variable (PHP) !! Description | |||
|- | |||
| $argv[1] || alert ID || Numeric identifier of the triggered alert | |||
|- | |||
| $argv[2] || rule name || Name of the anti-fraud rule (e.g., "SIP REGISTER flood") | |||
|- | |||
| $argv[3] || timestamp || Unix timestamp when the alert triggered | |||
|- | |||
| $argv[4] || alert data || JSON-encoded object with alert-specific data | |||
|} | |||
==== Alert Data Structure (JSON in $argv[4]) === | |||
The JSON structure varies by alert type: | |||
===== Realtime Alerts (REGISTER flood, PACKET flood, Concurrent calls) ===== | |||
<syntaxhighlight lang="json"> | |||
{ | |||
"alert_info": { | |||
"ip": "192.0.2.1", | |||
"port": 5060, | |||
"count": 1500 | |||
}, | |||
"rule_name": "SIP REGISTER flood", | |||
"triggered_at": "2025-01-05 10:30:00" | |||
} | |||
</syntaxhighlight> | |||
===== CDR-based Alerts (RTP, SIP Response, Country change) ===== | |||
<syntaxhighlight lang="json"> | |||
{ | |||
"cdr": [12345, 12346, 12347], | |||
"alert_type": "MOS below threshold", | |||
"threshold": 3.5, | |||
"actual_value": 2.8, | |||
"rule_name": "Low MOS Alert", | |||
"triggered_at": "2025-01-05 10:30:00" | |||
} | |||
</syntaxhighlight> | |||
===== Triggered Rules Structure (Multiple Rule Triggers) ===== | |||
Some alert types (like concurrent calls) return an array of triggered rules: | |||
<syntaxhighlight lang="json"> | |||
[ | |||
{ | |||
"rule_name": "Concurrent calls limit", | |||
"alert_info": { | |||
"ip": "192.0.2.1", | |||
"count": 250 | |||
} | |||
}, | |||
{ | |||
"rule_name": "Concurrent calls limit", | |||
"alert_info": { | |||
"ip": "198.51.100.5", | |||
"count": 180 | |||
} | |||
} | |||
] | |||
</syntaxhighlight> | |||
==== Accessing Data in Scripts === | |||
===== PHP Example ===== | |||
<syntaxhighlight lang="php"> | |||
#!/usr/bin/php | |||
<?php | |||
// Parse alert data from 4th argument | |||
$alertData = json_decode($argv[4]); | |||
// Check if it's a single alert or array of rules | |||
if (isset($alertData->alert_info)) { | |||
// Single alert | |||
echo "Alert: " . $argv[2] . "\n"; | |||
echo "IP: " . $alertData->alert_info->ip . "\n"; | |||
} else if (is_array($alertData)) { | |||
// Array of triggered rules (concurrent calls) | |||
foreach ($alertData as $rule) { | |||
echo "Blocking: " . $rule->alert_info->ip . "\n"; | |||
} | |||
} | |||
// For CDR-based alerts | |||
if (isset($alertData->cdr)) { | |||
$cdrIds = implode(',', $alertData->cdr); | |||
echo "Processing CDRs: " . $cdrIds . "\n"; | |||
} | |||
?> | |||
</syntaxhighlight> | |||
===== Bash Example === | |||
<syntaxhighlight lang="bash"> | |||
#!/bin/bash | |||
# Log all arguments for debugging | |||
echo "$(date): Alert triggered" >> /tmp/anti_fraud.log | |||
echo "Timestamp: $(date -d @$1)" >> /tmp/anti_fraud.log | |||
echo "Rule: $2" >> /tmp/anti_fraud.log | |||
echo "Alert Data: $4" >> /tmp/anti_fraud.log | |||
# Extract IP address using jq (if available) | |||
if command -v jq &> /dev/null; then | |||
IP=$(echo "$4" | jq -r '.alert_info.ip // empty') | |||
echo "Attacker IP: $IP" >> /tmp/anti_fraud.log | |||
fi | |||
</syntaxhighlight> | |||
==== Important Notes === | |||
* **Source Port in Realtime Alerts**: The <code>alert_info.ip</code> field contains the attacker IP, but source port may not be available for realtime alerts (processed before CDR creation). | |||
* **CDR IDs**: For CDR-based alerts, use the <code>cdr</code> array to query additional information from the database. | |||
* **Error Handling**: Always validate JSON structure and check for required fields before processing. | |||
* **Script Permissions**: Ensure the custom script is executable (e.g., <code>chmod +x /path/to/script.sh</code>). | |||
=== SIP REGISTER Flood/Attack === | === SIP REGISTER Flood/Attack === | ||
Revision as of 18:03, 5 January 2026
Category:GUI manual
Anti-Fraud Rules
Anti-fraud rules are accessed via GUI > Alerts > Anti Fraud. Rules combat fraud and attacks, with ongoing additions. Each rule supports custom scripts for actions like firewall rules, besides email alerts. Alerts are archived in Sent Alerts.
Overview
List of Fraud/Watchdog Alerts
| Alert Type | Processing | Description |
|---|---|---|
| Realtime concurrent calls | Realtime | Monitors concurrent calls per source IP |
| SIP REGISTER flood/attack | Realtime | Detects REGISTER flooding from single IP |
| SIP PACKETS flood/attack | Realtime | Detects generic SIP packet floods |
| Country/Continent destination | Realtime | Calls to specific country/continent (based on first INVITE) |
| Fraud: sequential | CDR-based | Detects high volume of calls to a destination within a time window |
| Change CDR country | CDR-based | Source IP geolocation changed between calls |
| Change REGISTER country | CDR-based | REGISTER source country changed since last success |
| Billing Watchdog | CDR-based | Billing anomaly detection |
Alert Processing Differences
VoIPmonitor processes alerts in two fundamentally different ways, which affects what data is available when the alert triggers:
Realtime Alerts
Processed directly by the sniffer as packets arrive. Triggered immediately based on packet inspection.
| Alert | Trigger Condition |
|---|---|
| Realtime concurrent calls | N+ concurrent calls from same IP |
| SIP REGISTER flood | N+ REGISTER attempts from same IP in interval |
| SIP PACKETS flood | N+ SIP packets from same IP in interval |
| Country/Continent destination | Call to monitored destination (first INVITE) |
Characteristics:
- Immediate triggering (no database delay)
- CDRs not yet available when alert fires
- Only IP address available in
alert_info(no source port)
CDR-based Alerts
Evaluated by the GUI after CDRs have been stored in the database.
| Alert | Trigger Condition |
|---|---|
| Change CDR country | IP geolocation differs from previous call |
| Change REGISTER country | REGISTER country differs from last successful registration |
| RTP alerts | Quality thresholds exceeded (MOS, jitter, loss) |
| SIP Response alerts | Specific SIP response codes |
Characteristics:
- Delay between call end and alert (CDR must be written first)
- Full CDR data available (including source port, duration, etc.)
- Can query database for additional context
Important Limitation: Source Port in Realtime Alerts
Realtime alerts provide the attacker's IP address in alert_info, but do not include the SIP source port.
The source port can be queried from cdr.caller_port, but this has critical limitations:
- Delay: CDRs are written after the realtime alert triggers
- Port may not exist: Flood attacks are often detected before CDR creation
Recommendation:
- For real-time defense: Block by IP address only (accept temporary impact on legitimate traffic from same IP)
- For non-real-time blocking: Use CDR-based alerts with database queries
Common Configuration
Options shared across anti-fraud rules:
| Option | Description |
|---|---|
| Enable hyperlinks | Makes email alert titles clickable links to rule definitions |
| IP include/exclude | Exclude IPs or networks (e.g., 10.0.0.0/8) or use IP groups
|
| Suppress repeating alerts | Limit alerts to once per X hours to avoid spamming |
| Numbers include/exclude | Filter source numbers/prefixes |
| External script | Path to custom script for automated actions |
International prefixes configuration:
| Setting | Description | Default |
|---|---|---|
| International prefixes | Prefixes indicating international calls | +, 00
|
| Min international length | Numbers shorter than this are treated as local | varies |
| Local numbers are in | Country for classifying international-prefixed calls as local | your country |
Getting Passed Arguments
Custom scripts are invoked with command-line arguments containing alert information. The fourth argument ($argv[4] in PHP) contains a JSON-encoded object with detailed alert data.
= Argument Structure
The script receives the following arguments:
| Argument Index | Variable (PHP) | Description |
|---|---|---|
| $argv[1] | alert ID | Numeric identifier of the triggered alert |
| $argv[2] | rule name | Name of the anti-fraud rule (e.g., "SIP REGISTER flood") |
| $argv[3] | timestamp | Unix timestamp when the alert triggered |
| $argv[4] | alert data | JSON-encoded object with alert-specific data |
= Alert Data Structure (JSON in $argv[4])
The JSON structure varies by alert type:
Realtime Alerts (REGISTER flood, PACKET flood, Concurrent calls)
{
"alert_info": {
"ip": "192.0.2.1",
"port": 5060,
"count": 1500
},
"rule_name": "SIP REGISTER flood",
"triggered_at": "2025-01-05 10:30:00"
}
CDR-based Alerts (RTP, SIP Response, Country change)
{
"cdr": [12345, 12346, 12347],
"alert_type": "MOS below threshold",
"threshold": 3.5,
"actual_value": 2.8,
"rule_name": "Low MOS Alert",
"triggered_at": "2025-01-05 10:30:00"
}
Triggered Rules Structure (Multiple Rule Triggers)
Some alert types (like concurrent calls) return an array of triggered rules:
[
{
"rule_name": "Concurrent calls limit",
"alert_info": {
"ip": "192.0.2.1",
"count": 250
}
},
{
"rule_name": "Concurrent calls limit",
"alert_info": {
"ip": "198.51.100.5",
"count": 180
}
}
]
= Accessing Data in Scripts
PHP Example
#!/usr/bin/php
<?php
// Parse alert data from 4th argument
$alertData = json_decode($argv[4]);
// Check if it's a single alert or array of rules
if (isset($alertData->alert_info)) {
// Single alert
echo "Alert: " . $argv[2] . "\n";
echo "IP: " . $alertData->alert_info->ip . "\n";
} else if (is_array($alertData)) {
// Array of triggered rules (concurrent calls)
foreach ($alertData as $rule) {
echo "Blocking: " . $rule->alert_info->ip . "\n";
}
}
// For CDR-based alerts
if (isset($alertData->cdr)) {
$cdrIds = implode(',', $alertData->cdr);
echo "Processing CDRs: " . $cdrIds . "\n";
}
?>
== Bash Example
#!/bin/bash
# Log all arguments for debugging
echo "$(date): Alert triggered" >> /tmp/anti_fraud.log
echo "Timestamp: $(date -d @$1)" >> /tmp/anti_fraud.log
echo "Rule: $2" >> /tmp/anti_fraud.log
echo "Alert Data: $4" >> /tmp/anti_fraud.log
# Extract IP address using jq (if available)
if command -v jq &> /dev/null; then
IP=$(echo "$4" | jq -r '.alert_info.ip // empty')
echo "Attacker IP: $IP" >> /tmp/anti_fraud.log
fi
= Important Notes
- **Source Port in Realtime Alerts**: The
alert_info.ipfield contains the attacker IP, but source port may not be available for realtime alerts (processed before CDR creation). - **CDR IDs**: For CDR-based alerts, use the
cdrarray to query additional information from the database. - **Error Handling**: Always validate JSON structure and check for required fields before processing.
- **Script Permissions**: Ensure the custom script is executable (e.g.,
chmod +x /path/to/script.sh).
SIP REGISTER Flood/Attack
Triggers when >= N registration attempts from an IP occur within the set interval.
Mitigation Strategies
When SIP REGISTER floods cause excessive CPU usage or system unresponsiveness:
1. Immediate Blocking via Custom Scripts
Configure a custom script in the SIP REGISTER flood alert rule to automatically block the attacker IP. The alert_info object contains the attacker's IP address.
# Block using iptables
iptables -A INPUT -s <ATTACKER_IP> -j DROP
# Block using ipset (more efficient for multiple IPs)
ipset add blacklist <ATTACKER_IP>
2. Network Edge Blocking (Recommended for Prevention)
For long-term protection, block at your network edge before traffic reaches VoIPmonitor:
- Session Border Controller (SBC): Configure rate limiting and IP blocking
- Firewall: Block malicious IPs at the perimeter
- Fail2ban: Automatically block IPs after repeated REGISTER failures
3. Reducing REGISTER Noise
- Disable REGISTER processing if not needed:
sip-register = noinvoipmonitor.conf - Filter REGISTER packets using firewall rules (block specific countries or networks)
- Use capture rules to exclude known good REGISTER sources from processing
Realtime Concurrent Calls
Tracks source IPs in realtime (not CDR-based) for concurrent calls. Useful against high-channel attacks.
- Parameters
-
- Concurrent calls limit: Trigger on international, local, or both exceeding limits
- Time period rules: Vary alerts by work/after hours (defined in Groups > TimePeriods)
Change CDR Country
Triggers when CDR IP source changes country/continent since last call.
- Parameters
-
- Exclude countries from alert: Whitelist countries to skip
Change REGISTER Country
Triggers when SIP REGISTER username changes country/continent since last successful registration.
- Parameters
-
- Exclude countries from alert: Whitelist countries to skip
Detecting User-Agent Changes
There is no built-in alert for detecting changes to a SIP registration's User-Agent (UA) string. However, you can enable database-level tracking of UA changes by configuring the sniffer to create new register state records when the UA changes.
To enable UA change tracking, set sip-register-state-compare-digest_ua = yes (or its alias sip-register-state-compare-ua = yes) in voipmonitor.conf. This forces the sniffer to create a new record in the register state table whenever the UA changes, even if other registration details remain the same. See Sniffer Configuration for details.
- Alternative fraud alerts for registration anomalies
-
- Change REGISTER country: Detects when registration source country changes
- Change CDR country: Detects when call source country changes
- Custom detection
-
- Query the
register_statedatabase table to detect UA changes programmatically - Use custom scripts with anti-fraud rules to trigger actions based on database queries
- Query the
Country/Continent Destination
Triggers on calls to specific country/continent, based on first SIP INVITE (realtime processing).
SIP PACKETS Flood/Attack
Triggers when >= N packets from an IP occur within the set interval.
Fraud: Sequential
Detects a large volume of calls to the same destination number within a short time period. This alert is useful for identifying sequential dialing patterns, such as repeated calls to premium rate numbers or destination abuse.
- Parameters
-
- Interval: Time window in seconds to monitor call volume (e.g., 3600 for 1 hour)
- Limit: Maximum number of calls allowed within the interval (e.g., 100)
- Called number filters: Destination numbers/prefixes to monitor
- Configuration for "Any Single Destination"
-
- To alert on call volume to any destination number (not specific numbers), leave the called number field empty. The alert will then detect excessive calling to any single number within the configured time window.
- Example Use Cases
-
- Alert when more than 50 calls are made to the same destination within 1 hour
- Detect sequential dialing to premium rate numbers
- Identify destination number abuse or toll fraud
Custom Script Examples
Custom scripts receive alert data as command-line arguments. The fourth argument ($argv[4] in PHP) contains JSON-encoded alert data.
Logging Passed Arguments
Simple script to log all arguments for debugging:
#!/bin/bash
echo "$(date): $@" >> /tmp/alert_debug.txt
RTP Alert: Store Audio Files
Script to automatically download audio for calls that triggered an RTP alert:
#!/usr/bin/php
<?php
// Configuration
$directory = '/home/alerts/audio';
$date = trim(`date '+%Y-%m-%d'`);
$guiDir = '/var/www/voipmonitor';
$destdir = $directory . '/' . $date;
// Create destination directory
`mkdir -p $destdir`;
// Parse alert data (4th argument contains JSON)
$alert = json_decode($argv[4]);
// Download audio for each CDR in the alert
foreach ($alert->cdr as $cdr) {
$params = json_encode([
'task' => 'getVoiceRecording',
'user' => 'admin',
'password' => 'admin',
'params' => ['cdrId' => $cdr]
]);
$command = "php $guiDir/php/api.php > $destdir/file_id_$cdr.pcap";
exec("echo '$params' | $command", $arr, $val);
}
?>
RTP Alert: Block IP After Threshold
Script to block IPs that exceed a threshold number of incidents:
#!/usr/bin/php
<?php
// Configuration
$Limit = 19; // Block after this many incidents
$blockCommand = "ssh root@pbx -p2112 ipset add blacklist"; // Remote blocking command
$verbose = 1; // 1 = dry-run, 0 = execute
// Parse alert data
$alertsData = json_decode($argv[4]);
// Build comma-separated list of CDR IDs
$cdrIds = implode(',', $alertsData->cdr);
// Query database for caller IPs and incident counts
$query = "SELECT INET_NTOA(sipcallerip) as ip, COUNT(*) as incidents
FROM voipmonitor.cdr
WHERE id IN ($cdrIds)
GROUP BY sipcallerip
ORDER BY incidents DESC";
$command = "mysql -h MYSQLHOST -u MYSQLUSER -pMYSQLPASS -N -e \"$query\"";
exec($command, $results);
// Process results and block IPs exceeding limit
foreach ($results as $line) {
list($ip, $count) = preg_split('/\s+/', trim($line));
if ($count > $Limit) {
if ($verbose) {
echo "$ip: $count incidents - would block\n";
} else {
exec("$blockCommand $ip", $output, $rc);
if ($rc != 0) {
error_log("Failed to block $ip");
}
}
}
}
?>
Concurrent Calls: Block Attacker IP
Script for blocking IPs based on concurrent calls alert. Enable "By caller IP" in alert settings.
#!/usr/bin/php
<?php
// Parse triggered rules (4th argument)
$triggeredRules = json_decode($argv[4]);
// Count triggers per IP address
$IPtriggers = [];
foreach ($triggeredRules as $rule) {
$ip = $rule->alert_info->ip;
$IPtriggers[$ip] = ($IPtriggers[$ip] ?? 0) + 1;
}
// Block all IPs that triggered the rule
foreach ($IPtriggers as $ip => $count) {
echo "Blocking $ip (triggered $count times)\n";
passthru("iptables -A INPUT -s $ip -j DROP", $ret);
if ($ret != 0) {
echo "ERROR: Failed to block $ip\n";
exit(1);
}
}
echo "Blocked " . count($IPtriggers) . " IP(s)\n";
?>
See Also
- Alerts & Reports - General alert configuration
- Capture Rules - Filter traffic before processing
- Sniffer Configuration -
sip-registerand other options - Groups - IP groups and time periods for alerts
AI Summary for RAG
Summary: VoIPmonitor anti-fraud rules for detecting SIP attacks (REGISTER floods, packet floods), concurrent calls abuse, geographic anomalies, and high-volume sequential calling patterns. Covers realtime vs CDR-based alert processing differences, custom script examples for automated IP blocking via iptables/ipset, and mitigation strategies for SIP REGISTER spam.
Keywords: anti-fraud, REGISTER flood, SIP attack, concurrent calls, country change, custom scripts, iptables, ipset, fail2ban, realtime alerts, CDR-based alerts, source port limitation, sequential calls, sequential dialing, destination abuse
Key Questions:
- What anti-fraud alerts are available in VoIPmonitor?
- How to block SIP REGISTER flood attacks?
- What is the difference between realtime and CDR-based alerts?
- How to create custom scripts for automated IP blocking?
- Why is source port not available in realtime alerts?
- How to configure an alert for a large volume of calls to any single destination number?
- What is the Fraud: sequential alert and how does it work?