There has been public discussions about the exploitation of the SSL PCT vulnerability. Exploit code was made publicly available (THCIISLame.c) and rumors of a potential worm that uses the vulnerability as an attack vector are spreading the security news.
What follows is my analysis of the vulnerability and the method of exploitation, it is based on the CORE IMPACT exploit module I wrote that shipped to our customers on April 16th. The THCIISLame.c exploit seems to be a direct port of the module's first version.
The vulnerable code is located in schannel.dll which is loaded by LSASS.exe, a dissembly of the vulnerable code translates roughly to the following C construct:
function(char *packet, unsigned int N) char buf[32]; unsigned int register i; if(N < 32) { memcpy(buf,packet,N); for(i = 0; i < N; i++) buf[i+N] = ~buf[i]; }
Compilation of the above code with optimizations and inline expansion translates to the following ASM that can be found in LSASS.exe:
.text:781786C8 mov [ebp-60], eax .text:781786CB mov eax, [esi+0Ch] .text:781786CE mov ecx, eax .text:781786D0 add esi, 30h .text:781786D3 mov edx, ecx .text:781786D5 lea edi, [ebp-24] .text:781786D8 shr ecx, 2 .text:781786DB rep movsd .text:781786DD mov ecx, edx .text:781786DF and ecx, 3 .text:781786E2 rep movsb .text:781786E4 xor esi, esi .text:781786E6 test eax, eax .text:781786E8 jbe short dontcopy .text:781786EA .text:781786EA loop: .text:781786EA mov dl, [ebp+esi-24] .text:781786EE lea ecx, [ebp+esi-24] .text:781786F2 inc esi .text:781786F3 not dl .text:781786F5 cmp esi, eax .text:781786F7 mov [ecx+eax], dl .text:781786FA jb short loop .text:781786FA dontcopy:
In the above C code N is a value obtained from the PCT packet. A value higher than 0x10 is enough to trigger the overflow. A value of 0x16 overwrites the return address. The boundary check (N<32) is done before the call to memcpy() but the concatenation code that follows it is logically wrong.
The vulnerability could be exploited to execute arbitrary code, for that
purpose the return address should be overwritten with an address
pointing to data controlled by the attacker, but the address of such data is
not predictable.
The usual way to reach the attacker code in Windows exploits is jumping to a portion of instructions at a known address that redirects the program flow to the attackers code. Those instructions are part of the vulnerable application code, or part of any module loaded by it, so the address depends on the application and system version, sometimes the address is the same in different version of the same modules and applications. It is part of the exploit developer's work to find those instructions to make the exploit reliable against different target configurations.
This is the approach I took for the first version of the PCT exploit, the THCISLame.c exploit uses the same technique although I have a different address.
In this case, when the vulnerable function returns to the address chosen by the attacker, there is no register pointing to the controllable data, but there is a pointer to the PCT packet on the thread's stack at [esp+6c].
If we can find a set of instructions in the vulnerable application memory equivalent to CALL [esp+6C] part of the job is done.
I used: add esp,6c ret
There are many occurrences of those instructions in the lsass.exe memory.
But there is still a problem to solve: The address at [esp+6c] points to the PCT packet header, so the fields of that header are going to be used
as executable code. If the PCT packet doesn't fulfil some protocol checks execution flow will not reach the vulnerable function so we need to craft a packet with valid field values and valid opcodes.
In this context a "valid field value" is one that allows the execution flow to reach the vulnerable function AND is also a valid opcode so as to prevent the application from crashing when it is executed.
Note that for successful exploitation, its not necessary to craft a
packet that complies with the PCT RFC (See RFC referenced at the end of this email)
The packet used on the first version of the exploit module was:
"\x80\x66\x01\x02\xbd\x00\x01\x00\x01\x00\x16\x8F\x86\x01\x00\x00\x00"
Here is a brief explanation of the values used:
Value Condition to fulfill XX YY (RecordLength): if(XX & 0x80) RecordLength = ((XX & 0x7f) << 8) | YY else RecordLength = ((XX & 0x3f) << 8) | YY
I selected XX=0x80 and YY=0x66 which satisfies the above condition.
01 0x01 (j):= 0x01 02 BD 0x02bd (k):0x0002 <= k < 0x301 < 0x8001
Here two bytes that satisfy the above condition can be used, 0x02 and 0xbd are just arbitrarily chosen values, because I like them! Note that 0xbd == mov ebp
00 01 0x0001 (l): > 0x0001, its better to keep it under 0x0003 00 01 0x0001 (m):<= 0x10 00 16 0x001A (N): (l+m+N+9 <= RecordLength) && (0 < N <= 0x20) 8F 0x008F (o): = 0x008F 86 01 0x8601 (p): >= 0x8001
Additionally, RecordLength must be less or equal to the packet size.
The crafted packet translates to the following ASM code:
80660102 and byte ptr [esi+0x1],0x2 bd00010001 mov ebp,0x1000100 0016 add [esi],dl 8f8601000000 pop [esi+0x1] eb20 jmp 0016f40b
The ESI register points to writable data in both XP and 2000, the register used by the first and fourth instructions can be changed but the third (00 16) is the right size to overwrite the return address.
A jump opcode (eb xx) could be used in the first two bytes if the packet's length is modified accordingly.
Looking at the conditions that must be met for each field we can see that there are more than 25 millions different packets that will trigger the vulnerability (combinations of the possible values for XX,YY,k,l,m and p)
Modifying the value for N is also possible but would require additional
payload to overwrite portions of the memory of the running process
with valid data.
Detection of an exploitation attempt:
In view of the above, detection of an attack that exploits this vulnerability should not rely entirely on packet bytes that can have value arbitrary chosen.
A proper check should *at least* check for the required fixed values: o == 0x8F 0x10 < N <= 0x20 (a value less than 0x10 does not overwrite the stack)
Relying on other packet bytes for a proper detection signature should be subject to careful analysis as there might be other execution paths reaching the vulnerable function.
The workaround proposed in Microsoft's bulletin MS04-011 does prevent exploitation of this vulnerability.
After further research I've found that it may be possible to write an exploit that doesn't need to carry a hardcoded address and would work against Windows XP and 2000 systems independent of service pack and hot fixes applied, except of course for MS04-011 which does fix the problem.
Exploitation has been successfully tested against the following systems:
Windows 2000 Professional - sp4 (i386) Windows 2000 Professional - sp3 (i386) Windows 2000 Professional - sp2 (i386) Windows 2000 Server - sp4 (i386) Windows 2000 Server - sp3 (i386) Windows 2000 Server - sp2 (i386) Windows 2000 Advanced Server - sp4 (i386) Windows 2000 Advanced Server - sp3 (i386) Windows 2000 Advanced Server - sp2 (i386) Windows XP Professional - sp0 (i386) Windows XP Professional - sp1 (i386)
(NT 4 exploitation seems possible with the same technique.)
The following services can be used as attack vectors:
IIS 4.0 IIS 5.0 IIS 5.1 Exchange 5.0 with SSL enabled Active Directory with SSL
The vulnerable IIS and Microsoft Exchange services are: HTTPS 443/tcp SMTP 25/tcp (STARTTLS) IMAP 993/tcp, POP3 995/tcp NNTP 563/tcp.
Active Directory: ldaps 636/tcp globalcatLDAPssl 3269/tcp.
Exploitation through the Analysis Services 2000 (included with SQL Server 2000) were not researched.
PCT must be enabled and a valid certificate installed.
References: http://www.microsoft.com/technet/security/bulletin/MS04-011.mspx http://www.develop.com/books/pws/draft-benaloh-pct-01.txt http://www.graphcomp.com/info/specs/ms/pct.htm http://www.coresecurity.com/products/coreimpact/index.php
Thanks Halvar Flake helped with the initial vulnerability analysis which demonstrated not only his code reversing expertise but also the great power of his bindiff tool.