README-SERIOUSLY.bestpractices.txt: Convert to markdown
[asterisk/asterisk.git] / README-SERIOUSLY.bestpractices.md
1 # Best Practices
2
3 The purpose of this document is to define best practices when working with
4 Asterisk in order to minimize possible security breaches and to provide tried
5 examples in field deployments. This is a living document and is subject to
6 change over time as best practices are defined.
7
8 * [Filtering Data]:
9         How to protect yourself from redial attacks
10 * [Proper Device Naming]:
11         Why to not use numbered extensions for devices
12 * [Secure Passwords]:
13         Secure passwords limit your risk to brute force attacks
14 * [Reducing Pattern Match Typos]:
15         Using the 'same' prefix, or using Goto()
16 * [Manager Class Authorizations]:
17         Recognizing potential issues with certain classes of authorization
18 * [Avoid Privilege Escalations]:
19         Disable the ability to execute functions that may escalate privileges
20
21
22 ## Additional Links
23
24 Additional links that contain useful information about best practices or
25 security are listed below.
26
27 * [Seven Steps to Better SIP Security][blog-sip-security]
28 * [Asterisk VoIP Security (webinar)][voip-security-webinar]
29
30
31 ## Filtering Data
32
33 In the Asterisk dialplan, several channel variables contain data potentially
34 supplied by outside sources. This could lead to a potential security concern
35 where those outside sources may send cleverly crafted strings of data which
36 could be utilized, e.g. to place calls to unexpected locations.
37
38 An example of this can be found in the use of pattern matching and the ${EXTEN}
39 channel variable. Note that ${EXTEN} is not the only system created channel
40 variable, so it is important to be aware of where the data you're using is
41 coming from.
42
43 For example, this common dialplan takes 2 or more characters of data, starting
44 with a number 0-9, and then accepts any additional information supplied by the
45 request.
46
47 **NOTE**:
48 > We use SIP in this example, but is not limited to SIP only; protocols such as
49 > Jabber/XMPP or IAX2 are also susceptible to the same sort of injection problem.
50
51 ```INI
52 [incoming]
53 exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
54 exten => _X.,n,Dial(SIP/${EXTEN})
55 exten => _X.,n,Hangup()
56 ```
57
58 This dialplan may be utilized to accept calls to extensions, which then dial a
59 numbered device name configured in one of the channel configuration files (such
60 as sip.conf, iax.conf, etc...) (see [Proper Device Naming] for more information
61 on why this approach is flawed).
62
63 The example we've given above looks harmless enough until you take into
64 consideration that several channel technologies accept characters that could
65 be utilized in a clever attack. For example, instead of just sending a request
66 to dial extension 500 (which in our example above would create the string
67 SIP/500 and is then used by the Dial() application to place a call), someone
68 could potentially send a string like "500&SIP/itsp/14165551212".
69
70 The string "500&SIP/itsp/14165551212" would then be contained within the
71 ${EXTEN} channel variable, which is then utilized by the Dial() application in
72 our example, thereby giving you the dialplan line of:
73
74 ```INI
75 exten => _X.,n,Dial(SIP/500&SIP/itsp/14165551212)
76 ```
77
78 Our example above has now provided someone with a method to place calls out of
79 your ITSP in a place where you didn't expect to allow it. There are a couple of
80 ways in which you can mitigate this impact: stricter pattern matching, or using
81 the FILTER() dialplan function.
82
83 The CALLERID(num) and CALLERID(name) values are other commonly used values that
84 are sources of data potentially supplied by outside sources.  If you use these
85 values as parameters to the System(), MixMonitor(), or Monitor() applications
86 or the SHELL() dialplan function, you can allow injection of arbitrary operating
87 system command execution.  The FILTER() dialplan function is available to remove
88 dangerous characters from untrusted strings to block the command injection.
89
90
91 ### Strict Pattern Matching
92
93 The simple way to mitigate this problem is with a strict pattern match that does
94 not utilize the period (.) or bang (!) characters to match on one-or-more
95 characters or zero-or-more characters (respectively). To fine tune our example
96 to only accept three digit extensions, we could change our pattern match to
97 be:
98
99 ```INI
100 exten => _XXX,n,Dial(SIP/${EXTEN})
101 ```
102
103 In this way, we have minimized our impact because we're not allowing anything
104 other than the numbers zero through nine. But in some cases we really do need to
105 handle variable pattern matches, such as when dialing international numbers
106 or when we want to handle something like a SIP URI. In this case, we'll need to
107 utilize the FILTER() dialplan function.
108
109
110 ### Using FILTER()
111
112 The FILTER() dialplan function is used to filter strings by only allowing
113 characters that you have specified. This is a perfect candidate for controlling
114 which characters you want to pass to the Dial() application, or any other
115 application which will contain dynamic information passed to Asterisk from an
116 external source. Lets take a look at how we can use FILTER() to control what
117 data we allow.
118
119 Using our previous example to accept any string length of 2 or more characters,
120 starting with a number of zero through nine, we can use FILTER() to limit what
121 we will accept to just numbers. Our example would then change to something like:
122
123 ```INI
124 [incoming]
125 exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
126 exten => _X.,n,Dial(SIP/${FILTER(0-9,${EXTEN})})
127 exten => _X.,n,Hangup()
128 ```
129
130 Note how we've wrapped the ${EXTEN} channel variable with the FILTER() function
131 which will then only pass back characters that fit into the numerical range that
132 we've defined.
133
134 Alternatively, if we didn't want to utilize the FILTER() function within the
135 Dial() application directly, we could save the value to a channel variable,
136 which has a side effect of being usable in other locations of your dialplan if
137 necessary, and to handle error checking in a separate location.
138
139 ```INI
140 [incoming]
141 exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
142 exten => _X.,n,Set(SAFE_EXTEN=${FILTER(0-9,${EXTEN})})
143 exten => _X.,n,Dial(SIP/${SAFE_EXTEN})
144 exten => _X.,n,Hangup()
145 ```
146
147 Now we can use the ${SAFE_EXTEN} channel variable anywhere throughout the rest
148 of our dialplan, knowing we've already filtered it. We could also perform an
149 error check to verify that what we've received in ${EXTEN} also matches the data
150 passed back by FILTER(), and to fail the call if things do not match.
151
152 ```INI
153 [incoming]
154 exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
155 exten => _X.,n,Set(SAFE_EXTEN=${FILTER(0-9,${EXTEN})})
156 exten => _X.,n,GotoIf($[${EXTEN} != ${SAFE_EXTEN}]?error,1)
157 exten => _X.,n,Dial(SIP/${SAFE_EXTEN})
158 exten => _X.,n,Hangup()
159
160 exten => error,1,Verbose(2,Values of EXTEN and SAFE_EXTEN did not match.)
161 exten => error,n,Verbose(2,EXTEN: "${EXTEN}" -- SAFE_EXTEN: "${SAFE_EXTEN}")
162 exten => error,n,Playback(silence/1&invalid)
163 exten => error,n,Hangup()
164 ```
165
166 Another example would be using FILTER() to control the characters we accept when
167 we're expecting to get a SIP URI for dialing.
168
169 ```INI
170 [incoming]
171 exten => _[0-9a-zA-Z].,1,Verbose(2,Incoming call to extension ${EXTEN})
172 exten => _[0-9a-zA-Z].,n,Dial(SIP/${FILTER(.@0-9a-zA-Z,${EXTEN})
173 exten => _[0-9a-zA-Z].,n,Hangup()
174 ```
175
176 Of course the FILTER() function doesn't check the formatting of the incoming
177 request. There is also the REGEX() dialplan function which can be used to
178 determine if the string passed to it matches the regular expression you've
179 created, and to take proper action on whether it matches or not. The creation of
180 regular expressions is left as an exercise for the reader.
181
182 More information about the FILTER() and REGEX() dialplan functions can be found
183 by typing "core show function FILTER" and "core show function REGEX" from your
184 Asterisk console.
185
186
187 ## Proper Device Naming
188
189 In Asterisk, the concept of an extension number being tied to a specific device
190 does not exist. Asterisk is aware of devices it can call or receive calls from,
191 and how you define in your dialplan how to reach those devices is up to you.
192
193 Because it has become common practice to think of a specific device as having an
194 extension number associated with it, it only becomes natural to think about
195 naming your devices the same as the extension number you're providing it. But
196 by doing this, you're limiting the powerful concept of separating user from
197 extensions, and extensions from devices.
198
199 It can also be a security hazard to name your devices with a number, as this can
200 open you up to brute force attacks. Many of the current exploits deal with
201 device configurations which utilize a number, and even worse, a password that
202 matches the devices name. For example, take a look at this poorly created device
203 in sip.conf:
204
205 ```INI
206 [1000]
207 type=friend
208 context=international_dialing
209 secret=1000
210 ```
211
212 As implied by the context, we've permitted a device named 1000 with a password
213 of 1000 to place calls internationally. If your PBX system is accessible via
214 the internet, then your system will be vulnerable to expensive international
215 calls. Even if your system is not accessible via the internet, people within
216 your organization could get access to dialing rules you'd prefer to reserve only
217 for certain people.
218
219 A more secure example for the device would be to use something like the MAC
220 address of the device, along with a strong password (see the section Secure
221 Passwords). The following example would be more secure:
222
223 ```INI
224 [0004f2040001]
225 type=friend
226 context=international_dialing
227 secret=aE3%B8*$jk^G
228 ```
229
230 Then in your dialplan, you would reference the device via the MAC address of the
231 device (or if using the softphone, a MAC address of a network interface on the
232 computer).
233
234 Also note that you should NOT use this password, as it will likely be one of the
235 first ones added to the dictionary for brute force attacks.
236
237
238 ## Secure Passwords
239
240 Secure passwords are necessary in many (if not all) environments, and Asterisk
241 is certainly no exception, especially when it comes to expensive long distance
242 calls that could potentially cost your company hundreds or thousands of dollars
243 on an expensive monthly phone bill, with little to no recourse to fight the
244 charges.
245
246 Whenever you are positioned to add a password to your system, whether that is
247 for a device configuration, a database connection, or any other secure
248 connection, be sure to use a secure password. A good example of a secure
249 password would be something like:
250
251 ```
252 aE3%B8*$jk^G
253 ```
254
255 Our password also contains 12 characters with a mixture of upper and
256 lower case characters, numbers, and symbols. Because these passwords are likely
257 to only be entered once, or loaded via a configuration file, there is
258 no need to create simple passwords, even in testing. Some of the holes found in
259 production systems used for exploitations involve finding the one test extension
260 that contains a weak password that was forgotten prior to putting a system into
261 production.
262
263 Using a web search you can find several online password generators such as
264 [Strong Password Generator] or there are several scripts that can be
265 used to generate a strong password.
266
267
268 ## Reducing Pattern Match Typos
269
270 As of Asterisk 1.6.2, a new method for reducing the number of complex pattern
271 matches you need to enter, which can reduce typos in your dialplan, has been
272 implemented. Traditionally, a dialplan with a complex pattern match would look
273 something like:
274
275 ```INI
276 exten => _[3-5]XXX,1,Verbose(Incoming call to ${EXTEN})
277 exten => _[3-5]XXX,n,Set(DEVICE=${DB(device/mac_address/${EXTEN})})
278 exten => _[3-5]XXX,n,Set(TECHNOLOGY=${DB(device/technology/${EXTEN})})
279 exten => _[3-5]XXX,n,GotoIf($[${ISNULL(${TECHNOLOGY})} | ${ISNULL(${DEVICE})}]?error,1)
280 exten => _[3-5]XXX,n,Dial(${TECHNOLOGY}/${DEVICE},${GLOBAL(TIMEOUT)})
281 exten => _[3-5]XXX,n,Set(vmFlag=${IF($[${DIALSTATUS} = BUSY]?b:u)})
282 exten => _[3-5]XXX,n,Voicemail(${EXTEN}@${GLOBAL(VOICEMAIL_CONTEXT)},${vmFlag})
283 exten => _[3-5]XXX,n,Hangup()
284
285 exten => error,1,Verbose(2,Unable to lookup technology or device for extension)
286 exten => error,n,Playback(silence/1&num-not-in-db)
287 exten => error,n,Hangup()
288 ```
289
290 Of course there exists the possibility for a typo when retyping the pattern
291 match _\[3-5\]XXX which will match on extensions 3000 through 5999. We can
292 minimize this error by utilizing the same => prefix on all lines beyond the
293 first one. Our same dialplan with using same => would look like the following:
294
295 ```INI
296 exten => _[3-5]XXX,1,Verbose(Incoming call to ${EXTEN})
297 same => n,Set(DEVICE=${DB(device/mac_address/${EXTEN})})
298 same => n,Set(TECHNOLOGY=${DB(device/technology/${EXTEN})})
299 same => n,GotoIf($[${ISNULL(${TECHNOLOGY})} | ${ISNULL(${DEVICE})}]?error,1)
300 same => n,Dial(${TECHNOLOGY}/${DEVICE},${GLOBAL(TIMEOUT)})
301 same => n,Set(vmFlag=${IF($[${DIALSTATUS} = BUSY]?b:u)})
302 same => n,Voicemail(${EXTEN}@${GLOBAL(VOICEMAIL_CONTEXT)},${vmFlag})
303 same => n,Hangup()
304
305 exten => error,1,Verbose(2,Unable to lookup technology or device for extension)
306 same => n,Playback(silence/1&num-not-in-db)
307 same => n,Hangup()
308 ```
309
310
311 ## Manager Class Authorizations
312
313 Manager accounts have associated class authorizations that define what actions
314 and events that account can execute/receive.  In order to run Asterisk commands
315 or dialplan applications that affect the system Asterisk executes on, the
316 "system" class authorization should be set on the account.
317
318 However, Manager commands that originate new calls into the Asterisk dialplan
319 have the potential to alter or affect the system as well, even though the
320 class authorization for origination commands is "originate".  Take, for example,
321 the Originate manager command:
322
323 ```
324 Action: Originate
325 Channel: SIP/foo
326 Exten: s
327 Context: default
328 Priority: 1
329 Application: System
330 Data: echo hello world!
331 ```
332
333 This manager command will attempt to execute an Asterisk application, System,
334 which is normally associated with the "system" class authorication.  While some
335 checks have been put into Asterisk to take this into account, certain dialplan
336 configurations and/or clever manipulation of the Originate manager action can
337 circumvent these checks.  For example, take the following dialplan:
338
339 ```INI
340 exten => s,1,Verbose(Incoming call)
341 same => n,MixMonitor(foo.wav,,${EXEC_COMMAND})
342 same => n,Dial(SIP/bar)
343 same => n,Hangup()
344 ```
345
346 Whatever has been defined in the variable EXEC_COMMAND will be executed after
347 MixMonitor has finished recording the call.  The dialplan writer may have
348 intended that this variable to be set by some other location in the dialplan;
349 however, the Manager action Originate allows for channel variables to be set by
350 the account initiating the new call.  This could allow the Originate action to
351 execute some command on the system by setting the EXEC_COMMAND dialplan variable
352 in the Variable: header.
353
354 In general, you should treat the Manager class authorization "originate" the
355 same as the class authorization "system".  Good system configuration, such as
356 not running Asterisk as root, can prevent serious problems from arising when
357 allowing external connections to originate calls into Asterisk.
358
359
360 ## Avoid Privilege Escalations
361
362 External control protocols, such as Manager, often have the ability to get and
363 set channel variables; which allows the execution of dialplan functions.
364
365 Dialplan functions within Asterisk are incredibly powerful, which is wonderful
366 for building applications using Asterisk. But during the read or write
367 execution, certain diaplan functions do much more. For example, reading the
368 SHELL() function can execute arbitrary commands on the system Asterisk is
369 running on. Writing to the FILE() function can change any file that Asterisk has
370 write access to.
371
372 When these functions are executed from an external protocol, that execution
373 could result in a privilege escalation. Asterisk can inhibit the execution of
374 these functions, if live_dangerously in the \[options\] section of asterisk.conf
375 is set to no.
376
377 In Asterisk 12 and later, live_dangerously defaults to no.
378
379
380 [voip-security-webinar]: https://www.asterisk.org/security/webinar/
381 [blog-sip-security]: http://blogs.digium.com/2009/03/28/sip-security/
382 [Strong Password Generator]: https://www.strongpasswordgenerator.com
383 [Filtering Data]: #filtering-data
384 [Proper Device Naming]: #proper-device-naming
385 [Secure Passwords]: #secure-passwords
386 [Reducing Pattern Match Typos]: #reducing-pattern-match-typos
387 [Manager Class Authorizations]: #manager-class-authorizations
388 [Avoid Privilege Escalations]: #avoid-privilege-escalations