对网络基础的学习

网络基础

引子

DNS、TCP/IP、HTTP 和编码。


第一站:DNS —— 互联网的地址簿

电脑不认识域名,只认识 IP 地址。这是所有故事的起点。

你要访问 www.example.com,网线那头其实需要的是 93.184.216.34 这样的数字。可让人去背一串数字显然不现实,于是有了 DNS:一个分布在全球的、巨大的地址簿。

查询是一次"层层追问"

当你敲下回车,DNS 解析大致是这样发生的:

  1. 浏览器先翻自己的缓存,看最近有没有问过这个域名
  2. 没有?翻操作系统的缓存,还有 /etc/hosts(Linux/macOS)或 C:\Windows\System32\drivers\etc\hosts
  3. 还没有?去找本地 DNS 服务器,一般是运营商给你的那个
  4. 本地 DNS 服务器也不知道,它就从根域名服务器开始,一级一级往下问:先是 .,再是 .com,最后问到 example.com 的权威服务器,拿到答案后再一路返回给你

第 4 步叫递归查询。整个过程在几十毫秒内完成,你毫无察觉。

想亲眼看看?打开终端:

dig www.example.com

你会看到一大段输出,重点在 ANSWER SECTION:

;; ANSWER SECTION:
www.example.com.    3600    IN    A    93.184.216.34

逐段拆开:3600 是 TTL,表示这个答案可以缓存 3600 秒;IN 是网络类型;A 是记录类型,表示"域名指向一个 IPv4 地址"。

常见的记录类型还有这些:

类型 含义
A 指向 IPv4 地址
AAAA 指向 IPv6 地址
CNAME 别名,指向另一个域名
MX 邮件服务器
NS 负责这个域的权威服务器
TXT 任意文本,常用来做域名验证

TXT 值得多说一句。它本来是给管理员写备注用的,安全圈却经常在里面翻出 SPF 记录、域名所有权验证串,甚至是一些忘了删的内部信息。

一个容易忽略的细节

DNS 默认走 UDP 53 端口。选 UDP 而不是 TCP,是因为查询就是一问一答,为了这么点数据先握手三次太亏了。只有当响应太大(比如开启了 DNSSEC)或者做区域传输时,才会切到 TCP 53。

在 CTF 里,DNS 能玩出什么花

  • 子域名爆破:一个主站往往挂着一堆子域,admin.xxx.com、test.xxx.com、old.xxx.com。用字典去枚举,经常能在犄角旮旯里翻出没做鉴权的后台。工具可以看看 subfinder、OneForAll。
  • DNS 隧道:DNS 查询通常不会被防火墙拦得太严,于是有人把要外传的数据切碎,塞进域名的子域里传出去。
  • DNS 重绑定:让同一个域名在短时间内解析到不同 IP,用来绕过同源策略的限制。

我第一次跑 dig 看到 ANSWER SECTION 的时候,有种很奇怪的感觉——互联网突然变得具体了。在那之前它一直是团雾。


第二站:TCP/IP —— 真正干搬运活的那批人

拿到 IP 地址之后,就要真的发数据了。这部分由 TCP/IP 负责。

它们其实是两个协议,各管一摊,得分开看。

IP:只管送到,不管好坏

IP 负责"把这个包裹送到哪个门牌号"。它很尽力,但不保证成功——包裹可能在路上丢了,可能绕远路导致后发的先到,也可能重复送了两份。

你可以把它想象成一个不负责的快递员:他会把件往你家门口一扔就走,至于丢没丢、顺序乱没乱,他不关心。

TCP:在你和服务器之间拉一根线

TCP 坐在 IP 上面,专门补这些窟窿。它保证:不丢、不重、不乱序,还能根据网络状况自动调节发送速度。

方法说穿了也很朴素——编号 + 确认。每个字节都有一个序号,接收方收到后回一个确认号,说"到这儿我都收到了"。发送方等一会儿没等到确认,就认为丢了,重发一遍。

三次握手,为什么偏偏是三次

TCP 建立连接前要握手三次:

客户端  ----  SYN      ---->  服务器     在吗?
客户端  <---- SYN+ACK  ----   服务器     在的,你还在吗?
客户端  ----  ACK      ---->  服务器     在的。

我一开始死记硬背,后来才想明白:TCP 是全双工的,两个方向的能力都得验证一遍。

两次握手只能确认"我能发、你能收",确认不了"你能发、我能收"。而服务器把自己的 SYN 和对客户端的 ACK 合并成一个包发出去,所以总共只需要三次。多一次浪费,少一次不够。

顺带提一句断开连接是四次挥手,因为 TCP 支持半关闭——我这边不发数据了,但你还可以继续发给我,所以 FIN 和 ACK 得分开发。

端口:一台机器上的多个门

一台服务器通常只有一个 IP,但要同时跑网页、SSH、数据库。靠什么区分?端口。

端口号是 0 到 65535 的整数,常见约定:

  • 22 → SSH
  • 53 → DNS
  • 80 → HTTP
  • 443 → HTTPS
  • 3306 → MySQL

IP 定位到机器,端口定位到机器上的程序。合起来叫"套接字"。

抓一次包看看

装个 Wireshark,随便访问一个 HTTP 网站,你会看到最前面孤零零的三个包——没有数据,就是纯粹的三次握手。过滤框里输入 tcp 只看 TCP 流量,输入 tcp.flags.syn == 1 && tcp.flags.ack == 0 可以精确筛出第一次握手的包。

看到那三个包的瞬间,课本上的图就活了。

在 CTF 里

流量分析题(Misc 方向的大头)基本就是给你一个 .pcap 文件,让你从里面捞东西。常用过滤语法:

http.request.method == "POST"     # 只看 POST 请求
tcp.stream eq 0                   # 只看第一条 TCP 流
tcp contains "flag"               # 全文搜索关键字
ftp.request.command == "USER"     # 看 FTP 登录

配合"追踪 TCP 流"功能,可以直接把这一整条会话的内容还原出来看。


第三站:HTTP —— 包裹里到底装了什么

前面两站解决的是"怎么送到"。HTTP 解决的是"送的东西长什么样"。

它的形状

一个 HTTP 请求拆开看是这样的:

GET /index.php?id=1 HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; ...)
Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ==
Accept: text/html

第一行叫请求行:方法 + 路径 + 版本。
然后是若干行 名字: 值 组成的请求头。
然后一个空行。
空行后面才是请求体(GET 请求一般没有)。

响应长得很像:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: session=xxxx; HttpOnly
Content-Length: 1234

<html>...</html>

那个空行很重要。它是头部和正文的分界线。很多题目就是在"怎么让服务器把你要的东西认成正文而不是头部"上做文章。

它是纯文本的

这是 HTTP 最伟大的设计,也是它最致命的缺陷。

伟大在于:你可以不用浏览器,直接用 nc 手写一个请求:

nc www.example.com 80
GET / HTTP/1.1
Host: www.example.com

敲两下回车,HTML 就哗哗地出来了。这种"原来我可以直接和服务器对话"的感觉,非常上瘾。

致命在于:既然是明文,链路上任何一个人都能看见内容,也都能改。你连的 WiFi、路过的路由器、运营商——理论上全都能知道你在干什么。这才有了 HTTPS。

HTTP 有个设定:服务器不记得你上一次请求干了什么。每个请求都是独立的,这叫无状态。

这个设计让服务器简单到可以轻松横向扩展,但问题也很明显——登录状态怎么维持?

于是有了 Cookie。服务器在响应里用 Set-Cookie 塞一个标识给你,浏览器存下来,之后每次请求都用 Cookie 头带上它。服务器一看:"哦,是你。"

Cookie 是客户端存的,也就是说它可以被改。 这句话值得划重点,它是相当一部分 Web 题的出发点。

状态码

码 含义
200 成功
301 / 302 重定向
403 服务器看懂了,但拒绝执行
404 找不到
500 服务器自己崩了

403 和 404 的区别值得琢磨:403 说明资源存在,只是不给你看;404 是压根没有。这个差别在渗透里是有用的信息。

HTTPS

HTTPS 不是新协议,而是在 HTTP 和 TCP 之间插了一层 TLS。HTTP 的内容先被 TLS 加密,再交给 TCP 送出去。所以你在 Wireshark 里抓 HTTPS 的流量,看到的是一堆看不懂的字节——应用层的内容已经锁起来了。

在 CTF 里

绝大多数 Web 题的本质,说穿了是同一句话:你能不能改这个包。

改 Host 头绕访问控制,改 X-Forwarded-For 伪造 IP,改 Cookie 提权,改 User-Agent 绕过设备判断,把 GET 换成 POST,在 URL 里塞个 ' 看看会不会报 SQL 错误……

一旦你意识到"那个请求包是我完全掌控的一段文本,我想怎么写就怎么写",一半的 Web 题就换了性质。

所以强烈建议:装个 Burp Suite,开代理,拦截一次自己的请求,手动改掉一个 header,然后放出去看看服务器怎么回应。这一步做完,你对 Web 的理解会往前跳一大截。


第四站:编码 —— 一切最终都是字节

前面说的所有东西,在网络上跑的时候都是字节流。而我们人类看字节流很费劲,于是有了各种编码。

URL 编码

URL 里有些字符是有语法含义的:? 分隔路径和参数,& 分隔参数,= 分隔键值,# 是锚点。那如果我想传一个本身就带 & 的内容呢?

转义。规则是把字节写成 % 加两位十六进制:

  • 空格 → %20
  • & → %26
  • 你 → %E4%BD%A0

最后那个是 UTF-8 编码下的"你",占 3 个字节。

Base64

Base64 解决的问题是:怎么让二进制数据安全穿过只认文本的通道。

比如你想在 URL 或 Cookie 里塞一张小图片,或者塞一段序列化后的对象——这些字节里可能含有不可打印字符,直接放进去会被破坏。Base64 把它们映射成 64 个可打印字符(A-Z、a-z、0-9、+、/),就安全了。

规则是 3 个字节一组,拆成 4 个 6 位,每个 6 位查表得一个字符,所以 3 字节变 4 字符。最后不够 3 字节就用 = 补齐,这就是你常在 Base64 串末尾看到等号的原因。

echo -n "flag{hello}" | base64
# ZmxhZ3toZWxsb30=

Base64 不是加密。 它的可逆性和加密毫无关系,它是编码,换个写法而已。。

Hex(十六进制)

一个字节写成两个十六进制字符。看二进制内容最直观的姿势:

xxd flag.png | head
# 00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR

开头的 8950 4e47 就是 PNG 的文件头。文件头(magic bytes)是隐写题和取证题的基本功——不管文件叫什么名字,看头几个字节就知道它到底是个什么东西。

字符集:乱码的真正来源

UTF-8 里一个中文通常 3 字节,GBK 里是 2 字节。你用 UTF-8 的码表去解一段 GBK 的字节,出来的就是一堆"锟斤拷"。

乱码基本都是"用 A 的码表解 B 的字节"。 理解这一句,你就掌握了所有乱码问题的通用解法。

在 CTF 里

编码题的套路通常是套娃:Base64 套 Base64 再套一层 Hex 再套一层 URL 编码,套个七八层,最后给你一个 flag。
手工解会疯。这时候用 CyberChef(在线的,浏览器直接打开),把密文丢进去,点一下那个魔法棒图标(Magic),它会自动猜测可能的编码链并给出结果。

编码这件事真正教会我的是:你看到的东西,和你以为的东西,可能不是一回事。 一个 .jpg 可能是 zip,一段看起来正常的 Base64 解出来可能是另一个 Base64。在安全领域,保持"这真的是它看起来的样子吗"这个疑问,比记住多少编码方案都重要。

posted @ 2026-10-25 12:01  qianwangxing  阅读(3)  评论(0)    收藏  举报