我根据pwnat的想法做了一些测试,它引入了一种没有第三方的NAT遍历方法:服务器将ICMP echo请求包发送到固定地址(例如,{{ 1}})其中没有回复的回应回复,客户端假装是Internet上的跳,向服务器发送ICMP超时报文,期望服务器前面的NAT转发ICMP超时消息到服务器。
在我向3.3.3.3
发送信息后,我在3.3.3.3
中运行以下代码,以便在Go中收听ICMP消息:
192.168.1.100
并且在package main
import (
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
func main() {
c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
fmt.Println("listen error", err)
}
rb := make([]byte, 1500)
for {
n, _, err := c.ReadFrom(rb)
if err != nil {
fmt.Printf("read err: %s\n", err)
}
reply, err := icmp.ParseMessage(1, rb[:n])
if err != nil {
fmt.Println("parse icmp err:", err)
return
}
switch reply.Type {
case ipv4.ICMPTypeTimeExceeded:
if _, ok := reply.Body.(*icmp.TimeExceeded); ok {
// internet header(20 bytes) plus the first 64 bits of the original datagram's data
//fmt.Println("recv id ", binary.BigEndian.Uint16(timeExceed.Data[22:24]))
fmt.Printf("ttl exceeded\n")
}
default:
}
}
}
中运行以发送伪造时间的程序超出了192.168.2.100
的消息:
192.168.1.100
问题是package main
import (
"errors"
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"net"
"os"
)
func sendTtle(host string) error {
conn, err := net.Dial("ip4:icmp", host)
if err != nil {
return err
}
// original IP header
h := ipv4.Header{
Version: 4,
Len: 20,
TotalLen: 20 + 8,
TTL: 64,
Protocol: 1,
}
h.Src = net.ParseIP(host)
h.Dst = net.ParseIP("3.3.3.3")
iph, err := h.Marshal()
if err != nil {
fmt.Println("ip header error", err)
return err
}
// 8 bytes of original datagram's data
echo := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: 3456, Seq: 1,
}}
oriReq, err := echo.Marshal(nil)
if err != nil {
return errors.New("Marshal error")
}
data := append(iph, oriReq...)
te := icmp.Message{
Type: ipv4.ICMPTypeTimeExceeded,
Code: 0,
Body: &icmp.TimeExceeded{
Data: data,
}}
if buf, err := te.Marshal(nil); err == nil {
fmt.Println("sent")
if _, err := conn.Write(buf); err != nil {
return errors.New("write error")
}
} else {
return errors.New("Marshal error")
}
return nil
}
func main() {
argc := len(os.Args)
if argc < 2 {
fmt.Println("usage: prpgram + host")
return
}
if err := sendTtle(os.Args[1]); err != nil {
fmt.Println("failed to send TTL exceeded message: ", err)
}
}
无法接收消息。可能的原因是什么?
答案 0 :(得分:2)
您的代码没有问题。如果您在同一网络中运行代码(我的意思是没有NAT /路由器参与),程序将按预期接收超出时间的消息。原因是pwnat使用的理论现在不起作用。
首先,您没有获得发送的echo请求的标识符
192.168.2.100
到3.3.3.3
,标识符将是唯一的
通过NAPT(如果有)映射到外部查询ID,以便它可以路由
future ICMP Echo使用相同的查询ID回复发件人。根据{{3}},
在NAPT设置中,如果ICMP中嵌入的IP消息恰好是 一个TCP,UDP或ICMP查询包,你还需要修改 TCP / UDP标头或查询中的适当TU端口号 ICMP查询标头中的标识符字段。
其次,根据rfc 5508:
如果NAT设备从私有领域收到ICMP错误数据包, 并且NAT没有嵌入式有效负载的活动映射, NAT应该静默地丢弃ICMP错误数据包。
因此伪造的时间超过了消息无法通过。 rfc 3022 ICMP error packet modifications section是关于此的更多细节。