SoFunction
Updated on 2025-04-13

A brief discussion on the fragility of SQL SERVER database password

I followed up the login process of the SQL SERVER database server and found that password calculation is very fragile. The password fragility of the SQL SERVER database reflects two aspects:
1. Password encryption algorithm when logging in to the network
2. Password encryption algorithm stored in database.

The following are the following:
1. Password encryption algorithm when logging in to the network
SQL SERVER network encryption passwords have always been very fragile. There are many written comparison tables on the Internet, but none of them are processed in specific algorithms. In fact, I will track SQL.
The SERVER login process is easy to obtain its decryption algorithm: OK, let's demonstrate the assembly process:
The TDS package of login type jumps to 4126a4 to execute
004DE72E: Generate the corresponding buffer of the size according to the received size field for the next copy
004DE748 Copy the LOGIN information from the received TDS BUF offset 8
004DE762: call     sub_54E4D0: Push the new copy of the buffer for parameter checking
The information in the TDS packet is processed in turn. Each field climate should have the length of each domain, and the length is compared at offset 0X24.
The following assembly code is an algorithm that implements decryption of network encryption passwords:
    .text:0065C880                 mov     cl, [edi]
    .text:0065C882                 mov     dl, cl
    .text:0065C884                 xor     cl, 5
    .text:0065C887                 xor     dl, 0AFh
    .text:0065C88A                 shr     dl, 4
    .text:0065C88D                 shl     cl, 4
    .text:0065C890                 or      dl, cl
    .text:0065C892                 mov     [edi], dl
    .text:0065C894                 inc     edi
    .text:0065C895                 dec     eax
    .text:0065C896                 jnz     short loc_65C880
    .text:0065C898                 jmp     loc_4DE7E6
It is easy to change it to C code. It can be seen that its encryption is very simple and is no different from plain text. Haha, you can embed this code in SNIFFER to decrypt the TDS login package you sniffed. In fact, 0XA5 is not a demarcation symbol for a specific SQL SERVER password field. It is just that the encryption algorithm will automatically encrypt 0x0 of the ASC double-byte representation to 0xa5. However, if a double-byte password is allowed, this is not the main reason for judging its demarcation.
void sqlpasswd(char * enp,char* dnp)
{
    int i;
    unsigned char a1;
    unsigned char a2;
    for(i=0;i<128;i++)
    {
        if(enp[i]==0)
            break;
        a1 = enp[i]^5;
        a1 = a1 << 4;
        a2 = enp[i]^0xaf;
        a2 = a2 >> 4;
        dnp[i]=a1|a2;
    }
    dnp[i]=0;
    dnp[i+1]=0;
    wprintf(L"passwd:%s\n",(const wchar_t *)dnp);
}

2. Password encryption algorithm stored in database.
The encryption method of SQL SERVER's password to database storage is also weird. The process is as follows:
After obtaining the password for the network decryption password
Call SQLSORT_14 at 005F9D5A, implement a conversion to uppercase password buffer for saving.
Then call a function at 004def6d to retrieve the encrypted PASSWORD in the database, in the form as follows:
2 bytes header 0x0100 (fixed)
4 bytes of HASH plus secret KEY
20 bytes HASH1
20 bytes HASH2
As an example I took out:
fx:0x0100 1751857F DFDEC4FB618D8D18EBA5A27F615639F607CD46BE DFDEC4FB618D8D18EBA5A27F615639F607CD46BE
Fixed
Password is: 123456

SQL first uses 4 bytes of HASH and secret KEY to supplement the buffers of its two passwords, one in uppercase and the other in lowercase. Then its encryption process is as follows: C function
    CryptAcquireContextW(&hProv,NULL,L("Microsoft Base Cryptographic Provider v1.0"),1,0xf0000000);
    CryptCreateHash(hProv,0x8004,NULL,NULL,&hhash);
    CryptCreateHash(hProv,0x8004,NULL,NULL,&hHash);
005F9DFE:
CryptHashData(hhash,passwdbuf,0x12,NULL);passwdbuf is a lowercase passwd buffer, and then a KEY is attached. As shown in the above example, it is correct.
{    {    {        {               {                      {             {         {         {        {        {       {       {      �
CryptHashData(hHash,PASSWDBUF,0x12,NULL); PASSWDBUF is a capital passwd buffer, and then a KEY is attached
005F9E3E:
CryptGetHashParam(hhash,2,&passwdout,&outlen,0); Take out the encrypted value of passwdbuf that is lowercase passwd
CryptGetHashParam(hHash,2,&PASSWDOUT,&OUTLEN,0); Take out the encrypted value of passwdbuf that is capitalized by passwd
These two sums are the PASSWORD encryption fields in the real database

Why are the above methods fragile? In fact, its true encryption length is only 20 bytes.
The 40-bit HASH value of the HASH1 spliced ​​in lowercase password + uppercase password is not as safe as a direct 20-bit HASH value. Because everyone knows the causal relationship between these two values,
Provide more information to the decryptor.
As the algorithm is the same, if HASH1=HASH2, it can be judged that the password must not use letters, and only passwords with numbers and symbols are used. For example, the HASH of the 123456 password retrieved above, the two HASHs are exactly equal.

It is because the letters are used, and the solution of the supplementary KEY, algorithm, and two encrypted strings should be greatly simplified.

Of course I have never studied encryption algorithms, but I just feel that this encryption method is really insecure. Haha, I hope the expert in decrypting algorithms will give me some advice.