Phumbling with Phoenix and vulnerability finding tim burrellmicrosoft
Phumbling with Phoenix and vulnerability finding tim. burrell@microsoft. com
The plan What is Phoenix? Example uses An MSRC case - Create. Text. Range Analysis/Demo
Phoenix Cool name and icon : ) Some documentation/support http: //connect. microsoft. com/phoenix
Phoenix compilation HIR AST S O U R C E not Phx (yet) CIL Reader Type Checker C I L C 1. dll MIR LIR MIR Lower SSA Const SSA Dest Canon Addr Modes EIR Lower Encode O Reg Alloc Lister B EH Lower J Stack Alloc E C Frame Gen T Switch Lower Block Layout Flow Opts C 2. exe
IR States More Abstract AST Less Abstract HIR MIR Lowering Raising Phases transform IR, either within a state or from one state to another. For instance, Lower transforms MIR into LIR. EIR
Simple Example void main(int argc, char** argv) { char * message; if (argc > 1) message = "Hello, Worldn"; else message = "Goodbye, Worldn"; printf(message); }
Simple Example: HIR & MIR START _main(Tech) _main: (refs=1) _argc, _argv = ENTERFUNC t 112 = CMP(GT) _argc, 1 CBRANCH(GT) t 112, $L 7, $L 6 $L 7: (refs=1) _message = ASSIGN &$SG 1074 GOTO $L 8 $L 6: (refs=1) _message = ASSIGN &$SG 1076 GOTO $L 8: (refs=2) = CALL &_printf, _message RET 0, $L 3(Tech) $L 3: (refs=1) EXITFUNC $L 2: (refs=0) END
Simple Example: LIR START _main(Tech) _main: (refs=1) _argc, _argv = ENTERFUNC jmp $L 12: (refs=1) ENTERBODY tv 112 -(EFLAGS) = cmp(GT) _argc[_FP], 1 jcc(GT) tv 112 -(EFLAGS), $L 7, $L 6 $L 7: (refs=1) _message[_FP] = mov &$SG 1074 jmp $L 8 $L 6: (refs=1) _message[_FP] = mov &$SG 1076 jmp $L 8: (refs=2) [ESP], {ESP} = push _message[_FP] {EAX ECX EDX. . . } = call &_printf, $out[ESP], {EAX ECX. . . } ESP, EFLAGS = add ESP, 4 tv 118 -(EAX) = mov 0 jmp $L 3: (refs=1) EXITBODY jmp $L 13: (refs=1) EXITFUNC tv 118 -(EAX) $L 2: (refs=0) END
Simple Example: EIR RAW DATA 0000: 00000010: 00000020: 00000030: 55 FC 00 00 8 B 00 FF 00 EC 00 75 8 B 51 00 FC E 5 83 00 FF 5 D 7 D E 9 15 C 3 08 07 00 00 01 0 F 8 E 0 C 00 00 00 C 7 45 FC 00 00 00 83 C 4 04 B 8 00 00 00 RELOCATIONS Offset -------00000026 0000001 D 00000011 Type --------DIR 32 Applied To --------00000000 Symbol Index -------D 7 6 Symbol Name -----__imp__printf $SG 1076 $SG 1074
Use compiler information for security analysis Useful Phoenix freebies: Binary disassembly Breaking code up into basic blocks Graphing utilities, flow/call graph Aliasing/dependencies Simulated/symbolic execution
The plan What is Phoenix? Example uses Threadsafe reference counting (COM) Inlined strcpy detection An MSRC case - Create. Text. Range Analysis/Demo
Reference counting in COM Add. Ref/Release Object freed when refcount reaches 0 Multithreaded environment
Add. Ref/Release grepping for ‘Interlocked’ Following function calls Eg overloading of the ++ operator What we miss Inconclusive rate of 18% False hit rate
COM and threadsafe reference-counting “In general it is a reasonable practice to always use the slightly less efficient Interlocked. Increment/Interlocked. Decrement versions as they are known to be safe in all contexts and relieve the developer from maintaining two versions of essentially the same code. ” Don Box, Essential COM
Inlined strcpy. . . Banned/deprecated APIs Inlined unchecked strcpy-like loops Custom terminators
Strcpy-like loops – the gory details Find a closed path across 1 or 2 basic blocks A read to and a write from an 8 - or 16 bit register Both the source of the read and the destination of the write must be incremented by a small amount (<=8) No comparisons on any reg that added to/subtracted from during the loop Other minor tricks
The plan What is Phoenix? An MSRC case - Create. Text. Range Demo
MS 06 -013 -Create. Text. Range HRESULT CInput: : create. Text. Range(IHTMLTxt. Range * * pp. Disp) { HRESULT hr = S_OK; CAuto. Range * p. Auto. Range = NULL; . . . if (!pp. Disp) { hr = E_INVALIDARG; goto Cleanup; } if (!Has. Slave. Ptr()) { goto Cleanup; }. . . *pp. Disp = p. Auto. Range; p. Auto. Range->Add. Ref(); Cleanup: . . . return hr; }
MS 06 -013 -Create. Text. Range HRESULT CInput: : create. Text. Range(IHTMLTxt. Range * * pp. Disp) { HRESULT hr = S_OK; CAuto. Range * p. Auto. Range = NULL; . . . if (!pp. Disp) { hr = E_INVALIDARG; goto Cleanup; } *pp. Disp = NULL; if (!Has. Slave. Ptr()) { hr = E_UNEXPECTED ; goto Cleanup; }. . . *pp. Disp = p. Auto. Range; p. Auto. Range->Add. Ref(); Cleanup: . . . return hr; }
MS 06 -013 -Create. Text. Range Exploitation: hr = (*p. Handler)(this, p. Srv. Provider, p. Disp, w. Entry, (PROPERTYDESC_BASIC_ABSTRACT *)p. Desc, w. Flags, pdispparams, pvar. Result); HRESULT CInput: : create. Text. Range( IHTMLTxt. Range * * pp. Disp ) if (hr == S_OK && pvar. Result && V_VT(pvar. Result) == VT_DISPATCH && V_DISPATCH(pvar. Result)) { IDispatch *pdisptemp = V_DISPATCH(pvar. Result); hr = pdisptemp->Query. Interface(IID_IDispatch, (LPVOID*)&V_DISPATCH(pvar. Result)); lized a i t i n-in u eap h g n e i l h l Ca on t y r o mem
MS 06 -013 -Create. Text. Range Key characteristics: Function has output pointer (pp. Disp) There is a [success] path that does not initialize *pp. Disp
Uninitialized output pointer Functional unit flowgraph : START *pp. Disp=. . . ; END
Unlink initialization nodes START *pp. Disp=. . . ; END
Comments SAL Inference Null-pointer derefs. . .
Null pointer issues if(ppv == NULL) { return E_POINTER; }. . . TRUE START if(ppv == NULL) FALSE return E_POINTER . . . END
Uninit Output Ptr revisited START if(pp. Disp==NULL) TRUE FALSE *pp. Disp=. . . ; END
Delete “ppv==NULL” edges START if(ppv==NULL) TRUE FALSE *ppv=. . . ; END
MS 06 -013 -Create. Text. Range HRESULT CInput: : create. Text. Range(IHTMLTxt. Range * * pp. Disp) { HRESULT hr = S_OK; CAuto. Range * p. Auto. Range = NULL; . . . if (!pp. Disp) { hr = E_INVALIDARG; goto Cleanup; } if (!Has. Slave. Ptr()) { goto Cleanup; }. . . *pp. Disp = p. Auto. Range; p. Auto. Range->Add. Ref(); Cleanup: . . . return hr; }
MS 06 -013 -Create. Text. Range HRESULT CInput: : create. Text. Range(IHTMLTxt. Range * * pp. Disp) { HRESULT hr = S_OK; CAuto. Range * p. Auto. Range = NULL; Initialization . . . if (!pp. Disp) { hr = E_INVALIDARG; goto Cleanup; } Validation checks if (!Has. Slave. Ptr()) { goto Cleanup; }. . . *pp. Disp = p. Auto. Range; p. Auto. Range->Add. Ref(); Cleanup: . . . return hr; } Main body of fn Cleanup and return
Create. Text. Range START HRESULT CAuto. Range * hr = S_OK; p. Auto. Range = NULL; if(!pp. Disp) hr = E_INVALIDARG; goto Cleanup; Cleanup: . . . return hr; END if(!has. Slave. Ptr()) *pp. Disp = p. Auto. Range; p. Auto. Range->Add. Ref();
Create. Text. Range START HRESULT CAuto. Range * hr = S_OK; p. Auto. Range = NULL; if(!pp. Disp) hr = E_INVALIDARG; goto Cleanup; Cleanup: . . . return hr; END if(!has. Slave. Ptr()) *pp. Disp = p. Auto. Range; p. Auto. Range->Add. Ref();
Create. Text. Range START HRESULT CAuto. Range * hr = S_OK; p. Auto. Range = NULL; if(!pp. Disp) hr = E_INVALIDARG; goto Cleanup; Cleanup: . . . return hr; END if(!has. Slave. Ptr()) *pp. Disp = p. Auto. Range; p. Auto. Range->Add. Ref();
The plan What is Phoenix? An MSRC case - Create. Text. Range Demo
Detecting null-derefs START if(ppv==NULL) TRUE FALSE *ppv=. . . ; END
Delete “ppv!=NULL” edges START if(ppv==NULL) TRUE FALSE *ppv=. . . ; END
Comments SAL Inference Null-pointer derefs. . .
Query. Interface(riid, ppv) *ppv should (almost) always be initialized Easily detectable via simple flowgraph connectedness check
Good books
Questions? Reporting vulns: secure@microsoft. com Email us about other stuff switech@microsoft. com
- Slides: 39