xray社区高级版证书生成

xray简介

xray 是一款功能强大的安全评估工具,由多名经验丰富的一线安全从业者呕心打造而成,主要特性有:

  • 检测速度快。发包速度快; 漏洞检测算法高效。
  • 支持范围广。大至 OWASP Top 10 通用漏洞检测,小至各种 CMS 框架 POC,均可以支持。
  • 代码质量高。编写代码的人员素质高, 通过 Code Review、单元测试、集成测试等多层验证来提高代码可靠性。
  • 高级可定制。通过配置文件暴露了引擎的各种参数,通过修改配置文件可以极大的客制化功能。
  • 安全无威胁。xray 定位为一款安全辅助评估工具,而不是攻击工具,内置的所有 payload 和 poc 均为无害化检查。

目前支持的漏洞检测类型包括:

  • XSS漏洞检测 (key: xss)
  • SQL 注入检测 (key: sqldet)
  • 命令/代码注入检测 (key: cmd_injection)
  • 目录枚举 (key: dirscan)
  • 路径穿越检测 (key: path_traversal)
  • XML 实体注入检测 (key: xxe)
  • 文件上传检测 (key: upload)
  • 弱口令检测 (key: brute_force)
  • jsonp 检测 (key: jsonp)
  • ssrf 检测 (key: ssrf)
  • 基线检查 (key: baseline)
  • 任意跳转检测 (key: redirect)
  • CRLF 注入 (key: crlf_injection)
  • Struts2 系列漏洞检测 (高级版,key: struts)
  • Thinkphp系列漏洞检测 (高级版,key: thinkphp)
  • POC 框架 (key: phantasm)

其中 POC 框架默认内置 Github 上贡献的 poc,用户也可以根据需要自行构建 poc 并运行。

进行破解

将xray-crack.exe放入xray相同目录中

C:\Users\icorgi\Desktop\xray>xray-crack.exe -h
Usage of xray-crack.exe:
  -c string
        patch xray,需要指定xray程序文件路径
  -g string
        生成一个永久license,需要指定用户名
  -p string
        解析官方证书,需要指定证书路径

先patch xray.exe

C:\Users\icorgi\Desktop\xray>xray-crack.exe -c xray.exe
Signature index: 0xae1ff5
Patch success: xray.exe

生成高级版license

C:\Users\icorgi\Desktop\xray>xray-crack.exe -g icorgi
temp aes iv: 93f64aeade398897dadae2d56d0b8395
证书已写入文件:xray-license.lic

破解效果

C:\Users\icorgi\Desktop\xray>xray

____  ___.________.    ____.   _____.___.
\   \/  /\_   __   \  /  _  \  \__  |   |
 \     /  |    _  _/ /  /_\  \  /   |   |
 /     \  |    |   \/    |    \ \____   |
\___/\  \ |____|   /\____|_   / / _____/
      \_/       \_/        \_/  \/

Version: 1.3.3/1d166d72/COMMUNITY-ADVANCED
Licensed to icorgi, license is valid until 2099-09-09 08:00:00

[INFO] 2020-10-14 15:20:56 [default:entry.go:157] loading config file from C:\Users\icorgi\Desktop\xray\config.yaml
NAME:
   xray - A powerful scanner engine [https://docs.xray.cool]

USAGE:
    [global options] command [command options] [arguments...]

COMMANDS:
     webscan      Run a webscan task
     servicescan  Run a service scan task
     poclint      lint yaml poc
     reverse      Run a standalone reverse server
     genca        Generate CA certificate and key
     upgrade      check new version and upgrade self if any updates found
     subdomain    Run a subdomain task
     version      Show version info
     help, h      Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --config FILE  Load configuration from FILE
   --help, -h     show help

main.go

package main

import (
    "bytes"
    "crypto"
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "debug/elf"
    "debug/macho"
    "debug/pe"
    "encoding/base64"
    "encoding/hex"
    "encoding/json"
    "encoding/pem"
    "flag"
    "fmt"
    "io/ioutil"
    "os"
    "strings"
    "time"
)

var (
    originPubKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2K+PRbp/yumhaVnN92JS
GuQiwj7df64jHAo8MvXLWjYxU/yvqB4LbGty8ymKQy33qaDNpu9jgE2s8cXrtftm
/UcvwDb8sTqWXpDhxYhcvJM30agxz3/8VwNJ4JOvhk9Gn+msYIUz+gXZMBuUFKhi
BOd6C2Pro03GYwVTNjfwH/Y9C5EfPKIKNU/5t2cYo+TuOBk5ooP+NTaDzB6rb7fd
E5uuNnF21x3rdiI9rZcKPbuU97/0OWNcIUh5wfxPNWwcmjYmFuZcxk/7dOUD65s4
pTplCoMLOelacB0l442dM4w2xNpn+Yg7i/ujmg37F+VguCZJWnoyImdhp/raccNG
+wIDAQAB
-----END PUBLIC KEY-----`
    newPublicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtKvyFB24hIEVwMs4Xi00
FCW41tqELGYb7f63A/lAsBPVSOvGrQ5UzuKmttatQF/IDD9UcHqqbi+B80pydiGS
eKJOaly0GuX6hfDd51/uo7E44LyzJSSBhTc1vtbL5JbNcapnxo4P6rJ1Uh9V7y8z
pRvc1G2da00mQSYoIg/9ty21j4So+Fz/v37qhK50EEIeXGJZb4uz9I9iKCHaazjI
Lf293Gzvp7EFEpZkKrh2VktKaERh+jHmJqEe0z7U/sz0cCa9ohS+TF5nxmkAZBel
CwEMXjkjGnCWO3wXJoyrXMn1GY/ilNPDFT7rSZBKLEIi7PrBD1pVLGdq2zTboenV
6wIDAQAB
-----END PUBLIC KEY-----`
    newPrivateKeyPem = `-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtKvyFB24hIEVwMs4Xi00FCW41tqELGYb7f63A/lAsBPVSOvG
rQ5UzuKmttatQF/IDD9UcHqqbi+B80pydiGSeKJOaly0GuX6hfDd51/uo7E44Lyz
JSSBhTc1vtbL5JbNcapnxo4P6rJ1Uh9V7y8zpRvc1G2da00mQSYoIg/9ty21j4So
+Fz/v37qhK50EEIeXGJZb4uz9I9iKCHaazjILf293Gzvp7EFEpZkKrh2VktKaERh
+jHmJqEe0z7U/sz0cCa9ohS+TF5nxmkAZBelCwEMXjkjGnCWO3wXJoyrXMn1GY/i
lNPDFT7rSZBKLEIi7PrBD1pVLGdq2zTboenV6wIDAQABAoIBAQCu3PSxr4pVBLLP
JGFsFQggr9nUaS4f4rwJfswXlnibcratmzVxbTt7+TYuJF0OvyVZZToOm0q01lpJ
5LYfy6J+C2kl3I+csRXl6Rh8xgase+x252vj+Q86phLon/A7UBGLf8htDjYti4et
chK0KtUramozV9xSbBsoVwvk2+FOFdiLsc+B3PyuydB0Lvov5EDBtZJ1GbnyWk/3
c++aL+lkjQbIs11A4Nwp7hUdPmM/Va8VK+DqWxbFCIr6rli5d9VOE//EHJ7S7aPp
+fxV9gyv1d0WBRNktH2t8O2JVn90379/EgWuonSlRG+HrhqZKrXIKuIFJEUmGUjs
8qJNzoERAoGBAOLjiGbXuOQHkshDqdB4xF1b4rvCBrr881dBAOnYqSyEUWuUD3et
4qX/7GaxWlSU2IteB+r5FyfEpmqUNmKVsgLkGh3lgeTU0Mss2+2xIAODNXvba8MV
UIawpvDFnLN2HEY/d+LYycBjWDk+6B1+dGlPZIxXF+8HqGnlqyBNFjP/AoGBAMva
WVB02FK4oXa8APTtvuQ2MP67Q95WdhZXdy8CEWnwJaknSTE3dXJ9nZZmFgHt54lo
KjbGfIOSCLeCqXm3ZGs5HQr2kY/xJXDJga6uNh71w66/q/W2z+30FFzta6BjYE/8
3pB+P4vUUsp/vb3SkNfRKdcNrtoL29UYdXM7QG4VAoGAQqLw/MN+2fofchHtXf0a
LxE9lkd2EpUYIxhEXGn1xc1W3HGv2UaIuphfpgmQribJMqV7Tde6pUNsXQEKuAmf
Lpov0XgGnl6itAmIzlanQGDY5HedPr6T1/sqDKz9SPf3depOG6HwH0EOOEHxijgJ
mKRos48gyGNHY1LA38vEKaECgYEAmu8fRsknyOdOwMFvMLiphyWw40pM8OVh5uUf
TnkR5ySAWynitSdjelsCtNZuD5VTjtm+i9cbt5v8SA1k5X9/MQc9jaGNTIuJW0mr
6Km7tJgx29UNyzjgnAgQmfhQ/pvJDcIxHjz16z66lfG0slshfwYX+L0LkenFcRaf
3a7A72kCgYEAhSSGHVkCTGteSyKxhbMVqTlxQQQWZKv4b+usqss00CKgs3CAKL8H
Crds7fq96xVDVCvxJGYMKQzG61MBa+e1f8YSdhl5EY1IltlHkZstgts7avG6MP6A
xMNjyLp1b84s2VVXTpSFA7i6KEUhl4NjqhZTslJht5Dfiy2Mmvfk2so=
-----END RSA PRIVATE KEY-----`
    licenseVersion2Byte = []byte{0x02}
    pre2Bytes           = []byte{0x00, 0x01}
    aesKeyNew, _        = hex.DecodeString("B293C506E0C7F60353C604961837B810")
)

var (
    licenseName   string
    originLicense string
    xrayFilePath  string
)

func main() {
    flag.StringVar(&licenseName, "g", "", "生成一个永久license,需要指定用户名")
    flag.StringVar(&originLicense, "p", "", "解析官方证书,需要指定证书路径")
    flag.StringVar(&xrayFilePath, "c", "", "patch xray,需要指定xray程序文件路径")

    flag.Parse()

    if originLicense != "" {
        parseAlready(originLicense)
    }

    if licenseName != "" {
        genNew(licenseName)
    }

    if xrayFilePath != "" {
        patch(xrayFilePath)
    }

}

func parseAlready(licenseFile string) {
    // 加载公钥
    pubKey := importPublicKey(originPubKeyPem)

    // 解析 xray-license.lic 文件
    licenseFileData, err := ioutil.ReadFile(licenseFile)
    if err != nil {
        panic(err.Error())
    }
    licenseString := string(licenseFileData)
    tmpStrings := strings.Split(licenseString, "\n")
    licenseString = ""
    for _, line := range tmpStrings {
        if !strings.HasPrefix(line, "#") && line != "" {
            licenseString += line
        }
    }
    //fmt.Println("your license:", licenseString)

    base64DecodeData, err := base64.StdEncoding.DecodeString(licenseString)
    if err != nil {
        panic(err)
    }

    //fmt.Println("base64 decode data:", hex.EncodeToString(base64DecodeData))

    licenseVersion := base64DecodeData[0]
    if licenseVersion == 2 {
        fmt.Println("version ok: 2")
    }

    //解密前有一个简单的变换处理
    right := len(base64DecodeData) - 1
    for l := 1; l < right; l++ {
        r := right - l
        if l >= r {
            break
        }
        base64DecodeData[l], base64DecodeData[r] = base64DecodeData[r], base64DecodeData[l]
    }
    //fmt.Println("trans bytes:", hex.EncodeToString(base64DecodeData))

    // aes解密license
    // | 1B : version | 16B : aes iv | 480B : cipher |
    aesDecData, err := Decrypt(base64DecodeData[17:], base64DecodeData[1:17])
    if err != nil {
        panic(err)
    }
    //fmt.Printf("AES DEC: %x\n", aesDecData)
    //fmt.Println(string(aesDecData))

    //另一个异或变换
    for i := 0; i < len(aesDecData); i++ {
        aesDecData[i] = aesDecData[i] ^ 0x44
    }
    //fmt.Println("trans 2 :", hex.EncodeToString(aesDecData))
    //fmt.Println("trans 2 string:", string(aesDecData))

    // 后半部分是明文的json
    licensePlainJsonBytes := aesDecData[0x102:]
    //fmt.Println("license info json:", string(licensePlainJsonBytes))
    //fmt.Println("pre2bytes:", hex.EncodeToString(aesDecData[:0x2]))

    license := License{}
    err = json.Unmarshal([]byte(licensePlainJsonBytes), &license)
    if err != nil {
        panic(err)
    }
    fmt.Println("license parsed:", license)

    // rsa 验证签名 pss
    sum := sha256.Sum256(licensePlainJsonBytes)
    //fmt.Println(sum)

    // rsa使用 sha256算法,对 aes解密后的数据第三个字节开始,到后面json明文前面为止是签名
    //fmt.Println("解析出来的签名:", aesDecData[2:0x102])

    err = rsa.VerifyPSS(pubKey, crypto.SHA256, sum[:], aesDecData[2:0x102], nil)
    if err != nil {
        fmt.Println(err.Error())
    } else {
        fmt.Println("varify success")
    }
}

func genNew(name string) {
    validTime, err := time.Parse("2006-01-02 15:04:05", "2099-09-09 00:00:00")

    license := License{
        LicenseId:      "00000000000000000000000000000000",
        UserId:         "00000000000000000000000000000000",
        UserName:       name,
        Distribution:   "COMMUNITY-ADVANCED",
        NotValidBefore: 1591891200,
        NotValidAfter:  validTime.Unix(),
    }

    licensePlainJsonBytes, _ := json.Marshal(license)
    //licensePlainJson := string(licensePlainJsonBytes)
    //fmt.Println("明文license信息:", licensePlainJson)

    // rsa sign
    priKey := importPrivateKey(newPrivateKeyPem)

    //sha256sum
    sum := sha256.Sum256(licensePlainJsonBytes)
    signature, err := rsa.SignPSS(rand.Reader, priKey, crypto.SHA256, sum[:], nil)
    if err != nil {
        panic(err)
    }

    licenseInfoWithSign := append(signature, licensePlainJsonBytes...)
    data2Enc := append(pre2Bytes, licenseInfoWithSign...)

    // 加密前一次异或
    for i := 0; i < len(data2Enc); i++ {
        data2Enc[i] = data2Enc[i] ^ 0x44
    }

    // session iv
    iv := make([]byte, 16)
    _, _ = rand.Read(iv)
    fmt.Println("temp aes iv:", hex.EncodeToString(iv))
    aesEnc, err := Encrypt(data2Enc, iv)
    if err != nil {
        panic(err)
    }
    //fmt.Println(aesEnc)

    allBytes := append(iv, aesEnc...)
    allBytes = append(licenseVersion2Byte, allBytes...)

    // 左右交换
    right := len(allBytes) - 1
    for l := 1; l < right; l++ {
        r := right - l
        if l >= r {
            break
        }
        allBytes[l], allBytes[r] = allBytes[r], allBytes[l]
    }

    licenseText := base64.StdEncoding.EncodeToString(allBytes)

    fileText := `# xray license
# 需要重命名为 xray-license.lic 和 xray 可执行程序放在同一个文件夹中
# user_name: Chinese
# distribution: COMMUNITY-ADVANCED
# 仅对修改后的xray有效
` + licenseText + `
`

    err = ioutil.WriteFile("xray-license.lic", []byte(fileText), os.ModePerm)
    if err == nil {
        fmt.Println("证书已写入文件:xray-license.lic")
    }
}

func Decrypt(decodeData []byte, iv []byte) ([]byte, error) {
    block, _ := aes.NewCipher(aesKeyNew)
    blockMode := cipher.NewCBCDecrypter(block, iv)
    origin_data := make([]byte, len(decodeData))
    blockMode.CryptBlocks(origin_data, decodeData)
    return unpad(origin_data), nil
}

func unpad(ciphertext []byte) []byte {
    length := len(ciphertext)
    unpadding := int(ciphertext[length-1])
    return ciphertext[:(length - unpadding)]
}

func Encrypt(text []byte, iv []byte) ([]byte, error) {
    block, _ := aes.NewCipher(aesKeyNew)
    blockSize := block.BlockSize()
    originData := pad(text, blockSize)
    blockMode := cipher.NewCBCEncrypter(block, iv)
    crypted := make([]byte, len(originData))
    blockMode.CryptBlocks(crypted, originData)
    //fmt.Println(len(originData))
    return crypted, nil
}

func pad(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

type License struct {
    LicenseId      string `json:"license_id"`
    UserId         string `json:"user_id"`
    UserName       string `json:"user_name"`
    Distribution   string `json:"distribution"`
    NotValidBefore int64  `json:"not_valid_before"`
    NotValidAfter  int64  `json:"not_valid_after"`
}

func importPublicKey(key string) *rsa.PublicKey {
    block, _ := pem.Decode([]byte(key))
    if block == nil {
        panic("unable to decode publicKey to request")
    }

    pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
    return pub.(*rsa.PublicKey)
}

func importPrivateKey(key string) *rsa.PrivateKey {
    block, _ := pem.Decode([]byte(key))
    privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        panic(err)
    }
    return privateKey
}

var (
    origin386Bytes, _     = hex.DecodeString("0F95C083F0018844245083C430C3")
    new386Bytes, _        = hex.DecodeString("0F94C083F0018844245083C430C3")
    originAmd64Bytes, _   = hex.DecodeString("000F84BE020000")
    newAmd64Bytes, _      = hex.DecodeString("000F85BE020000")
    originArmBytes, _     = hex.DecodeString("000050E30000A0E30100A013010020E254")
    newArmBytes, _        = hex.DecodeString("000050E30000A0E30100A0130100A0E354")
    originAArch64Bytes, _ = hex.DecodeString("1F001FEBE0079F9A000040D2E0C3")
    newAArch64Bytes, _    = hex.DecodeString("1F001FEBE0079F9A200080D2E0C3")
)

func patch(filePath string) {
    var (
        originBytes []byte
        newBytes    []byte
        maxIndex    uint64 = 0
    )

    if elfFile, err := elf.Open(filePath); err == nil {
        switch elfFile.Machine {
        case elf.EM_386:
            fmt.Println("linux 386")
            originBytes = origin386Bytes
            newBytes = new386Bytes
        case elf.EM_X86_64:
            fmt.Println("linux amd64")
            originBytes = originAmd64Bytes
            newBytes = newAmd64Bytes
        case elf.EM_ARM:
            fmt.Println("linux arm")
            originBytes = originArmBytes
            newBytes = newArmBytes
        case elf.EM_AARCH64:
            fmt.Println("linux arm64")
            originBytes = originAArch64Bytes
            newBytes = newAArch64Bytes
        default:
            fmt.Println("Unsupported linux platform!!")
        }
        sections := elfFile.Sections
        for _, i := range sections {
            if i.Name == ".text" {
                maxIndex = i.Addr + i.Size
                fmt.Printf("[.text] offset: %#x, addr: %#x-%#x\n", i.Offset, i.Addr, maxIndex)
            }
        }
    } else if peFile, err := pe.Open(filePath); err == nil {
        switch peFile.Machine {
        case pe.IMAGE_FILE_MACHINE_AMD64:
            fmt.Println("windows amd64")
            originBytes = originAmd64Bytes
            newBytes = newAmd64Bytes
        case pe.IMAGE_FILE_MACHINE_I386:
            fmt.Println("windows i386")
            originBytes = origin386Bytes
            newBytes = new386Bytes
        default:
            fmt.Println("Unsupported windows platform!!")

        }
    } else if machoFile, err := macho.Open(filePath); err == nil {
        switch machoFile.Cpu {
        case macho.CpuAmd64:
            fmt.Println("darwin amd64")
            originBytes = originAmd64Bytes
            newBytes = newAmd64Bytes
        case macho.Cpu386:
            fmt.Println("darwin 386")
            originBytes = origin386Bytes
            newBytes = new386Bytes
        default:
            fmt.Println("Unsupported darwin platform!!")
        }
    } else {
        fmt.Println("Can NOT parse file")
        return
    }

    origin, err := ioutil.ReadFile(filePath)
    loc := bytes.LastIndex(origin, originBytes)

    if loc > 0 {
        fmt.Printf("Signature index: %#x\n", loc)
        newFile := replace(origin, newBytes, loc)
        err = ioutil.WriteFile(filePath, newFile, os.ModePerm)
        if err == nil {
            fmt.Println("Patch success:", filePath)
        }
    } else {
        fmt.Println("Can't find signature")
    }
}

func replace(origin, new []byte, index int) []byte {
    n := make([]byte, len(origin))
    copy(n[:index], origin[:index])
    copy(n[index:index+len(new)], new)
    copy(n[index+len(new):], origin[index+len(new):])
    return n
}

patch来自https://github.com/zu1k/xray-crack
20201127更新:支持到1.4.5

仅有 1 条评论
  1. Azu Azu

    表哥,能发一个吗?

添加新评论