前言

目的

本篇文章的目的如下

本次实验主要是为了满足我对SSR(ShadowsocksR)混淆的工作方式的好奇心而做(我想知道混淆混在哪个地方),

使用的应用层协议包含http、ws(Websocket)、vless、tls


PS:听说现在某些地区要是做了混淆,IP反而会ISP被加入临时黑名单,因为检测到HOST和实际DNS请求的域名不符,

当然可以直接使用服务器ip进行ssr连接而不是使用域名(也不知道ISP会不会检测ip是否在伪造的域名的ip列表中,我相信他们有这个能力)

关于代理的知识可以看下一篇文章:http://blog.lxscloud.top/2023/01/29/%E7%AE%80%E8%B0%88%E4%BB%A3%E7%90%86/


内容

本篇文章的内容如下

  • 对SSR混淆的工作方式进行测试,同时尝试对不同混淆参数进行观察

  • 同时对github在上面发现的一款强大的开源软件glider进行测试,观察其传输报文

  • 实验将使用wireshark进行抓包,观察其发送的HTTP、ws报文

  • 关于我所知道的运营商免流知识,以及验证自己的一个想法(收手吧阿祖,运营商免流已经没机会了)

使用的软件:

  • ShadowsocksR
  • ShadowsocksR-dotnet4.0.exe
  • glider
  • Wireshark
  • Python3,请使用python3运行本文提供的代码

什么是混淆

如下是一个正常的HTTP请求

360截图18141217223351

Wireshark中可以见到HTTP请求

360截图18470126429160

仔细查看HTTP报文,可以发现如下信息:HOST、UA等,

这些信息称为header,也就是请求头

360截图17260827387857

如果能将header中的信息改掉,那么就称为混淆,或者说是伪造

(下面的图片只是为了看到变化,不要太过在意GET和:8080那里的变化)

(应该关注的地方是a.lxscloud.top变成了b.lxscloud.top以及User-Agent的变化)

360截图18180718244723

以上的意思大致为:

本来我访问的是a.lxscloud.top,

但是我通过一些手段让这个请求的Host等发生变化,

让流量监测设备误以为我访问的是b.lxscloud.top,

但实际上我访问的还是a.lxscloud.top这个服务器

ssr的作者破娃酱(breakwa11)是这样看待混淆的:

  1. 遇到运营商QoS,使用混淆能提速
  2. 所在网络有严格限制,仅能使用 80443 端口,不认识的协议根本不能用的(如学校、公司、政府办公网络)
  3. 对自己的隐私有要求的,希望在运营商的连接记录里留下看起来正常的访问记录
  4. 试图绕过学校或运营商的计费系统,即免流『该部分应用较普遍,配合抓包大法可以爽歪歪』
  5. 第五类其它黑科技用途保密

正文

ShadowsocksR

关于ShadowsocksR不必多说,懂的都懂

下面直接开始

http_simple模式

实验

服务端

服务端启动命令如下(首先要有ShadowsocksR的python源码,这里就不提供下载了,很容易找到)

使用8080端口,加密方式是aes-256-cfb,协议是auth_sha1_v4,

混淆模式是http_simple

1
python3 server.py -p 8080  -k password -m aes-256-cfb -O auth_sha1_v4 -o http_simple

客户端

客户端使用ShadowsocksR-dotnet4.0.exe,因为我使用的是Windows电脑

混淆参数填的是b.lxscloud.top#User-Agent: test,

也就是HOST改为b.lxscloud.top,再加上User-Agent: test的header

image-20221229155144531

抓包

比较有意思是请求的path会发生变化,但是好像会重复

360截图17081030405678

360截图176906227673104

查看其header,除了我填上去的header,并没有其它的信息

360截图170909199097112

此时给他再加上一个header,使用\n分隔

header我设置的是newheader: aaaaa

360截图187201216773105

再次抓包查看,发现出现了新header

360截图18510714409058

尝试

一个问题

从上面的测试还发现一个问题:HOST中出现了一个端口号8080

由于ssr服务器的端口就是8080,因此当改为其它端口,host中的端口也改为其他端口,

下面是验证,将服务器改为8094端口

1
python3 server.py -p 8094  -k password -m aes-256-cfb -O auth_sha1_v4 -o http_simple

客户端设置如下,除了端口其它信息并未更改

360截图18231117779964

抓包查看,验证了猜想

在ssr中的混淆若是想要在伪造的host中不出现端口,只能使用80端口作为ssr服务器的通讯端口(亲测)

360截图173102178311175

那有没有办法不使用80端口也让伪造的host中不出现端口呢?

我做了以下尝试发现不行

(1)使用CRLF

360截图17280616104911

抓包得如下信息,即失败,似乎#是必须要出现的

360截图18141219196738

(2)使用#,但同时使用CRLF(就是说我想把ssr弄的Host无效化)

360截图18720118109137104

抓包发现\n好像和ssr的分隔符冲突了

360截图184701296177107

尝试转义无效(其实就算有效也没法把ssr伪造host去掉)

360截图17081028103844

(3)再次尝试:使用#,但同时使用CRLF

360截图170010168614093

还是不行\r\n看起来被转义了,被当成字符了

360截图17161104162330

http_post模式

服务端

使用8094端口,加密方式是aes-256-cfb,协议是auth_sha1_v4,

混淆模式是http_post

1
python3 server.py -p 8094  -k password -m aes-256-cfb -O auth_sha1_v4 -o http_post

客户端

360截图16540531101135104

抓包

抓到的报文如下,确实是POST请求

360截图17001013433151

查看请求内容

360截图1724010199150119

tls1.2_ticket_auth模式

服务端

使用8094端口,加密方式是aes-256-cfb,协议是auth_sha1_v4,

混淆模式是tls1.2_ticket_auth

1
python3 server.py -p 8094  -k password -m aes-256-cfb -O auth_sha1_v4 -o tls1.2_ticket_auth

客户端

360截图17290507466971

抓包

抓到的报文如下,此时只能看到tcp报文了

360截图17651126215637

总结

总的来说,ShadowsocksR的http_simple混淆模式和http_post混淆模式都是模拟Http请求,用户可以自定义header


Glider

关于glider

glider是我之前在github上找到的一个强大的软件,这个项目我认为是非常棒的一个项目

glider是使用go语言编写的,在glider仓库中有相当多编译好的版本可以使用

(i了i了,二进制文件下载即用,很老的x86电脑,MIPS架构的路由器、Arm板子上经过测试都能用,跑100Mbps轻轻松松)

项目地址https://github.com/nadoo/glider

360截图18720118353675

glider支持的协议特别多,像ss、ssr、http、socks5、tls、vmess、vless都是支持的,

还有一些其他强大的功能比如说转发链(也可以说是代理链),dns、dhcp服务器、负载均衡功能等,

同时其性能也不错,因此我认为可以放弃使用一些代理软件了,可以直接选择glider

官方说明如下

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
Direct scheme:
direct://

Only needed when you want to load balance multiple interfaces directly:
glider -verbose -listen :8443 -forward direct://#interface=eth0 -forward direct://#interface=eth1 -strategy rr

Or you can use the high availability mode:
glider -verbose -listen :8443 -forward direct://#interface=eth0&priority=100 -forward direct://#interface=eth1&priority=200 -strategy ha

--
Http scheme:
http://[user:pass@]host:port

--
KCP scheme:
kcp://CRYPT:KEY@host:port[?dataShards=NUM&parityShards=NUM&mode=MODE]

Available crypt types for KCP:
none, sm4, tea, xor, aes, aes-128, aes-192, blowfish, twofish, cast5, 3des, xtea, salsa20

Available modes for KCP:
fast, fast2, fast3, normal, default: fast

--
Simple-Obfs scheme:
simple-obfs://host:port[?type=TYPE&host=HOST&uri=URI&ua=UA]

Available types for simple-obfs:
http, tls

--
Reject scheme:
reject://

--
Smux scheme:
smux://host:port

--
Socks4 scheme:
socks4://host:port

--
Socks5 scheme:
socks5://[user:pass@]host:port

--
SS scheme:
ss://method:pass@host:port

Available methods for ss:
AEAD Ciphers:
AEAD_AES_128_GCM AEAD_AES_192_GCM AEAD_AES_256_GCM AEAD_CHACHA20_POLY1305 AEAD_XCHACHA20_POLY1305
Stream Ciphers:
AES-128-CFB AES-128-CTR AES-192-CFB AES-192-CTR AES-256-CFB AES-256-CTR CHACHA20-IETF XCHACHA20 CHACHA20 RC4-MD5
Alias:
chacha20-ietf-poly1305 = AEAD_CHACHA20_POLY1305, xchacha20-ietf-poly1305 = AEAD_XCHACHA20_POLY1305
Plain: NONE

--
SSH scheme:
ssh://user[:pass]@host:port[?key=keypath&timeout=SECONDS]
timeout: timeout of ssh handshake and channel operation, default: 5

--
SSR scheme:
ssr://method:pass@host:port?protocol=xxx&protocol_param=yyy&obfs=zzz&obfs_param=xyz

--
TLS client scheme:
tls://host:port[?serverName=SERVERNAME][&skipVerify=true][&cert=PATH][&alpn=proto1][&alpn=proto2]

Proxy over tls client:
tls://host:port[?skipVerify=true][&serverName=SERVERNAME],scheme://
tls://host:port[?skipVerify=true],http://[user:pass@]
tls://host:port[?skipVerify=true],socks5://[user:pass@]
tls://host:port[?skipVerify=true],vmess://[security:]uuid@?alterID=num

TLS server scheme:
tls://host:port?cert=PATH&key=PATH[&alpn=proto1][&alpn=proto2]

Proxy over tls server:
tls://host:port?cert=PATH&key=PATH,scheme://
tls://host:port?cert=PATH&key=PATH,http://
tls://host:port?cert=PATH&key=PATH,socks5://
tls://host:port?cert=PATH&key=PATH,ss://method:pass@

--
Trojan client scheme:
trojan://pass@host:port[?serverName=SERVERNAME][&skipVerify=true][&cert=PATH]
trojanc://pass@host:port (cleartext, without TLS)

Trojan server scheme:
trojan://pass@host:port?cert=PATH&key=PATH[&fallback=127.0.0.1]
trojanc://pass@host:port[?fallback=127.0.0.1] (cleartext, without TLS)

--
Unix domain socket scheme:
unix://path

--
VLESS scheme:
vless://uuid@host:port[?fallback=127.0.0.1:80]

--
VMess scheme:
vmess://[security:]uuid@host:port[?alterID=num]
if alterID=0 or not set, VMessAEAD will be enabled

Available security for vmess:
zero, none, aes-128-gcm, chacha20-poly1305

--
Websocket client scheme:
ws://host:port[/path][?host=HOST][&origin=ORIGIN]
wss://host:port[/path][?serverName=SERVERNAME][&skipVerify=true][&cert=PATH][&host=HOST][&origin=ORIGIN]

Websocket server scheme:
ws://:port[/path][?host=HOST]
wss://:port[/path]?cert=PATH&key=PATH[?host=HOST]

Websocket with a specified proxy protocol:
ws://host:port[/path][?host=HOST],scheme://
ws://host:port[/path][?host=HOST],http://[user:pass@]
ws://host:port[/path][?host=HOST],socks5://[user:pass@]

TLS and Websocket with a specified proxy protocol:
tls://host:port[?skipVerify=true][&serverName=SERVERNAME],ws://[@/path[?host=HOST]],scheme://
tls://host:port[?skipVerify=true],ws://[@/path[?host=HOST]],http://[user:pass@]
tls://host:port[?skipVerify=true],ws://[@/path[?host=HOST]],socks5://[user:pass@]
tls://host:port[?skipVerify=true],ws://[@/path[?host=HOST]],vmess://[security:]uuid@?alterID=num

--
VM socket scheme(linux only):
vsock://[CID]:port

if you want to listen on any address, just set CID to 4294967295.

这里就不多说了,直接开始,

下面只用到了glider最基本的功能,glider真的很强大,且无需安装

ws+vless

服务端

参数介绍:

(更多例子可以看https://github.com/nadoo/glider/blob/master/config/glider.conf.example)

  • -verbose 详细输出
  • ws:// 使用ws协议
  • :8094 监听0.0.0.0:8094
  • /mypath 请求路径
  • ?host=myhost.com 设置host为myhost.com
  • , 通过前面的协议传输后再使用后面的协议
  • vless:// 使用vless协议
  • 707f20ea-d4b8-4d1d-8e2e-2c86cb2ed97a 认证用的uuid
  • ?fallback=127.0.0.1:8331 这个我也不太懂,这样填能用
1
./glider -verbose -listen ws://:8094/mypath?host=myhost.com,vless://707f20ea-d4b8-4d1d-8e2e-2c86cb2ed97a@?fallback=127.0.0.1:8331

客户端

参数介绍:

  • -listen socks5://0.0.0.0:8444 本地起一个socks5服务器
1
./glider -verbose -listen socks5://0.0.0.0:8444 -forward ws://你的服务器ip:8094/mypath?host=myhost.com,vless://707f20ea-d4b8-4d1d-8e2e-2c86cb2ed97a@127.0.0.1:8331

然后可以使用curl来发起一个请求

1
curl --socks5-hostname 127.0.0.1:8444 https://www.baidu.com

抓包

360截图172104255894101

开始的时候发出了切换到ws的请求报文

host不带端口,非常好,path也是设置的内容

360截图17040513282126

后面就是websocket传输了

360截图16720404617346

tls+vless

服务端

注意:

cert=1_blog.lxscloud.top_bundle.crt&key=2_blog.lxscloud.top.key是我的域名blog.lxscloud.top的证书文件,

如果你想要自己尝试测试,需要换成你自己的证书

1
./glider -verbose -listen tls://:8094?cert=1_blog.lxscloud.top_bundle.crt\&key=2_blog.lxscloud.top.key,vless://707f20ea-d4b8-4d1d-8e2e-2c86cb2ed97a@?fallback=127.0.0.1:8331

客户端

注意:

域名必须与证书对应,这里blog.lxscloud.top和上面服务端的证书对应

1
./glider -verbose -listen socks5://0.0.0.0:8444 -forward tls://blog.lxscloud.top:8094,vless://707f20ea-d4b8-4d1d-8e2e-2c86cb2ed97a@127.0.0.1:8331

抓包

可以发现是tcp报文,我以为会显示tls(可能是我的wireshark抓不到?)

360截图1757112188106114

但是直接访问https网页是有tls报文的

360截图17630325705887

数据中没发现有明文

360截图1794061389125145


关于免流

所谓免流,这里指的是运营商免流,运营商的一些应用如掌上营业厅等使用的时候是免流量

(免流量即不扣除通用流量,使用的流量计入免费流量)

所以这里的免流是以技术手段欺骗运营商的流量计费系统达到消耗流量但不计费的目的


本文仅供技术交流,若有读者因观看本文并做出尝试从而使运营商遭受损失,本文概不负责

本人尝试时并未对运营商设备造成破坏,亦无对运营商服务器进行扫描渗透,对运营商的所有访问均为正常访问

近些年来的免流方式

简单梳理总结为四种路径:

  • 本地免流,也称本地代理(一般使用tiny proxy等)

    在手机上开启一个代理服务器使应用流量走此代理,代理服务器处理http/https报文,修改Host或增加其它header项

    • 双host

      如下是一个例子:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      伪装:
      dir.wo186.tv:809

      模式:
      mode=wap;
      listen_port=65080;
      uid=3004;
      daemon=on;

      http_ip=10.0.0.172;
      http_port=80;
      http_del="Host,X-Online-Host";
      http_first="[M] [U] [V]\r\nConnection: ゲ\rHost:dir.wo186.tv:809\r\nHost: [H]\r\n";

      https_connect=on;
      https_ip=10.0.0.172;
      https_port=80;
      https_del="Host";
      https_first="[M] / [V]\r\nConnection: あ\rHost:dir.wo186.tv:809\r\nHost: [H]\r\n";

      dns_tcp=http;
      dns_listen_port=65053;
      dns_url="119.29.29.29";

      解释:

      • 10.0.0.172 是移动和联通手机wap上网的代理服务器,wap模式默认通过这个代理服务器上网

      • http_del="Host,X-Online-Host"; 删去原本header中的Host,X-Online-Host

      • [M] 请求方法: GET、POST等

      • [U] uri

      • [V] http版本,如HTTP/1.1

      • [H] 目标host

        也就是说利用dir.wo186.tv:809这个host做混淆欺骗计费系统

    • x-online-host,替换host为免流host然后x-online-host为实际host(失效)

      x-online-host实际上是关于移动网关的私有代理协议,移动的代理服务器会认为x-online-host是实际host然后向其请求,

      达到计费系统会检测到用户访问的是免流网址,但是网络服务器返回给用户的却是实际网址的网页的效果

    • 前缀免流,也称川免模式(失效)

      在请求头网址前加上一个前缀(运营商设定的用于识别)即可达到免流效果

    • 后缀免流(失效)

      某些地区的联通计费系统只要在请求的网址中检测到了wap.10010.com就认定为免流,形式可为?wap.10010.com或&wap.10010.com

    • 伪装彩信(失效)

      把文件类型信息(MIME)改成application/vnd.wap.mms-message,让计费系统认为是彩信

  • 直连免流(一般使用tiny proxy)

    • 通过联通内部人员搭建的代理服务器(基本上找不到了)

    • 通过UC的代理服务器(uc浏览器器的免流是通过此方式实现的),因为UC浏览器免流(有效性待验证)

    • 百度直连,通过百度的代理服务器(配合免流软件处理headers,伪装百度APP,因为百度代理服务器不能直接连接),因为百度APP免流


      实际上百度直连和uc直连原理是一样的,都是欺骗人家的代理服务器,让服务器以为使用的是自家APP访问网页

      (有效性待验证,搜索引擎搜索得知2022年3月份有效,估计目前已失效)

  • 云免(公网上搭建代理或vpn服务器),有的运营商对端口有要求,如80或443

    • 早期指定端口免流,即走这个端口(如137/138/139等端口)不计流量(失效)

    • OpenVpn(tcp或udp,通过自定义headers的方式)(失效)

    • SSR(http,通过自定义headers的方式)(失效)

    • V2Ray(ws+vmess,通过自定义headers的方式)(失效)

    • V2Ray套CDN,协议免流(一些运营商将cdn提供商ip或域名列入免流白名单,比如某大王卡配合某讯cdn?)

      (搜索引擎搜索得知部分地区有效,有效性待验证)


    云免应该已经无了,和用的啥软件无关

  • 运营商免

    • 联通809,原理是利用联通的某个自建CDN(其IP列入免流白名单)反向代理服务,可反向代理自己的v2ray服务器(失效)

      具体可参考:https://github.com/xiaotailang0417/809

    • Amy免流,沃音乐接口动态免流(看起来很高级的玩法?应该也是反向代理,未找到有效利用方法)(有效性待验证)

    • 技术手段(如上云免使用的技术)使通用流量走定向流量,各种互联网卡如bilibli卡,大王卡等(目前有效)

    • 电信停机卡免流,使用缴费绿色通道的host混淆(目前有效)

我的尝试

由于云免可控性较高,且要求较少,这里我尝试了

  • 使用SSR的http混淆

    混淆参数类似下图

    Screenshot_2023-01-06-21-35-32-44_d781df61b52c92696515f54d94c52b89

  • glider的ws+vless(ws的host伪装成联通的pushservice服务器,path也和其一致)

    联通的pushservice服务器如下

    Screenshot_2023-01-06-21-34-29-79_6a7ba8316e3b96f0fa7c3d22648160db

其实这两个尝试也是文章前半段讲的内容,免流混淆无非就是改改header,所以这里不再多说

这里要讲的是如今运营商的免流策略


我需要确定一个能免流的请求,方法很简单,只需要利用运营商app中查询详单的功能

它标注的流量类型类似如下,我只需发送请求并记下时间,然后查询这个时间记录的流量类型

360截图184306308511087

首先先从抓到的HTTP请求(抓取自运营商app)中选取一个可能是免流的请求

Screenshot_2023-01-06-14-01-50-79_6a7ba8316e3b96f0fa7c3d22648160db

对其进行重发

Screenshot_2023-01-06-14-06-25-36_6a7ba8316e3b96f0fa7c3d22648160db

可以看到重发成功

Screenshot_2023-01-06-14-06-39-10_6a7ba8316e3b96f0fa7c3d22648160db

之后再查看详单确定是免流请求

然后进一步尝试,使用浏览器直接访问其IP(多访问几次多消耗一些流量以用于确定),

即GET请求不带任何参数cookie

Screenshot_2023-01-06-14-01-11-48_a87fd7db6caa850b517aa6fa9d2fcd0e

检验确定,发现此时间是消耗免费流量,而我此段时间无后台应用,只干了上面的事情

因此得出此免流依靠IP白名单(也就是说运营商混淆免流的时代已经过去了,珍惜现在的定向免流)

360截图17140308667883

当然这时候就有人说了,既然是IP白名单,那么只要我能找到运营商列入白名单的代理服务器\vpn就行了

确实,不过未经授权的渗透测试都是不合法的哦,而且列入IP白名单的一般是运营商自家服务器,并且人家的代理服务器可能有密码验证等


关于IP源地址伪造

所谓IP源地址伪造,即伪造TCP包或UDP包的源IP地址,

由于IP数据报的源地址(源IP和源端口)和MAC地址是可以更改的(使用RAW_SOCKET发送构造的IP报文),

由于目的地址不变, 报文能够被送到目的主机(不绝对,请继续往下看)

作用

  • DDOS攻击手法,使用较小的成本模拟不同IP对主机的访问
  • 本地测试手段,模拟多用户访问,用于测试服务端功能是否完善
  • 伪装IP,用于隐藏自己的地址(目前已无效,即使有效想查还是能查到)
  • 欺骗服务器,绕过IP白名单

伪造TCP包的源IP地址

通常TCP伪造IP源地址用的比较少,因为TCP存在三次握手,需要收发ACK和SYN包,

那么如何解决呢?一种方式就是猜测SYN序列号

为了方便,一般伪造IP源地址的是UDP包

发送伪造源IP地址的UDP包

提供较为简单且可控性较高的两种方式(使用Python)

使用Scapy(较简单)

需要安装scapy这个包

1
pip3 install scapy
源码

保存为scapy_fakeip.py

1
2
3
4
5
6
7
from scapy.all import (send, IP, UDP)

TargetIP ="192.168.77.77" #目的地址
load="00000" #发送的内容

#模拟10.10.10.10:33310向192.168.77.77:33310发送一个udp包
send(IP(src="10.10.10.10", dst=TargetIP) / UDP(sport=[33310], dport=[33310])/load)
运行
1
python3 scapy_fakeip.py

在192.168.77.77这个主机上监听UDP,端口33310

360截图18430708466078

使用Raw_socket配合dpkt(可控性较高)

注意:打开Raw_socket需要root权限

需要安装dpkt这个包

1
pip3 install dpkt
源码

保存为fakeip3.py

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
# coding=utf-8
import socket, dpkt, time

class SenderRawScoket:
def __init__(self, dst, dport, src, sport = 10000):
self.dst = socket.gethostbyname(dst)
self.dport = dport
self.src = src
self.sport = sport

self.sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
self.sock.connect((self.dst, 1))

def Send(self, ip_packet):
self.sock.sendall(bytes(ip_packet))

def Process(self, msg):
u = dpkt.udp.UDP()
u.sport = self.sport
u.dport = self.dport
u.data = msg
u.ulen = len(u)

# IP 的 str 会触发 IP 的校验和计算,也会触发 TCP UDP 的校验和计算
# TCP/UDP的校验和是: 源IP,目的IP,协议,TCP或UDP包(头+内容)
#u.sum = ?

i = dpkt.ip.IP(data = u)
#i.off = dpkt.ip.IP_DF # frag off
i.p = dpkt.ip.IP_PROTO_UDP
i.src = socket.inet_aton(self.src) # xp sp2之后 禁止发送非本机IP地址的数据包;linux, server无限制
i.dst = socket.inet_aton(self.dst)
i.len = len(i)

self.Send(i)


mySocket = SenderRawScoket("192.168.77.224", 33310, "192.168.1.1")
for i in range(100):
mySocket.Process(b"h")
time.sleep(0.001)
运行

请在linux主机上运行(windows有限制),确保有root权限

1
python3 fakeip3.py
监听

在192.168.77.224上监听33310的udp,

结果这里就不多说了

360截图17450528094015

直接看抓包结果

360截图178606017187100

360截图1628071997138109

局限性

1.想要发送伪造IP的数据包,发送主机与接收此数据包的主机之间不能存在Nat转换

在Nat设备转发上网的内部网络中无法向公网主机发送伪造IP的数据包,这是由Nat转换的原理决定的

因为Nat设备在转发此数据包时会将报文中的源IP替换为Nat转发设备的IP,

所以在公网主机上收到的数据包的源地址来自最后一台转发此数据包的Nat设备

如:

我的网络拓扑图如下(R1、R2均使用Easy IP的方式做转换)

360截图17860602517560

此时向公网设备发送一个伪造了IP的UDP数据包

360截图18141217625646

服务器上看到的发送者IP正是运营商的出网IP

360截图17380404878470

2.运营商现已存在IP源保护(详见后文)

如:

两台公网主机,一台做发送主机,一台做接收主机

发送主机发送伪造IP的UDP数据包

360截图17380406361638

接收主机未收到该数据包

360截图16821217115151108

经过测试,使用手机移动数据功能发送伪造IP的UDP数据包同样无法发送

一个想法

已知运营商免流依靠IP白名单,这个是我通过访问某个联通的服务器(此服务是免流的),然后检查流量记录得知的(前文提及)

想法

即如今运营商区分客户访问的网站是否免流会检查客户发送的数据包的目的地址或接收数据源地址是否存在白名单中,

而不是依靠应用层协议的报文(Host, Path, UA)区分此次收发数据是否免流,

当然不排除某些与运营商合作的公司的免流方式就是基于headers中的Host等,这里仅讨论运营商服务免流

那我只需要在我的代理服务器上利用伪造源IP的手段,伪装成白名单IP不就好了?

而对于UDP收发问题,客户端正常发送接收即可,至少我能省下下行流量

先说结果:寄,原因请看后面的防护手段,运营商默认开启这玩意

测试

找来两台具有公网IP的服务器

这台监听udp端口33310

360截图17001018549281

这台运行上面的伪装源IP发送UDP的程序

360截图18430709455257

查看是否接收发现无消息

360截图175711187010567

而正常nc有消息

360截图17600725657860

同时手机使用数据功能,能发送,但服务器收不到

使用su获取root权限然后使用termux,

python配合dpkt+raw_socket发送

Screenshot_20230106-141125

所以没必要继续实施了

本地实验(绕iptables)

在iptables上添加如下条目

解释:不转发来自172.43.1.0/24的主机发送的数据包通过vmbr0接口到192.168.0.0/16

1
iptables -I FORWARD -s 172.43.1.0/24 -d 192.168.0.0/16 -o vmbr0 -j DROP

可见处于172.43.1.0/24的主机无法访问192.168.77.1

360截图18720117294660

在处于172.43.1.0/24的主机上发送伪造源IP的udp数据包

360截图17001022272360

处于192.168.77.77的主机接收到udp包

360截图175711161029095

用处应该很多,请发挥脑洞

防护手段

开启IP源保护功能

在转发设备(如交换机、路由器等)上开启IP源保护功能,

发出的数据包的IP字段或MAC地址实际IP或MAC地址不符,则丢弃此数据包,

在某些路由交换设备中实际IP或MAC地址来源于DHC Snooping所获得的用户IP地址及MAC表项

最后

带v2ray plugin的shadowsocks使用ws时报文应该和ws+vless看起来差不了多少,

这里就不测试了,感兴趣的话朋友们可以自己抓包看看

注意:非libev版本的shadowsocks若使用Stream cipher进行加密则可能存在信息泄露的危险,

攻击者可以使用Redirect attack(重定向攻击)从ss-server解密消息,前提是能抓到使用者发送的tcp报文,

所以建议换用Shadowsocks-libev同时使用AEAD的加密方式


本文到这里结束了,感谢观看

EOF