华为H3C iNode客户端802.1X协议的分析和破解

我司一直使用华为H3C(表面叫华三,实际上就是华为)客户端做上网认证。这货最大的问题是终端管控,会看看你客户端安装了什么,有没有插便携WiFi设备等等,如果不满足条件,就不给上网。一直很好奇,它是如何传输这些信息的,是否可能被重放攻击呢?于是借着搜索,分析了一把它的协议,总结一下如此:

  • 1.首先是客户端用mac地址广播消息,说:“我要上网,服务器在哪里”
  • 2.服务器接到请求,说:“哥在这里,交出用户名”
  • 3.客户端说:“用户名是我的mac地址,给你”。我司是用mac地址作为用户名的。主要Identity字段:aAtxdzQ1Tx8rPxELPVbcxXI= 001F29038A21,后面的部分便是我的mac地址(前面的字段实际上非常重要,这里先跳过)
  • 4.服务器说:“用户名正确,给你个随机值,用这个和你的密码做个MD5上来看看”
  • 5.客户端乖乖送上MD5值,密码还是我的mac值
  • 6.服务器说:“看来是正确的,放你一马吧”

实际上,这就是标准的802.1X的EAP握手过程。从过程中可以发现,客户端并没有携带过多的客户端信息到服务端。也就是说,终端管控仅仅是在客户端进行的,如果能够重放,那么不需要H3C的客户端,一样可以上网。那么问题来了,能否重放呢?放狗一搜,和我有同样痛苦的兄弟,大有人在。这里就有一个工程

用后发现,第一次可以,之后掉线再拨号就不行了,报错说E63100->无效认证客户端版本。分析了一下程序,发现除了MD5-Challenge过程外,其它都是写死的。那么哪个地方传输了客户端版本号呢?把重点放在了第三步中的乱码字段上。又研究了一个更加透彻的工程,发现该工程的这个字段不是写死的,是每次动态生成。果然该字段就是加密的客户端版本号。如果第一次是成功的,之后就失败了,看来字段是不可以重放的。

因为第二个工程是C写的,不能用于macOS,而第一个工程是Python写的,通用性更好。所以决定把该代码移植过去,顺便分析一下该加密过程,就有了我的这个最终工程:https://github.com/tony1016/YaH3C

其加密过程如下,因为我写了很详细的注释,大家基本上可以直接读懂,不懂留言给我吧

def encryptH3cVersion(self):  
        # generate 32bit random int
        randomInt=random.getrandbits(32)

        # transform the int to 8 bytes hex string
        randomKey="%08x"%randomInt
        logging.debug("[randomKey]"+':'.join(x.encode('hex') for x in randomKey))

        # generate 16 bytes message
        data=EAPAuth.H3C_VERSION+chr(0)+chr(0)+chr(0)

        # the  1st  time  encryt data with randomKey
        data=self.XOR(data,randomKey)
        logging.debug("[data after the 1st time encrypt]"+':'.join(x.encode('hex') for x in data))

        # transform host number to network number
        randomInt=socket.htonl(randomInt)
        logging.debug("[htonl random]:%x"%randomInt)

        # append 4 bytes random int to data
        data=data+struct.pack(">I", randomInt)[::-1]

        # encrypt data with H3C_KEY
        data=self.XOR(data,EAPAuth.H3C_KEY)
        logging.debug("[data after the 2nd time encrypt]"+':'.join(x.encode('hex') for x in data))

        # return data encrypt with base64
        data=base64.b64encode(data)
        logging.debug("[data return in base64]"+':'.join(x.encode('hex') for x in data))
        logging.debug("[that is]"+data)

        return data

    def XOR(self,dataString,keyString ):
        logging.debug("[dataString]"+':'.join(x.encode('hex') for x in dataString))
        logging.debug("[keyString]"+':'.join(x.encode('hex') for x in keyString))


        # forward order xor
        newData=""
        for i in range(0,len(dataString)):
             newData+=chr(ord(dataString[i])^ord(keyString[i%len(keyString)]))
        dataString=newData
        logging.debug("[dataString after forward xor]"+':'.join(x.encode('hex') for x in dataString))


        # inverse order xor 
        newData=""
        for i in range(0,len(dataString)):
            newData+=chr(ord(dataString[len(dataString)-1-i])^ord(keyString[i%len(keyString)]))
        newData=newData[::-1]
        logging.debug("[dataString after inverse xor]"+':'.join(x.encode('hex') for x in newData))
        return newData

算法中,最关键的是加密了两个值H3C_VERSION="EN V5.20-0408"3C_KEY="HuaWei3COM1X"。看来iNode的密钥是泄漏了。再深度挖掘下去,发现其实已经泄漏的包括两组密钥,一个是这个,一个是Mac客户端的密钥。

对于为什么流行的客户端破解版,都是各大高校的。原因是运营商为了暴利,不允许高校学生私接路由器。对于这种无耻的行为,这种客户端被破解是要被高度赞赏,高度宣传的。鄙视这种国企行为。

最后,转载请保留原文地址https://story.tonylee.name/2016/07/13/hua-wei-h3c-inodeke-hu-duan-802-1xxie-yi-de-fen-xi-he-po-jie/