题解作者:Layton Chen
出题人、验题人、文案设计等:见 Hackergame 2021 幕后工作人员。
-
题目分类:web
-
题目分值:200
“听说没?【大砍刀】平台又双叒做活动啦!参与活动就送 0.5 个 flag 呢,攒满 1 个 flag 即可免费提取!”
“还有这么好的事情?我也要参加!”
“快点吧!我已经拿到 flag 了呢!再不参加 flag 就要发完了呢。”
“那怎么才能参加呢?”
“这还不简单!点击下面的链接就行”
公告:本题在小概率情况下会产生操作时间限制无法重置的现象,表现为一直显示“操作速度太快了,请稍后再试!”,现已修复,请大家重新点击按钮后稍等几秒钟即可恢复。
本题的背景是【大砍刀】平台的 Flag 红包活动,通过分享助力链接,可以获得 Flag 碎片。但是随着活动的进行,每次助力链接的收益会不断减少。本题绝无捏造、仿冒国内著名互联网产品,也没有违反《互联网用户账户名称信息管理规定(征求意见稿)》及其他相关法律法规。
本题的主要考察点为 IPv4 协议以及 HTTP 协议,而不是钞能力或好友数。使用代理或好友助力等方式是无法攒到 1 个 Flag 的。
应当可以很容易发现,用户通过点击助力按钮,即可积攒 Flag 。但是题目写出会对源地址进行检查, 位于同一个 /8 网络内的用户只能助力一次。(一个 /8 网段内的所有 IP 地址的第一个字节是相同的。很容易可以知道, IPv4 中至多只有 256 个 /8 网段。
其实,如果对 Flag 数量进行多项式拟合,可以发现 flag 数量为一精确的二次函数:
flag = (-0.0000076*(count-256)^2+1)
最终需要攒齐全部 256 个 /8 网段的助力才可获得全部 Flag。
即便没有上面这一步,应当可以很快意识(也许很难)到使用好友助力或使用代理池是不可行的,这是由于不是全部 IPv4 /8 地址块是可用的。这包括:
- RFC1700 定义的 0.0.0.0/8 和回环地址 127.0.0.0/8。
- RFC1918 定义的私有地址 10.0.0.0/8、192.168.0.0/16 ,172.16.0.0/12
- RFC3171 定义的组播地址 224.0.0.0/4
- RFC1700 定义的保留地址 240.0.0.0/4
- 用于特殊网络的 14.0.0.0/8 , 24.0.0.0/8 以及 39.0.0.0/8
- 美国国防部宣告的大量 IPv4 /8 网段,例如 6.0.0.0/8 , 7.0.0.0/8 等等 十几个 /8 网段
详细信息可用参考 RFC3330.
因此,我们需要伪造 IPv4 源地址的方式来欺骗服务器地址。事实上,服务器通过两种手段来检测远程 IP 地址。首先是通过调用搜狐的接口https://pv.sohu.com/cityjson?ie=utf-8
来识别远程地址。并将识别的远程地址通过表单中的 ip 字段传送给服务器。
第二个手段是服务器的检测方式。这里,服务器存在 X-Forwarded-For
欺骗漏洞。 X-Forwarded-For 是一个扩展的 HTTP 头标,通常由反向代理服务器(如 Nginx )在转发 HTTP 协议时添加。这是因为代理服务器在进行转发时,后端服务器接收到的 TCP/IP 协议的源地址将是代理服务器的地址,而不是远程客户的地址。中转服务器通过这一头标来保留远程地址这一信息。然而,这一头标是不被认证且很容易被伪造的,因此可用构造出任意远程地址。另一个相似功能的头标是 X-Remote-IP
。事实上,本文题目服务器对这两个头标均存在识别漏洞。
X-Forwarded-For
的格式非常简单,只需要将源地址的 IP 地址记录其中即可。当存在多个中转服务器的时候,后续中转服务器会将自己的地址写在该头标的末尾,并使用逗号进行分割。
综上,我们可用构造出用于伪造攻击的脚本如下 run.py
:
import requests
from requests.api import head
import time
url = "<助力连接的地址>"
for i in range(0,256):
ip = f"{i}.1.1.1"
ret = requests.post(url, data={"ip": ip}, headers={"X-Forwarded-For": ip})
time.sleep(1.2)
print(i)
注意到本题为了防止 DoS 攻击,实现了一个简单的令牌桶流量控制算法,因此需要控制请求发送速率。
出题者在 hackergame 群里看到分享连接并点击参与了助力,但是其实知道这对解题不会存在任何帮助。
出题者还看到了各位群友发送的截图显示,到达 10 分钟时间限制却没有完成全部助力而功亏一篑,表示非常愧疚(也许是暗爽)。