MITIGATOR Challenge Response

This describes the MITIGATOR Challenge Response (MCR) protocol for developers of external systems. The MCR countermeasure is described in the built-in help.

MITIGATOR Challenge Response (MCR) is a protocol for IP authentication on MITIGATOR. The protocol can be implemented both by a protected application and separately, for example, when a game launcher is being checked, and game traffic is passed. The program that implements the protocol and passes the test is called the client (in the example above, the client is the launcher).

MCR exists in variants for TCP and UDP.

Designations:

  • secret key key — no less than 8 bytes;
  • the value for the cookie test — 4 bytes;
  • hash is an unsigned 4-byte integer.

+ means concatenation in formulas. The crc32(value, init) function calculates CRC32 (Castagnoli) with an initial 32-bit init value from a given value of any length. If init is not specified, it is 0.

The contents of TCP and UDP client packets should be padded with zeros up to a length of 400 to reduce the в пакетах на защиту. Messages of a different length, as well as incorrect ones, are discarded.

Reference implementation — mcr.py script (download) — may work as MITIGATOR (server mode) or as a client (client mode). The key can be specified as a hex string (--key_hex 3132333435363738), the same as in the MITIGATOR interface, or “as is” (--key_raw 12345678 is equivalent to the previous option). Examples are given in the relevant sections.

MCR protocol over TCP

  1. The client connects to the MITIGATOR using a protected IP and any port.

  2. The client sends a challenge request (Request message, 400 bytes):

    +-------+-------+-------+-------+-------+-------+-------+-------+----
    |  'M'  |  'C'  |  'R'  |  'H'  |  '3'  |  '1'  |  '1'  |  '0'  | ...
    +-------+-------+-------+-------+-------+-------+-------+-------+----
    
  3. MITIGATOR responds with a challenge (Challenge message, 8 bytes):

    +-------+-------+-------+-------+-------+-------+-------+-------+
    |  'M'  |  'C'  |  'R'  |  'C'  |        cookie (opaque)        |
    +-------+-------+-------+-------+-------+-------+-------+-------+
    
  4. The client passes the challenge (Response message, 400 bytes):

    +-------+-------+-------+-------+-------+-------+-------+-------+----
    |  'M'  |  'C'  |  'R'  |  'R'  | hash = crc32(cookie + key, 0) | ...
    +-------+-------+-------+-------+-------+-------+-------+-------+----
    

    The hash value is passed to big-endian.

  5. MITIGATOR checks the hash and closes the connection with RST.

Testing

python3 mcr.py --host 127.0.0.1 --port 1234 --key_hex 1234567812345678 server
python3 mcr.py --host 127.0.0.1 --port 1234 --key_hex 1234567812345678 client

MCR protocol over UDP

Using UDP allows MCR to be embedded within the application protocol. This is relevant when using NAT, when MCR messages and application traffic can receive different external IPs or change them during operation.

Description

  1. The client sends a challenge request to any port of the protected IP (Request message, 400 bytes):

    +-------+-------+-------+-------+-------+-------+-------+-------+----
    |  'M'  |  'C'  |  'R'  |  'H'  |  '3'  |  '1'  |  '1'  |  '0'  | ...
    +-------+-------+-------+-------+-------+-------+-------+-------+----
    
  2. MITIGATOR responds with a challenge (Challenge message, 8 bytes):

    +-------+-------+-------+-------+-------+-------+-------+-------+
    |  'M'  |  'C'  |  'R'  |  'C'  |        cookie (opaque)        |
    +-------+-------+-------+-------+-------+-------+-------+-------+
    
  3. The client passes the challenge (Response message, 400 bytes):

    +-------+-------+-------+-------+-------+-------+-------+-------+
    |  'M'  |  'C'  |  'R'  |  'R'  |         cookie (copy)         |
    +-------+-------+-------+-------+-------+-------+-------+-------+
    |  hash1 = crc32(cookie + key)  | hash2 = crc32(cookie, hash1)  |
    +-------+-------+-------+-------+-------+-------+-------+-------+
    | ...                                                           |
    

    The cookie bytes are copied from the Challenge message “as is”. The hash1 и hash2 values are passed to little-endian.

Regardless of the success of authentication, nothing is reported to the client. This complicates the brute-force attack.

Packets starting with MCRH3110 and MCRR signature are always dropped and not sent to the server. This allows MCR UDP to be used inside an existing stream with a server that does not support MCR.

Testing

python3 mcr.py --host 127.0.0.1 --port 1234 --key_hex 1234567812345678 --udp server
python3 mcr.py --host 127.0.0.1 --port 1234 --key_hex 1234567812345678 --udp client