mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
227 lines
7.7 KiB
Go
227 lines
7.7 KiB
Go
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
|
||
|
||
}
|