Kamailio World 2021
Fred Posner
@fredposner
SIP Attack Handling
SIP Attack Handling: Agenda
●
Introduction
●
Kamailio Modules
●
Kamailio Config
●
Other Handling
●
APIBAN
Introduction
Who am I?
●
I’m Fred
●
Matrix:
@fred:matrix.lod.com
●
Twitter: @fredposner
●
VoIP Consultant
●
Based in Florida
What do you mean by SIP attack?
●
Unwanted SIP Traffic
●
Script Kiddie
●
Fuzzing
●
UDP/TCP/TLS
●
SQL Injection
Main Risks
●
Denial of Service
●
Fraud
●
Unauthorized Access
●
Compromised Data
Examples
Example
2021/08/28 12:23:37.123621 193.46.255.203:64932 ->
192.168.7.63:5060
INVITE sip:+421332304403@XXXX SIP/2.0
Via: SIP/2.0/UDP
193.46.255.203:64932;branch=z9hG4bK1444585349
Max-Forwards: 70
From: <sip:7000@XXXX>;tag=204899679
To: <sip:+421332304403@XXXX>
Call-ID: 1621039940-1946143325-953698149
CSeq: 1 INVITE
Contact: <sip:7000@193.46.255.203:64932>
Content-Type: application/sdp
Content-Length: 208
Allow: ACK, BYE, CANCEL, INFO, INVITE, MESSAGE, NOTIFY,
OPTIONS, PRACK, REFER, REGISTER, SUBSCRIBE, UPDATE,
PUBLISH
User-Agent: Linksys-SPA942
v=0
o=7000 16264 18299 IN IP4 192.168.1.83
s=call
c=IN IP4 192.168.1.83
t=0 0
m=audio 25282 RTP/AVP 0 101
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-11
Example
2021/08/28 12:32:18.516537 193.46.255.195:59160 ->
192.168.7.63:5060
INVITE sip:0046812400356@XXXX SIP/2.0
Via: SIP/2.0/UDP
193.46.255.195:59160;branch=z9hG4bK1663022028
Max-Forwards: 70
From: <sip:120@XXXX>;tag=2056781479
To: <sip:0046812400356@XXXX>
Call-ID: 1605879512-581542184-1615033911
CSeq: 1 INVITE
Contact: <sip:120@193.46.255.195:59160>
Content-Type: application/sdp
Content-Length: 207
Allow: ACK, BYE, CANCEL, INFO, INVITE, MESSAGE, NOTIFY,
OPTIONS, PRACK, REFER, REGISTER, SUBSCRIBE, UPDATE,
PUBLISH
User-Agent: Linksys-SPA942
v=0
o=120 16264 18299 IN IP4 192.168.1.83
s=call
c=IN IP4 192.168.1.83
t=0 0
m=audio 25282 RTP/AVP 0 101
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-11
Kamailio Modules
Kamailio Modules: PIKE
●
Tracks number of SIP
messages per IP per
period of time.
●
Supports ipv4, ipv6
●
Easy to implement
Kamailio Modules: PIKE
loadmodule "pike.so"
...
modparam("pike",
"sampling_time_unit", 2)
modparam("pike",
"reqs_density_per_unit", 20)
modparam("pike",
"remove_latency", 4)
route {
if (!pike_check_req()) {
xlog("L_ALERT","ALERT:
pike block $rm from $fu
(IP:$si:$sp)n");
exit;
}
Kamailio Modules: PIKE
●
Pairs beautifully with
HTABLE/DMQ
●
Use ds lists, AUTH,
HTABLE, etc. to skip
nodes allowing high
traffic.
Kamailio Modules: SECFILTER
●
Lists for allow/block
by user-agent, ip,
country, domains,
users
●
SQL injection block
Kamailio Modules: SECFILTER
loadmodule "geoip2.so"
loadmodule "secfilter.so"
...
modparam("secfilter",
"db_url", DBURL)
modparam("secfilter",
"dst_exact_match", 0)
if (geoip2_match("$si", "src")) {
secf_check_country($gip2(src=>cc));
# return values ...
# 2 = allow list
# 1 = not found
# -1 = error
# -2 = block list
if ($? == -2) {
xalert("$rm from $si blocked because
Country '$gip2(src=>cc)' is in block list");
exit;
}
}
Kamailio Modules: SECFILTER
secf_check_from_hdr();
# return values ...
# 4 = name allowed
# 3 = domain allowed
# 2 = user allowed
# 1 = not found
# -1 = error
# -2 = user in block list
# -3 = domain in block list
# -4 = name in block list
switch ($?) {
case -2:
xalert("$rm to $si blocked because From user '$fU' is in block list");
exit;
case -3:
xalert("$rm to $si blocked because From domain '$fd' is in block list");
case -4:
xalert("$rm to $si blocked because From name '$fn' is in block list");
exit;
};
if (is_method("INVITE")) {
secf_check_dst($rU);
if ($? == -2) {
xalert("$rm from $si blocked
because destination $rU is in
block list");
exit;
}
}
Kamailio Modules: Other Modules
●
HTABLE
●
DMQ
●
PERMISSIONS
●
GEOIP/2
●
PHONENUM
●
PIPE/RATELIMIT
Kamailio Config
Kamailio Config
●
HTABLE is your best
friend
●
Temporarily block for
a period of time
●
Count occurrences
Temporarily Block
modparam("htable",
"htable",
"ipban=>size=8;autoexpire=3
00;dmqreplicate=1;")
●
5 min (300 s)
●
Replicate to all nodes
if($sht(ipban=>$si)!=$null) {
# ip is already blocked
xdbg("request from blocked IP - $rm from $fu (IP:$si:
$sp)n");
exit;
}
if(src_ip!=myself && !dmq_is_from_node() && !
ds_is_from_list()) {
if (!pike_check_req()) {
xlog("L_INFO","[R-REQINT] pike blocking $rm from $fu (IP:
$si:$sp)n");
$sht(ipban=>$si) = 1;
exit;
}
}
Count Auth Attempts
...
modparam("htable", "htable", "a=>size=8;")
...
if(is_present_hf("Authorization"))
{
if($sht(a=>$au::auth_count)==3)
{
$var(exp) = $Ts - 900;
if($sht(a=>$au::last_auth) > $var(exp))
{
sl_send_reply("403", "Try later");
exit;
} else {
$sht(a=>$au::auth_count) = 0;
}
}
if(!www_authenticate("$td", "subscriber"))
{
switch ($retcode) {
case -1:
sl_send_reply("403", "Forbidden");
exit;
case -2:
if($sht(a=>$au::auth_count) == $null)
$sht(a=>$au::auth_count) = 0;
$sht(a=>$au::auth_count) = $sht(a=>$au::auth_count) + 1;
if($sht(a=>$au::auth_count) == 3)
xlog("auth failed 3rd time - src ip: $sin");
$sht(a=>$au::last_auth) = $Ts;
break;
}
www_challenge("$td"/*realm*/,"0"/*qop*/);
exit;
}
$sht(a=>$au::auth_count) = 0;
} else {
www_challenge("$td","0");
exit;
}
Count Anything
●
Failed REGISTERs
●
INVITEs
●
404s
●
Call Rate
●
International, etc.
Kamailio Config
●
XLOG
– Log when a block
happens
– Review logs
●
DIALOG
– Keep track of active
calls
– Works with DMQ
Kamailio Config
●
SANITY
if(!sanity_check("17895",
"7")) {
xlog("Malformed SIP
request from $si:$spn");
exit;
}
●
TOPOH/TOPOS
– Security by obscurity
●
Server Header / Agent
Header
– Version if you’re good
at updating
Other Handling
Other Handling
●
Update Kamailio
●
Update OS
●
Keep firewall, etc. up
to date
Fail2Ban
●
Blocking an IP
address in IP tables
performs better than
drop/exit/etc.
●
Bias:
I don’t like fail2ban
●
Bias:
I really don’t like
fail2ban
iptables-api
●
Simple API for adding &
removing ipaddresses
●
APIBANLOCAL chain
●
Open Source
●
https://github.com/
palner/iptables-api
iptables-api
loadmodule "http_client.so"
loadmodule "htable.so"
...
modparam("htable", "htable", "ipban=>size=8;autoexpire=60;")
...
if (!pike_check_req()) {
xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)n");
$sht(ipban=>$si) = 1;
http_client_query("http://localhost:8082/addip/$si", "$var(apinfo)");
exit;
}
...
event_route[htable:expired:ipban] {
xlog("mytable record expired $shtrecord(key) => $shtrecord(value)n");
http_client_query("http://localhost:8082/removeip/$shtrecord(key)", "$var(apinfo)");
}
iptables-api
Aug 31 16:13:00 kamaPIlio
/usr/local/sbin/kamailio[5387]: WARNING: {1 1 ACK
11-520601@172.16.20.202} pike [pike_funcs.c:135]:
pike_check_ipaddr(): PIKE - BLOCKing ip
172.16.20.202, node=0x6594b390
Aug 31 16:13:00 kamaPIlio
/usr/local/sbin/kamailio[5387]: ALERT: {1 1 ACK 11-
520601@172.16.20.202} <script>: ALERT: pike
blocking ACK from sip:sipp@172.16.20.202:5060
(IP:172.16.20.202:5060)
Aug 31 16:13:02 kamaPIlio
/usr/local/sbin/kamailio[5397]: WARNING: pike
[pike_funcs.c:315]: refresh_node(): PIKE -
UNBLOCKing node 0x6594b390
Aug 31 16:14:10 kamaPIlio
/usr/local/sbin/kamailio[5397]: ERROR: <script>:
mytable record expired 172.16.20.202 => 1
2021/08/31 16:13:00 172.16.20.202
is a valid ip address
2021/08/31 16:13:00 IPTABLES
doesn't contain APIBANLOCAL.
Creating now...
2021/08/31 16:14:10 processing
removeIPAddress 172.16.20.202
2021/08/31 16:14:10
172.16.20.202 is a valid ip
address
APIBAN
APIBAN
●
Free (as in beer)
●
Community sharing of bad
actors via API
●
Honeypots
●
Client for IPTABLES or
example for Kamailio
●
https://apiban.org
Thank You for flying Kamailio
●
https://qxork.com
●
Fred Posner
●
@fredposner

SIP Attack Handling (Kamailio World 2021)

  • 1.
    Kamailio World 2021 FredPosner @fredposner SIP Attack Handling
  • 2.
    SIP Attack Handling:Agenda ● Introduction ● Kamailio Modules ● Kamailio Config ● Other Handling ● APIBAN
  • 3.
  • 4.
    Who am I? ● I’mFred ● Matrix: @fred:matrix.lod.com ● Twitter: @fredposner ● VoIP Consultant ● Based in Florida
  • 5.
    What do youmean by SIP attack? ● Unwanted SIP Traffic ● Script Kiddie ● Fuzzing ● UDP/TCP/TLS ● SQL Injection
  • 6.
    Main Risks ● Denial ofService ● Fraud ● Unauthorized Access ● Compromised Data
  • 7.
  • 8.
    Example 2021/08/28 12:23:37.123621 193.46.255.203:64932-> 192.168.7.63:5060 INVITE sip:+421332304403@XXXX SIP/2.0 Via: SIP/2.0/UDP 193.46.255.203:64932;branch=z9hG4bK1444585349 Max-Forwards: 70 From: <sip:7000@XXXX>;tag=204899679 To: <sip:+421332304403@XXXX> Call-ID: 1621039940-1946143325-953698149 CSeq: 1 INVITE Contact: <sip:[email protected]:64932> Content-Type: application/sdp Content-Length: 208 Allow: ACK, BYE, CANCEL, INFO, INVITE, MESSAGE, NOTIFY, OPTIONS, PRACK, REFER, REGISTER, SUBSCRIBE, UPDATE, PUBLISH User-Agent: Linksys-SPA942 v=0 o=7000 16264 18299 IN IP4 192.168.1.83 s=call c=IN IP4 192.168.1.83 t=0 0 m=audio 25282 RTP/AVP 0 101 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-11
  • 9.
    Example 2021/08/28 12:32:18.516537 193.46.255.195:59160-> 192.168.7.63:5060 INVITE sip:0046812400356@XXXX SIP/2.0 Via: SIP/2.0/UDP 193.46.255.195:59160;branch=z9hG4bK1663022028 Max-Forwards: 70 From: <sip:120@XXXX>;tag=2056781479 To: <sip:0046812400356@XXXX> Call-ID: 1605879512-581542184-1615033911 CSeq: 1 INVITE Contact: <sip:[email protected]:59160> Content-Type: application/sdp Content-Length: 207 Allow: ACK, BYE, CANCEL, INFO, INVITE, MESSAGE, NOTIFY, OPTIONS, PRACK, REFER, REGISTER, SUBSCRIBE, UPDATE, PUBLISH User-Agent: Linksys-SPA942 v=0 o=120 16264 18299 IN IP4 192.168.1.83 s=call c=IN IP4 192.168.1.83 t=0 0 m=audio 25282 RTP/AVP 0 101 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-11
  • 10.
  • 11.
    Kamailio Modules: PIKE ● Tracksnumber of SIP messages per IP per period of time. ● Supports ipv4, ipv6 ● Easy to implement
  • 12.
    Kamailio Modules: PIKE loadmodule"pike.so" ... modparam("pike", "sampling_time_unit", 2) modparam("pike", "reqs_density_per_unit", 20) modparam("pike", "remove_latency", 4) route { if (!pike_check_req()) { xlog("L_ALERT","ALERT: pike block $rm from $fu (IP:$si:$sp)n"); exit; }
  • 13.
    Kamailio Modules: PIKE ● Pairsbeautifully with HTABLE/DMQ ● Use ds lists, AUTH, HTABLE, etc. to skip nodes allowing high traffic.
  • 14.
    Kamailio Modules: SECFILTER ● Listsfor allow/block by user-agent, ip, country, domains, users ● SQL injection block
  • 15.
    Kamailio Modules: SECFILTER loadmodule"geoip2.so" loadmodule "secfilter.so" ... modparam("secfilter", "db_url", DBURL) modparam("secfilter", "dst_exact_match", 0) if (geoip2_match("$si", "src")) { secf_check_country($gip2(src=>cc)); # return values ... # 2 = allow list # 1 = not found # -1 = error # -2 = block list if ($? == -2) { xalert("$rm from $si blocked because Country '$gip2(src=>cc)' is in block list"); exit; } }
  • 16.
    Kamailio Modules: SECFILTER secf_check_from_hdr(); #return values ... # 4 = name allowed # 3 = domain allowed # 2 = user allowed # 1 = not found # -1 = error # -2 = user in block list # -3 = domain in block list # -4 = name in block list switch ($?) { case -2: xalert("$rm to $si blocked because From user '$fU' is in block list"); exit; case -3: xalert("$rm to $si blocked because From domain '$fd' is in block list"); case -4: xalert("$rm to $si blocked because From name '$fn' is in block list"); exit; }; if (is_method("INVITE")) { secf_check_dst($rU); if ($? == -2) { xalert("$rm from $si blocked because destination $rU is in block list"); exit; } }
  • 17.
    Kamailio Modules: OtherModules ● HTABLE ● DMQ ● PERMISSIONS ● GEOIP/2 ● PHONENUM ● PIPE/RATELIMIT
  • 18.
  • 19.
    Kamailio Config ● HTABLE isyour best friend ● Temporarily block for a period of time ● Count occurrences
  • 20.
    Temporarily Block modparam("htable", "htable", "ipban=>size=8;autoexpire=3 00;dmqreplicate=1;") ● 5 min(300 s) ● Replicate to all nodes if($sht(ipban=>$si)!=$null) { # ip is already blocked xdbg("request from blocked IP - $rm from $fu (IP:$si: $sp)n"); exit; } if(src_ip!=myself && !dmq_is_from_node() && ! ds_is_from_list()) { if (!pike_check_req()) { xlog("L_INFO","[R-REQINT] pike blocking $rm from $fu (IP: $si:$sp)n"); $sht(ipban=>$si) = 1; exit; } }
  • 21.
    Count Auth Attempts ... modparam("htable","htable", "a=>size=8;") ... if(is_present_hf("Authorization")) { if($sht(a=>$au::auth_count)==3) { $var(exp) = $Ts - 900; if($sht(a=>$au::last_auth) > $var(exp)) { sl_send_reply("403", "Try later"); exit; } else { $sht(a=>$au::auth_count) = 0; } } if(!www_authenticate("$td", "subscriber")) { switch ($retcode) { case -1: sl_send_reply("403", "Forbidden"); exit; case -2: if($sht(a=>$au::auth_count) == $null) $sht(a=>$au::auth_count) = 0; $sht(a=>$au::auth_count) = $sht(a=>$au::auth_count) + 1; if($sht(a=>$au::auth_count) == 3) xlog("auth failed 3rd time - src ip: $sin"); $sht(a=>$au::last_auth) = $Ts; break; } www_challenge("$td"/*realm*/,"0"/*qop*/); exit; } $sht(a=>$au::auth_count) = 0; } else { www_challenge("$td","0"); exit; }
  • 22.
  • 23.
    Kamailio Config ● XLOG – Logwhen a block happens – Review logs ● DIALOG – Keep track of active calls – Works with DMQ
  • 24.
    Kamailio Config ● SANITY if(!sanity_check("17895", "7")) { xlog("MalformedSIP request from $si:$spn"); exit; } ● TOPOH/TOPOS – Security by obscurity ● Server Header / Agent Header – Version if you’re good at updating
  • 25.
  • 26.
    Other Handling ● Update Kamailio ● UpdateOS ● Keep firewall, etc. up to date
  • 27.
    Fail2Ban ● Blocking an IP addressin IP tables performs better than drop/exit/etc. ● Bias: I don’t like fail2ban ● Bias: I really don’t like fail2ban
  • 28.
    iptables-api ● Simple API foradding & removing ipaddresses ● APIBANLOCAL chain ● Open Source ● https://github.com/ palner/iptables-api
  • 29.
    iptables-api loadmodule "http_client.so" loadmodule "htable.so" ... modparam("htable","htable", "ipban=>size=8;autoexpire=60;") ... if (!pike_check_req()) { xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)n"); $sht(ipban=>$si) = 1; http_client_query("http://localhost:8082/addip/$si", "$var(apinfo)"); exit; } ... event_route[htable:expired:ipban] { xlog("mytable record expired $shtrecord(key) => $shtrecord(value)n"); http_client_query("http://localhost:8082/removeip/$shtrecord(key)", "$var(apinfo)"); }
  • 30.
    iptables-api Aug 31 16:13:00kamaPIlio /usr/local/sbin/kamailio[5387]: WARNING: {1 1 ACK [email protected]} pike [pike_funcs.c:135]: pike_check_ipaddr(): PIKE - BLOCKing ip 172.16.20.202, node=0x6594b390 Aug 31 16:13:00 kamaPIlio /usr/local/sbin/kamailio[5387]: ALERT: {1 1 ACK 11- [email protected]} <script>: ALERT: pike blocking ACK from sip:[email protected]:5060 (IP:172.16.20.202:5060) Aug 31 16:13:02 kamaPIlio /usr/local/sbin/kamailio[5397]: WARNING: pike [pike_funcs.c:315]: refresh_node(): PIKE - UNBLOCKing node 0x6594b390 Aug 31 16:14:10 kamaPIlio /usr/local/sbin/kamailio[5397]: ERROR: <script>: mytable record expired 172.16.20.202 => 1 2021/08/31 16:13:00 172.16.20.202 is a valid ip address 2021/08/31 16:13:00 IPTABLES doesn't contain APIBANLOCAL. Creating now... 2021/08/31 16:14:10 processing removeIPAddress 172.16.20.202 2021/08/31 16:14:10 172.16.20.202 is a valid ip address
  • 31.
  • 32.
    APIBAN ● Free (as inbeer) ● Community sharing of bad actors via API ● Honeypots ● Client for IPTABLES or example for Kamailio ● https://apiban.org
  • 33.
    Thank You forflying Kamailio ● https://qxork.com ● Fred Posner ● @fredposner