nmon对主流数据库mysql的扫描功能源码实现探索

168 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

[toc]

简介

探索nmon对主流的数据库如何实现的发现功能,如已知一个设备的ip,如果才能知道这台设备的3306或其他端口是否暴露了mysql服务
rpm version: nmap-6.40-19.el7.src.rpm

nmap支持哪些sql

[kira@192 nselib]$ pwd
/home/kira/rpmbuild/BUILD/nmap-6.40/nselib
[kira@192 nselib]$ find ./ -name "*sql*"
./pgsql.lua
./data/http-sql-errors.lst
./data/mysql-cis.audit
./mssql.lua
./mysql.lua
[kira@192 nselib]$
  • nmap支持Postgresql、mysql、microsoft sql server三种数据库

rpm源码构建

yumdownland --source nmap               # 下载源码
rpm -ivh nmap-6.40-19.el7.src.rpm       # 展开
cd rpmbuild/SPEC                        # 进入到spec文件目录
rpmbuild -bp nmap.spec                  # 构建项目

Postgresql

mysql

源码分析

在nmon项目中搜索mysql字样,并排除以下文件 *.nse,*.xml,*.lst,*.audit,*.diff,*.db,*.txt 后,发现主要涉及到mysql的代码段均在 BUILD/nmap-6.40/nselib/mysql.lua:

   15  local table = require "table"
   16: _ENV = stdnse.module("mysql", stdnse.seeall)
   17  

   83  
   84: --- Parses a MySQL header
   85  --

  181  
  182: --- Attempts to Login to the remote mysql server
  183  --
  • 重要函数
    --- Recieves the server greeting upon intial connection
    --
    -- @param socket already connected to the remote server
    -- @return status true on success, false on failure
    -- @return response table with the following fields <code>proto</code>, <code>version</code>,
    -- <code>threadid</code>, <code>salt</code>, <code>capabilities</code>, <code>charset</code> and
    -- <code>status</code> or error message on failure (status == false)
    function receiveGreeting( socket )
    
    • 接受建立连接后紧接而来的服务器问候语
    ......
    	pos, response = decodeHeader( data, 1 ) 
    
    -- do we need to read the remainder
    if ( #data - HEADER_SIZE < response.len ) then
    	local tmp = try( socket:receive_bytes( response.len - #data + HEADER_SIZE ) )
    	data = data .. tmp
    end
    			
    local is_error
    pos, is_error = bin.unpack( "C", data, pos ) 
    
    if ( is_error == 0xff ) then
    	pos, response.errorcode = bin.unpack( "S", data, pos )
    	pos, response.errormsg = bin.unpack("A" .. (#data - pos + 1), data, pos )
    
    	return false, response.errormsg
    end
    ......
    
    • 这里是解析问候语后,如果信息不对表示不是mysql的信息,返回,再往后的代码正常解析剩余消息
  • 其他重要函数
    local function createLoginHash(pass, salt)
    function loginRequest( socket, params, username, password, salt )
    function sqlQuery( socket, query )
    

nmon流程分析

  • tcp链接至mysql,mysql服务端会立即发送一条问候语 OoSmuR.png
  • nmap解析这条问候语的消息,分析这是一条mysql的报文(后续可能还会尝试登陆),从而认定该ip的该端口为一个mysql服务端服务端口

存在的问题

  • mysql的这条消息语官方删除了文档,并且不同版本可能会存在误差,官方未标注
  • nmap使用了自己写的lua脚本,并未使用mysql的官方库

mysql帮助文档