alphasec academy

& "C:\Program Files\Wireshark\tshark.exe" -i Wi-Fi -l -T fields -e data "icmp[0]=8" | % { -join ($_ -split "(.{2})" -match "." | % { [char][byte]"0x$_"}) } - wyświetl payload pakietów ICMP

Dodatkowe informacje

tshark to konsolowy brat znanego i lubianego sniffera pakietów - Wiresharka. Powyższy oneliner będzie nasłuchiwał na interfejsie o nazwie
Wi-Fi
pakietów ICMP Echo Request (pakiety ICMP o typie 8), czyli na popularne pingi. Następnie, będzie wyświetlał ładunek takich pakietów w wersji tekstowej. Co ciekawe, analizując domyślny ładunek takich pingów, możemy stwierdzić z jakiego systemu operacyjnego został wysłany.
W celu wygodniejszej pracy w konsoli z tsharkiem, moglibyśmy dodać katalog Wiresharka do zmiennej środowiskowej
$env:PATH
, co zostało omówione w aptm.in/protip/0075:
[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path','Machine')+';C:\Program Files\Wireshark', 'Machine')
Moglibyśmy wtedy po prostu użyć:
tshark -i Wi-Fi -l -T fields -e data "icmp[0]=8" | % { -join ($_ -split "(.{2})" -match "." | % { [char][byte]"0x$_"}) }

Idąc głębiej

Żeby wszystko było jasne, rozbijmy sobie naszego jednolinijkowca na części pierwsze.
  • & "C:\Program Files\Wireshark\tshark.exe
    - uruchamiamy aplikację
    tshark.exe
    wykorzystując operator wywołania
    &
    , który pozwala uruchomić aplikację, skrypt bądź blok skryptu,
  • -i Wi-Fi
    - wskazujemy interfejs, na którym chcemy sniffować pakiety, w naszym wypadku jest to interfejs
    Wi-Fi
    ; by zobaczyć dostępne interfejsy sieciowe, możemy wykorzystać
    tshark
    a z parametrem
    -D
    , czyli:
    & "C:\Program Files\Wireshark\tshark.exe" -D
    lub jeśli Wireshark jest w zmiennej
    $env:PATH
    , po prostu:
    tshark -D
    ,
  • -l
    - wyświetlaj natychmiast każdy przechwycony pakiet,
  • -T fields -e data
    - wskazujemy, że interesuje nas jedynie pole
    data
    pakietu, które w przypadku pakietów ICMP Echo request będzie zawierało payload pinga,
  • "icmp[0]=8"
    - definiujemy filtr, przekazując, że interesują nas jedynie pakiety ICMP o typie 8 (ICMP Echo request),
  • | % { ... }
    - każdy przechwycony pakiet wysyłamy do dalszego przetwarzania wykorzystując cmdlet
    ForEach-Object
    posiadający alias
    %
    ,
  • -join ($_ -split "(.{2})" -match "." | % { [char][byte]"0x$_" })
    - jako, że
    tshark
    w polu danych zwróci strumień bajtów w postaci szesnastkowej, dzielimy cały string na dwuznakowe łańcuchy (wykorzystując trick z operatorem
    -split
    omówiony już w protipie aptm.in/protip/0072), następnie każdy taki szesnastkowy dwuliterowiec rzutujemy na bajt, a następnie na znak; operator
    -join
    na początku wyrażenia, składa nam tak wygenerowaną tablicę znaków w jeden string.

Idąc szerzej

W powyższym przykładzie nie mamy informacji o adresie pakietu - wyłącznie payload. Dlatego, zamiast
-T fields -e data
możemy poprosić
tshark
a o zwracanie danych w postaci JSON - możemy do tego wykorzystać
-T ek
, co spowoduje wyświetlanie pakietów jako jednolinijkowe stringo JSON (
ek
oznacza format przeznaczony do importu przez Elasticsearch). Co ciekawe, naturalnym mogłoby się tutaj wydawać
-T json
, jednak nie nada to się do naszych celów, bo tak generowany JSON jest wyświetlany w wielu linijkach, z wcięciami, co utrudnia parsowanie (ale ładnie wygląda;). A dlaczego potrzebujemy każdy pakiet jako jednolijkowy JSON? Ponieważ wykorzystując cmdlet
ConvertFrom-Json
, z łatwością przekonwertujemy pakiety zwracane przez
tshark
a do PowerShellowych obiektów:
& "C:\Program Files\Wireshark\tshark.exe" -i Wi-Fi -l -T ek  "icmp[0]=8"|% {
    $pkt = ($_|ConvertFrom-Json)
    if ($pkt.layers.icmp.data.data_data_data) {
        $data = -join ($pkt.layers.icmp.data.data_data_data -split ":"|%{[char][byte]"0x$_"})
        $pkt.layers.ip.ip_ip_src + ":" + $data
    }
}
Zwróćcie uwagę na to, że tym razem payload pakietu ICMP jest przedstawiony również jako dwuznakowe, szesnastkowe bajty, ale tym razem są rozdzielone dwukropkami, co nieco upraszcza całość.
Żeby poznać z jakimi właściwościami pakietu mamy do czynienia, moglibyśmy na przykład jako ćwieczenie skonwertowany ze stringa obiekt przekonwertować ponownie na JSON, czyli:
& "C:\Program Files\Wireshark\tshark.exe" -i Wi-Fi -l -T ek  "icmp[0]=8"|% {
    $pkt = ($_|ConvertFrom-Json)
    $pkt | ConvertTo-Json
}

Bonus - niespodzianka zagadka

Przeanalizujcie poniższy skrypt i zobaczcie co się wydarzy, kiedy do hosta, na którym ten skrypt jest uruchomiony ktoś wyśle pakiet ICMP Echo request z payloadem
nosiemasiema
(np. wykorzystując klasę
Net.NetworkInformation.Ping
którą już wcześniej wykorzystywaliśmy: aptm.in/protip/0072).
$cmds = @{
    "nosiemasiema" = { 
        $rule = New-NetFirewallRule -DisplayName "8080 - icmp knocking, src=$($args.ip)" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8080 -RemoteAddress $args.ip
        Write-Host "Witamy witamy, regula dla $($args.ip) dodana ($($rule.Name))"; 
    }
}

& 'C:\Program Files\Wireshark\tshark.exe' -i Wi-Fi -l -T ek  "icmp[0]=8" | ForEach-Object { 
    $json = ConvertFrom-Json -InputObject $_
    $ip = $json.layers.ip.ip_ip_src
    if ($json.layers.icmp.data.data_data_data) {
        $data = -join ($json.layers.icmp.data.data_data_data -split ":" | ForEach-Object { [char][Convert]::ToInt16($_, 16) })
        if ($cmds.Contains($data)) {
            Invoke-Command -ScriptBlock $cmds.$data -ArgumentList @{ip=$ip}
        }
    }
}
A na koniec wiecie, PowerShell działa również świetnie na Linuksach czy MacOS-ach.

Przydatne linki


Subskrybuj

Jeśli chcesz otrzymywać nowe, mięsiste protipy na maila, a także zostać czasem powiadomiony o wartościowych wydarzeniach - dołącz do subskrybentów.