将 SSL 与 Bash 的 /dev/tcp 一起使用

Posted

技术标签:

【中文标题】将 SSL 与 Bash 的 /dev/tcp 一起使用【英文标题】:Using SSL with Bash's /dev/tcp 【发布时间】:2016-09-12 02:14:26 【问题描述】:

我刚刚用 bash 编写了一个 IRC 机器人(我知道,我知道)。它可以完成我需要的一切(SASL 身份验证、解析链接等),但它不通过 SSL 连接。在 IRC 上进行了很多谷歌搜索和很多麻烦之后,我还没有找到让 /dev/tcp 使用 SSL 的方法。这是我当前的代码:

#!/bin/bash

if [[ "$1" == "-debug" ]]; then
    set -x
fi

irc_send() 
    printf ">>> %s\n" "$1"
    printf "%s\r\n" "$1" >&3 &


sasl_successful() 
    while read -ru3 line; do
        printf "%s\n" "$line"
        read -r location numeric rest <<< "$line"

        if [[ "$numeric" == "903" ]]; then
            return 0
        elif [[ "$numeric" == "904" || "$numeric" == "906" ]]; then
            return 1
        fi
    done


sasl_connect() 
    user="$1"
    pass="$2"
    server_pass="$3"
    nick="$4"
    ident="$5"
    realname="$6"
    saslstring="$(printf '%s\0%s\0%s' "$user" "$user" "$pass" | base64)"

    irc_send "CAP REQ :sasl"

    if [[ "$server_pass" ]]; then
        irc_send "PASS $server_pass"
    fi

    irc_send "NICK $nick"
    irc_send "USER $ident * * :$realname"
    irc_send "AUTHENTICATE PLAIN"
    irc_send "AUTHENTICATE $saslstring"

    if sasl_successful; then
        irc_send "CAP END"
        return 0
    else
        return 1
    fi


get_title() 
    xmllint --html --xpath '//title/text()' - <<< "$(curl -sL "$1")" 2> /dev/null


domain_base() 
    domain="$(python -c "import urlparse; print urlparse.urlparse('$1').netloc")"

    if [[ -z "$domain" ]]; then
        echo "$1"
    else
        echo "$domain"
    fi


links=(
    'http://static.giantbomb.com/uploads/square_small/2/25062/833357-link_avatar3.jpg'
    'http://vignette1.wikia.nocookie.net/zelda/images/2/2a/Fierce_Deity_Link.png/revision/latest?cb=20100124002042'
    'http://8wayrun.com/attachments/lnksc2art2-jpg.3846/'
    'https://camo.githubusercontent.com/9bb56499161ec0a5c20b6b3a3af674f51072af7c/687474703a2f2f7777772e6e6f727468636173746c652e636f2e756b2f6775696c642f6172742f616e6e615f6c2f6c696e6b312e6a7067'
    'http://www.jdubuzz.com/files/2015/05/Link_3_ST.png'
    'http://www.smashbros.com/images/og/link.jpg'
    'https://upload.wikimedia.org/wikipedia/en/3/39/Wakerlink.jpg'
)

host="irc.freenode.net"
server_pass=""
port=6667
nick="mewtwo"
user="mewtwo"
realname="A simple irc bot written in bash."
channels="#somechannel"
username="$1"
password="$2"

exec 3<>"/dev/tcp/$host/$port"

if ! sasl_connect "$username" "$password" "$server_pass" "$nick" "$user" "$realname"; then
    printf "Could not connect.\n" >&2
fi

irc_send "JOIN $channels"

while :; do
    irc_send "PING $RANDOM"
    sleep 1m
done &

while read -ru3 line; do
    line="$(perl -pe 's/\r\n/\n/' <<< "$line")"
    read -r from type target msg <<<  "$line"
    msg="$msg#:" nick="$from#:" nick="$nick%%!*" host="$from%%@*" host="$from#"$host"@"

    # parsing logic
    if [[ "$type" == "PRIVMSG" ]]; then
        printf "[%s] %s@%s: %s\n" "$target" "$nick" "$host" "$msg" &
    else
        printf "%s\n" "$line" &
    fi

    # response logic
    if [[ "$type" == "PRIVMSG" ]]; then
        if [[ "$msg" == "link?" ]]; then
            irc_send "PRIVMSG $target :$links[RANDOM % $#links[@]]"
        fi

        urls=($(grep -oPm 1 '(?:https?:\/\/)?([a-z\d-]*\.)?[a-z\d-]+\.[a-z]+(?:\/\S*)?(?(?<=\.(jpg|png|gif))(*SKIP)(*F))' <<< "$msg"))

        for url in "$urls[@]"; do
            irc_send "PRIVMSG $target :[$(get_title "$url")] - $(domain_base "$url")"
        done
    fi
done

欢迎提出任何建议!

【问题讨论】:

"让 /dev/tcp 使用 SSL" 但为什么呢? TLS 已经这么复杂了……为什么不直接设置一个本地通道呢?它会很好地为您处理 TLS,您只需通过 TCP/IP 在本地连接到它。 TLS 要求在交换任何数据之前在 TCP 之上进行各种交换,我怀疑您是否可以简单地在 bash 中重做,即使不考虑性能和安全限制。 我也使用这种技术来检查我的家庭网络上的端口可用性。很高兴知道如何使用 SSL。我刚刚遇到您的问题,正在寻找自己的答案。 【参考方案1】:

使用 OpenSSL 打开 SSL 套接字并使用 stdin stdout 与之对话

openssl s_client irc.freenode.net:7070

【讨论】:

以上是关于将 SSL 与 Bash 的 /dev/tcp 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

反弹shell基础

bash 网络接口

反弹shell方法总结

反弹shell的各种基础姿势

Linux下几种反弹Shell方法的总结---持续更新

Bash Special Redirection 分析