CUC (6) CUCM (28) Jabber (6) Python (2) Routing (3) Solarwinds Orion NPM (4) switching (1) Video (6) voice (3)

Sunday, 8 May 2016

Hardening your cisco VCS expressway. Prevent Toll fraud

It's important that you give this some thought, actually quite a bit of thought. If you want to prevent toll fraud across your UC network and, more specifically, across your VCS expressway, start paying attention.

The main difference between someone compromising a server in your network, compared to someone using, and essentially compromising, your voice infrastructure to make long distance calls to banana republics, is that your Telco will slam you with a big fat phone bill in the next billing cycle.  Nowadays a lot of companies have embraced SIP URI dialing and have also facilitate this in a business to business scenario. This is a good thing, but it also comes with some risks.

I checked out a few articles/posts out there on the inter webs about toll fraud and I must conclude that most of them are very generic and do not provide any workable hints and tips on how to prevent Toll fraud, when you have a Cisco VCS deployed.  I am trying to change that in this article. 

The VCS facilitates (among other things) business to business communications. This means it's pretty much accessible to who ever can dial into it, or and this is what hackers use, anyone who is aware you have a public srv record.  Having a  srv record, is like putting your details in the phone directory, but at the same crucial to your VCS's operation. 

Assuming you have your VCS expressway in a DMZ with a firewall in front of it, it will allow all incoming SIP INVITES through ports 5060 and 5061. So your firewall will not prevent toll fraud.  Toll fraud prevention will therefore need to happen on an application level, i.e. your VCS and CUCM.

The VCS has a number of options to harden it against toll fraud. So let's dive into the good stuff.

Toll fraud generally comes in the shape of someone sending forged SIP invites to your VCS (sometimes spoofing your domain name as the source, but not necessarily) and trying to transit your network to reach an international number. Typically these destination numbers make you incur flag fall costs, so even though there might not be a successful voice stream set up, calls to that particular number might be enough for you to be charged a small initial fee for each call. 

Below is an example of such a forged INVITE, instructing the VCS-e to resolve a number in some banana republic. Notice the none standard 5070 port and forged From field:

 Via: SIP/2.0/UDP;branch=z9hG4bK-effa656dd1c6e2ed91d6409abd1f6eef;rport
 Call-ID: effa656dd1c6e2ed91d6409abd1f6eef
 Contact: <sip:200@>
 From: "200" <>;tag=3e4f4ee3
 To: "+50230083033" <>
 Max-Forwards: 70
 User-Agent: sipcli/v1.8
 Content-Type: application/sdp
 Content-Length: 282

 o=sipcli-Session 2027421348 551703021 IN IP4
 c=IN IP4
 t=0 0
 m=audio 5072 RTP/AVP 18 0 8 101
 a=fmtp:101 0-15
 a=rtpmap:18 G729/8000
 a=rtpmap:0 PCMU/8000
 a=rtpmap:8 PCMA/8000
 a=rtpmap:101 telephone-event/8000

Based on the SIP INVITE above,  essentially what you want to achieve is that SIP INVITES coming into your VCS, are only allowed to dial endpoints that are considered 'On Net'. For instance, phones with URI's, WebEx and or a Telepresence server allowing your business partners to contact people within your organisation.  As always, its best to drop these unwanted SIP INVITES as close to the source as possible, i.e. on your VCS Expressway. One compelling reason to do this is, that should you allow these INVITES through your traversal zone onto your VCS control, they could consume traversal zone licenses, potentially swamping all legit traffic.

VCS's work in pairs, which means you can pretty much implement a double layer of policies and filtering. For this, you have the following available, in descending order of importance:

-transform rules
-call policies
-search rule

I will only discuss call policies and seach rules, because transform rules are not really needed, so use them as you see fit.

for this post I have used a scenario where people have the following URI configured on their end points:




So, based on that, I only want to allow inbound calls that fall within these "ranges". Allowing inbound calls only to land to valid endpoints and not somehow route it across to the PSTN.

Call policies

Call policies are quite powerful and can be compared to access lists on a router or firewall. Or maybe even CSS's on CUCM. Call Policies have two actions: REJECT or ALLOW.  Call policies use the same sort of regular expressions as search rules. The best place to find out what the syntax for these is to go to the help on the Web GUI on the VCS itself. ( FYI, I have added the regular expression syntax out at the bottom, which comes from that very same help page.)  

The way I personally like to configure call policies is very similar to the search rules in the next part of this blog. Namely; explicitly allow only calls to on net  end points only, and explicitly block all else. Theoretically, if you do this well, there is no real need to be really careful with your search rules anymore, as the call policy rules will block and allow what is needed.

So when your dial plan allows for instance for 5 digit extensions, E.164 as well as emails as URI's, you could use the following rules as your allowed call policy rules:




Go to Configuration > Call Policy >  Rules to configure call policy rules

For  this, I configured the following rules:

As you can see all i did was define 3 rules, in accordance with what I described above to and then Rejecting all else that goes to  

Of course, this does not reject calls to  or  but who cares really, cos these are external domains; call them as much as you like.

Now you have configured your call policies, let's move on and actually make call routing decisions, for calls that are allowed through. Let's talk about search rules.

Search rules

Configuration > Dialplan > Search Rules

Search rules are being processed after transform rules and call policies. And can best be compared with static routes on routers or route patterns on CUCM. Search rules don't have an action, but point to the next destination when a certain destination pattern is hit.  What I advise to do is tighten your search rules, so that it only covers your On net dial plan which means everything else will drop out at the bottom, pretty much in the same way as you did with your call policies.

So for instance if you use  5 digits internally, you can add a search rule:


or if you use email addresses as URI


In case you use E.164 URI's (Australia for example)




if you're in the UK.

The issue with those last two E164 regular expression search rules, is that it essentially they open your VCS dial plan up for the whole Australian and UK numbering plan respectively. So you want to make these rules more specific and only include the number ranges you have in place. If you run a large organisation that spans dozens of number rages in multiple countries and domains, you have quite a task. but let's rest that topic for a minute.

Either way, there is no one size fits all in covering your On net numbering plan with search rules, every organisation is different. 

I prefer to add an explicit match all, sort of like an explicit deny any any on a firewall, that catches all that is not part of my on net dial plan.

What I have done, pretty much as a test only, is translate my wildcard pattern into and run that into a phone with as it's URI. That way, when someone attempts to connect to an unwanted number, that phone rings. Its just a good way of keeping an eye on toll fraud attempts.  Alternatively in the example below, you could point the wildcard pattern back to the DNS zone after and translate it into a bogus domain name like

If you use an wildcard pattern like the one above and point that to your traversal zone, without somehow manipulating it, you are opening yourself up for unwanted calls.

There is a third layer of filtering, should an unwanted call attempt still slip through the cracks of the call policy and search rules, namely CUCM Calling Search Spaces. The VCS control communicates to your CUCM, using a SIP Trunk, and like any trunk, you can configure it with an Incoming Call CSS (see below).

I won't go into who CSS's work, but what I can say is the Incoming Calls Calling Search Space should only be able to resolve enpoints and patterns that are On net ONLY, or at least should not be able to resolve IDD numbers to Paraguay.

Again this if fairly easy to test, by spinning up a 3rd party SIP Voip client and hitting your VCSe with a URI that should not be allowed, or is not On Net, for instance a mobile number
Testing your search rules and call policies

It's fairly easy to test your search rule on the VCS(e) if you go to Configuration > Dialplan > Search Rules you will have tools available to test the search rule logic (see below). 

If you choose "perform a test search for an alias" the VCS actually simulates a call through its engine and the simulates call can actually been found back in the event log.

I suggest that after you put in all the search rules and Call policies, you test the buggery out of it.

Example, I added a call policy with a reject rule \d{5}*)? and I have configured it to REJECT.  so after I done that, and I go and perform a test for that alias (, I get the following output:

Search (1)
State: Completed
Found: False
Reason: Forbidden
Info: Policy Response
CallSerial Number: 840bbf61-d8bd-4f54-b454-adc3f597b95f
Tag: fb36d05a-088e-4b0f-a98b-96a446c961c0
Source (1)
Authenticated: False
Aliases (1)
Alias (1)
Type: Url
Origin: Unknown
Value: xcom-locate
Zone (1)
Name: DefaultZone
Type: Default
Path (1)
Hop (1)
Destination (1)
Alias (1)
Type: Url
Origin: Unknown
StartTime: 2016-05-05 16:20:26
Duration: 0
SubSearch (1)
Type: Transforms
Action: Not Transformed
ResultAlias (1)
Type: Url
Origin: Unknown
SubSearch (1)
Type: Admin Policy
Action: Reject

As you can see above, after the VCS has checked any applicable transforms, is matches the call policy  \d{5}*)?   and therefore rejects the call. Which is exactly the behavior we are after. Of course, if you wanted to allow that exact call policy, you would have to change the ction to "allow". But for testing purposes, its better to set to rule to REJECT, because this way, it will show up as a SIP 403 forbidden. This way you know exactly that your call policy gets hit, rather than the dial number slipping through the cracks and being routes by your search rules,  

OK, so now let me spin up Acano (which is a great way of testing URI dialing from external, for as long as it lasts at least) and attempt an actual call into the VCS to that same alias and see how the VCS deals with it.

As you can see above, which is taken from the event log of the VCSe, the call is rejected and marked as "Forbidden".

So if you pull the detailed diagnostics logs (Maintenance > Diagnostics > Diagnostics Logging) for this particular call , you can see a 403 Forbidden, is sent to the originator of the call/INVITE

SIP/2.0 403 Forbidden
Via: SIP/2.0/TLS;branch=z9hG4bK95cbb2633618cdcd1bb354a9d51f1775;received=;ingress-zone=DefaultZone
Call-ID: bb14ffdf-6e3b-4b43-8737-725a1f14f403
CSeq: 928888779 INVITE
From: "Finn McCool" <>;tag=63400258ef442ad6
To: <>;tag=622f0ddcc6152685
Server: TANDBERG/4130 (X8.5.1)
Warning: 399 "Policy Response"

Content-Length: 0

This 403 is a bit different from a 404 Not found being sent out when there is no applicable search rule and is a clear indication that the inbound call does not pass the implemented call policy.

Finally you can test your Incoming calls Calling search space by making an inbound call and run a trace on you CUCM, to see if the CSS applied to the Trunk to the VCS, actually allows or block the incoming URI.


Regular expressions

Regular expressions can be used in conjunction with a number of VCS features such as alias transformations, zone transformations, CPL policy and ENUM. The VCSuses POSIX format regular expression syntax. The table below provides a list of commonly used special characters in regular expression syntax. This is only a subset of the full range of expressions available. For a detailed description of regular expression syntax see the publication Regular Expression Pocket Reference.
.Matches any single character.
\dMatches any decimal digit, i.e. 0-9.
*Matches 0 or more repetitions of the previous character or expression..* matches against any sequence of characters
+Matches 1 or more repetitions of the previous character or expression.
?Matches 0 or 1 repetitions of the previous character or expression.9?123 matches against 9123 and 123
{n}Matches n repetitions of the previous character or expression\d{3} matches 3 digits
{n,m}Matches n to m repetitions of the previous character or expression\d{3,5} matches 3, 4 or 5 digits
Matches a set of specified characters. Each character in the set can be specified individually, or a range can be specified by giving the first character in the range followed by the - character and then the last character in the range.
You cannot use special characters within the [] - they will be taken literally.
[a-z] matches any alphabetical character
[0-9#*] matches against any single E.164 character - the E.164 character set is made up of the digits 0-9 plus the hash key (#) and the asterisk key (*)
Matches anything except the set of specified characters. Each character in the set can be specified individually, or a range can be specified by giving the first character in the range followed by the - character and then the last character in the range.
You cannot use special characters within the [] - they will be taken literally.
[^a-z] matches any non-alphabetical character
[^0-9#*] matches anything other than the digits 0-9, the hash key (#) and the asterisk key (*)
(...)Groups a set of matching characters together. Groups can then be referenced in order using the characters \1, \2, etc. as part of a replace string.A regular expression can be constructed to transform a URI containing a user’s full name to a URI based on their initials. The regular expression (.).*_(.).*( would match against the user john_smith@example.comand with a replace string of \1\2\3 would transform it to
|Matches against one expression or an alternate expression..*@example.(net|com) matches against any URI for the or the domain
\Escapes a regular expression special character.
Signifies the start of a line.
When used immediately after an opening brace, negates the character set inside the brace.
[^abc] matches any single character that is NOT one of a, b or c
$Signifies the end of a line.^\d\d\d$ matches any string that is exactly 3 digits long
(?!...)Negative lookahead. Defines a subexpression that must not be present.
(?!.*$).* matches any string that does not end
(?!alice).* matches any string that does not start with alice
(?<!...)Negative lookbehind. Defines a subexpression that must not be present..*(?<!net) matches any string that does not end with net


  1. This comment has been removed by the author.

  2. Thanks for this post - my VCS was getting hammered, but after adding some Calling Policies I now see 486 Call rejected in my logs. Makes me rest a bit easier.


  3. Thanks for this post, is very usefull!!