Making international calls by call forwarding

Hi, I’ve noticed that our PBX has been compromised by someone in order to make premium international calls. I know the calls are being made through the PSTN, and I have checked the items in this thread (we are on FreePBX 14 anyway).
I’m trying to understand how this has been achieved, so can be prevented for future. Our current call flow looks like;

  • Inbound route
  • Call Flow
  • Time Condition
  • Ring Group containing extensions + mobile number with 10 sec timeout (Ring All)
  • Ring Group containing only mobile number

What I can see from the logs is that the call comes in from the PSTN, and goes through and gets redirected to the mobile number

[2018-03-02 20:45:26] VERBOSE[23217][C-00001457] netsock2.c: Using SIP RTP CoS mark 5
[2018-03-02 20:45:26] VERBOSE[23217][C-00001457] app_dial.c: Called SIP/Trunk-out/447XXXXXXXXX
[2018-03-02 20:45:27] VERBOSE[23217][C-00001457] app_dial.c: SIP/Trunk-out-00005a1b is making progress passing it to Local/447XXXXXXXXX@from-internal-00002fb5;2
[2018-03-02 20:45:27] VERBOSE[23193][C-00001457] app_dial.c: Local/447XXXXXXXXX@from-internal-00002fb5;1 is making progress passing it to SIP/trunk-in-00005a0b
[2018-03-02 20:45:34] VERBOSE[23217][C-00001457] app_dial.c: SIP/Trunk-out-00005a1b answered Local/447XXXXXXXXX@from-internal-00002fb5;2
[2018-03-02 20:45:34] VERBOSE[23218][C-00001457] bridge_channel.c: Channel SIP/Trunk-out-00005a1b joined ‘simple_bridge’ basic-bridge
[2018-03-02 20:45:34] VERBOSE[23193][C-00001457] app_dial.c: Local/447XXXXXXXXX@from-internal-00002fb5;1 answered SIP/trunk-in-00005a0b

Somehow, the caller manages to get themselves on hold, and then transfers themselves to another extension using *93 feature code, and then set call forwarding to an external number?

[2018-03-02 20:45:37] VERBOSE[23217][C-00001457] file.c: <Local/447XXXXXXXXX@from-internal-00002fb5;2> Playing ‘pbx-transfer.ulaw’ (language ‘en’)
[2018-03-02 20:45:37] VERBOSE[23218][C-00001457] res_musiconhold.c: Started music on hold, class ‘default’, on channel ‘SIP/Trunk-out-00005a1b’
[2018-03-02 20:45:39] VERBOSE[23220][C-00001457] pbx.c: Executing [*93@from-internal-xfer:1] Answer(“Local/*93@from-internal-xfer-00002fb6;2”, “”) in new stack
[2018-03-02 20:45:39] VERBOSE[23221][C-00001457] bridge_channel.c: Channel Local/*93@from-internal-xfer-00002fb6;1 joined ‘simple_bridge’ basic-bridge <1451c271-cfef-4542-a427-b8e9a0ab6d17>
[2018-03-02 20:45:39] VERBOSE[23222][C-00001457] bridge_channel.c: Channel Local/447XXXXXXXXX@from-internal-00002fb5;2 left ‘simple_bridge’ basic-bridge
[2018-03-02 20:45:39] VERBOSE[23222][C-00001457] bridge_channel.c: Channel Local/447XXXXXXXXX@from-internal-00002fb5;2 joined ‘simple_bridge’ basic-bridge <1451c271-cfef-4542-a427-b8e9a0ab6d17>
[2018-03-02 20:45:39] VERBOSE[23220][C-00001457] pbx.c: Executing [*93@from-internal-xfer:2] Wait(“Local/*93@from-internal-xfer-00002fb6;2”, “1”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [*93@from-internal-xfer:3] Macro(“Local/*93@from-internal-xfer-00002fb6;2”, “user-callerid,”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:1] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “TOUCH_MONITOR=1520023539.47499”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:2] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “AMPUSER=”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:3] GotoIf(“Local/*93@from-internal-xfer-00002fb6;2”, “0?report”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:4] ExecIf(“Local/*93@from-internal-xfer-00002fb6;2”, “1?Set(REALCALLERIDNUM=)”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:5] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “AMPUSER=”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:6] GotoIf(“Local/*93@from-internal-xfer-00002fb6;2”, “0?limit”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:7] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “AMPUSERCIDNAME=”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:8] ExecIf(“Local/*93@from-internal-xfer-00002fb6;2”, “0?Set(__CIDMASQUERADING=TRUE)”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:9] GotoIf(“Local/*93@from-internal-xfer-00002fb6;2”, “1?report”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx_builtins.c: Goto (macro-user-callerid,s,16)
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:16] NoOp(“Local/*93@from-internal-xfer-00002fb6;2”, “Macro Depth is 1”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:17] GotoIf(“Local/*93@from-internal-xfer-00002fb6;2”, “1?report2:macroerror”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx_builtins.c: Goto (macro-user-callerid,s,19)
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:19] GotoIf(“Local/*93@from-internal-xfer-00002fb6;2”, “0?continue”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:20] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “__TTL=62”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:21] GotoIf(“Local/*93@from-internal-xfer-00002fb6;2”, “1?continue”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx_builtins.c: Goto (macro-user-callerid,s,37)
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:37] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “CALLERID(number)=”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:38] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “CALLERID(name)=unavailable”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:39] GotoIf(“Local/*93@from-internal-xfer-00002fb6;2”, “0?cnum”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:40] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “CDR(cnam)=unavailable”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:41] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “CDR(cnum)=”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [s@macro-user-callerid:42] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “CHANNEL(language)=en”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [*93@from-internal-xfer:4] Gosub(“Local/*93@from-internal-xfer-00002fb6;2”, “app-cf-prompting-on,lang-playback,1(hook_0)”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [lang-playback@app-cf-prompting-on:1] GosubIf(“Local/*93@from-internal-xfer-00002fb6;2”, “1?app-cf-prompting-on,en,hook_0():app-cf-prompting-on,en,hook_0()”) in new stack
[2018-03-02 20:45:40] VERBOSE[23220][C-00001457] pbx.c: Executing [en@app-cf-prompting-on:1] Read(“Local/*93@from-internal-xfer-00002fb6;2”, “fromext,call-fwd-unconditional&please-enter-your-extension-then-press-pound,”) in new stack
[2018-03-02 20:45:41] VERBOSE[23220][C-00001457] file.c: <Local/*93@from-internal-xfer-00002fb6;2> Playing ‘call-fwd-unconditional.ulaw’ (language ‘en’)
[2018-03-02 20:45:41] VERBOSE[23218][C-00001457] res_musiconhold.c: Stopped music on hold on SIP/Trunk-out-00005a1b
[2018-03-02 20:45:41] VERBOSE[23218][C-00001457] bridge_channel.c: Channel SIP/Trunk-out-00005a1b left ‘simple_bridge’ basic-bridge
[2018-03-02 20:45:41] VERBOSE[23217][C-00001457] file.c: <Local/447XXXXXXXXX@from-internal-00002fb5;2> Playing ‘beeperr.ulaw’ (language ‘en’)
[2018-03-02 20:45:43] VERBOSE[23220][C-00001457] file.c: <Local/*93@from-internal-xfer-00002fb6;2> Playing ‘please-enter-your-extension-then-press-pound.slin’ (language ‘en’)
[2018-03-02 20:45:51] VERBOSE[23220][C-00001457] app_read.c: User entered ‘206’
[2018-03-02 20:45:51] VERBOSE[23220][C-00001457] pbx.c: Executing [en@app-cf-prompting-on:2] Return(“Local/*93@from-internal-xfer-00002fb6;2”, “”) in new stack
[2018-03-02 20:45:51] VERBOSE[23220][C-00001457] pbx.c: Executing [lang-playback@app-cf-prompting-on:2] Return(“Local/*93@from-internal-xfer-00002fb6;2”, “”) in new stack
[2018-03-02 20:45:51] VERBOSE[23220][C-00001457] pbx.c: Executing [*93@from-internal-xfer:5] Set(“Local/*93@from-internal-xfer-00002fb6;2”, “fromext=206”) in new stack
[2018-03-02 20:45:51] VERBOSE[23220][C-00001457] pbx.c: Executing [*93@from-internal-xfer:6] Wait(“Local/*93@from-internal-xfer-00002fb6;2”, “1”) in new stack
[2018-03-02 20:45:52] VERBOSE[23220][C-00001457] pbx.c: Executing [*93@from-internal-xfer:7] Gosub(“Local/*93@from-internal-xfer-00002fb6;2”, “app-cf-prompting-on,lang-playback,1(hook_1)”) in new stack
[2018-03-02 20:45:52] VERBOSE[23220][C-00001457] pbx.c: Executing [lang-playback@app-cf-prompting-on:1] GosubIf(“Local/*93@from-internal-xfer-00002fb6;2”, “1?app-cf-prompting-on,en,hook_1():app-cf-prompting-on,en,hook_1()”) in new stack
[2018-03-02 20:45:52] VERBOSE[23220][C-00001457] pbx.c: Executing [en@app-cf-prompting-on:3] Read(“Local/*93@from-internal-xfer-00002fb6;2”, “toext,agent-newlocation,”) in new stack
[2018-03-02 20:45:52] VERBOSE[23220][C-00001457] file.c: <Local/*93@from-internal-xfer-00002fb6;2> Playing ‘agent-newlocation.ulaw’ (language ‘en’)
[2018-03-02 20:46:06] VERBOSE[23220][C-00001457] app_read.c: User entered ‘0014084542500’

Any ideas how they are managing to do this and what measures can be taken to prevent it?
I can provide more logs, but it just means a lot of redacting if posting in public.

I suspect that after the call to the mobile was answered (live or voicemail), the attacker dialed *2 (Attended Transfer) then at the dial tone dialed *93 (Call Forwarding All Prompting Activate), entered your extension number and the international number. Upon calling in again, the call is forwarded to the international number. Normally, the “Disallow transfer features for inbound callers” option which defaults to Yes should block this.
Perhaps there is a bug and the ring group somehow bypasses the option. You can verify this with a test call from your mobile.

For starters, if you don’t need the in-call DTMF functions at all (you use the transfer button on the phone or app to transfer a call, etc.), just remove the T and t from Asterisk Dial Options and Asterisk Outbound Trunk Dial Options . If you must have these functions, change them to obscure sequences that would be hard for an attacker to guess.

You may also want to disable stuff like *93 which can cause trouble even without a security vulnerability, because it allows any internal user to set up or change forwarding for any other user. If you need this functionality, limit it to specific users or use a long code that is essentially a password.

For additional protection, you could set your regular outbound routes to deny countries that you don’t normally call, and premium numbers ranges in the countries you do call. You would then add a password-protected route that bypassed the restrictions.

Your trunking provider may allow you to set a maximum call rate on your normal prefix; an additional password-protected route would send a different prefix with a higher limit.

Weirdly I couldn’t replicate it when trying to do what I could see happened in Asterisk logs.
It happened a second time a few days later, and so I’ve just disabled all call forwarding short codes, because we don’t need the functionality for anything.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.