-
-
Save halmartin/28e013a9034be04777073bccc918cb95 to your computer and use it in GitHub Desktop.
Fujitsu iRMC S4 PoC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# https://watchmysys.com/blog/2023/01/fujitsu-irmc-s4-license/ | |
import argparse | |
import base64 | |
import binascii | |
import zlib | |
import hmac | |
import hashlib | |
import struct | |
from Crypto.Cipher import AES | |
# obtain values from /usr/local/lib/libfts_license.so.1.12.1 | |
# Note that in python, you enter binary hex values as b"\x0d\x0e..." | |
HMAC_KEY = b"" | |
HMAC_MSG = b"" * 4 | |
AES_IV = b"" | |
def init_lookup_table(): | |
out = [] | |
for i in range(0x100): | |
lookup_table_entry = i << 0x18 | |
for k in range(8): | |
if lookup_table_entry >> 31: | |
inlr = lookup_table_entry << 1 | |
if lookup_table_entry >> 31: | |
lookup_table_entry = inlr ^ 0x4c11db7 | |
else: | |
lookup_table_entry = lookup_table_entry << 1 | |
lookup_table_entry &= 0xffffffff | |
out.append(lookup_table_entry) | |
return out | |
def spd_crc32(param_1, x): | |
tbl = init_lookup_table() | |
for pbVar1 in param_1: | |
x = (tbl[(pbVar1 ^ x >> 0x18) & 0xff] ^ x << 8) & 0xffffffff | |
return x | |
def simple_generator(ext_features, type, serial): | |
if ext_features.lower() == "kvm": | |
features = b"\x01\x00\x00\x00" | |
elif ext_features.lower() == "kvm_media": | |
features = b"\x03\x00\x00\x00" | |
elif ext_features.lower() == "kvm_media_elcm": | |
# this license type doesn't validate on my TX chassis | |
# but apparently works on RX chassis | |
if type.lower() == "tx": | |
print("License may not be valid for TX chassis with eLCM enabled") | |
features = b"\x0f\x00\x00\x00" | |
return license_generator(serial, features, type.lower()) | |
def license_generator(serial, features, type): | |
# chassis type TX | |
struct_data = 0xffffff00 | |
if type == "rx": | |
# chassis type RX | |
struct_data = 0xffffff05 | |
DATA = b'iRMC' \ | |
+ features \ | |
+ struct.pack('>I', struct_data) + \ | |
struct.pack('<I', spd_crc32(serial.encode("ASCII"), 1)) | |
print(binascii.hexlify(DATA).decode('utf-8')) | |
aes_key = hmac.new(HMAC_KEY, HMAC_MSG, hashlib.sha1).digest() | |
# this is AES-128, so only take the first 16 bytes of the aes_key | |
cipher = AES.new(aes_key[:16], AES.MODE_CBC, iv=AES_IV) | |
encrypted_license = cipher.encrypt(DATA) | |
encoded_license = base64.b32encode(encrypted_license) | |
license = encoded_license.decode("UTF-8").replace("=","") | |
return '-'.join(license[i:i+4] for i in range(0, len(license), 4)) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-t", "--type", type=str, default="tx", help="License type, valid values are 'TX' or 'RX'") | |
parser.add_argument("-f", "--features", type=str, default="kvm_media", help="License type, valid values are 'KVM', 'KVM_Media', or 'KVM_Media_eLCM'") | |
parser.add_argument("serial") | |
args = parser.parse_args() | |
if len(HMAC_KEY) != 16 or len(HMAC_MSG) != 16*4 or len(AES_IV) != 16: | |
print("You are missing the HMAC and AES values") | |
else: | |
print(simple_generator(args.features, args.type, args.serial)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@Alotire432 Please do not post personal information in a public comment on GitHub. My contact information is available on my profile.
Your values for
HMAC_KEY
,HMAC_MSG
, andAES_IV
are incorrect.