https://crocs.fi.muni.cz @CRoCS_MUNI PV286 - Secure coding principles and practices Secure coding introduction + language level vulnerabilities: Buffer overflow, type overflow, strings Łukasz Chmielewski chmiel@fi.muni.cz (based on the lecture by P. Svenda) (email me with your questions/feedback) Centre for Research on Cryptography and Security, Masaryk University Consultation hours: Friday 9.30-11.00 in A406 (but email me before). https://crocs.fi.muni.cz @CRoCS_MUNI This Lecture • Course trivia: PV286+PA193 • Short Project Presentation (by Jan Kvapil) • The lecture itself. If we do not finish, then please check: – https://is.muni.cz/auth/el/fi/jaro2022/PA193/um/video/PA193_01_BufferOverflowStrings_2022.video5 • Materials: – https://is.muni.cz/auth/el/fi/jaro2024/PV286/um/ | PV286 - Secure coding2 https://crocs.fi.muni.cz @CRoCS_MUNI COURSE TRIVIA: PV286+PA193_00_COURSE_ORGANISATION_2024 | PV286 - Secure coding3 https://crocs.fi.muni.cz @CRoCS_MUNI Problem? https://nvd.nist.gov/ | PV286 - Secure coding4 https://crocs.fi.muni.cz @CRoCS_MUNI What is the cost of insecure software • Increased risk and failures due to generally increased usage of computers • Fixing bug in released version is more expensive – Testing, announcements… • Liability laws – Need to notify, settlements, GDPR... • Reputation loss – (unfortunately, does not seem to be at the moment) • Cost of defense is decreasing – better training (like this course ☺), automated tools, development methods, new langs… – but the complexity of software is also increasing | PV286 - Secure coding5 https://crocs.fi.muni.cz @CRoCS_MUNI There is HUGE market for (undisclosed) vulnerabilities • Up to millions of dollars for single undisclosed exploit • Payed over defined period it stays undiscovered – Product vendor is not notified and cannot fix • Ethics: export restrictions to sell exploit kits – But HackingTeam, Cellebrite, NSO… https://zerodium.com/program.html | PV286 - Secure coding6 https://crocs.fi.muni.cz @CRoCS_MUNI What software security means? • Use of generic good development and security practices – Education, testing, defence in depth, code review… – Safety (random errors CRC good enough) vs. security (intentional attacker recomputing CRC after malicious change) – Security is process, not product (Secure Development Lifecycle) • Have systematic deployment, maintenance and mitigation of issues (including the security relevant) – Monitor, triage, fix, update process, detection of issues in 3rd party libs… • Usability - easy to use right, hard to misuse – Hard for developers to misuse or misconfigure (API security…), hard for end-users to make a mistake – If misuse, then limit its impact, secure defaults… • Automated and manual review and testing – Continuous integration, pentesting, security code review • Language-specific issues and procedures, corresponding tooling and automation – Buffer overflow (C/C++), code injection (Java)… • Use of secure cryptographic primitives – Cryptographic libraries, random numbers, password handling, secure channels, key distribution… Icons made by geotatah, eucalypt, freepik from www.flaticon.com | PV286 - Secure coding7 https://crocs.fi.muni.cz @CRoCS_MUNI Defensive programming • Term coined by Kernighan and Plauger, 1981 – “writing the program so it can cope with small disasters” – talked about in introductory programming courses • Practice of coding with the mind-set that errors are inevitable, and something will always go wrong – prepare program for unexpected behavior and inputs – prepare program for easier testing and bug diagnostics • Defensive programming targets mainly unintentional errors (not intentional attacks) – But increasingly given security connotation | PV286 - Secure coding8 https://crocs.fi.muni.cz @CRoCS_MUNI WHERE TO LEARN ABOUT BUGS AND RESULTING VULNERABILITIES? | PV286 - Secure coding9 https://crocs.fi.muni.cz @CRoCS_MUNI Attacker goals and related vulnerabilities • Bug is unintended and unwanted behavior which attacker can use to: 1. Steal some data (keys in memory, content of files…) 2. Bypass some protection (access rights, authentication, hijack session) 3. Execute malicious code (custom payload, ROP…) 4. Cause denial of service (resource exhaustion, infinite loop, regex) 5. … • The real attack (exploit) often combines multiple steps – E.g., DoS to deplete memory resulting in failed dynamic allocation, then write to null pointer, then execute malicious payload | PV286 - Secure coding10 https://crocs.fi.muni.cz @CRoCS_MUNI Where to find relevant bug patterns and info • Taxonomies of vulnerabilities (systematic) – Common Weakness Enumeration (CWE) https://cwe.mitre.org/ – Wikipedia (https://en.wikipedia.org/wiki/Memory_safety ...) • List of real vulnerabilities detected and reported (complex real-world examples) – Common Vulnerabilities and Exposures (CVE) https://cve.mitre.org/ • Lists of frequent bugs (prioritization) – The CWE Top 25 https://cwe.mitre.org/top25/archive/2020/2020_cwe_top25.html – OWASP TOP10 https://owasp.org/www-project-top-ten/ – HackerOne TOP 10 https://www.hackerone.com/top-10-vulnerabilities – Veracode TOP 10 by language https://info.veracode.com/state-of-software-security-volume-11- flaw-frequency-by-language-infosheet-resource.html – Significant differences between usage domains (web vs. embedded devices) • Bug patterns searched for by specific tool (understanding bugs & tool used) – E.g., FindSecurityBugs (Java): https://find-sec-bugs.github.io/bugs.htm | PV286 - Secure coding11 https://crocs.fi.muni.cz @CRoCS_MUNI Common Weakness Enumeration (CWE) • Taxonomy of vulnerabilities https://cwe.mitre.org/ • List of vulnerability categories, sub-categories, examples and mitigation – Baseline for vulnerability identification, mitigation and prevention – Itself is great study material including examples • Example CWE-124 Buffer Underwrite – https://cwe.mitre.org/data/definitions/124.html int main() { // ... strncpy(destBuf, &srcBuf[find(srcBuf, ch)], 1024); } | PV286 - Secure coding12 https://crocs.fi.muni.cz @CRoCS_MUNI https://cwe.mitre.org/data/definitions/124.html https://crocs.fi.muni.cz @CRoCS_MUNI https://crocs.fi.muni.cz @CRoCS_MUNI Frequent bugs – worth of prioritization (CWE/CVE) https://cwe.mitre.org/top25/archive/2020/2020_cwe_top25.html • Score by presence in real vulnerabilities – Common Vulnerabilities and Exposures (CVE) | PV286 - Secure coding15 https://crocs.fi.muni.cz @CRoCS_MUNI Frequent bugs – worth of prioritization (web) • Be aware: – Differences between software domains (web, OS kernel, libraries…) – Detection bias – bugs we can more easily detect seem to be more frequent https://owasp.org/www-project-top-ten/ | PV286 - Secure coding16 https://crocs.fi.muni.cz @CRoCS_MUNI Example: Injection (1. OWASP TOP 10, 3. CWE Top 25) • Goal: Return records from DB for the provided customer ID (custID) String query = "SELECT * FROM accounts WHERE custID='" + request.getParameter("id") + “’”; • User/attacker will provide customer ID as follows: – http://example.com/app/accountView?id=' or '1'='1 • Resulting SQL command after expansion (executed by database engine) – SELECT * FROM accounts WHERE custID='' or '1'='1’ • Mitigation – Don’t try to detect and fix injection by checking input arguments yourself! – Read about defenses, use dedicated secure API (e.g., PreparedStatement in this case) – https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html https://owasp.org/www-project-top-ten/2017/A1_2017-Injection | PV286 - Secure coding17 https://crocs.fi.muni.cz @CRoCS_MUNI CWE flaw types by language https://info.veracode.com/state-of-software-security-volume-11-flaw-frequency-by-language-infosheet-resource.html 18 https://crocs.fi.muni.cz @CRoCS_MUNI Bugs patterns searched by tools • Bug description • Example of vulnerable code • References to other lists – CWE, OWASP… https://find-sec-bugs.github.io/bugs.htm | PV286 - Secure coding19 https://crocs.fi.muni.cz @CRoCS_MUNI Digging deeper and learning more… • Read top-level categories from CWE Software Development – Get broad overview https://cwe.mitre.org/data/definitions/699.html • Read details about top vulnerabilities from OWASP or CWE list – Likely the most common ones • Find, read about and test several vulnerabilities in detail – Which applies to your favorite language (e.g., Java) – And target domain (e.g., server database backend) in detail – Learn more about system by understanding all details • Experiment with several automatic tools to detect such vulnerabilities • Think like an attacker, have fun ☺ | PV286 - Secure coding20 https://crocs.fi.muni.cz @CRoCS_MUNI Vulnerability disclosure basics • Bug, Vulnerability, Proof of Concept (PoC), Exploit – Bug = buffer overflow – Vulnerability = execution of malicious code – Proof of Concept = tool triggering buffer overflow and crashing program – Exploit = tool trigger buffer overflow, executing custom payload and creating root account on target machine • Public disclosure, Uncoordinated public disclosure, Zero-day • Responsible disclosure, disclosure period/deadline, bugbounty • Whitehats, blackhats, red teams, blue teams | PV286 - Secure coding21 https://crocs.fi.muni.cz @CRoCS_MUNI HOW TO PREVENT, DETECT AND MITIGATE CODE BUGS? | PV286 - Secure coding22 https://crocs.fi.muni.cz @CRoCS_MUNI How to prevent, detect and mitigate code bugs? 1. Protection on the source code level – E.g., languages with/without implicit protection (containers/languages with array boundary checking) – E.g., input checking, sanitization, safe alternatives to vulnerable function like safe string manipulation 2. Protection by extensive testing (source code/binary/bytecode level) – E.g., automatic detection by static and dynamic checkers – E.g., code review, security testing 3. Protection by compiler (+ compiler flags) – E.g., runtime checks introduced by compiler (stack protection) 4. Protection by execution environment – E.g., DEP, ASLR, sandboxing, hardware isolation... 5. Protection by defense in depth – All above in systematic secure development lifecycle, multiple layers of defense | PV286 - Secure coding23 https://crocs.fi.muni.cz @CRoCS_MUNI Microsoft’s Secure Development Lifecycle (SDL) https://www.microsoft.com/en-us/securityengineering/sdl/practices | PV286 - Secure coding24 https://crocs.fi.muni.cz @CRoCS_MUNI Use secure-by default languages and libraries • Ideally, language is already designed to be more secure – Partially true for newer languages like Go or Rust – But new systematic issues may be found later • Libraries – Use functions from platform standard API (e.g., AndroidKeyStore provider) – Use libraries which are hard to be used incorrectly • E.g., Libsodium’s crypto_secretbox_easy() vs. OpenSSL vs. own custom code – Monitor used libraries/packages for new vulnerabilities (dependbot) • Don’t design or implement own libraries especially not cryptographic – Developing own library code likely means repeating other’s mistakes – Cryptographic code is extremely difficult to code securely | PV286 - Secure coding25 https://crocs.fi.muni.cz @CRoCS_MUNI Use of more secure versions of functions • Consider language removing whole class of vulnerabilities – E.g., Rust to replace memory-related errors in C • If language is fixed, then use more secure / hardened functions – E.g., Secure C library ISO/IEC 9899:2011 – E.g., java.lang.Math precise arithmetic extensions – E.g., Smart pointers in C++ • Follow best practices, standards and coding standards – E.g., CERT C Coding Standard https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard – (there are many of them, pick for your domain and/or already used in project) char *gets( char *buffer ); char *gets_s( char *buffer, size_t sizeInCharacters ); | PV286 - Secure coding26 https://crocs.fi.muni.cz @CRoCS_MUNI Utilize hardening by compiler and platform • Attack: Write attacker’s code on stack (e.g., via buffer overflow) and execute it • Protection: Data Execution Prevention (DEP) – memory pages with nonexecutable bit set (checked by CPU when using IP) • Attack: Learn where sensitive info is placed, read from that address (or write) • Protection: Address Space Layout Randomization (ASLR) – addresses are changed for every program run (hard to predict exact position) • Attack: Change return address and jump into unexpected functions (Returnoriented programming (ROP)) • Protection: Control flow integrity – build graph of allowed jumps from source code, enforce during runtime | PV286 - Secure coding27 https://crocs.fi.muni.cz @CRoCS_MUNI AUTOMATION AND TOOLING | PV286 - Secure coding28 https://crocs.fi.muni.cz @CRoCS_MUNI Static vs. dynamic analysis • Static analysis – Static Application Security Testing (SAST) – Examine program’s code without executing it – Can examine both source code and compiled code • source code is easier to understand (more metadata) – Can be applied on unfinished code – Manual code audit is kind of “static” analysis • Dynamic analysis – Code is executed = program is “running” – Input values are supplied, internal memory is examined… – Code must compile/run, code coverage by inputs is crucial • Important: no single tool will ever catch all issues | PV286 - Secure coding29 https://crocs.fi.muni.cz @CRoCS_MUNI Automated analysis tools limitations • Don’t expect tools to catch all issues! • Overall program architecture is not understood – sensitivity of program path – impact of errors on other parts • Application semantics is not understood – Is string returned to the user? Can string also contain passwords? • Social context is not understood – Who is using the system? High entropy keys encrypted under short guessable password? | PV286 - Secure coding30 https://crocs.fi.muni.cz @CRoCS_MUNI Always design for testability • “Code that isn't tested doesn't work - this seems to be the safe assumption.” Kent Beck • Code written in a way which is easier to test – Proper decomposition, unit tests, mock objects – Source code annotations (with subsequent analysis) • Code with extensive quality tests is easier to analyze by static and dynamic tools • References – https://en.wikipedia.org/wiki/Design_For_Test – http://www.agiledata.org/essays/tdd.html | PV286 - Secure coding31 https://crocs.fi.muni.cz @CRoCS_MUNI CONTINUOUS INTEGRATION | PV286 - Secure coding32 https://crocs.fi.muni.cz @CRoCS_MUNI Tests, Continuous integration… • Running tools manually is insufficient for continuously developed projects • Include static and dynamic analysis into Continuous Integration process • Static analysis can be run on unfinished code chunks even before commit – On developer side, on commits before merge… • Dynamic analysis requires sufficient code coverage => quality tests • Time-consuming analysis can be run “overnight” on server (after push) – Or continuously like non-stop fuzzing of the current version of application • Tools for automatic monitoring of vulnerable components – Well-known packages, libraries used by your project with known vulnerability – E.g., GitHub’s Dependabot | PV286 - Secure coding33 https://crocs.fi.muni.cz @CRoCS_MUNI Continuous Integration: GitHub&Travis CI example GitHub COMMIT Branch: Test Web hook Artifacts Tests Tests OK | PV286 - Secure coding34 https://crocs.fi.muni.cz @CRoCS_MUNI CI: adding code analysis (e.g., CppCheck, Coverity) GitHub COMMIT Branch: Test Web hook Tests | PV286 - Secure coding35 https://crocs.fi.muni.cz @CRoCS_MUNI Dependabot (GitHub) | PV286 - Secure coding36 https://crocs.fi.muni.cz @CRoCS_MUNI TYPICAL PROBLEMS FROM REAL WORLD | PV286 - Secure coding37 https://crocs.fi.muni.cz @CRoCS_MUNI Typical issues – where theory meets practice ☺ • Insufficient knowledge/education of developers (mature developer would not do majority of issues) – Education is time-consuming and expensive (complement with tooling, security champions) • Legacy code – Too many issues reported by tools to fix – Fix itself can break things (so developers reluctant to fix what is “not” broken) • Missing specification of the expected behavior – Missing analysis, changing implementation target – If implemented code is successful, then is used elsewhere in different condition (original assumptions will be invalidated) • Adding security only later (“Functionality first!”) – It's happening all the time • Heavy dependance on 3rd party libs – No direct control over code, vulnerabilities outside our codebase, possibly unmaintained code (fix means fork) – But re-implementing a wheel is usually a worse issue • Using open-source code can be tricky, you usually must care about: – Licenses (tools to help with like Whitesource, Blackduck) – Open vulnerabilities, time-to-fix, how active is community – In mature organizations, there's usually a open-source governance program that helps developers with choosing the right OSS tools | PV286 - Secure coding38 https://crocs.fi.muni.cz @CRoCS_MUNI Typical issues – where theory meets practice ☺ • Human issues – No problem before we started to look for them – Hard to admit own failures (If I cannot break it, nobody can. “But it is not exploitable”). – Unresponsive/threatening companies – Same with knowledge, lack of maturity, code guidelines, frameworks • Security economics – Problem is known, yet not fixed – these who need to pay for fix are not these who will suffer – Frequently, developer’s KPI is functionality, not security • Customers do not want to update (new version can break things) – Big upgrades mean big risks, small releases/upgrades can help with that • Trust, but Verify – Many companies do not deliver what they promised – Security is very common area: insecure updates, insecure installation procedures (curl & chmod & sudo) • Improper adoption of new tech – protobuf, JSON, JWT, serialization... – New languages (like "go") are cool, but you need to learn new tooling, test frameworks, CI/CD pipelines, dependencies, ... • The other side – open-source great tools become also commercial (and free version get semi-abandoned) | PV286 - Secure coding39 https://crocs.fi.muni.cz @CRoCS_MUNI Questions | PV286 - Secure coding40 https://crocs.fi.muni.cz @CRoCS_MUNI DIGGING DEEPER… | PV286 - Secure coding41 https://crocs.fi.muni.cz @CRoCS_MUNI Motivation problem • Quiz – what is insecure in given program? • Can you come up with attack? • Classic buffer overflow • Detailed exploitation demo during labs this week #define USER_INPUT_MAX_LENGTH 20 char buffer[USER_INPUT_MAX_LENGTH]; bool isAdmin = false; gets(buffer); | PV286 - Secure coding42 ! https://crocs.fi.muni.cz @CRoCS_MUNI Process memory layout http://www.drdobbs.com/security/anatomy-of-a-stack-smashing-attack-and-h/240001832# | PV286 - Secure coding43 https://crocs.fi.muni.cz @CRoCS_MUNI Stack memory layout http://www.drdobbs.com/security/anatomy-of-a-stack-smashing-attack-and-h/240001832# | PV286 - Secure coding44 https://crocs.fi.muni.cz @CRoCS_MUNI Stack overflow http://www.drdobbs.com/security/anatomy-of-a-stack-smashing-attack-and-h/240001832# | PV286 - Secure coding45 https://crocs.fi.muni.cz @CRoCS_MUNI Type-overflow vulnerabilities - motivation • Quiz – what is insecure in given program? • Can you come up with attack? • And what about following variant? – Be aware: char can be both signed (x64) or unsigned (ARM) for (unsigned char i = 10; i >= 0; i--) { /* ... */ } for (char i = 10; i >= 0; i--) { /* ... */ } | PV286 - Secure coding47 ! https://crocs.fi.muni.cz @CRoCS_MUNI Type overflow – basic problem • Types are having limited range for the values – char: 256 values, int: 232 values – add, multiplication can reach lower/upper limit – char value = 250 + 10 == ? • Signed vs. unsigned types – for (unsigned char i = 10; i >= 0; i--) {/* ... */ } • Type value will underflow/overflow – CPU overflow flag is set – but without active checking not detected in program • Occurs also in higher-level languages (Java…) | PV286 - Secure coding48 https://crocs.fi.muni.cz @CRoCS_MUNI EXAMPLE: MAKE HUGE MONEY WITH TYPE OVERFLOW | PV286 - Secure coding49 https://crocs.fi.muni.cz @CRoCS_MUNI Make HUGE money with type overflow • Bitcoin block 74638 (15th August 2010) CBlock(hash=0000000000790ab3, ver=1, hashPrevBlock=0000000000606865, hashMerk nTime=1281891957, nBits=1c00800e, nNonce=28192719, vtx=2) CTransaction(hash=012cd8, ver=1, vin.size=1, vout.size=1, nLockTime=0) CTxIn(COutPoint(000000, -1), coinbase 040e80001c028f00) CTxOut(nValue= 50.51000000, scriptPubKey=0x4F4BA55D1580F8C3A8A2C7) CTransaction(hash=1d5e51, ver=1, vin.size=1, vout.size=2, nLockTime=0) CTxIn(COutPoint(237fe8, 0), scriptSig=0xA87C02384E1F184B79C6AC) CTxOut(nValue=92233720368.54275808, scriptPubKey=OP_DUP OP_HASH160 0xB7 CTxOut(nValue=92233720368.54275808, scriptPubKey=OP_DUP OP_HASH160 0x15 vMerkleTree: 012cd8 1d5e51 618eba Block hash: 0000000000790ab3f22ec756ad43b6ab569abf0bddeb97c67a6f7b1470a7ec1c Transaction hash: 1d5e512a9723cbef373b970eb52f1e9598ad67e7408077a82fdac194b653 Input transaction (with 0.5BTC) https://blockexplorer.com/tx/237fe8348fc77ace11049931 058abb034c99698c7fe99b1cc022b1365a705d39 Mining block reward (was 50BTC at 2010, now smaller) 2 output transactions (each with 9*1010 BTC) !!! Should have been rejected by miners as value(output) >> value(input), but was not! | PV286 - Secure coding50 https://crocs.fi.muni.cz @CRoCS_MUNI Bug dissection • Bitcoin code uses integer encoding of numbers with fixed position of decimal point (INT64) – Smallest fraction of BTC is one Satoshi (sat) = 1/108 BTC – 33.54 BTC == 33.54 * 108 => 3354000000 • BTW: Why using float numbers is not a good idea? • CTxOut value:92233720368.54275808 BTC = 0x7ffffffffff85ee0 • INT64_MAX = 0x7fffffffffffffff • Sum of 2 CTx = 0xfffffffffff0bdc0 (overflow) = -100000010 = -0.01BTC – Difference between input & output interpreted as miner fee | PV286 - Secure coding52 https://crocs.fi.muni.cz @CRoCS_MUNI Type overflow – Bitcoin #include #include using namespace std; // Works for Visual Studio compiler, replace __int64 with int64 for other compilers int main() { const __int64 valueMaxInt64 = 0x7fffffffffffffffLL; const float COIN = 100000000; // should be __int64 as well, made float for simple printing __int64 valueIn = 50000000; // value of input transaction CTxIn cout << "CTxIn = " << valueIn / COIN << endl; __int64 valueOut1 = 9223372036854275808L; // first out cout << "CTxOut1 = " << valueOut1 / COIN << endl; __int64 valueOut2 = 9223372036854275808L; // second out cout << "CTxOut2 = " << valueOut2 / COIN << endl; __int64 valueOutSum = valueOut1 + valueOut2; // sum which overflow cout << "CTxOut sum = " << valueOutSum / COIN << endl; // Difference between input and output is interpreted as fee for a miner (0.01 BTC) __int64 fee = valueIn - valueOutSum; cout << "Miner fee = " << fee / COIN << endl; return 0; } Try this at hom e! | PV286 - Secure coding53 https://crocs.fi.muni.cz @CRoCS_MUNI BugFix – proper checking for overflow https://github.com/bitcoin/bitcoin/commit/d4c6b90ca3f9b47adb1b2724a0c3514f80635c84#diff-118fcbaaba162ba17933c7893247df3aR1013 | PV286 - Secure coding55 https://crocs.fi.muni.cz @CRoCS_MUNI Questions • When exactly overflow happens? • Why mining reward was 50.51 and not exactly 50? – CTxOut(nValue= 50.51000000 • How to check for type overflow? Try this at hom e! | PV286 - Secure coding56 https://crocs.fi.muni.cz @CRoCS_MUNI SOURCE CODE PROTECTIONS COMPILER PROTECTIONS PLATFORM PROTECTIONS | PV286 - Secure coding59 https://crocs.fi.muni.cz @CRoCS_MUNI Safe add and mult operations in C/C++ • Compiler-specific non-standard extensions of C/C++ • GCC: __builtin_add_overflow, __builtin_mul_overflow … – Result returned as third (pointer passed) argument – Returns true if overflow occurs – https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html • MSVC: SafeInt wrapper template (for int, char…) – Overloaded all common operations (drop in replacement) – Returns SafeIntException if overflow/underflow – https://learn.microsoft.com/en-us/cpp/safeint/safeint-library?view=msvc-170 bool __builtin_add_overflow (type1 a, type2 b, type3 *res) #include using namespace msl::utilities; // Normal use SafeInt c1 = 1; SafeInt c2 = 2; c1 = c1 + c2; | PV286 - Secure coding60 https://crocs.fi.muni.cz @CRoCS_MUNI Safe add and mult operations in Java • Java SE 8 introduces extensions to java.lang.Math • ArithmeticException thrown if overflow/underflow public static int addExact(int x, int y) public static long addExact(long x, long y) public static int decrementExact(int a) public static long decrementExact(long a) public static int incrementExact(int a) public static long incrementExact(long a) public static int multiplyExact(int x, int y) public static long multiplyExact(long x, long y) public static int negateExact(int a) public static long negateExact(long a) public static int subtractExact(int x, int y) public static long subtractExact(long x, long y) public static int toIntExact(long value) | PV286 - Secure coding61 https://crocs.fi.muni.cz @CRoCS_MUNI Format string vulnerabilities - motivation • Quiz – what is insecure in given program? • Can you come up with attack? int main(int argc, char * argv[]) { printf(argv[1]); return 0; } | PV286 - Secure coding62 https://crocs.fi.muni.cz @CRoCS_MUNI Format string vulnerabilities • Wide class of functions accepting format string – printf("%s", X); – resulting string is returned to user (= potential attacker) – formatting string can be under attacker’s control – variables formatted into string can be controlled • Resulting vulnerability – memory content from stack is formatted into string – possibly any memory if attacker control buffer pointer | PV286 - Secure coding63 https://crocs.fi.muni.cz @CRoCS_MUNI Information disclosure vulnerabilities • Exploitable memory vulnerability leading to read access (not write access) – attacker learns some information from the memory • Direct exploitation – secret information (cryptographic key, password...) • Precursor for next step (very important with DEP&ASLR) – module version – current memory layout after ASLR (stack/heap pointers) – stack protection cookies (/GS) | PV286 - Secure coding64 https://crocs.fi.muni.cz @CRoCS_MUNI Format string vulnerability - example • Example retrieval of security cookie and return address int main(int argc, char* argv[]) { char buf[64] = {}; sprintf(buf, argv[1]); printf("%s\n", buf); return 0; } argv[1] submitted by an attacker E.g., %x%x%x….%x Stack content is printed Including security cookie and RA Don’t let user/attacker to provide own formatting strings | PV286 - Secure coding65 ! https://crocs.fi.muni.cz @CRoCS_MUNI Non-terminating functions - example • What is wrong with following code? int main(int argc, char* argv[]) { char buf[16]; strncpy(buf, argv[1], sizeof(buf)); return printf("%s\n",buf); } | PV286 - Secure coding66 ! https://crocs.fi.muni.cz @CRoCS_MUNI strncpy - manual http://www.cplusplus.com/reference/cstring/strncpy/?kw=strncpy | PV286 - Secure coding67 https://crocs.fi.muni.cz @CRoCS_MUNI Non-terminating functions for strings • strncpy • snprintf • vsnprintf • mbstowcs • MultiByteToWideChar • Non-null terminated Unicode string more dangerous – C-string processing stops on first zero – any binary zero (ASCII) – 16-bit aligned wide zero character (UNICODE) • wcsncpy • snwprintf • vsnwprintf • wcstombs • WideCharToMultiByte Null termination specific for C, but terminating/separating characters relevant in any other language | PV286 - Secure coding68 https://crocs.fi.muni.cz @CRoCS_MUNI Heap overflow Buffer overflow in allocation 1 overwrites header for allocation 2 (and possibly other) Linked list between allocated blocks Felix "FX" Lindner, http://www.h-online.com/security/features/A-Heap-of-Risk-747220.html Corrupted allocation 2 data are later processed by unlink() function | PV286 - Secure coding69 https://crocs.fi.muni.cz @CRoCS_MUNI Secure C library – selected functions • Formatted input/output functions – gets_s – scanf_s, wscanf_s, fscanf_s, fwscanf_s, sscanf_s, swscanf_s, vfscanf_s, vfwscanf_s, vscanf_s, vwscanf_s, vsscanf_s, vswscanf_s – fprintf_s, fwprintf_s, printf_s, printf_s, snprintf_s, snwprintf_s, sprintf_s, swprintf_s, vfprintf_s, vfwprintf_s, vprintf_s, vwprintf_s, vsnprintf_s, vsnwprintf_s, vsprintf_s, vswprintf_s – functions take additional argument with buffer length • File-related functions – tmpfile_s, tmpnam_s, fopen_s, freopen_s • takes pointer to resulting file handle as parameter • return error code char *gets( char *buffer ); char *gets_s( char *buffer, size_t sizeInCharacters ); | PV286 - Secure coding71 https://crocs.fi.muni.cz @CRoCS_MUNI Secure C library – selected functions • Environment, utilities – getenv_s, wgetenv_s – bsearch_s, qsort_s • Memory copy functions – memcpy_s, memmove_s, strcpy_s, wcscpy_s, strncpy_s, wcsncpy_s • Concatenation functions – strcat_s, wcscat_s, strncat_s, wcsncat_s • Search functions – strtok_s, wcstok_s • Time manipulation functions... | PV286 - Secure coding72 https://crocs.fi.muni.cz @CRoCS_MUNI Secure C library • Secure versions of commonly misused functions – bounds checking for string handling functions – better error handling • Also added to new C standard ISO/IEC 9899:2011 • Microsoft Security-Enhanced Versions of CRT Functions – MSVC compiler issue warning C4996, more functions then in C11 • Secure C Library – http://docwiki.embarcadero.com/RADStudio/XE3/en/Secure_C_Library – https://docs.microsoft.com/en-us/cpp/c-runtime-library/security-enhanced-versions-of-crt-functions – https://docs.microsoft.com/en-us/cpp/c-runtime-library/security-features-in-the-crt – http://www.drdobbs.com/cpp/the-new-c-standard-explored/232901670 | PV286 - Secure coding74 https://crocs.fi.muni.cz @CRoCS_MUNI SOURCE CODE PROTECTIONS COMPILER PROTECTIONS PLATFORM PROTECTIONS | PV286 - Secure coding75 https://crocs.fi.muni.cz @CRoCS_MUNI – randomized cookie between local variables and return address – function prolog (add security cookie) – and epilog (check cookie) Stack without canary word http://www.drdobbs.com/security/anatomy-of-a-stack-smashing-attack-and-h/240001832# Canary word (CY) | PV286 - Secure coding77 ! https://crocs.fi.muni.cz @CRoCS_MUNI MSVC Compiler security flags - /GS • /GS switch (added from 2003, improves in time) – http://msdn.microsoft.com/en-us/library/8dbf701c.aspx – multiple different protections against buffer overflow – mostly focused on stack protection • /GS protects: – return address of function – address of exception handler – vulnerable function parameters (arguments) – some of the local buffers (GS buffers) • /GS protection is (automatically) added only when needed – to limit performance impact, decided by compiler (/GS rules) – #pragma strict_gs_check(on) - enforce strict rules application /GS is applied in both DEBUG and RELEASE modes | PV286 - Secure coding78 https://crocs.fi.muni.cz @CRoCS_MUNI /GS – what is NOT protected • /GS compiler option does not protect against all buffer overrun security attacks • Corruption of address in vtable – (table of addresses for virtual methods) • Example: buffer and a vtable in an object, a buffer overrun could corrupt the vtable • Functions with variable arguments list (...) Automatic tools add vital protections, but are NOT replacement for secure defensive programming | PV286 - Secure coding83 https://crocs.fi.muni.cz @CRoCS_MUNI GCC compiler - StackGuard & ProPolice • StackGuard released in 1997 as extension to GCC – but never included as official buffer overflow protection • GCC Stack-Smashing Protector (ProPolice) – patch to GCC 3.x – included in GCC 4.1 release – -fstack-protector (string protection only) – -fstack-protector-all (protection of all types) – on some systems enabled by default (OpenBSD) • -fno-stack-protector (disable protection) | PV286 - Secure coding85 ! https://crocs.fi.muni.cz @CRoCS_MUNI GCC-fstack-protector-all Can an attacker still bypass stack canary? Example: Stack canary | PV286 - Secure coding89 https://crocs.fi.muni.cz @CRoCS_MUNI How to bypass stack protection cookie? • Scenario: – long-term running of daemon on server – no exchange of cookie between calls 1. Obtain security cookie by one call – cookie is now known and can be incorporated into stack-smashing data 2. Use second call to change only the return address What attacker can do with changed return address? | PV286 - Secure coding91 ! https://crocs.fi.muni.cz @CRoCS_MUNI SOURCE CODE PROTECTIONS COMPILER PROTECTIONS PLATFORM PROTECTIONS | PV286 - Secure coding92 https://crocs.fi.muni.cz @CRoCS_MUNI Data Execution Prevention (DEP) • Motto: When boundary between code and data blurs (buffer overflow, SQL injection…) then exploitation might be possible • Data Execution Prevention (DEP) – prevents application to execute code from non-executable memory region – available in modern operating systems • Linux > 2.6.8, WinXPSP2, Mac OSX, iOS, Android… – difference between ‘hardware’ and ‘software’ based DEP | PV286 - Secure coding93 ! https://crocs.fi.muni.cz @CRoCS_MUNI Hardware DEP • Supported from AMD64 and Intel Pentium 4 – OS must add support of this feature (around 2004) • CPU marks memory page as non-executable – most significant bit (63th) in page table entry (NX bit) – 0 == execute, 1 == data-only (non-executable) • Protection typically against buffer overflows • Cannot protect against all attacks! – e.g., code compiled at runtime (produced by JIT compiler) must have both instructions and data in executable page – attacker redirect execution to generated code (JIT spray) – used to bypass Adobe PDF and Flash security features | PV286 - Secure coding94 https://crocs.fi.muni.cz @CRoCS_MUNI Software “DEP” • Unrelated to NX bit (no CPU support required) • When exception is raised, OS checks if exception handling routine pointer is in executable area – Microsoft’s Safe Structured Exception Handling • Software DEP is not preventing general execution in non-executable pages – different form of protection than hardware DEP | PV286 - Secure coding95 https://crocs.fi.muni.cz @CRoCS_MUNI Address Space Layout Randomization (ASLR) • Random reposition of executable base, stack, heap and libraries address in process’s address space – aim is to prevent exploit to reliably jump to required address • Performed every time a process is loaded into memory – random offset added to otherwise fixed address – applies to program and also dynamic libraries – entropy of random offset is important (bruteforce) • Operating System kernel ASLR (kASLR) – more problematic as long-running (random, but fixed until reboot) • Introduced by Memco software (1997) – fully implemented in Linux PaX patch (2001) – MS Vista, enabled by default (2007), MS Win 8 more entropy (2012) | PV286 - Secure coding96 ! https://crocs.fi.muni.cz @CRoCS_MUNI ASLR – impact on attacks • ASLR introduced big shift in attacker mentality • Attacks are now based on gaps in ASLR – legacy programs/libraries/functions without ASLR support • ! /DYNAMICBASE – address space spraying (heap/JIT) – predictable memory regions, insufficient entropy Can attacker execute desired functionality without changing code? | PV286 - Secure coding101 https://crocs.fi.muni.cz @CRoCS_MUNI Return-oriented programming (ROP) • Return-into-library technique (Solar Designer, 1997) – method for bypassing DEP – no write of attacker’s code to stack (as is prevented by DEP) 1. function return address replaced by pointer to standard library function 2. library function arguments replaced according to attackers needs 3. function return results in execution of library function and given arguments – Example: system call wrappers like system() • Borrowed code chunks – Problem: 64-bit hardware introduced different calling convention • first arguments to function passed in CPU registers instead of via stack – attacker tries to find instruction sequences from any function that pop values from the stack into registers (automated search by ROPgadget) – necessary arguments are inserted into registers – return-into-library attack is then executed as before | PV286 - Secure coding102 ! https://crocs.fi.muni.cz @CRoCS_MUNI Control flow integrity • Promising technique with low overhead • Classic CFI (2005), Modular CFI (2014) – avg 5% impact, 12% in worst case – part of LLVM C compiler (CFI usable for other languages as well) 1. Analysis of source code to establish control-flow graph (which function can call what other functions) 2. Assign shared labels between valid caller X and callee Y 3. When returning into function X, shared label is checked 4. Return to other function is not permitted https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-carlini.pdf | PV286 - Secure coding103 ! https://crocs.fi.muni.cz @CRoCS_MUNI DEP and ASLR should be combined • “For ASLR to be effective, DEP/NX must be enabled by default too.” M. Howard, Microsoft • /GS combined with /DYNAMICBASE and /NXCOMPAT – /NXCOMPAT (==DEP) – prevents insertion of new attacker's code and forces ROP – /DYNAMICBASE (==ASLR) randomizes code chunks utilized by ROP – /GS prevents modification of return pointer used later for ROP – /DYNAMICBASE randomizes position of master cookie for /GS • Visual Studio → Configuration properties → – Linker → All options – C/C++ → All options | PV286 - Secure coding104 ! https://crocs.fi.muni.cz @CRoCS_MUNI SUMMARY | PV286 - Secure coding105 https://crocs.fi.muni.cz @CRoCS_MUNI Mandatory reading • SANS: 2017 State of Application Security – https://web.archive.org/web/20180119191652/https://www.sans.org/reading- room/whitepapers/application/2017-state-application-security-balancing-speed-risk- 38100 – Which applications are of main security concern? – What is expected time to deploy patch for critical security vulnerability? – How does your organization test applications for vulnerabilities? – Which language is the most common source of security risk? | PV286 - Secure coding106 https://crocs.fi.muni.cz @CRoCS_MUNI Optional reading • Marcel Böhme: “Guarantees in Software Security” – An article from Ferbuary 2024: https://arxiv.org/abs/2402.01944 – Interesting read with many practical examples. However, it is academic and might not be detailed enough (e.g., if you never heard about a particular bug, then it is hard to follow since it is not explained in detail). – “We review general approaches to reason about the security of a software system and reflect upon the guarantees they provide. We introduce a taxonomy of fundamental challenges towards the provision of guarantees, and discuss how these challenges are routinely exploited to attack a system in spite of credible assurances about the absence of such bugs. “ | PV286 - Secure coding107 https://crocs.fi.muni.cz @CRoCS_MUNI Questions | PV286 - Secure coding108