Skip to content

Commit

Permalink
Try get ip from pcap on the fly (danielpaulus#110)
Browse files Browse the repository at this point in the history
an experimental feature to use pcap to grab the local network IPv4 and IPv6 of a device:

using the WiFi MAC address
waiting for the mac to appear as source combined with a ipv4 layer
dump ipv4, ipv6 and mac source address
Example:

{"Mac":"b4:85:e1:7a:61:1c","IPv4":"192.168.2.106","IPv6":"2003:c2:6f05:cc01:f575:9abd:9c1e:7927"}

This waits for network traffic, so it can take a while if nothing happens. To speed it up start apple maps f.ex. like:
ios launch com.apple.Maps

NOTE: Automatic Wifi Must be disabled!
Disabling the private or random MAC address feature on your iOS 14 device
Go to the Settings app on your iOS device.
Tap on Wi-Fi.
Tap the information button. ...
Tap the toggle switch next to Private Address to disable it.
Turn OFF your device's Wi-Fi and then ON again.

Addressed danielpaulus#106

Co-authored-by: Daniel Paulus <[email protected]>
  • Loading branch information
danielpaulus and Daniel Paulus authored Apr 7, 2022
1 parent 84b1332 commit ccaee45
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 2 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/Masterminds/semver v1.5.0
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa
github.com/google/gopacket v1.1.19
github.com/google/uuid v1.1.2
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
github.com/sirupsen/logrus v1.6.0
Expand Down
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
Expand All @@ -28,16 +30,28 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210812204632-0ba0e8f03122 h1:AOT7vJYHE32m61R8d1WlcqhOO1AocesDsKpcMq+UOaA=
golang.org/x/crypto v0.0.0-20210812204632-0ba0e8f03122/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
17 changes: 17 additions & 0 deletions ios/lockdown_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,23 @@ func GetProductVersion(device DeviceEntry) (*semver.Version, error) {
return v, err
}

//GetWifiMac gets the static MAC address of the device WiFi.
//note: this does not report the dynamic MAC if you enable the
//"automatic WiFi address" feature.
func GetWifiMac(device DeviceEntry) (string, error) {
lockdownConnection, err := ConnectLockdownWithSession(device)
if err != nil {
return "", err
}
defer lockdownConnection.Close()
wifiMac, err := lockdownConnection.GetValue("WiFiAddress")
if err != nil {
return "", err
}

return wifiMac.(string), err
}

//GetProductVersion returns the ProductVersion of the device f.ex. "10.3"
func (lockDownConn *LockDownConnection) GetProductVersion() (string, error) {
msg, err := lockDownConn.GetValue("ProductVersion")
Expand Down
95 changes: 95 additions & 0 deletions ios/pcap/ipfinder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package pcap

import (
"github.com/danielpaulus/go-ios/ios"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
log "github.com/sirupsen/logrus"
)

type NetworkInfo struct {
Mac string
IPv4 string
IPv6 string
}

func (n NetworkInfo) complete() bool {
return n.IPv6 != "" && n.Mac != "" && n.IPv4 != ""
}

//FindIp reads pcap packets until one is found that matches the given MAC
//and contains an IP address. This won't work if the iOS device "automatic Wifi address" privacy
//feature is enabled. The MAC needs to be static.
func FindIp(device ios.DeviceEntry) (NetworkInfo, error) {
mac, err := ios.GetWifiMac(device)
if err != nil {
return NetworkInfo{}, err
}
return findIp(device, mac)

}


func findIp(device ios.DeviceEntry, mac string) (NetworkInfo, error) {
intf, err := ios.ConnectToService(device, "com.apple.pcapd")
if err != nil {
return NetworkInfo{}, err
}
plistCodec := ios.NewPlistCodec()
info := NetworkInfo{}
info.Mac = mac
for {
b, err := plistCodec.Decode(intf.Reader())
if err != nil {
return NetworkInfo{}, err
}
decodedBytes, err := fromBytes(b)
if err != nil {
return NetworkInfo{}, err
}
packet, err := getPacket(decodedBytes)
if err != nil {
return NetworkInfo{}, err
}
if len(packet) > 0 {
err:=findIP(packet, &info)
if err != nil {
return NetworkInfo{}, err
}
if info.complete() {
return info, nil
}
}
}
}

func findIP(p []byte, info *NetworkInfo) error {
packet := gopacket.NewPacket(p, layers.LayerTypeEthernet, gopacket.Default)
// Get the TCP layer from this packet
if tcpLayer := packet.Layer(layers.LayerTypeEthernet); tcpLayer != nil {
tcp, _ := tcpLayer.(*layers.Ethernet)
if tcp.SrcMAC.String() == info.Mac {
if log.IsLevelEnabled(log.DebugLevel) {
log.Debugf("found packet for %s", info.Mac)
for _, layer := range packet.Layers() {
log.Debugf("layer:%s", layer.LayerType().String())
}
}
if ipv4Layer := packet.Layer(layers.LayerTypeIPv4); ipv4Layer != nil {
ipv4, ok := ipv4Layer.(*layers.IPv4)
if ok {
info.IPv4 = ipv4.SrcIP.String()
log.Debugf("ip4 found:%s", info.IPv4)
}
}
if ipv6Layer := packet.Layer(layers.LayerTypeIPv6); ipv6Layer != nil {
ipv6, ok := ipv6Layer.(*layers.IPv6)
if ok {
info.IPv6 = ipv6.SrcIP.String()
log.Debugf("ip6 found:%s", info.IPv6)
}
}
}
}
return nil
}
4 changes: 2 additions & 2 deletions ios/pcap/pcap.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func writePacket(f *os.File, packet []byte) error {
now := time.Now()
phs := &PcaprecHdrS{
int(now.Unix()),
int(now.UnixNano()/1e3 - now.Unix() * 1e6),
int(now.UnixNano()/1e3 - now.Unix()*1e6),
len(packet),
len(packet),
}
Expand Down Expand Up @@ -182,7 +182,7 @@ func getPacket(buf []byte) ([]byte, error) {
}
}

log.Info("IOSPacketHeader: ", iph.ToString())
//log.Info("IOSPacketHeader: ", iph.ToString())
packet, err := ioutil.ReadAll(preader)
if err != nil {
return packet, err
Expand Down
13 changes: 13 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Usage:
ios diagnostics list [options]
ios pair [--p12file=<orgid>] [--password=<p12password>] [options]
ios ps [options]
ios ip [options]
ios forward [options] <hostPort> <targetPort>
ios dproxy [--binary]
ios readpair [options]
Expand Down Expand Up @@ -116,6 +117,11 @@ The commands work as following:
> to pair without a trust dialog. Specify the password either with the argument or
> by setting the environment variable 'P12_PASSWORD'
ios ps [options] Dumps a list of running processes on the device
ios ip [options] Uses the live pcap iOS packet capture to wait until it finds one that contains the IP address of the device.
> It relies on the MAC address of the WiFi adapter to know which is the right IP.
> You have to disable the "automatic wifi address"-privacy feature of the device for this to work.
> If you wanna speed it up, open apple maps or similar to force network traffic.
> f.ex. "ios launch com.apple.Maps"
ios forward [options] <hostPort> <targetPort> Similar to iproxy, forward a TCP connection to the device.
ios dproxy [--binary] Starts the reverse engineering proxy server.
> It dumps every communication in plain text so it can be implemented easily.
Expand Down Expand Up @@ -216,6 +222,13 @@ The commands work as following:
deviceState(device, false, enable, profileTypeId, profileId)
}

b, _ = arguments.Bool("ip")
if b {
ip, err := pcap.FindIp(device)
exitIfError("failed", err)
println(convertToJSONString(ip))
return
}
b, _ = arguments.Bool("pcap")
if b {
p, _ := arguments.String("--process")
Expand Down

0 comments on commit ccaee45

Please sign in to comment.