Jednog sam dana trebao skenirati Wi-Fi mreže iz Android aplikacija i dobiti detaljne podatke o pristupnim točkama.
Ovdje smo se morali suočiti s nekoliko poteškoća:
Ovaj članak govori o tome kako dobiti sveobuhvatne podatke o Wi-Fi okruženju iz Android koda bez NDK-a, hakiranja, ali samo pomoću Android API-ja i razumjeti kako to protumačiti.
Nemojmo odgađati i počnimo pisati kod.
1. Izradite projekt
Ova je bilješka namijenjena onima koji su izradili Android projekt više puta, stoga izostavljamo detalje ove stavke. Kod u nastavku bit će predstavljen u Kotlinu, minSdkVersion=23.
2. Dopuštenja za pristup
Za rad s Wi-Fi iz aplikacije, morat ćete dobiti nekoliko dozvola od korisnika. U skladu s
Dakle, u AndroidManifest.xml ćemo dodati:
<uses-permission android_name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android_name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android_name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android_name="android.permission.ACCESS_FINE_LOCATION"/>
A u kodu koji sadrži poveznicu na trenutnu aktivnost:
import android.app.Activity
import android.content.Context
import android.location.LocationManager
import androidx.core.app.ActivityCompat
....
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
ActivityCompat.requestPermissions(
activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE),
1
)
makeEnableLocationServices(activity.applicationContext)
} else {
ActivityCompat.requestPermissions(
activity,
arrayOf(Manifest.permission.CHANGE_WIFI_STATE),
1
)
}
/* включает экран включения службы по определению местоположения */
fun makeEnableLocationServices(context: Context) {
// TODO: перед вызовом этой функции надо рассказать пользователю, зачем Вам доступ к местоположению
val lm: LocationManager =
context.applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val gpsEnabled: Boolean = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
val networkEnabled: Boolean = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!gpsEnabled && !networkEnabled) {
context.startActivity(Intent(ACTION_LOCATION_SOURCE_SETTINGS));
}
}
3. Napravite BroadcastReceiver i pretplatite se na događaje ažuriranja podataka o skeniranju okruženja Wi-Fi mreže
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiScanReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
if (success) {
scanSuccess()
}
}
}
val intentFilter = IntentFilter()
/* подписываемся на сообщения о получении новых результатов сканирования */
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
context.registerReceiver(wifiScanReceiver, intentFilter)
val success = wifiManager.startScan()
if (!success) {
/* что-то не получилось при запуске сканирования, проверьте выданые разрешения */
}
....
private fun scanSuccess() {
/* вот они, результаты сканирования */
val results: List<ScanResult> = wifiManager.scanResults
}
Metoda WiFiManager.startScan u dokumentaciji je označena kao depricated od API verzije 28, ali isključena.
Ukupno smo dobili popis objekata
4. Pogledajte ScanResult i razumite uvjete
Pogledajmo neka polja ove klase i opišimo što ona znače:
SSID — Identifikator skupa usluga naziv je mreže
BSSID – Osnovni identifikator skupa usluga – MAC adresa mrežnog adaptera (Wi-Fi točka)
nivo — Indikator jačine primljenog signala [dBm (ruski dBm) — Decibel, referentna snaga 1 mW.] — Indikator jačine primljenog signala. Uzima vrijednost od 0 do -100, što je dalje od 0, veća je snaga signala izgubljena na putu od Wi-Fi točke do vašeg uređaja. Više detalja možete pronaći, na primjer, na
val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
val numberOfLevels = 5
val level = WifiManager.calculateSignalLevel(level, numberOfLevels)
frekvencija — radna frekvencija Wi-Fi točke [Hz]. Osim same frekvencije, možda će vas zanimati i kanal tzv. Svaka točka ima svoju radnu čistoću. U vrijeme pisanja, najpopularniji raspon Wi-Fi točaka je 2.4 GHz. Ali, da budemo precizniji, točka prenosi informacije na vaš telefon na numeriranoj frekvenciji bliskoj navedenoj. Broj kanala i odgovarajućih frekvencija
/* по частоте определяем номер канала */
val channel: Int
get() {
return if (frequency in 2412..2484) {
(frequency - 2412) / 5 + 1
} else if (frequency in 5170..5825) {
(frequency - 5170) / 5 + 34
} else {
-1
}
}
sposobnosti - najzanimljivije područje za analizu, rad s kojim je zahtijevao puno vremena. Ovdje su u retku ispisane "sposobnosti" točke. U ovom slučaju ne morate tražiti pojedinosti interpretacije niza u dokumentaciji. Evo nekoliko primjera onoga što bi moglo biti u ovom retku:
[WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][WPS][ESS]
[WPA2-PSK-CCMP][ESS]
[WPA2-PSK-CCMP+TKIP][ESS]
[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS]
[ESS][WPS]
5. Razumijevanje kratica i mogućnosti raščlanjivanja
Vrijedno je spomenuti da se klase paketa android.net.wifi.* koriste ispod haube od strane uslužnog programa za Linux
Djelovat ćemo dosljedno. Razmotrimo prvo izlaz formata u kojem su elementi unutar zagrada odvojeni znakom “-“:
[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]
Prvo značenje opisuje tzv. način provjere autentičnosti. Odnosno, koji redoslijed radnji moraju izvršiti uređaj i pristupna točka da bi se pristupna točka mogla koristiti i kako šifrirati sadržaj. U trenutku pisanja ovog posta najčešće opcije su WPA i WPA2, kod kojih ili svaki povezani uređaj izravno ili putem tzv. RADIUS poslužitelj (WPA-Enterprice) daje lozinku preko šifriranog kanala. Najvjerojatnije pristupna točka u vašem domu pruža vezu prema ovoj shemi. Razlika između druge i prve verzije je u tome što ima jaču šifru: AES nasuprot nesigurnom TKIP-u. WPA3, koji je složeniji i napredniji, također se postupno uvodi. Teoretski, možda postoji opcija s enterprice rješenjem CCKM (Cisco Centralized Key Management), ali na to nisam nikad naišao.
Pristupna točka je možda konfigurirana za provjeru autentičnosti pomoću MAC adrese. Ili, ako pristupna točka daje podatke koristeći zastarjeli WEP algoritam, tada zapravo nema provjere autentičnosti (tajni ključ ovdje je ključ za šifriranje). Takve opcije svrstavamo u OSTALO.
Postoji i metoda koja je popularna u javnom wi-fiju sa skrivenim Captive Portal Detection - zahtjev za autentifikaciju putem preglednika. Takve pristupne točke skeneru izgledaju kao otvorene (što i jesu sa stajališta fizičke veze). Stoga ih svrstavamo u OTVORENE.
Druga vrijednost može se označiti kao algoritam za upravljanje ključem. Ovo je parametar gore opisane metode provjere autentičnosti. Govori o tome kako se točno razmjenjuju ključevi šifriranja. Razmotrimo moguće opcije. EAP - koristi se u spomenutom WPA-Enterpriceu, koristi bazu podataka za provjeru unesenih autentifikacijskih podataka. SAE - koristi se u naprednom WPA3, otpornijem na grubu silu. PSK - najčešća opcija, uključuje unos lozinke i njezin prijenos u šifriranom obliku. IEEE8021X - prema međunarodnom standardu (različit od onog koji podržava obitelj WPA). OWE (Opportunistic Wireless Encryption) je proširenje standarda IEEE 802.11 za točke koje smo klasificirali kao OPEN. OWE osigurava sigurnost podataka koji se prenose preko nezaštićene mreže šifrirajući ih. Moguća je i opcija kada nema pristupnih ključeva, nazovimo ovu opciju NEMA.
Treći parametar je tzv. sheme šifriranja — kako se točno šifra koristi za zaštitu prenesenih podataka. Nabrojimo opcije. WEP - koristi RC4 stream šifru, tajni ključ je ključ za šifriranje, što se smatra neprihvatljivim u svijetu moderne kriptografije. TKIP - koristi se u WPA, CKIP - u WPA2. TKIP+CKIP - može se navesti u točkama sposobnim za WPA i WPA2 radi kompatibilnosti unazad.
Umjesto tri elementa, možete pronaći usamljenu WEP oznaku:
[WEP]
Kao što smo gore spomenuli, to je dovoljno da ne odredite algoritam za korištenje ključeva, koji ne postoji, i metodu šifriranja, koja je prema zadanim postavkama ista.
Sada razmotrite ovu zagradu:
[ESS]
ovo Wi-Fi način rada ili Topologija Wi-Fi mreže. Možete naići na način BSS (Basic Service Set) - kada postoji jedna pristupna točka preko koje povezani uređaji komuniciraju. Može se pronaći na lokalnim mrežama. Pristupne točke su u pravilu potrebne za povezivanje uređaja iz različitih lokalnih mreža, pa su dio Extended Service Sets - ESS. Tip IBSSs (Independent Basic Service Sets) označava da je uređaj dio Peer-to-Peer mreže.
Također možete vidjeti WPS oznaku:
[WPS]
WPS (Wi-Fi Protected Setup) je protokol za poluautomatsku inicijalizaciju Wi-Fi mreže. Za inicijalizaciju, korisnik ili unese lozinku od 8 znakova ili pritisne gumb na usmjerivaču. Ako je vaša pristupna točka prve vrste i ovaj potvrdni okvir se pojavljuje pored naziva vaše pristupne točke, toplo vam preporučujemo da odete na administratorsku ploču i onemogućite WPS pristup. Činjenica je da se često 8-znamenkasti PIN može saznati po MAC adresi ili se može srediti u dogledno vrijeme, što netko nepošteno može iskoristiti.
6. Napravite model i funkciju parsiranja
Na temelju onoga što smo gore saznali, opisat ćemo što se dogodilo pomoću klasa podataka:
/* схема аутентификации */
enum class AuthMethod {
WPA3,
WPA2,
WPA, // Wi-Fi Protected Access
OTHER, // включает в себя Shared Key Authentication и др. использующие mac-address-based и WEP
CCKM, // Cisco
OPEN // Open Authentication. Может быть со скрытым Captive Portal Detection - запрос аутентификации через браузер
}
/* алгоритм ввода ключей */
enum class KeyManagementAlgorithm {
IEEE8021X, // по стандарту
EAP, // Extensible Authentication Protocol, расширяемый протокол аутентификации
PSK, // Pre-Shared Key — каждый узел вводит пароль для доступа к сети
WEP, // в WEP пароль является ключом шифрования (No auth key)
SAE, // Simultaneous Authentication of Equals - может быть в WPA3
OWE, // Opportunistic Wireless Encryption - в роутерах новых поколений, публичных сетях типа OPEN
NONE // может быть без шифрования в OPEN, OTHER
}
/* метод шифрования */
enum class CipherMethod {
WEP, // Wired Equivalent Privacy, Аналог шифрования трафика в проводных сетях
TKIP, // Temporal Key Integrity Protocol
CCMP, // Counter Mode with Cipher Block Chaining Message Authentication Code Protocol,
// протокол блочного шифрования с кодом аутентичности сообщения и режимом сцепления блоков и счетчика
// на основе AES
NONE // может быть без шифрования в OPEN, OTHER
}
/* набор методов шифрования и протоколов, по которым может работать точка */
data class Capability(
var authScheme: AuthMethod? = null,
var keyManagementAlgorithm: KeyManagementAlgorithm? = null,
var cipherMethod: CipherMethod? = null
)
/* Режим работы WiFi (или топология сетей WiFi) */
enum class TopologyMode {
IBSS, // Эпизодическая сеть (Ad-Hoc или IBSS – Independent Basic Service Set).
BSS, // Основная зона обслуживания Basic Service Set (BSS) или Infrastructure Mode.
ESS // Расширенная зона обслуживания ESS – Extended Service Set.
}
Sada napišimo funkciju koja će analizirati polje mogućnosti:
private fun parseCapabilities(capabilitiesString: String): List < Capability > {
val capabilities: List < Capability > = capabilitiesString
.splitByBrackets()
.filter {
!it.isTopology() && !it.isWps()
}
.flatMap {
parseCapability(it)
}
return
if (!capabilities.isEmpty()) {
capabilities
} else {
listOf(Capability(AuthMethod.OPEN, KeyManagementAlgorithm.NONE, CipherMethod.NONE))
}
}
private fun parseCapability(part: String): List < Capability > {
if (part.contains("WEP")) {
return listOf(Capability(
AuthMethod.OTHER,
KeyManagementAlgorithm.WEP,
CipherMethod.WEP
))
}
val authScheme = when {
part.contains("WPA3") - > AuthMethod.WPA3
part.contains("WPA2") - > AuthMethod.WPA2
part.contains("WPA") - > AuthMethod.WPA
else - > null
}
val keyManagementAlgorithm = when {
part.contains("OWE") - > KeyManagementAlgorithm.OWE
part.contains("SAE") - > KeyManagementAlgorithm.SAE
part.contains("IEEE802.1X") - > KeyManagementAlgorithm.IEEE8021X
part.contains("EAP") - > KeyManagementAlgorithm.EAP
part.contains("PSK") - > KeyManagementAlgorithm.PSK
else - > null
}
val capabilities = ArrayList < Capability > ()
if (part.contains("TKIP") || part.contains("CCMP")) {
if (part.contains("TKIP")) {
capabilities.add(Capability(
authScheme ? : AuthMethod.OPEN,
keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
CipherMethod.TKIP
))
}
if (part.contains("CCMP")) {
capabilities.add(Capability(
authScheme ? : AuthMethod.OPEN,
keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
CipherMethod.CCMP
))
}
} else if (authScheme != null || keyManagementAlgorithm != null) {
capabilities.add(Capability(
authScheme ? : AuthMethod.OPEN,
keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
CipherMethod.NONE
))
}
return capabilities
}
private fun parseTopologyMode(capabilitiesString: String): TopologyMode ? {
return capabilitiesString
.splitByBrackets()
.mapNotNull {
when {
it.contains("ESS") - > TopologyMode.ESS
it.contains("BSS") - > TopologyMode.BSS
it.contains("IBSS") - > TopologyMode.IBSS
else - > null
}
}
.firstOrNull()
}
private fun parseWPSAvailable(capabilitiesString: String): Boolean {
return capabilitiesString
.splitByBrackets()
.any {
it.isWps()
}
}
private fun String.splitByBrackets(): List < String > {
val m = Pattern.compile("[(.*?)]").matcher(this)
val parts = ArrayList < String > ()
while (m.find()) {
parts.add(m.group().replace("[", "").replace("]", ""))
}
return parts
}
private fun String.isTopology(): Boolean {
return TopologyMode.values().any {
this == it.name
}
}
private fun String.isWps(): Boolean {
return this == "WPS"
}
8. Pogledajte rezultat
Skenirat ću mrežu i pokazati vam što sam našao. Prikazani su rezultati jednostavnog izlaza putem Log.d:
Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true
Ostalo je neistraženo pitanje povezivanja na mrežu iz aplikacijskog koda. Reći ću samo da su vam za čitanje spremljenih lozinki iz OS-a mobilnog uređaja potrebna root prava i spremnost da preturate po datotečnom sustavu kako biste pročitali wpa_supplicant.conf. Ako logika aplikacije zahtijeva unos lozinke izvana, veza se može uspostaviti kroz klasu
Hvala
Ako mislite da nešto treba dodati ili ispraviti, napišite u komentarima :)
Izvor: www.habr.com