0x00 前言
在MSSQL认证过程中,不同版本的TDS协议error-msg编码不同。如何用正确的姿势处理这些乱码,化腐朽为神奇是本篇要做的。
0x01 UTF-8编码与UTF-16编码
UTF-8和UTF-16都处理相同的Unicode字符,并且都是可变长度编码,每个字符最多需要32位。但是,在选择多语言数据库或列中使用UTF-8还是UTF-16方面存在重要的差异:
UTF-8使用8位编码常见的ASCII字符,包括英语和数字。在UTF-8中,ASCII字符占一个字节,拉丁,希腊和西里尔字母的其他字符占两个字节,中文和日语字符占三个字节。
但是UTF-16在编号0到65535(在UCS-2和UTF-16中都可用)中的每个字符至少使用2个字节,而编号65536到1114111使用与UTF-8相同的4个字节。
存储边界如下表所示:
Code Range (hexadecimal) | Code Range (decimal) | Storage bytes with UTF-8 | Storage bytes with UTF-16 |
---|---|---|---|
000000 – 00007F (ASCII) | 0 - 127 | 1 | 2 |
000080 – 00009F 0000A0 – 0003FF 000400 – 0007FF | 128 – 159 160 – 1,023 1,024 – 2,047 | 2 | 2 |
000800 – 003FFF 004000 – 00FFFF | 2,048 - 16,383 16,384 – 65,535 | 3 | 2 |
010000 – 03FFFF 040000 – 10FFFF | 65,536 – 262,143 262,144 – 1,114,111 | 4 | 4 |
0x02 TDS编码需求
TDS协议版本 | 编码格式 |
---|---|
TDS 4 | ASCII |
TDS 5 | ASCII |
TDS 7.x | UTF16LE |
0x03 python解码
TDS 7.0抓包
源码
err_msg = '\x28\x75\x37\x62\x20\x00\x27\x00\x73\x00\x61\x00\x27\x00\x20\x00\x7b\x76\x55\x5f\x31\x59\x25\x8d\x02\x30'
print err_msg.decode('utf16')
# out:用户 'sa' 登录失败。
Tips
- TDS4的报错是ascii码的,所以直接在python中print就可以了
- 后来发现TDS7的报错信息都是两个字节一个单元,ascii码的字符已变成了两个字节,并且跟着\x00,以为是UTF8,后来发现UTF8是单字节的,效率比UTF16高。
0x04 参考文献
https://www.freetds.org/tds.html
https://malwaremusings.com/scripts/parsetds-py-2/