数美滑块验证码是一种常见的安全验证方式,用于防止自动化脚本和机器人进行恶意操作。本文将详细介绍如何通过抓包获取滑块图片信息、分析加密参数、生成滑动轨迹等步骤,成功破解数美滑块验证码。以下是我们要实现的主要步骤:
抓取滑块图片信息并计算滑动距离
分析加密参数
生成滑动轨迹并进行DES加密
验证破解结果
1. 抓取滑块图片信息并计算滑动距离更多内容联系1436423940
首先,进入数美滑块验证码的演示页面,进行抓包操作以获取滑块验证码的前景和背景图片。我们通过net/http从网站获取图片:
go
package main
import (
"bytes"
"encoding/json"
"fmt"
"image"
"image/jpeg"
"image/png"
"io/ioutil"
"net/http"
"os"
"strings"
"gocv.io/x/gocv"
)
type ImageURLs struct {
Fg string `json:"fg"`
Bg string `json:"bg"`
}
func downloadImage(url string) (image.Image, error) {
response, err := http.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
img, _, err := image.Decode(response.Body)
if err != nil {
return nil, err
}
return img, nil
}
func getImages(registerURL string) (image.Image, image.Image, error) {
resp, err := http.Post(registerURL, "application/json", strings.NewReader("{}"))
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, nil, err
}
var urls ImageURLs
err = json.Unmarshal(body, &urls)
if err != nil {
return nil, nil, err
}
fgImg, err := downloadImage(urls.Fg)
if err != nil {
return nil, nil, err
}
bgImg, err := downloadImage(urls.Bg)
if err != nil {
return nil, nil, err
}
return fgImg, bgImg, nil
}
func getDistance(fgImage, bgImage image.Image) int {
fgBuffer := new(bytes.Buffer)
png.Encode(fgBuffer, fgImage)
bgBuffer := new(bytes.Buffer)
jpeg.Encode(bgBuffer, bgImage, nil)
fgMat, _ := gocv.IMDecode(fgBuffer.Bytes(), gocv.IMReadColor)
bgMat, _ := gocv.IMDecode(bgBuffer.Bytes(), gocv.IMReadColor)
result := gocv.NewMat()
gocv.MatchTemplate(fgMat, bgMat, &result, gocv.TmCCoeffNormed, gocv.NewMat())
_, _, _, maxLoc := gocv.MinMaxLoc(result)
return maxLoc.X
}
func main() {
registerURL := "https://www.ishumei.com/trial/captcha.html"
fgImage, bgImage, err := getImages(registerURL)
if err != nil {
fmt.Println("Error fetching images:", err)
return
}
distance := getDistance(fgImage, bgImage)
fmt.Println("Calculated distance:", distance)
}
2. 分析加密参数
在滑动滑块的过程中,我们需要分析加密参数。抓包查看请求信息,可以看到有一个fverify的验证信息。如果正确的话,riskLevel返回值为PASS,失败为REJECT。
通过在浏览器中设置断点,我们可以找到参数aw等的生成函数,并确定这些参数的加密方式。使用断点调试后,发现是通过DES加密。
以下是通过crypto/des库实现DES加密的示例代码:
go
package main
import (
"bytes"
"crypto/cipher"
"crypto/des"
"encoding/base64"
"fmt"
)
func pad(data []byte, blockSize int) []byte {
paddingSize := blockSize - (len(data) % blockSize)
padding := bytes.Repeat([]byte{0}, paddingSize)
return append(data, padding...)
}
func encryptContent(message, key string, flag bool) (string, error) {
block, err := des.NewCipher([]byte(key))
if err != nil {
return "", err
}
plainText := []byte(strings.ReplaceAll(message, " ", ""))
plainText = pad(plainText, block.BlockSize())
var result []byte
if flag {
result = make([]byte, len(plainText))
mode := cipher.NewECBEncrypter(block)
mode.CryptBlocks(result, plainText)
} else {
result = make([]byte, len(plainText))
mode := cipher.NewECBDecrypter(block)
mode.CryptBlocks(result, plainText)
}
return base64.StdEncoding.EncodeToString(result), nil
}
func main() {
message := "Hello, World!"
key := "your_key_here"
flag := true
encryptedMessage, err := encryptContent(message, key, flag)
if err != nil {
fmt.Println("Error encrypting message:", err)
return
}
fmt.Println("Encrypted message:", encryptedMessage)
}
3. 生成滑动轨迹并进行DES加密
滑动轨迹可以通过模拟人的滑动行为来生成,包括一些随机的抖动和速度变化。以下是生成滑动轨迹的示例代码:
go
package main
import (
"encoding/json"
"fmt"
"math/rand"
"time"
)
func getRandom(distance int) ([][3]int, error) {
rand.Seed(time.Now().UnixNano())
track := [][3]int{{0, 0, 0}}
for i := 0; i < 10; i++ {
x := 0
y := rand.Intn(3) - 1
t := 100*(i+1) + rand.Intn(3)
track = append(track, [3]int{x, y, t})
}
for i := 1; i < len(track)-5; i++ {
track[i][0] = distance / 2
}
for i := len(track) - 5; i < len(track)-1; i++ {
track[i][0] = distance + rand.Intn(4)
}
track[len(track)-1][0] = distance
trackJSON, err := json.Marshal(track)
if err != nil {
return nil, err
}
fmt.Println("Slide track:", string(trackJSON))
return track, nil
}
func main() {
distance := 100 // 假设滑动距离为100
track, err := getRandom(distance)
if err != nil {
fmt.Println("Error generating track:", err)
return
}
fmt.Println("Generated slide track:", track)
}
4. 验证破解结果
最后,结合前面的步骤,实现滑块破解。以下是完整的示例代码:
go
package main
import (
"bytes"
"crypto/cipher"
"crypto/des"
"encoding/base64"
"encoding/json"
"fmt"
"image"
"image/jpeg"
"image/png"
"io/ioutil"
"net/http"
"strings"
"gocv.io/x/gocv"
)
type ImageURLs struct {
Fg string `json:"fg"`
Bg string `json:"bg"`
}
func downloadImage(url string) (image.Image, error) {
response, err := http.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
img, _, err := image.Decode(response.Body)
if err != nil {
return nil, err
}
return img, nil
}
func getImages(registerURL string) (image.Image, image.Image, error) {
resp, err := http.Post(registerURL, "application/json", strings.NewReader("{}"))
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, nil, err
}
var urls ImageURLs
err = json.Unmarshal(body, &urls)
if err != nil {
return nil, nil, err
}
fgImg, err := downloadImage(urls.Fg)
if err != nil {
return nil, nil, err
}
bgImg, err := downloadImage(urls.Bg)
if err != nil {
return nil, nil, err
}
return fgImg, bgImg, nil
}
func getDistance(fgImage, bgImage image.Image) int {
fgBuffer := new(bytes.Buffer)
png.Encode(fgBuffer, fgImage)
bgBuffer := new(bytes.Buffer)
jpeg.Encode(bgBuffer, bgImage, nil)
fgMat, _ := gocv.IMDecode(fgBuffer.Bytes(), gocv.IMReadColor)
bgMat, _ := gocv.IMDecode(bgBuffer.Bytes(), gocv.IMReadColor)
result := gocv.NewMat()
gocv.MatchTemplate(fgMat, bgMat, &result, gocv.TmCCoeffNormed, gocv.NewMat())
_, _, _, maxLoc := gocv.MinMaxLoc(result)
return maxLoc.X
}
func pad(data []byte, blockSize int) []byte {
paddingSize := blockSize - (len(data) % blockSize)
padding := bytes.Repeat([]byte{0}, paddingSize)
return append(data, padding...)
}
func encryptContent(message, key string, flag bool) (string, error) {
block, err := des.NewCipher([]byte(key))
if err != nil {
return "", err
}
plainText := []byte(strings.ReplaceAll(message, " ", ""))
plainText = pad(plainText, block.BlockSize())
var result []byte
if flag {
result = make([]byte, len(plainText))
mode := cipher.NewECBEncrypter(block)
mode.CryptBlocks(result, plainText)
} else {
result = make([]byte, len(plainText))
mode := cipher.NewECBDecrypter(block)
mode.CryptBlocks(result, plainText)
}
return base64.StdEncoding.EncodeToString(result), nil
}
func getRandom(distance int) ([][3]int, error) {
track := [][3]int{{0, 0, 0}}
for i := 0; i < 10; i++ {
x := 0
y := rand.Intn(3) - 1
t := 100*(i+1) + rand.Intn(3)
track = append(track, [3]int{x, y, t})
}
for i := 1; i < len(track)-5; i++ {
track[i][0] = distance / 2
}
for i := len(track) - 5; i < len(track)-1; i++ {
track[i][0] = distance + rand.Intn(4)
}
track[len(track)-1][0] = distance
trackJSON, err := json.Marshal(track)
if err != nil {
return nil, err
}
fmt.Println("Slide track:", string(trackJSON))
return track, nil
}
func main() {
registerURL := "https://www.ishumei.com/trial/captcha.html"
fgImage, bgImage, err := getImages(registerURL)
if err != nil {
fmt.Println("Error fetching images:", err)
return
}
distance := getDistance(fgImage, bgImage)
fmt.Println("Calculated distance:", distance)
track, err := getRandom(distance)
if err != nil {
fmt.Println("Error generating track:", err)
return
}
nm, err := json.Marshal(track)
if err != nil {
fmt.Println("Error marshalling track:", err)
return
}
dy := track[len(track)-1][2]
key := "your_key_here"
flag := true
encryptedNM, err := encryptContent(string(nm), key, flag)
if err != nil {
fmt.Println("Error encrypting nm:", err)
return
}
encryptedDY, err := encryptContent(fmt.Sprint(dy), key, flag)
if err != nil {
fmt.Println("Error encrypting dy:", err)
return
}
verifyData := map[string]string{
"nm": encryptedNM,
"dy": encryptedDY,
"rid": "register_id_here",
"dl": fmt.Sprint(distance),
}
verifyDataJSON, err := json.Marshal(verifyData)
if err != nil {
fmt.Println("Error marshalling verify data:", err)
return
}
resp, err := http.Post("https://www.ishumei.com/trial/fverify", "application/json", bytes.NewBuffer(verifyDataJSON))
if err != nil {
fmt.Println("Error verifying:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
var result map[string]string
err = json.Unmarshal(body, &result)
if err != nil {
fmt.Println("Error unmarshalling response:", err)
return
}
if result["riskLevel"] == "PASS" {
fmt.Println("验证成功")
} else {
fmt.Println("验证失败")
}
}