Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

DevSecCon London 2018: Variant Analysis – A critical step in handling vulnerabilities

180 views

Published on

KEVIN BACKHOUSE
With the increasing awareness and adoption of DevSecOps, organisations are beginning to fully understand the crucial role that security plays, integrating it into every part of the development and deployment process, from start to finish. New processes such as vulnerability disclosures & bug bounty programs, red team exercises, pen-testing initiatives and static & dynamic code analysis are putting security front and center. These initiatives are proving to be an incredible source for discovering previously unknown vulnerabilities, and fixes are generally implemented and deployed pretty quickly. However, this response is often not quite enough.

In software development, we frequently see the same logical coding mistakes being made repeatedly over the course of a project’s lifetime, and sometimes across multiple projects. Sometimes there are a number of simultaneously active instances of these mistakes, and sometimes there’s only ever one active instance at a time, but it keeps reappearing. When these mistakes lead to security vulnerabilities, the consequences can be severe.

With each vulnerability discovered or reported, if the root cause was a bug in the code, we’re presented with an opportunity to investigate how often this mistake is repeated, whether there are any other unknown vulnerabilities as a result, and implement a process to prevent it reappearing. In this talk, I’ll be introducing Variant Analysis, a process for doing just this, and discuss how it can be integrated into your development and security operations. I’ll also be sharing real-world stories of what has happened when variant analysis was neglected, as well as stories of when it’s saved the day.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

DevSecCon London 2018: Variant Analysis – A critical step in handling vulnerabilities

  1. 1. LONDON 18-19 OCT 2018 Variant Analysis – A critical step in handling vulnerabilities Kevin Backhouse Sam Lanning
  2. 2. LONDON 18-19 OCT 2018 Variant Analysis: who is it for? • Organizations that develop their own software • The software is security or safety critical • Primary use case: incident response
  3. 3. LONDON 18-19 OCT 2018 Ghostscript (Tavis Ormandy)
  4. 4. LONDON 18-19 OCT 2018
  5. 5. LONDON 18-19 OCT 2018
  6. 6. LONDON 18-19 OCT 2018
  7. 7. LONDON 18-19 OCT 2018 S2-008 Johannes Dahse, Bruce Phillips S2-032 / CVE-2016-3081 Nike Zheng S2-033 / CVE-2016-3087 Alvaro Munoz S2-037 / CVE-2016-4438 Chao Jack PKAV_香草, Shinsaku Nomura S2-045 / CVE-2017-5638 Nike Zheng S2-046 / CVE-2017-5638 Chris Frohoff, Nike Zheng, Alvaro Munoz S2-057 / CVE-2018-11776 Man Yue Mo My colleague! Apache Struts 2 OGNL injections
  8. 8. LONDON 18-19 OCT 2018 Apple packet-mangler (CVE-2017-13904, CVE-2018-4249)
  9. 9. LONDON 18-19 OCT 2018 packet-mangler.c (macOS 10.13) • Two bugs • Infinite loop • Stack buffer overflow • Both remotely triggerable (if packet-mangler is enabled)
  10. 10. LONDON 18-19 OCT 2018 while (tcp_optlen) { if (tcp_opt_buf[i] == 0x1) { PKT_MNGLR_LOG(LOG_INFO, "Skipping NOPn"); tcp_optlen--; i++; continue; } else if ((tcp_opt_buf[i] != 0) && (tcp_opt_buf[i] != TCP_OPT_MULTIPATH_TCP)) { PKT_MNGLR_LOG(LOG_INFO, "Skipping option %xn", tcp_opt_buf[i]); tcp_optlen -= tcp_opt_buf[i+1]; i += tcp_opt_buf[i+1]; continue; } else if (tcp_opt_buf[i] == TCP_OPT_MULTIPATH_TCP) { int j = 0; int mptcpoptlen = tcp_opt_buf[i+1]; … for (; j < mptcpoptlen; j++) { if (p_pkt_mnglr->proto_action_mask & PKT_MNGLR_TCP_ACT_NOP_MPTCP) { tcp_opt_buf[i+j] = 0x1; } } tcp_optlen -= mptcpoptlen; i += mptcpoptlen; } else { tcp_optlen--; i++; } } packet-mangler.c macOS 10.13 1. Attacker controlled 2. Could be any value from -128 to 127 Out of bounds write if mptcpoptlen is large Loops until tcp_optlen == 0 1. Grows if mptcpoptlen < 0 2. Goes negative if mptcpoptlen > tcp_optlen
  11. 11. LONDON 18-19 OCT 2018 while (tcp_optlen > 0) { if (tcp_opt_buf[i] == 0x1) { PKT_MNGLR_LOG(LOG_INFO, "Skipping NOPn"); tcp_optlen--; i++; continue; } else if ((tcp_opt_buf[i] != 0) && (tcp_opt_buf[i] != TCP_OPT_MULTIPATH_TCP)) { PKT_MNGLR_LOG(LOG_INFO, "Skipping option %xn", tcp_opt_buf[i]); tcp_optlen -= tcp_opt_buf[i+1]; i += tcp_opt_buf[i+1]; continue; } else if (tcp_opt_buf[i] == TCP_OPT_MULTIPATH_TCP) { int j = 0; unsigned char mptcpoptlen = tcp_opt_buf[i+1]; ... for (; j < mptcpoptlen && j < tcp_optlen; j++) { if (p_pkt_mnglr->proto_action_mask & PKT_MNGLR_TCP_ACT_NOP_MPTCP) { tcp_opt_buf[i+j] = 0x1; } } tcp_optlen -= mptcpoptlen; i += mptcpoptlen; } else { tcp_optlen--; i++; } } packet-mangler.c macOS 10.13.2 1. Attacker controlled 2. Could be zero Don’t allow negative values Cannot be negative Bounds check
  12. 12. LONDON 18-19 OCT 2018 while (tcp_optlen > 0) { if (tcp_opt_buf[i] == 0x1) { PKT_MNGLR_LOG(LOG_INFO, "Skipping NOPn"); tcp_optlen--; i++; continue; } else if ((tcp_opt_buf[i] != 0) && (tcp_opt_buf[i] != TCP_OPT_MULTIPATH_TCP)) { PKT_MNGLR_LOG(LOG_INFO, "Skipping option %xn", tcp_opt_buf[i]); /* Minimum TCP option size is 2 */ if (tcp_opt_buf[i+1] < 2) { PKT_MNGLR_LOG(LOG_ERR, "Received suspicious TCP option"); goto drop_it; } tcp_optlen -= tcp_opt_buf[i+1]; i += tcp_opt_buf[i+1]; continue; } else if (tcp_opt_buf[i] == TCP_OPT_MULTIPATH_TCP) { int j = 0; unsigned char mptcpoptlen = tcp_opt_buf[i+1]; ... for (; j < mptcpoptlen && j < tcp_optlen; j++) { if (p_pkt_mnglr->proto_action_mask & PKT_MNGLR_TCP_ACT_NOP_MPTCP) { tcp_opt_buf[i+j] = 0x1; } } packet-mangler.c macOS 10.13.5 bounds check
  13. 13. LONDON 18-19 OCT 2018 packet-mangler.c (macOS 10.13) • Two bugs • Infinite loop • Stack buffer overflow • Both remotely triggerable (if packet-mangler is enabled)
  14. 14. LONDON 18-19 OCT 2018 int i = 0; tcp_optlen = (tcp.th_off << 2)-sizeof(struct tcphdr); PKT_MNGLR_LOG(LOG_INFO, "Packet from F5 is TCPn"); PKT_MNGLR_LOG(LOG_INFO, "Optlen: %dn", tcp_optlen); orig_tcp_optlen = tcp_optlen; if (orig_tcp_optlen) { error = mbuf_copydata(*data, offset+sizeof(struct tcphdr), orig_tcp_optlen, tcp_opt_buf); if (error) { PKT_MNGLR_LOG(LOG_ERR, "Failed to copy tcp options"); goto input_done; } } while (tcp_optlen > 0) { if (tcp_opt_buf[i] == 0x1) { ... packet-mangler.c macOS 10.13.2User controlled (could be zero) Could be negative Implicit cast to size_t could overflow negatively. Unlimited amount of user controlled data gets copied to stack
  15. 15. LONDON 18-19 OCT 2018 int i = 0, off; off = (tcp.th_off << 2); if (off < (int) sizeof(struct tcphdr) || off > ip_pld_len) { PKT_MNGLR_LOG(LOG_ERR, "TCP header offset is wrong: %d", off); goto drop_it; } tcp_optlen = off - sizeof(struct tcphdr); PKT_MNGLR_LOG(LOG_INFO, "Packet from F5 is TCPn"); PKT_MNGLR_LOG(LOG_INFO, "Optlen: %dn", tcp_optlen); orig_tcp_optlen = tcp_optlen; if (orig_tcp_optlen) { error = mbuf_copydata(*data, offset+sizeof(struct tcphdr), orig_tcp_optlen, tcp_opt_buf); if (error) { PKT_MNGLR_LOG(LOG_ERR, "Failed to copy tcp options: error %d offset %d optlen %d", error, offset, orig_tcp_optlen); goto input_done; } } while (tcp_optlen > 0) { if (tcp_opt_buf[i] == 0x1) { ... packet-mangler.c macOS 10.13.5 bounds check
  16. 16. LONDON 18-19 OCT 2018 packet-mangler summary • Multiple bugs found in 55 lines of code • It took multiple tries to fix all the bugs: • My initial PoC did not trigger all the bugs • Apple only fixed the symptoms of the PoC
  17. 17. LONDON 18-19 OCT 2018 1. Badly tested area of the codebase 2. Flawed design makes the code bug prone 3. Confusing API leads to errors 4. Bug duplication due to copy/paste 5. The responsible developer made similar mistakes elsewhere Reasons why bugs are rarely unique vulns bugs Kev’s rule of thumb: #bugs > 100 * #vulns co-located bugs scattered bugs
  18. 18. LONDON 18-19 OCT 2018 Incident response process
  19. 19. LONDON 18-19 OCT 2018 Techniques for discovering variants 1. Add a regression test 2. Code review: • Thorough code review of the affected function/module 3. Add unit tests • Check code coverage results 4. Fuzz testing • Throwing random inputs at it might uncover other issues • Use the known issue as a starting point 5. Check other code written by this developer 6. Search the code for similar patterns
  20. 20. LONDON 18-19 OCT 2018 Example of a dangerous coding pattern librelp (rsyslog) CVE-2018-1000140 while(!bFoundPositiveMatch) { /* loop broken below */ … iAllNames += snprintf(allNames+iAllNames, sizeof(allNames)-iAllNames, "DNSname: %s; ", szAltName); … } output is fed back into size argument
  21. 21. LONDON 18-19 OCT 2018 Code as data • Import source code into a database • Write queries to find patterns
  22. 22. LONDON 18-19 OCT 2018 Michael Fanning: “A Microsoft DevSecOps Static Application Security Testing (SAST) Exercise” https://blogs.msdn.microsoft.com/devops/2018/08/21/microsoft-devsecops-static-application-security-testing-sast-exercise/
  23. 23. LONDON 18-19 OCT 2018 kev@semmle.com @kevin_backhouse sam@semmle.com @samlanning lgtm.com

×