Implemen'ng ¡a ¡ver'cally ¡ hardened ¡DNP3 ¡control ¡stack ¡ Sven ¡M. ¡Hallberg, ¡ ¡ ¡ ¡Sergey ¡Bratus, ¡ ¡ ¡ ¡ ¡Adam ¡Crain, ¡ Meredith ¡L. ¡Pa<erson, ¡ ¡ ¡ ¡Maxwell ¡Koo, ¡ ¡ ¡ ¡Sean ¡W. ¡Smith ¡ Sponsor: ¡
Outline • Parsers , ¡ security , ¡and ¡the ¡LangSec ¡viewpoint ¡ ¡ • Building ¡a ¡safer ¡DNP3 ¡parser ¡from ¡scratch ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡“ Make ¡the ¡parser ¡code ¡look ¡like ¡the ¡grammar ” ¡ - ¡ ¡ ¡ ¡ ¡a.k.a. ¡ Parser ¡combinators ¡ ¡(using ¡the ¡ Hammer ¡kit) ¡ ¡ • Case ¡study: ¡a ¡DNP3 ¡filtering ¡proxy ¡ ¡ • Lessons ¡learned ¡/ ¡discussion ¡ ¡
What is syntax & why check it? • What ¡we ¡parse ¡for ¡(“syntax”): ¡ ¡ ¡ ¡-‑ ¡object ¡boundaries ¡in ¡message, ¡ ¡ ¡ ¡ ¡-‑ ¡object ¡embeddings ¡in ¡other ¡objects, ¡ ¡ ¡ ¡-‑ ¡whether ¡it’s ¡legal ¡for ¡objects ¡to ¡appear ¡in ¡message ¡in ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡a ¡given ¡posiSon ¡ ¡ • ValidaSng ¡syntax ¡should: ¡ ¡ ¡ ¡-‑ ¡create ¡expected ¡pre-‑condiSons ¡for ¡the ¡rest ¡of ¡the ¡code ¡ ¡ ¡ ¡-‑ ¡assure ¡predictable ¡behavior ¡of ¡code ¡on ¡input ¡data ¡
LangSec ¡ • Many ¡security ¡issues ¡are ¡ language ¡ recogni'on ¡issues ¡ - exploit ¡= ¡accepSng ¡bad ¡input, ¡leVng ¡it ¡act ¡on ¡program ¡ internals. ¡What ¡to ¡accept? ¡What ¡is ¡expected? ¡What ¡is ¡valid? ¡ - ¡ ¡ • If ¡security ¡seems ¡like ¡an ¡uphill ¡ba<le… ¡ syntax ¡complexity ¡is ¡likely ¡at ¡fault ¡(the ¡higher ¡up ¡Chomsky’s ¡ hierarchy ¡of ¡grammars, ¡the ¡harder ¡to ¡parse ¡correctly) ¡ ¡ • Some ¡syntax ¡is ¡ poison : ¡(eg.: ¡nested ¡length, ¡fields ¡that ¡must ¡all ¡ agree; ¡several ¡sources ¡of ¡truth, ¡context-‑dependence) ¡
Solve ¡language ¡problems ¡with ¡a ¡language ¡ approach ¡ ¡ • Start ¡with ¡a ¡grammar ¡ • If ¡you ¡don’t ¡know ¡what ¡ valid ¡or ¡ expected ¡syntax/content ¡of ¡ a ¡message ¡is, ¡how ¡can ¡you ¡check ¡it? ¡Or ¡interoperate? ¡ • If ¡the ¡protocol ¡comes ¡without ¡a ¡grammar, ¡you ¡need ¡to ¡ derive ¡one. ¡It ¡sucks, ¡but ¡it’s ¡the ¡only ¡way. ¡ • Write ¡the ¡parser ¡to ¡ look ¡ like ¡the ¡grammar: ¡succinct ¡& ¡ ¡ ¡ ¡ ¡ ¡ incrementally ¡testable ¡(from ¡the ¡leaf ¡nodes/primiSves ¡up) ¡ ¡ • Don’t ¡start ¡ processing ¡before ¡you’re ¡done ¡ parsing ¡ ¡ ¡
The ¡Recognizer ¡design ¡pa<ern ¡ ¡ Language grammar& Spec& Processing:&& only&well3typed& Recognizer& objects,& Input& for&input& no&raw&inputs&& language& & Reject&& invalid& inputs& Only&valid/expected&inputs,& semanCc&acCons&past&this&line&
Parsing & protocol anti-patterns • “ Shotgun ¡ parsers ”: ¡input ¡validity ¡checks ¡ intermixed ¡with ¡ processing ¡code; ¡no ¡clear ¡separaSon ¡boundary ¡ • OpenSSL’s ¡Heartbleed, ¡GNU ¡TLS ¡Hello ¡bug, ¡… ¡ • Unnecessarily ¡complex ¡syntax ¡(e.g., ¡context-‑ sensi've ¡where ¡ context-‑ free ¡or ¡ regular ¡would ¡suffice) ¡ • Objects’ ¡interpretaSon ¡& ¡legality ¡depends ¡on ¡sibling ¡object ¡contents ¡ • Parser ¡ differen'als ¡(parsers ¡disagree ¡about ¡message ¡contents) ¡ • X.509 ¡CA ¡vs ¡client ¡bugs, ¡Android ¡Master ¡Key ¡bugs, ¡… ¡ • Overloaded ¡fields ¡ • recent ¡NTP ¡vulnerabiliSes ¡ ¡ ¡ • … ¡(see ¡our ¡IEEE ¡SecDev ¡2016 ¡paper) ¡ ¡
DNP3 issues are not theoretical • 2013 ¡to ¡2014 ¡– ¡Over ¡ 30 ¡CVEs ¡related ¡to ¡input ¡validaSon ¡ with ¡DNP3 ¡implementaSons. ¡ ¡ ¡ ¡ ¡(“ Robus ¡Master ¡Serial ¡Killer ”, ¡ ¡Sistrunk ¡& ¡Crain, ¡2014) ¡ ¡ • Out ¡of ¡ dozens ¡of ¡implementaSons ¡only ¡a ¡small ¡few ¡were ¡ defect-‑free. ¡ • Low-‑defect ¡implementaSons ¡chose ¡a ¡conservaSve ¡subset ¡
DNP3 Complex? ¡
DNP3 Complex?? ¡
DNP3 Complex! ¡
Vuln #1 FA 82 00 00 01 00 02 00 00 00 00 FF FF FF FF 0 4294967295 Group 1 4 byte Unsolicited Variation 0 start/stop Response Sizeless?! ● infinite loop ● missing data ● integer overflow? ● accepts broadcast From: Adam Crain, Chris Sistrunk “Project Robus, Master Serial Killer”, S4x14
Vuln #2 DD 82 00 00 0A 02 01 00 00 FF FF 0 65535 2 byte UNSOL start/stop Group 10 ● infinite loop Variation 2 ● missing data Binary Output ● unexpected data Status ● integer overflow? From: Adam Crain, Chris Sistrunk “Project Robus, Master Serial Killer”, S4x14
Vuln #3 CRC CRC 05 64 06 44 64 00 64 00 FF F2 C0 1D 0A 100 100 FIR / FIN SEQ = 0 1 byte unconfirmed payload user data ● transport header only ● unhandled exception From: Adam Crain, Chris Sistrunk “Project Robus, Master Serial Killer”, S4x14
Vuln #4 (TMW integration) DD 82 00 00 0C 01 00 00 01 rnd(11) rnd(11) CROB #1 CROB #2 Control 1 byte Unsolicited Relay start/stop Response Output Block ● buffer overrun ● not malformed! ● unexpected objects ● accepts broadcast From: Adam Crain, Chris Sistrunk “Project Robus, Master Serial Killer”, S4x14
Vuln #5 (TMW integration) FA 82 00 00 02 02 01 01 00 FF FF 1 65535 Group 2 2 byte Unsolicited Var 2 start/stop Response (event) ● stable infinite loop ● max range - 1 and no data ● accepts broadcast From: Adam Crain, Chris Sistrunk “Project Robus, Master Serial Killer”, S4x14
Language Poison • Range: ¡( start , ¡ stop ) • If ¡we ¡can't ¡get ¡this ¡right ¡in ¡2016… • Be<er: ¡( start , ¡ count ), ¡as ¡in ¡Modbus ¡& ¡IEC ¡104 ¡ • Would ¡ ideally ¡like ¡to ¡avoid ¡counts ¡in ¡the ¡first ¡place l => ¡Context-‑free ¡is ¡much ¡easier ¡to ¡parse
Syntax spills into semantics // group 50 (times)... g50v1_time_oblock = dnp3_p_single (G_V(TIME, TIME), time); Read requests & responses; Object ¡group ¡50: ¡ 'me ¡and ¡ date Write requests (to set time)
Syntax spills … where? Object ¡group ¡51: ¡common ¡Sme-‑of-‑occurance “should the relative time variants generate an error unless preceded by a CTO object in the same message?”
Implementation Goals / Principles • Be ¡as ¡ gramma'cal ¡as ¡possible ¡ • Want ¡the ¡parser ¡to ¡look ¡like ¡a ¡ CFG , ¡though ¡we ¡can't ¡be ¡ ¡ • Avoid ¡code ¡duplicaSon ¡(much ¡abstracSon) ¡ ¡ • Capture ¡DNP3's ¡" true " ¡syntax ¡ • Reject ¡at ¡ syntax ¡level ¡what ¡other ¡checkers ¡may ¡(or ¡may ¡ not!) ¡do ¡later ¡in ¡the ¡code ¡
Parser combinators: a natural choice • Hammer ¡parser ¡construcSon ¡kit: ¡C/C++ ¡ ¡ ¡ • Bindings ¡for ¡Java, ¡Python, ¡Ruby, ¡.NET, ¡Go ¡ • Three ¡algorithmic ¡parsing ¡back-‑ends ¡ ¡ • Freely ¡available ¡on ¡GitHub: ¡ h<ps://github.com/UpstandingHackers/hammer ¡
Parser combinators at a glance (1)
Parser combinators at a glance (2)
Parser Combinators: code looks like the grammar • Have ¡primiSves ¡ ¡ ¡ ¡ ¡ HParser *seqno = h_bits(4, false); HParser *bit = h_bits(1, false); ... ¡ • Combined ¡to ¡form ¡higher-‑level ¡structures ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ h_choice, h_many, h_many1, ... ¡ • define ¡own ¡combinators ¡
Example – Fragment Header Flags ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ /* --- uns,con,fin,fir --- */ conflags = h_sequence(bit,zro,one,one, NULL); // CONFIRM reqflags = h_sequence(zro,zro,one,one, NULL); // always fin,fir! unsflags = h_sequence(one,one,ign,ign, NULL); // unsolicited rspflags = h_sequence(zro,bit,bit,bit, NULL); ¡ ¡
Example - CROB Object crob = h_sequence(h_bits(4, false), // op type bit, // queue flag bit, // clear flag tcc, h_uint8(), // count h_uint32(), // on-time [ms] h_uint32(), // off-time [ms] status, // 7 bits dnp3_p_reserved(1), NULL));
Recommend
More recommend