4 ms·
How does one go about conducting such audits? Is it just a case of looking at the code long with an experienced eye to spot potential flaws? Or are there standa
by weavie 8y ago
How does one go about conducting such audits? Is it just a case of looking at the code long with an experienced eye to spot potential flaws? Or are there standard techniques and tools that people follow?
- tptacek 8y agoThere are a bunch of different approaches. The simplest and probably the most common is to simply read the code. With experience, patterns of vulnerabilities pop out at you; also, you get good at quickly eliminating code that isn't likely to be in the critical path of a vulnerability, allowing you to focus on the code that is. Some people start from patterns and work backwards through code looking for reachability. 10 years ago, you might have done that by sweeping for memcpy's and working back to inputs. Nowadays you'd probably be looking for pointer/length math, or allocations and frees. A primitive automation technique is get the target hooked up to a debugger and then run a blind fuzzer at it looking for faults. More advanced fuzzers will track basic block coverage and tune inputs to reach new paths. If you're really committed to a particular project (like, someone's paying you to do it, and you have a fair bit of time), you might hoist the code out of its natural setting and build a test harness for it, so you can fuzz it "in the abstract" without having to deal with any of its surrounding code. I've done that for OS work before (you'd be surprised how much of a kernel you can "port" back to userland, if all you need to do is exercise logic). Peers of mine have also instrumented virtual machines like QEMU to do this kind of testing. Finally, the most modern way to do this kind of work is to generate models for the code and then use provers to verify things about them. SMT solvers were all the rage for this a few years ago; my sense is that code proving tools have gotten more interesting than that since then.
- justincormack 8y agoYou can already run NetBSD in userland (rump kernel).
- tptacek 8y agoRight, I'm not being very precise; you don't necessarily want the whole kernel (because then you have to model inputs for all the interactions with all the kernel subsystems), but rather to isolate the one component under test.
- severine 8y ago> OS work What is OS in this context? Operative System? Open Source? Other Stuff?
- exikyut 8y agoThe word "kernel" is 10 words away to the right, so the first (and traditional) interpretation, "Operating System".
- ben_bai 8y ago1) reading code, spotting standard bugs, or with domain know-how spotting logic errors. 2) static code analyzers (i.e. llvm scan-build). Lots of false positives, still requires 1). 3) fuzzing (i.e. afl). Usually some setup needed, still requires 1).
- Fnoord 8y agoWith binaries (not source code) such as firmware the answer often seems "run it through IDA".
- qop 8y agoThat's like asking how web development happens. Standards are sort of a double edged sword in infosec, because: * if I can just run a scripted audit and go home, then any dipshit can do that and security professionals won't have jobs. Or fewer ones will. Which means less infosec software gets produced. * if an attacker has access to that script, it's more or less a matter of time until they develop an exploit to circumvent it, slightly dependent on their skill. Eg, industrial software might be in less danger here because the exploit surface is limited to in-facility, if their network stack is good. So, patterns in general are a smell worth investigating. If something works, I try and find out if my PM will gift me some time to automate and smoke test what I come up with. If something never works, I learn, but I also automate that too, and generally just try it anyways. Tooling is more or less standard, kali linux, unix tools, and then whatever they've found to work. Maybe eighty percent of what I use is basic kali toolbox stuff w/ whatever extensions I've collected, and the rest is tools I wrote for mapping, measuring, and muscling my way to success. Lots of old python, some new python, tons of C, I've got perl scripts laying around, I've got afl installed somewhere, I use lua for some things. Memory errors are common security issues. There's tools like valgrind to help find those. I don't really know how data race stressing is done, but I'm sure that's a common route in finding network stack bugs. Afl-fuzz finds a lot of data processing bugs, off by ones, pointer/deref issues, etc. They've found some pretty big ones, too. When I am handed code to audit, I'm looking for areas where I can tell the author was rushed, or where he was copying code from somewhere. The more the better, I want to know what he thinks like, how he writes, and that helps me find something that would be difficult for him to implement. Sometimes you get a big obfuscated mess and you gotta try and make a rough 50,000ft map of it and start profiling, even stepping through with qemu if that's what it takes to get a clue. Infosec is one of those devilish details kind of fields. Once you get the feel for how things break, then it's mostly rote work. Sometimes you just gotta trust that if you read enough code you'll find a piece that sucks enough for you to break something. Sometimes you don't find anything. But I'm not a researcher, so I'd then move on to other pastures, whereas the research auditor presumably has to write a report or talk to his peers? That's a bit over my head, tbqh.
- irundebian 8y agoIn theory it should be possible to conduct such audits ("assessments" probably fits better) in a scientific and thorough manner, so that the process and its result are replicable. I assume that in most cases software security assessments are not done in this way probably resulting in the finding of some bugs but no true assurance statements of the code itself. If somebody here can give some references on the state of the art of software security assessments I would be very thankful for that.
- FrozenVoid 8y ago1.Invalid inputs potential: Inputs->outputs. If you can stuff invalid input and the code can't detect it or crashes, its a vulnerability. Fuzzers automate this step by creating lots of hostile/invalid input state. 2.Off-by-one,length/stack/buffer-overflows: check the length of input/buffers, does the code handle all cases? C memory leak detectors/memory sanitizers can detect this. 3.Logic/Design flaws: Does code path assumes something that can be changed before or after execution? Does the code assumes a fast path that requires all circumstances to be correct? Does the code ignores something that influences later execution(e.g. generic approach where special handling is required, special handling deferred to later step, losing global state information(e.g.with function calls))? Static analysis tools will find most of this. 4. Exceptional/Corner cases: is the code exhaustive? Can it handle all states of program? Usually the error is programmer assuming X can't happen and optimize it out, but due code evolution X suddenly becomes possible or was possible with exotic configuration/state. This often can't be automated even with static analysis tools because is program-specific knowledge. Rewriting it in Ada/rust/ocaml might be an alternative: they allow to specify exhaustive compliance with requirements and check all state combinations at compile time. Functional programming can also handle this with additional overhead and restricting the program global state. Security-centric stuff should not be manual: C requires to do it manually or introduces run-time asserts. The reason world doesn't run everything in Ada or equivalent, is that flexibility and speed are often as critical as security: network stack that is 100% proven secure but twice slower will be replaced by network stack that is 99% secure and is twice faster. Same applies to most latency requirements: if you program is secure but introduces X latency, it will be replaced by faster stuff that works reasonably well.
- irundebian 8y agoI guess a lot of desktop users would be very fine if they had 100% proven secure hostile-environment-exposing network stacks as long its able to handle some dozens of mbits. However I don't think that a proven secure network stack will be so slow, so that's interrupting normal network experience.
- FrozenVoid 8y agoMost users don't see security, they see speed and latency. Example for gaming: why are most games in C++? C++ provides fastest speed/latency from the hardware without low-level effort. In all areas where real-time control is critical, speed/latency are most important. Imagine a Java GC stopping a program for a few milliseconds to recover memory, while it controls a fighter jet. A server that is 30% slower because its written in Ada. A program that requires 50% more memory, exceeding physical RAM and starting to swap. Even C sometimes not fit to the task of extracting maximum performance, especially on embedded/mobile devices. Assembler(which is far less secure than C) is still used for speed-critical loops, audio/video decoders, cryptography and compression.