Clan x86

Technical (Development, Security, etc.) => General Programming => Botdev => Topic started by: Punk on May 25, 2009, 04:26:29 pm

Title: SID_AUTH_INFO Signature
Post by: Punk on May 25, 2009, 04:26:29 pm
I'm looking for some information on the 0x50 128-bit signature that battle.net includes at the end of the packet. I've done countless hours of trying to find documentation on this, but have found close to none. I talked this over with brew and we came to the conclusion that the signature is generated by the servers ipaddress in conjuction with powmod.

I'm relatively new to encryption so right now I'm stuck at a brick wall. I'm trying to write a gateway (in C or VB6, haven't decided yet) for Warcraft III. Unfortunately, in order to do this, I have to update the signature battle.net sends to the client, else wise, the Warcraft III client will pop an error informing me that the server I am trying to connect to doesn't appear to be a battle.net server.

So, ultimately, I need a way to generate the 128-bit signature.
Title: Re: SID_AUTH_INFO Signature
Post by: iago on May 25, 2009, 04:42:43 pm
You can find an implementation somewhere on my wiki or, if nothing else, in JavaOp2. :)

<edit>
Quote
    // I don't really like this function being here, but I can't think of anywhere else it might belong :-/
    private void checkServerSignature(byte []sig, byte []ip) throws IOException
    {
        // The constants
        BigIntegerEx key = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, new byte[] { 0x01, 0x00, 0x01, 0x00 });
        BigIntegerEx mod = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, new byte[]
        {
                (byte) 0xD5, (byte) 0xA3, (byte) 0xD6, (byte) 0xAB, (byte) 0x0F, (byte) 0x0D, (byte) 0xC5, (byte) 0x0F, (byte) 0xC3, (byte) 0xFA, (byte) 0x6E, (byte) 0x78, (byte) 0x9D, (byte) 0x0B, (byte) 0xE3, (byte) 0x32,
                (byte) 0xB0, (byte) 0xFA, (byte) 0x20, (byte) 0xE8, (byte) 0x42, (byte) 0x19, (byte) 0xB4, (byte) 0xA1, (byte) 0x3A, (byte) 0x3B, (byte) 0xCD, (byte) 0x0E, (byte) 0x8F, (byte) 0xB5, (byte) 0x56, (byte) 0xB5,
                (byte) 0xDC, (byte) 0xE5, (byte) 0xC1, (byte) 0xFC, (byte) 0x2D, (byte) 0xBA, (byte) 0x56, (byte) 0x35, (byte) 0x29, (byte) 0x0F, (byte) 0x48, (byte) 0x0B, (byte) 0x15, (byte) 0x5A, (byte) 0x39, (byte) 0xFC,
                (byte) 0x88, (byte) 0x07, (byte) 0x43, (byte) 0x9E, (byte) 0xCB, (byte) 0xF3, (byte) 0xB8, (byte) 0x73, (byte) 0xC9, (byte) 0xE1, (byte) 0x77, (byte) 0xD5, (byte) 0xA1, (byte) 0x06, (byte) 0xA6, (byte) 0x20,
                (byte) 0xD0, (byte) 0x82, (byte) 0xC5, (byte) 0x2D, (byte) 0x4D, (byte) 0xD3, (byte) 0x25, (byte) 0xF4, (byte) 0xFD, (byte) 0x26, (byte) 0xFC, (byte) 0xE4, (byte) 0xC2, (byte) 0x00, (byte) 0xDD, (byte) 0x98,
                (byte) 0x2A, (byte) 0xF4, (byte) 0x3D, (byte) 0x5E, (byte) 0x08, (byte) 0x8A, (byte) 0xD3, (byte) 0x20, (byte) 0x41, (byte) 0x84, (byte) 0x32, (byte) 0x69, (byte) 0x8E, (byte) 0x8A, (byte) 0x34, (byte) 0x76,
                (byte) 0xEA, (byte) 0x16, (byte) 0x8E, (byte) 0x66, (byte) 0x40, (byte) 0xD9, (byte) 0x32, (byte) 0xB0, (byte) 0x2D, (byte) 0xF5, (byte) 0xBD, (byte) 0xE7, (byte) 0x57, (byte) 0x51, (byte) 0x78, (byte) 0x96,
                (byte) 0xC2, (byte) 0xED, (byte) 0x40, (byte) 0x41, (byte) 0xCC, (byte) 0x54, (byte) 0x9D, (byte) 0xFD, (byte) 0xB6, (byte) 0x8D, (byte) 0xC2, (byte) 0xBA, (byte) 0x7F, (byte) 0x69, (byte) 0x8D, (byte) 0xCF
        });
       
        // Do the calculation
        byte []result = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, sig).modPow(key, mod).toByteArray();
       
        // Create the array of the correct result
        byte []correctResult = new byte[result.length];
        // Put the ip into the array
        correctResult[0] = ip[0];
        correctResult[1] = ip[1];
        correctResult[2] = ip[2];
        correctResult[3] = ip[3];

        // Pad the result with 0xBB's
        for(int i = 4; i < correctResult.length; i++)
            correctResult = (byte) 0xBB;
       
        for(int i = 0; i < result.length; i++)
            if(result != correctResult)
                throw new IOException("Error! Server failed validation check!");
    }

Think you can figure it out from there?
Title: Re: SID_AUTH_INFO Signature
Post by: MyndFyre on May 26, 2009, 02:55:46 am
I also have it implemented in C#: http://code.google.com/p/jinxbot/source/browse/trunk/development/projects/BNSharp/MBNCSUtil/NLS.cs (line 399).

Skywing authored an article that discussed this briefly: http://uninformed.org/index.cgi?v=2&a=1&p=17
Title: Re: SID_AUTH_INFO Signature
Post by: sdfg on May 26, 2009, 07:54:13 am
I talked this over with brew and we came to the conclusion that the signature is generated by the servers ipaddress in conjuction with powmod.

You must've misunderstood, it's not generated with powmod, it's checked with powmod :( i'm sure brew wouldn't say something dumb like that.

The signature is a 1024 byte number that, when raised to the power of 0x10001, modulus this big honkin' number, it comes out to another 1024 byte number where the first four bytes are the ip address of the server you'd like to connect to, and the rest are 0xBBs. Finding such a unique number takes a lot of effort unless you have Blizzard's algorithm to do this. This is somewhat similar to how Starcraft checks if a warden module is indeed from Blizzard, imagine the results if you connected to a pvpgn server that sent some arbitrary code to execute... =[
They're smart people. They've been in this business for a while, and it really is not as simple as you and everyone else in this thread makes it seem (they've implemented the code to check the signature, not to generate one, since that's the entire point behind this security).
Title: Re: SID_AUTH_INFO Signature
Post by: Punk on May 26, 2009, 11:43:05 am
Thanks for the help though guys. I guess I'll leave this one be.

Btw, when I said
Code: [Select]
I talked this over with brew and we came to the conclusion that the signature is generated by the servers ipaddress in conjuction with powmod.
I didn't say it was used to create the encryption, I meant that powmod was related to its enc / decrpy somehow. But yeah, I understand now. Thanks for clearing that up :-P
Title: Re: SID_AUTH_INFO Signature
Post by: iago on May 26, 2009, 12:10:01 pm
Aha, I just noticed that you asked how to generate the signature, not how to verify it -- the easy answer is, it's impossible. :)

The long answer is, you have to hack Blizzard or something if you want it.
Title: Re: SID_AUTH_INFO Signature
Post by: Camel on May 26, 2009, 02:06:32 pm
the easy answer is, it's impossible. :)
Tut-tut, iago! It's impossible just because the public key is 1024 bits? Brute forcing the key would be trivial! Never mind how many lifetimes it would take...

[edit] Out of curiosity, does the official client allow any way to bypass this check?
Title: Re: SID_AUTH_INFO Signature
Post by: iago on May 26, 2009, 05:20:50 pm
the easy answer is, it's impossible. :)
Tut-tut, iago! It's impossible just because the public key is 1024 bits? Brute forcing the key would be trivial! Never mind how many lifetimes it would take...

[edit] Out of curiosity, does the official client allow any way to bypass this check?
Not anymore. Original versions of War3 worked fine if you just didn't include the check (or maybe if you 00'ed it out, I forget now). But they fixed that loophole.
Title: Re: SID_AUTH_INFO Signature
Post by: Punk on May 26, 2009, 06:58:48 pm
Brew gave me a good idea. What if you temporarily changed the subroutine that verifies the address to always return a pos value then change it back after 0x51?
Title: Re: SID_AUTH_INFO Signature
Post by: iago on May 26, 2009, 07:53:58 pm
If you mean modify the client, that's certainly possible -- you can easily modify the client to always accept a server signature.
Title: Re: SID_AUTH_INFO Signature
Post by: Camel on May 26, 2009, 09:22:46 pm
bool verifyItIsBlizzard() {
    return YES_IT_IS;
}
Title: Re: SID_AUTH_INFO Signature
Post by: Punk on May 27, 2009, 04:49:15 pm
bool verifyItIsBlizzard() {
    return YES_IT_IS;
}


I wish it where that easy :-P
Title: Re: SID_AUTH_INFO Signature
Post by: sdfg on May 28, 2009, 12:15:37 am
Brew gave me a good idea. What if you temporarily changed the subroutine that verifies the address to always return a pos value then change it back after 0x51?

bool verifyItIsBlizzard() {
    return YES_IT_IS;
}


Yup!
It's 7 bytes, all you need to do is find out where to put them!
Title: Re: SID_AUTH_INFO Signature
Post by: Joe on May 29, 2009, 05:00:47 am
Aha, I just noticed that you asked how to generate the signature, not how to verify it -- the easy answer is, it's impossible. :)

The long answer is, you have to hack Blizzard or something if you want it.


Well, it's 128 characters. That means that there's only 10^128 different possibilities. It shouldn't take more than a few hours to generate the one for your IP.

And since it's mod, I think there may be more than one correct number.
Title: Re: SID_AUTH_INFO Signature
Post by: Hdx on May 29, 2009, 09:29:17 am
Aha, I just noticed that you asked how to generate the signature, not how to verify it -- the easy answer is, it's impossible. :)

The long answer is, you have to hack Blizzard or something if you want it.


Well, it's 128 characters. That means that there's only 255^128 different possibilities. It shouldn't take more than a few hours decades to generate the one for your IP.

And since it's mod, I think there may be more than one correct number.
neh?
Title: Re: SID_AUTH_INFO Signature
Post by: Camel on May 29, 2009, 12:00:01 pm
Well, it's 128 characters. That means that there's only 10^128 different possibilities. It shouldn't take more than a few hours to generate the one for your IP.

And since it's mod, I think there may be more than one correct number.
No. Just no.

It's 8^128, actually. That would take an astronomically long time to guess. Assuming you have a 2GHz processor, and you could generate and test a key in a single cycle, google calculator says:
Quote
8^128 / 2GHz in years = 6.2430045 × 1098 years

Without the private key, there's no point trying to generate one.
Title: Re: SID_AUTH_INFO Signature
Post by: sdfg on May 29, 2009, 04:54:24 pm
Correct me if i'm wrong, but using the birthday attack principle couldn't you get that down to 8^64?
Title: Re: SID_AUTH_INFO Signature
Post by: iago on May 29, 2009, 05:32:59 pm
Correct me if i'm wrong, but using the birthday attack principle couldn't you get that down to 8^64?
No, I don't think the birthday attack applies here, since you can't get them to encrypt arbitrary plaintext. Or something. :)
Title: Re: SID_AUTH_INFO Signature
Post by: Joe on May 29, 2009, 07:08:13 pm
You can find an implementation somewhere on my wiki or, if nothing else, in JavaOp2. :)

<edit>
Quote
    // I don't really like this function being here, but I can't think of anywhere else it might belong :-/
    private void checkServerSignature(byte []sig, byte []ip) throws IOException
    {
        // The constants
        BigIntegerEx key = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, new byte[] { 0x01, 0x00, 0x01, 0x00 });
        BigIntegerEx mod = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, new byte[]
        {
                (byte) 0xD5, (byte) 0xA3, (byte) 0xD6, (byte) 0xAB, (byte) 0x0F, (byte) 0x0D, (byte) 0xC5, (byte) 0x0F, (byte) 0xC3, (byte) 0xFA, (byte) 0x6E, (byte) 0x78, (byte) 0x9D, (byte) 0x0B, (byte) 0xE3, (byte) 0x32,
                (byte) 0xB0, (byte) 0xFA, (byte) 0x20, (byte) 0xE8, (byte) 0x42, (byte) 0x19, (byte) 0xB4, (byte) 0xA1, (byte) 0x3A, (byte) 0x3B, (byte) 0xCD, (byte) 0x0E, (byte) 0x8F, (byte) 0xB5, (byte) 0x56, (byte) 0xB5,
                (byte) 0xDC, (byte) 0xE5, (byte) 0xC1, (byte) 0xFC, (byte) 0x2D, (byte) 0xBA, (byte) 0x56, (byte) 0x35, (byte) 0x29, (byte) 0x0F, (byte) 0x48, (byte) 0x0B, (byte) 0x15, (byte) 0x5A, (byte) 0x39, (byte) 0xFC,
                (byte) 0x88, (byte) 0x07, (byte) 0x43, (byte) 0x9E, (byte) 0xCB, (byte) 0xF3, (byte) 0xB8, (byte) 0x73, (byte) 0xC9, (byte) 0xE1, (byte) 0x77, (byte) 0xD5, (byte) 0xA1, (byte) 0x06, (byte) 0xA6, (byte) 0x20,
                (byte) 0xD0, (byte) 0x82, (byte) 0xC5, (byte) 0x2D, (byte) 0x4D, (byte) 0xD3, (byte) 0x25, (byte) 0xF4, (byte) 0xFD, (byte) 0x26, (byte) 0xFC, (byte) 0xE4, (byte) 0xC2, (byte) 0x00, (byte) 0xDD, (byte) 0x98,
                (byte) 0x2A, (byte) 0xF4, (byte) 0x3D, (byte) 0x5E, (byte) 0x08, (byte) 0x8A, (byte) 0xD3, (byte) 0x20, (byte) 0x41, (byte) 0x84, (byte) 0x32, (byte) 0x69, (byte) 0x8E, (byte) 0x8A, (byte) 0x34, (byte) 0x76,
                (byte) 0xEA, (byte) 0x16, (byte) 0x8E, (byte) 0x66, (byte) 0x40, (byte) 0xD9, (byte) 0x32, (byte) 0xB0, (byte) 0x2D, (byte) 0xF5, (byte) 0xBD, (byte) 0xE7, (byte) 0x57, (byte) 0x51, (byte) 0x78, (byte) 0x96,
                (byte) 0xC2, (byte) 0xED, (byte) 0x40, (byte) 0x41, (byte) 0xCC, (byte) 0x54, (byte) 0x9D, (byte) 0xFD, (byte) 0xB6, (byte) 0x8D, (byte) 0xC2, (byte) 0xBA, (byte) 0x7F, (byte) 0x69, (byte) 0x8D, (byte) 0xCF
        });
       
        // Do the calculation
        byte []result = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, sig).modPow(key, mod).toByteArray();
       
        for(int i = 0; i < 4; i++)
            if(result[i] != ip[i])
                throw new IOException("Error! Server failed validation check!");

        for(int i = 4; i < result.length; i++)
            if(result[i] != (byte) 0xBB)
                throw new IOException("Error! Server failed validation check!");

    }


Think you can figure it out from there?


Fixed?
Title: Re: SID_AUTH_INFO Signature
Post by: Camel on May 30, 2009, 03:08:27 am
Correct me if i'm wrong, but using the birthday attack principle couldn't you get that down to 8^64?
The birthday attack principle is based on the idea that hashing sqrt(hash strength) variations of each of two different inputs will (probably) result in a hash collision. A classic example is getting a digital signature on an evil message by requesting a signature on sqrt(strength) variants of an innocent message, and then testing each of those signatures for collision with sqrt(strength) variants of an evil message.

There are still O(strength) comparisons, simply fewer hashes.

I don't think the birthday attack applies here, since you can't get them to encrypt arbitrary plaintext. Or something. :)
The reason iago gave is sufficient to preclude the possibility of performing a birthday attack, but there's an even better reason: what the client expects to see is that the hash itself matches the IP address, not the message. The very nature of the birthday attack is finding hashing collisions, but the hash is invariant.