fscan/Plugins/ms17010.go

227 lines
7.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package Plugins
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"github.com/shadow1ng/fscan/common"
"strings"
"time"
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
)
func AesEncrypt(orig string, key string) string {
// 转成字节数组
origData := []byte(orig)
k := []byte(key)
// 分组秘钥
// NewCipher该函数限制了输入k的长度必须为16, 24或者32
block, _ := aes.NewCipher(k)
// 获取秘钥块的长度
blockSize := block.BlockSize()
// 补全码
origData = PKCS7Padding(origData, blockSize)
// 加密模式
blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
// 创建数组
cryted := make([]byte, len(origData))
// 加密
blockMode.CryptBlocks(cryted, origData)
return base64.StdEncoding.EncodeToString(cryted)
}
func AesDecrypt(cryted string, key string) string {
// 转成字节数组
crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
k := []byte(key)
// 分组秘钥
block, _ := aes.NewCipher(k)
// 获取秘钥块的长度
blockSize := block.BlockSize()
// 加密模式
blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
// 创建数组
orig := make([]byte, len(crytedByte))
// 解密
blockMode.CryptBlocks(orig, crytedByte)
// 去补全码
orig = PKCS7UnPadding(orig)
return string(orig)
}
//补码
//AES加密数据块分组长度必须为128bit(byte[16])密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个。
func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
padding := blocksize - len(ciphertext)%blocksize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
//去码
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
var (
key ="0123456789topsec"
negotiateProtocolRequest_enc ="PnS50rhbh1nkb4JDjAnoOuFjxijddlAUbLUDi6xFyu5FGu3ui3aKZg7uqp/KfbQdSL1oEjs+/vXFWUrIaX5UGuEzNMwMbbLjRJjRqnrxi9puFZlBy92ioaf/0eVPeVsd/y21mEz0uWxYrw1Q5OJO9ibgKVFWBwH4oDSJgfwIRRI/Erob5s1WwVOTKRFwbbwKkaNi2OPSok4Qit4Be5/Ugl0P4iXal47TgUouo/Tnm/hafQuiUEnU/NHgwyax8O0WEkBBV9RQ6tEIpyGBoVXqNHBD2svOLCHXtOZ0JR8lpmBbVqVYmOnbvC/TtUphlltyD2XaI2eM6P9snMEs/tH6AjvSzy4MiArc2ehCvI8KkrzRr2Ely6+sQPikE4ILDXJV"
sessionSetupRequest_enc ="OSuNN6y67H6V31XBAy0ObMjquG9VG30Be+HtUPppjqzUa+j1Sb1RXnlMhmNKBfdA060UgJhPAWEA0mHvgtuZINyl673/8Gly0NYdXSDAsvHsrUZZ4F/ghxQlRasFqo91RTCYyT2uR2mblhUC8HbEPjgUCmbGG4JGACJRMtHrWMAEyynCLd+RGGAUp5rceIaeEnHSUOjs1IIyjfmsi0HxdjNYlNX2BvFe5saBdjc92k3RQrYruaN6Y4eKMAZcR188ZF9UDelR3OP+guwAmOs6DfvNoo+f236V2Vfofq9y66/aKE5Z6pIF1+d5J+kPiYgyC4pt59rRR5lAW8VNS18frmeaob/f3DhikECQRxLyHs4oFiWKpVLq6Gw4eR0Xg6LR"
treeConnectRequest_enc ="Io2yBzE7AkWMamTGFTL9O7P9ExaQpPaIEO/w+j1dFE/2ZQtpWH36u7Kv6Sj962hbLoT0EbqKeh7OzgDVkdz4DIeFapPixtiGQ8bI5Gl+NDUB3gdWDei9HNVbpGV2v/2tMF/hFesLnPLlB5m1mVweDofFPNwexEzHSaDYcBD4wddaX/N8qPdxKUx3inIMd4kKLnKyq5lyqerqG1XLvyB3XFHmWrGsg57YNMOJR4j4T3N/ydl3B92FcO6zH0qntEn4dsWinnutQznDHQ1AuV1Bag=="
transNamedPipeRequest_enc ="Tudw0vZes6K4es+7e3d3wwSSJ4MwynBWhFM5oH+z1gNUbPCKa6XjKwyeD+PT/PNHnp+Tl7RDHVq3TOMQgCgQBXP02QeO2oW6adqUOLIBIIyhrPdWHP2Z7wrQNuwHoS2DgSDpBneQqnJcfVjv8dYFzYENz3oIYX74IkAgHb+NCAPwNdVkDLjm5Z0qG4Qu40V/2kNgNjLP0ucy3oSoPL6FFQ=="
trans2SessionSetupRequest_enc ="rJEocuY9iMIM8KGtr4RlvGxp6meKD7h/ROQSKYiLQ6m5p1Qa3vrDkengdGcp930bh39NIW21eKe1Zr2dt/zXB6lYlXmQ/bgAsNEQW2cvWMs1yA2z8Ua6SIq46DynJDCQV2oWTuYKaqcy68Tno91vHsO8khooMT7bzx4EUbgN9zhKva/CkTKPXOrHBjcF9Wpv5XJDCmhLAD5EqL317Cdqgfcd+59kitYFva7N2st4aMc="
negotiateProtocolRequest, _ = hex.DecodeString(AesDecrypt(negotiateProtocolRequest_enc, key))
sessionSetupRequest, _ = hex.DecodeString(AesDecrypt(sessionSetupRequest_enc, key))
treeConnectRequest, _ = hex.DecodeString(AesDecrypt(treeConnectRequest_enc, key))
transNamedPipeRequest, _ = hex.DecodeString(AesDecrypt(transNamedPipeRequest_enc, key))
trans2SessionSetupRequest, _ = hex.DecodeString(AesDecrypt(trans2SessionSetupRequest_enc, key))
)
func MS17010(info *common.HostInfo) error {
if common.IsBrute {
return nil
}
err := MS17010Scan(info)
if err != nil {
errlog := fmt.Sprintf("[-] Ms17010 %v %v", info.Host, err)
common.LogError(errlog)
}
return err
}
func MS17010Scan(info *common.HostInfo) error {
ip := info.Host
// connecting to a host in LAN if reachable should be very quick
conn, err := common.WrapperTcpWithTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second)
defer func() {
if conn != nil {
conn.Close()
}
}()
if err != nil {
//fmt.Printf("failed to connect to %s\n", ip)
return err
}
err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err != nil {
//fmt.Printf("failed to connect to %s\n", ip)
return err
}
_, err = conn.Write(negotiateProtocolRequest)
if err != nil {
return err
}
reply := make([]byte, 1024)
// let alone half packet
if n, err := conn.Read(reply); err != nil || n < 36 {
return err
}
if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
// status != 0
return err
}
_, err = conn.Write(sessionSetupRequest)
if err != nil {
return err
}
n, err := conn.Read(reply)
if err != nil || n < 36 {
return err
}
if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
// status != 0
//fmt.Printf("can't determine whether %s is vulnerable or not\n", ip)
var Err = errors.New("can't determine whether target is vulnerable or not")
return Err
}
// extract OS info
var os string
sessionSetupResponse := reply[36:n]
if wordCount := sessionSetupResponse[0]; wordCount != 0 {
// find byte count
byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9])
if n != int(byteCount)+45 {
fmt.Println("[-]", ip+":445", "ms17010 invalid session setup AndX response")
} else {
// two continous null bytes indicates end of a unicode string
for i := 10; i < len(sessionSetupResponse)-1; i++ {
if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 {
os = string(sessionSetupResponse[10:i])
os = strings.Replace(os, string([]byte{0x00}), "", -1)
break
}
}
}
}
userID := reply[32:34]
treeConnectRequest[32] = userID[0]
treeConnectRequest[33] = userID[1]
// TODO change the ip in tree path though it doesn't matter
_, err = conn.Write(treeConnectRequest)
if err != nil {
return err
}
if n, err := conn.Read(reply); err != nil || n < 36 {
return err
}
treeID := reply[28:30]
transNamedPipeRequest[28] = treeID[0]
transNamedPipeRequest[29] = treeID[1]
transNamedPipeRequest[32] = userID[0]
transNamedPipeRequest[33] = userID[1]
_, err = conn.Write(transNamedPipeRequest)
if err != nil {
return err
}
if n, err := conn.Read(reply); err != nil || n < 36 {
return err
}
if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 {
//fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os)
//if runtime.GOOS=="windows" {fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os)
//} else{fmt.Printf("\033[33m%s\tMS17-010\t(%s)\033[0m\n", ip, os)}
result := fmt.Sprintf("[+] %s\tMS17-010\t(%s)", ip, os)
common.LogSuccess(result)
defer func() {
if common.SC != "" {
MS17010EXP(info)
}
}()
// detect present of DOUBLEPULSAR SMB implant
trans2SessionSetupRequest[28] = treeID[0]
trans2SessionSetupRequest[29] = treeID[1]
trans2SessionSetupRequest[32] = userID[0]
trans2SessionSetupRequest[33] = userID[1]
_, err = conn.Write(trans2SessionSetupRequest)
if err != nil {
return err
}
if n, err := conn.Read(reply); err != nil || n < 36 {
return err
}
if reply[34] == 0x51 {
result := fmt.Sprintf("[+] %s has DOUBLEPULSAR SMB IMPLANT", ip)
common.LogSuccess(result)
}
} else {
result := fmt.Sprintf("[*] %s (%s)", ip, os)
common.LogSuccess(result)
}
return err
}