前两天 t00ls.net 有人发了个帖子,要求解密海洋顶端 2006+ 的一个密码,以下是解密详细过程。

    海洋顶端是很出名的 ASP 木马,2006 年海洋顶端出了最新版本也是最后一个版本:2006 Plus (2006+)。

    海洋顶端以往的各个版本密码都是明文存放的,这回 2006+ 专门有个 vbs 脚本 (以下采用 Asp 脚本的加密函数,和 vbs 的功能一模一样) 用于加密密码。

    加密密码的脚本是在 down 回来的 vbs 目录里面名为 Encode.vbs 的文件,先看海洋顶端 2006+ 原始密码加密算法代码:

海洋顶端 2006+ 原始密码加密算法:

<%
Function IIf(var, val1, val2)
    If var = True Then
        IIf = val1
    Else
        IIf = val2
    End If
End Function

Function Encode(strPass)
        Dim i, theStr, strTmp
        For i = 1 To Len(strPass) 'for循环得到密码各个字符的Ascii值,每位值都在0-9
            strTmp = Asc(Mid(strPass, i, 1)) '求每位字符的Ascii码
            theStr = theStr & Abs(strTmp) '将得到的Ascii码拼接起来
        Next
        strPass = theStr
        theStr = ""
        Do While Len(strPass) > 16 '当拼接起来Ascii码大于十六位执行JoinCutStr函数处理,使之小于等于16位
            strPass = JoinCutStr(strPass)
        Loop
        For i = 1 To Len(strPass) '这个for循环处理每个字符,把 7、8、9 转为 C、D、E,其余不变
            strTmp = CInt(Mid(strPass, i, 1)) '取每位数字转换为整型(没啥实际效果,转不转都一样)
            strTmp = IIf(strTmp > 6, Chr(strTmp + 60), strTmp) '如果这位数字大于6,则加上60转成Ascii码,并从Ascii码转换为字符(也就是 C、D、E),否则不变。
            theStr = theStr & strTmp '将结果拼接起来
        Next
        Encode = theStr
End Function

Function JoinCutStr(str) 'JoinCutStr函数把奇数位和偶数位的ascii相加整除2得到新字符,取值在0-9
        Dim i, theStr
        For i = 1 To Len(str)
            If Len(str) - i = 0 Then Exit For
            theStr = theStr & Chr(CInt((Asc(Mid(str, i, 1)) + Asc(Mid(str, i + 1, 1))) / 2))
            i = i + 1
        Next
        JoinCutStr = theStr
End Function
%>

    先说明一下什么是:把奇数位和偶数位的ascii相加整除2得到新字符。如一串数字:0123456789,然后依次把奇数位和偶数位的数字相加,再把相加的结果除以2,并取整数,运算过程如下:

    运算:(0+1)/2 (2+3)/2 (4+5)/2 (6+7)/2 (8+7)/2,并将结果取整数,得到:0 2 4 6 8。

    这个加密算法不是很复杂,其主要思想是:先依次把每个字符取ascii值,得到的一串数字作为字符对待,如果位数大于16,则折半处理(把奇数位和偶数位的ascii相加整除2得到新字符串,得到的字符串位数为原来的一半),直至小等于16,然后把7、8、9分别替换为C、D、E得到最后结果。

    我们得到了密文,第一步,我们可以把密文中的C、D、E替换回去,也就是分别替换为7、8、9,然后我们得到一串数字组成的字符串。比如字符lake2编码之后是10DEC10C10150,我们替换之,得到1089710710150,由于字符的ascii在32-127,所以可以很轻松的把字符区分开:108、97、107、101、50,正好是lake2各个字符的ascii值。

    千万不要以为这个算法这么简单就破解了,因为上述情况只是若干种情况里面最简单的一种而已。

    字符lake2的ascii值位数是11,所以并没有经过JoinCutStr函数处理,如果明文密码是lake2lake2的话,问题就复杂得多了。

    JoinCutStr函数把奇数位和偶数位的ascii相加整除2得到新字符串,但这里造成了逆向的困难。因为1234经过处理,得到的是13;1133、1134、1233、1234、1124等等经过处理,得到的仍然是13。即同一个结果对应不同的原因,多数情况下我们不知道到底哪一个才对,只好穷举。但是即使是穷举且排除那些包含不可显示字符的密码,也很难知道哪一个密码才是对的。

    我们虽然不知道使用者真正的密码是多少,但是却可以利用得到的任意一个密码登陆,因为它和真正密码加密之后的值是一样的。这个有点像MD5的碰撞,只是这个算法可以根据hash比较容易的构造碰撞,而MD5则很困难。

    还有一种比较麻烦的情况:明文密码包含中文。中文的ascii绝对值都很大,要逆向回去还是很麻烦的,所以我们还是构造碰撞吧。

    针对最简单的那种情况我们也可以用一个Asp来反编码明文密码,以下代码即实现此功能,copy保存为Asp文件运行即可。

    由于海洋顶端2006+这个猥琐的密码加密算法,当原始明文密码大于8位的时候,解码算法变得非常棘手,以下是小于等于8位解法:

海洋顶端2006+密码小于等于8位解密算法:

<%
Function Decode(Tmp)
Dim S, X, F
For i = 1 To Len(Tmp)
    S = Mid(Tmp, i, 1)
    If Asc(S) > 60 Then S = Asc(S) - 60
    X = X & S
Next
S = ""
For i = 1 To Len(X)
    S = Mid(X, i, 2)
    F = F & Chr(S)
    i = i + 1
Next
Decode = F
End Function

Response.Write Decode(Encode("123456")) & "<br>"
%>

    后面两种情况,如果要编程序破解的话感觉比较困难,就不写了。

    下面让我们通过构造碰撞来破解海洋顶端 2006 Plus 的默认密码。

    打开海洋顶端 2006 Plus文件,得到它的编码过的密码是:02200200251001,我的程序不能恢复,看来是经过JoinCutStr函数处理的。让我们大胆的还原:10 31 22 10 01 22 10 01 22 55 11 10 01 11,整合一下:103 122 100 122 100 122 55 11 100 111,这里有个ascii值11,这个字符也是可以显示的,既然是碰撞,只好将就了。我们得到我们的明文密码:gzdzdz7 chr(11) do

    因为chr(11)是换行符,格式原因不能显示,你可以把以下代码保存为vbs运行之,得到密码:

Call InputBox("海洋的默认密码碰撞", , "gzdzdz7" & chr(11) & "do")

    然后你用它登陆没有改过密码的海洋顶端木马,呵呵,进去了吧。下面再提供一个可以登陆但不同的密码用以证明这是碰撞:

Call InputBox("海洋的默认密码碰撞", , "gqdzdz7ne" & chr(11))

    如上所述,当原始明文密码大于八位的时候,编程进行还原太复杂了,还不如手工碰撞算法来得快,过程如下:

海洋顶端 2006+ 手工碰撞解密算法:

原密文:
    DD0301646431

第一步:
    将 C、D、E 分别替换为 7、8、9。
    880301646431

第二步:
    把奇数位和偶数位的运算还原,拆开并分组。
    88 88 10 51 00 11 66 44 66 44 51 11

第三步:
    按照 Ascii 码的取值范围:32-127,进行拆分重组。
    88 88 105 100 116 64 46 64 45 111

第四步:
    输出 Ascii 码对应的字符,便是结果,既:XXidt@.@-o。
    Response.Write Chr(88) & Chr(88) & Chr(105) & Chr(100) & Chr(116) & Chr(64) & Chr(46) & Chr(64) & Chr(45) & Chr(111)

    最后,我们来下个结论:在得到海洋顶端2006+编码后的密码之后,就算不能恢复出明文密码,也可以利用碰撞来登陆系统。至于如何得到编码后的密码,呵呵,那就超出本文的范围了。