- vừa được xem lúc

Phân tích CVE-2017-3066 - AMF Deserialization trong Adobe ColdFusion

0 0 11

Người đăng: Real Alpha Man

Theo Viblo Asia

1. Giới thiệu

Adobe ColdFusion là một nền tảng phát triển ứng dụng web nhanh chóng, ngôn ngữ lập trình được sử dụng với nền tảng Adobe ColdFusion cũng thường được gọi là ColdFusion, mặc dù được biết chính xác hơn là CFML. ColdFusion ban đầu được thiết kế để giúp dễ dàng kết nối các trang HTML đơn giản với cơ sở dữ liệu. Đến phiên bản 2 (1996), nó đã trở thành một nền tảng đầy đủ bao gồm cả IDE

2. Về lỗ hổng

Đây là một lỗ hổng liên quan đến AMF Deserialization, tuy là một CVE từ lâu nhưng do có nhiều kiến thức mới với mình, vì vậy mình sẽ phân tích lại nó.

2.1. Vị trí lỗi

Vị trí gây ra lỗi là /flex2gateway/amf cấu hình trong cfusion/wwwroot/WEB-INF/flex/services-config.xml

Trong file web.xml, nơi handle chức năng này là

MessageBrokerServlet được handle bởi coldfusion.bootstrap.BootstrapServlet với param khi init service là coldfusion.flex.ColdFusionMessageBrokerServlet

2.2. Vòng đời của một Servlet

Một Servlet cơ bản sẽ có 3 phần, init(), service()destroy().

  • Init method được gọi bởi Servlet container để cho biết rằng một Servlet được khởi tạo thành công và sắp đưa vào sử dụng
  • Service method được gọi để thông báo cho Servlet container về các request của client. Method này sử dụng ServletRequest object để collect data request của client và dùng ServletResponse object để tạo output.
  • Destroy method chạy duy nhất 1 lần để báo hiệu sự kết thúc của Servlet instance.

2.3. Nơi diễn ra Deserialization

Đầu tiên, ta xét đến method init() của coldfusion.bootstrap.BootstrapServlet:

Hàm này lấy đầu vào là servlet.class, chính là coldfusion.flex.ColdFusionMessageBrokerServlet, sau đó đưa vào hàm ClassloaderHelper.initServletClass.

Trong hàm này, nó tiếp tục gọi đến loadClass để class này được load.

Tiếp theo, xét đến method service() của coldfusion.bootstrap.BootstrapServlet:

Nó sẽ gọi đến coldfusion.flex.ColdFusionMessageBrokerServlet#services()

Trong hàm này, nó gọi đến hàm services() của MessageBrokerServletColdFusionMessageBrokerServlet đã implement nó.

 public void service(HttpServletRequest req, HttpServletResponse res) { ... encoded = ((HttpServletRequest)req).getContextPath(); String pathInfo = ((HttpServletRequest)req).getPathInfo(); String endpointPath = ((HttpServletRequest)req).getServletPath(); if (pathInfo != null) { endpointPath = endpointPath + pathInfo; } Endpoint endpoint; try { endpoint = this.broker.getEndpoint(endpointPath, encoded); } catch (MessageException var29) { ... try { ... endpoint.service((HttpServletRequest)req, res);

Như ta đã xem xét ở trên, với endpoint là /flex2gateway/amf thì Endpoint class của nó sẽ là flex.messaging.endpoints.AMFEndpoint.

Vì thế việc gọi endpoint.service((HttpServletRequest)req, res); sẽ gọi tới flex.messaging.endpoints.AMFEndpoint#services()

Điều đặc biệt ở đây là trong AMFEndpoint không có phương thức services, nhưng như ta thấy như sau:

flex.messaging.endpoints.AMFEndpoint kế thừa flex.messaging.endpoints.BasePollingHTTPEndpoint, rồi nó kế thừa từ flex.messaging.endpoints.BaseHTTPEndpoint, và trong flex.messaging.endpoints.BaseHTTPEndpoint có phương thức services(). Theo tính chất trong OOP, phương thức lớp cha không được lớp con override thì khi gọi phương thức đó từ lớp con sẽ gọi đến phương thức đó trong lớp cha. Do vậy AMFEndpoint.service() --> BasePollingHTTPEndpoint.service() --> BaseHTTPEndpoint.service().

Trong hàm này, nó gọi tới filterChain#invoke() với

Hàm createFilterChain() trả về một object là serializationFilter

AMFFilter là một abstract class và được 4 Filter Class implement, trong đó có flex.messaging.endpoints.amf.SerializationFilter.

Do vậy, this.filterChain#invoke() sẽ gọi tới flex.messaging.endpoints.amf.SerializationFilter.invoke().

 public void invoke(ActionContext context) throws IOException { SerializationContext sc = SerializationContext.getSerializationContext(); try { MessageDeserializer deserializer = sc.newMessageDeserializer(); InputStream in = FlexContext.getHttpRequest().getInputStream(); deserializer.initialize(sc, in, debugTrace); int reqLen = FlexContext.getHttpRequest().getContentLength(); context.setDeserializedBytes(reqLen); ... ActionMessage m = new ActionMessage(); context.setRequestMessage(m); deserializer.readMessage(m, context); success = true;

Phương thức readMessage là liên quan đến AMF Deserialization, thứ ta sẽ tìm hiểu tiếp ở phần sau.

Kết quả: Gửi request tới /flex2gateway/amf với input là 1 Object để thực hiện deserialize.

2.4. Tìm hiểu về AMF Deserialization

AMF (Action Message Format) là định dạng binary serialization thường được sử dụng bởi các ứng dụng Flash. Có một số thư viện sử dụng AMF thường dùng như:

Mỗi thư viện này đều đã bị ảnh hưởng bởi một trong số các kiểu tấn công:

  • XML external entity (XXE)
  • Tạo đối tượng và thiết lập thuộc tính tùy ý
  • Deserialization thông qua RMI

Một trong những tính năng mới của các đối tượng AMF3 là bổ sung hai đặc điểm nhất định, được gọi là ExternalizableDynamic:

  • Externalizable: Một instance của class implement flash.utils.IExternalizable và kiểm soát hoàn toàn việc serialization các thành phần của nó. Nó tương tự với java.io.Externalizable interface. Trên thực tế, tất cả thư viện nêu trên đều xây dựng flash.utils.IExternalizable từ đặc điểm kỹ thuật tương đương vớijava.io.Externalizable của Java, cho phép tái tạo bất kỳ lớp nào implement java.io.Externalizable. Nó sử dụng 2 method là readExternal(java.io.ObjectInput)writeExternal(java.io.ObjectInput) để deserialize/serialize object.
  • Dynamic: Một instance của các class definition với các đặc điểm được khai báo động, các public variable và method có thể được thêm và bớt trong runtime. Nó tương tự với chức năng của JavaBean: cho phép khởi tạo đối tượng bằng cách chỉ định tên lớp, tên và giá trị của thuộc tính. Trên thực tế, nhiều triển khai sử dụng các tiện ích JavaBeans hiện có như java.beans.Introspector (Flamingo, Flex BlazeDS, WebORB) hoặc tự triển khai một chức năng tương tự (GraniteDS).

Trong trường hợp cụ thể này, lỗ hổng nằm ở thư viện Apache BlazeDS - CVE-2017-5641 version <= 4.7.2

Phương thức readMessage:

Trong đó readHeaderreadBody:

Hàm readObject():

readObjectvalue():

readScriptObject():

Method Amf3Input.readScriptObject()xác định class đang được xử lý có implement java.io.Externalizable hay không.

Nếu ta dùng 1 Object có implement Externalizable thì sẽ tới method readExternal() của object đang được xử lý.

readExternalizable():

Như vậy đây là 1 hướng trong khai thác AMF Deserialization.

Nếu class không implement Externalizable sẽ chuyển sang 1 nhánh khác lấy các property của class và sử dụng BeanProxy.setValue() để set lại các giá trị này.

Khi đó BeanProxy sẽ cố gắng tìm các setter method của class và invoke.

Đây là hướng khác trong khai thác AMF Deserialzation.

Như vậy, chain của lỗ hổng trong thư viện này có thể tóm tắt lại như sau:

Sau đây mình sẽ trình bày cách khai thác đối với lỗ hổng này.

2.5. Chuyển từ Externalizable.readExternal() sang ObjectInputStream.readObject()

Dùng MetaDataEntry.readExternal()

Tìm ra được class này bằng cách: tìm trong các class implement từ java.io.Externalizable có phương thức readExternal() call được sang readObject().

Trong org.apache.axis2.util.MetaDataEntry#readExternal sẽ gọi tới SafeObjectInputStream.install.

Khi đó nó sẽ khởi tạo bằng việc gọi tới org.apache.axis2.context.externalize.SafeObjectInputStream#readObject.

Rồi readObjectOverride thực hiện gọi readObject của Java Native.

Trong lib của server có Commons BeanUtils 1.8.0, vì vậy chain CommonsBeanutil1 sẽ hoạt động, tuy nhiên cần wrapper bởi MetaDataEntry. Cách dễ nhất là download ysoserial về rồi build lại (nhớ đổi phiên bản từ 1,9.2 thành 1.8.0 của common-beanutils) sau đó wrapper MetaDataEntry.

POC:

image.png

Tham khảo

https://docs.google.com/presentation/d/116DwvGitgknoiq_AOLmRlrkjCrUWfi38t_u-GdU4k2k

https://codewhitesec.blogspot.com/2017/04/amf.html

Bình luận

Bài viết tương tự

- vừa được xem lúc

Linux Hardening and System Auditing (P1)

. Ngày nay, các hệ thống Linux được sử dụng trong suốt quá trình tính toán, từ các hệ thống nhúng đến hầu như tất cả các siêu máy tính, đồng thời đảm bảo một vị trí quan trọng trong các hệ thống máy chủ trên toàn thế giới. Linux đem lại cho người dùng khả năng tùy biến cao, sự ổn định và độ tin cậy

0 0 32

- vừa được xem lúc

Tìm bug với Eyewitness

. Chào các bạn, trong bài này mình sẽ viết về tool Eyewitness. Eyewiteness có tính năng chính là chụp hình lại giao diện trang web sau đó tạo một report thông qua file .

0 0 24

- vừa được xem lúc

Tôi đã debug code PHP như nào!

. Nhân dịp đầu xuân năm mới, mình xin gửi lời chúc an lành tới tất cả thành viên của viblo.asia.

0 0 46

- vừa được xem lúc

OAuth 2.0 và vài vấn đề bảo mật liên quan (Phần 2)

III. Demo một số tấn công vào cơ chế OAuth. Trong phần này mình sẽ demo một số kiểu tấn công của OAuth dựa trên các bài lab được thiết kế bởi Portswigger. a.

0 0 85

- vừa được xem lúc

OAuth 2.0 và vài vấn đề bảo mật liên quan (Phần 1)

Trong thời đại công nghệ ngày nay, việc đăng nhập bằng các tài khoản của các nền tảng khác không phải điều gì xa lạ đối với mỗi người dùng chúng ta. Việc này khả thi nhờ một vài cơ chế khác nhau, một trong số đó là OAuth 2.

0 0 40

- vừa được xem lúc

Hành trình pass OSCP trong lần thi đầu tiên (2020)

Vào một chiều đông 17/12/2020, tôi nhận được cái email thông báo đã pass OSCP ngay lần thử đầu tiên. Sau đó, tôi bắt đầu tìm hiểu về Security và quyết định học cái gì đó cho riêng mình.

0 0 180