0x01 漏洞描述
HTMLy 是一个开源的基于 PHP 的博客平台。它可以让用户创建安全、轻量且功能强大的网站或博客,并且即使在拥有数千篇文章的情况下,也能高效扩展。
该系统存在存储型XSS漏洞,由于xxx.php 文件中的xxx函数 对用户传入的数据没有进行严格过滤,导致用户可以在新建文章时写入恶意的攻击代码,由此触发XSS攻击。
0x02 环境搭建
版本信息
通过phpstudy 进行搭建
php:7.1.9
apache:2.4.39
htmly版本:2.9.9 最新版本
安装htmly
- 也可以直接下载installer.php 进行一键安装,默认下载最新版本
- 下载源码
Release Composer Vendor Update and Improvements · danpros/htmly (github.com) - 将文件夹放入phpstudy的web目录下
C:\phpstudy_pro\WWW - 根据
README.md中的步骤,修改htmly的配置文件- 在config文件夹中将example重命名为
config.ini - 修改
config.ini,设置siteurl的地址1
2; The URL of your blog.
site.url = "http://htmly:8088/\/" - 在
config/users的文件夹中,将example重命名为htmly.ini(填入自己像设置的用户名即可) - 修改
htmly.ini,填入密码

- 在config文件夹中将example重命名为
- 在phpstudy中创建项目

- 访问
http://htmly:8088/install.php页面,进行安装 - 成功安装后跳转到该页面

- 访问
http://htmly:8088/login进入到管理员页面

phpstorm动态调试
参考往期文章,配置动态调试
thinkphp5.0 文件包含漏洞分析-超详细保姆级 - Gryffinbit的思维殿堂 0x03 动态调试章节
0x03 漏洞分析
XSS漏洞原理
跨站脚本攻击XSS通过将恶意得Script代码注入到Web页面中,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。
漏洞函数
在htmly.php中,对传入的数据进行了处理
1 | add_content($title, $tag, $url, $content, $user, $draft, $category, 'post', $description, null, $dateTime); |

在对$content变量进行的定义
1 | $content = from($_REQUEST, 'content'); |

用户传入content数据,经过from函数进行处理并赋值给$content变量。跟进from函数。这个函数可以从数组中提取单个值或多个值(如果$name是数组),并且在提取过程中处理换行符和去除空白。
1 | function from($source, $name) |
这个from()函数的作用是从指定的$source数组(例如$_REQUEST)中提取指定键的值,并进行一些处理。以下是对代码的详细解释:
$map = array("\r\n" => "\n", "\r" => "\n");:- 这是一个映射数组,用于将Windows和Mac风格的换行符(
\r\n和\r)转换为Unix风格的换行符(\n)。这有助于统一处理不同操作系统下的换行符,确保数据一致性。
- 这是一个映射数组,用于将Windows和Mac风格的换行符(
if (is_array($name)):- 如果
$name是一个数组,函数将遍历这个数组,从$source中提取每个键的值,并进行处理。
- 如果
$data = array();:- 如果
$name是数组,函数会创建一个空数组$data来存储结果。
- 如果
foreach ($name as $k):- 遍历
$name数组中的每个键$k。
- 遍历
$data[$k] = isset($source[$k]) ? trim(strtr($source[$k], $map)) : null;:- 对于每个键
$k,检查它是否存在于$source数组中。 - 如果存在,使用
strtr()函数将换行符替换成\n,再用trim()去掉值的首尾空白字符,然后将结果存入$data[$k]。 - 如果键不存在,将结果设置为
null。
- 对于每个键
return $data;:- 如果
$name是数组,返回处理后的结果数组$data。
- 如果
return isset($source[$name]) ? trim(strtr($source[$name], $map)) : null;:- 如果
$name不是数组,则直接从$source中获取对应的值,处理后返回。 - 如果键不存在,返回
null。
- 如果
由于该函数对传入的数据没有进行严格过滤,所以导致了漏洞的存在。
0x04 攻击演示
漏洞点:http://htmly:8088///add/content?type=post
文章内容写入处存在xss
点击xss的文章
触发xss漏洞