-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
145 lines (131 loc) · 3.35 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package main
import (
"encoding/base64"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"strconv"
"strings"
"time"
)
type LoginConfirm struct {
Login_confirm struct {
Login_locked string
Token string
Login_confirm string
}
}
type SysInfo struct {
Sysinfo struct {
Model string
Uptime string
Hw_version string
Serial_num string
Date_info string
Fw_version string
Linerate_us string
Linerate_ds string
Lanip string
Lanmac string
Wangw string
Wanmac string
Wan_model string
Wandns1 string
Wandns2 string
Token string
Sysinfo string
}
}
func getTimeStamp() string{
t := time.Now()
return strconv.FormatInt(t.Unix(), 10)
}
func doRequest(method string, url string, header map[string]string) (*http.Response, error) {
// set the timeout to 3 seconds because if the fastgate restarts, it will not respond
client := &http.Client{
Timeout: 3 * time.Second,
}
req, err := http.NewRequest(method, url, nil)
if err != nil {
log.Fatal(err)
}
for key, value := range header {
req.Header.Set(key,value)
}
return client.Do(req)
}
func main(){
user := "admin"
// during my analysis I found that the password is base64 encoded
pass := base64.URLEncoding.EncodeToString([]byte("admin"))
defaultHeader := map[string]string{
"Connection": "keep-alive",
"Pragma": "no-cache",
"Cache-Control": "no-cache",
"Accept": "application/json, text/plain, */*",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
"DNT": "1",
"Referer": "http://192.168.1.254/",
"Accept-Language": "en-US,en;q=0.9",
}
// get login token
resp, err := doRequest(
"GET",
"http://192.168.1.254/status.cgi?_="+getTimeStamp()+"&cmd=7&nvget=login_confirm",
defaultHeader,
)
if err != nil {
log.Fatal(err)
}
bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var loginPage LoginConfirm
if err := json.Unmarshal(bodyText, &loginPage); err != nil {
log.Fatal(err)
}
log.Printf("Login page token: %s\n", loginPage.Login_confirm.Token)
// do login and get session cookie
resp, err = doRequest(
"GET",
"http://192.168.1.254/status.cgi?_="+getTimeStamp()+"&cmd=3&nvget=login_confirm&password="+pass+"&remember_me=1&token="+loginPage.Login_confirm.Token+"&username="+user,
defaultHeader,
)
if err != nil {
log.Fatal(err)
}
// get only first part of cookies
loginCookie := strings.Split(resp.Header.Get("Set-cookie"), ";")[0]
log.Printf("Session cookie: %s\n", loginCookie)
// assign the cookie to the header
defaultHeader["Cookie"] = loginCookie
// get system info options token, every page inside the fastgate require a unique token
resp, err = doRequest(
"GET",
"http://192.168.1.254/status.cgi?_="+getTimeStamp()+"&nvget=sysinfo",
defaultHeader,
)
if err != nil {
log.Fatal(err)
}
bodyText, err = ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var sysInfoPage SysInfo
if err := json.Unmarshal(bodyText, &sysInfoPage); err != nil {
log.Fatal(err)
}
log.Printf("System info page token: %s\n", sysInfoPage.Sysinfo.Token)
// the magic (do restart)
resp, err = doRequest(
"GET",
"http://192.168.1.254/status.cgi?_="+getTimeStamp()+"&act=nvset&service=reset&token="+sysInfoPage.Sysinfo.Token,
defaultHeader,
)
if err != nil {
log.Fatal(err)
}
}