HTTP Request Smuggling

buaii·2023년 9월 18일
0

CTF

목록 보기
2/5

HTTP Request Smuggling

주말에 팀원분들과 함께 HITCON CTF에 참여했다
Login System이라는 web문제를 시도했지만 못풀었다 ㅠ

WriteUp
https://github.com/maple3142/My-CTF-Challenges/tree/master/HITCON%20CTF%202023/Login%20System

대회가 끝나고 문제를 만드신 분의 write-up을 보고 알게된 내용을 정리하고자 한다
0xOne님의 PPT자료도 참고해서 정리했다

우선 웹 기능부터 살펴보자

유저를 등록하고 로그인하면 profile을 보여주는 정말 단순한 웹서버이다






HTTP Request Smuggling

Reverse Proxy Server 또는 Load Balance 사용 시 
CL(Content Length)와 TE(Transfer-Encoding)의
⁠처리를 프론트엔드와 백엔드가 다르게 한다는 점을 이용한 공격

Background

  • Proxy : 일반적인 Proxy 서버, 클라이언트의 요청을 가로채서 서버에게 보내고
    ⁠    서버에게 받은 Response를 다시 클라이언트에게 반환

  • Reversed Proxy : 웹 서버로 오는 요청을 가로채는 Proxy 서버, 주로 Load Balancing에 활용
    서버의 IP를 노출시킬 필요가 없어짐, 성능 향상을 위한 캐시 데이터 저장 가능
    (Load balancing) : 서버가 처리해야할 업무를 분산처리

HTTP Request Smuggling

Reverse Proxy Server 또는 Load Balance 사용 시 
CL(Content Length)와 TE(Transfer-Encoding)의 처리를 
프론트엔드와 백엔드가 다르게 한다는 점을 이용한 공격



⁠Content Length는 말 그대로 body의 총 길이를 인식

Transfer Encoding은 컨텐츠 인코딩 방식을 결정
chunked는 데이터를 분산 청크로 전송, 각 Chunk는 Length와 Data로 구분

  • ⁠⁠CL.TE : Front가 CL을 통해 판단, Back은 TE를 통해 판단
  • ⁠TE.CL : Front가 TE를 통해 판단, Back은 CL을 통해 판단
  • ⁠TE.TE : Front와 Back 둘다 TE로 판단




아래는 chunked가 데이터를 처리하는 방법을 나타낸 사진이다


body의 데이터 길이를 계산할 필요가 없으며, 각각의 chunk마다 길이가 주어지고 0의 길이를 받으면 패킷이 끝나는 걸로 확인한다
이처럼 0으로 판단하냐, 제공된 길이를 통해 판단하느냐의 차이로 CL.TE , TE.CL이 가능하게 된다


CL.TE

Frontend에서 Cotent Length를, Backend에서 Transfer-Encoding을 이용하여 패킷 길이를 계산하는 경우 Exploit

CL은 SMUGGLED 까지 패킷으로 인식
TE는 0 까지 패킷으로 인식

즉, 프론트엔드에서는 SMUGGLED까지를 패킷으로 받아들여 통과했지만, 백엔드에서 SMUGGLED는 새로운 패킷의 시작점으로 인식하게 된다



TE.CL

Frontend에서 Transfer-Encoding를, Backend에서 Content-Length을 이용하여 패킷 길이를 계산하는 경우 Exploit


TE는 0 까지 패킷으로 인식
CL은 8 까지 패킷으로 인식

즉, 프론트엔드에서는 0까지 패킷으로 받아들여 통과했지만, 백엔드에서 SMUGGLED는 새로운 패킷의 시작점으로 인식하게 된다



TE.TE

⁠Frontend, Backend 모두 Transfer-Encoding를 통해 패킷 길이를 계산하는 경우

위 사진처럼 어떤 방식으로든 헤더를 난독화 하여, Front & Back 둘 중 하나가 헤더를 처리하지 않도록 함


WriteUp

HTTP Requests Smuggling에 대해서 알아보았으니 문제를 확인해보자
문제에서 사용된방법은 TE.TE가 사용되었다

nim과 node.js모두 TE를 통해 패킷을 인식한다
nim에서는 대문자 CHUNKED를 처리하지 못하지만,
node.js는 문제없이 읽어들이게 된다

writeup의 코드를 보면 POST /change_password HTTP/1.0...을 data에 담아
HTTP smuggling을 작동하게 하고 비밀번호 변경을 권한없이도 실행하게 한다

그리고 username을 입력값 검증없이 파일명으로 그대로 사용하고 있다
username에 ../../같은 pathtravelsal을 넣어도 문제가 없다는 뜻이다

사용자 이름을 조작하여 설정파일로 만든 후
새로운 계정을 조작된 설정파일을 사용하도록 한다면 원하는대로 권한을 사용할 수 있게 된다

writeup을 보면 위 방법을 사용해서 yaml파일을 생성 후
privilegeLevel을 js코드로 작성해 flag를 출력하도록 되어있다

yamluser = os.urandom(8).hex()
json_inject(
    yamluser + ".yaml\0",
    """"peko", "access": {"profile": true, "flag":true}, "privilegeLevel": { toString: !!js/function "function(){ console.log('pwned'); flag=process.mainModule.require('child_process').execSync('/readflag','utf-8').toString(); return flag }" } } # """,
    priloc="after",
)

대회참여날 문제풀때는 단순히 /flag엔드포인트에 접근하는걸 목표로 했지만
지금 다시 코드를 보니 flag를 hash처리해서 보여주기 때문에 flag를 알 수 가없다

그래서 단순히 flag권한을 부여하는게 아니라 privilegeLevel에 ejs가 실행가능한 코드를 넣어주는 것이다

exploit

결론적으로 exploit이 되는 과정을 정리하자면

  1. username.yaml\0을 넣어 설정파일로 만들어지게 한다
  2. HTTP Requests smuggling을 통해 PrivilegeLevel에 js코드를 삽입한다
  3. 두번째 계정을 만든다
  4. HTTP Requests smuggling을 통해 PrivilegeLevel이 pathtravesal을 통해 1번에서 만든 설정파일로 지정되도록 해준다
  5. 두번째 계정으로 login하여 privilegeLevel을 확인해 flag를 획득한다


exploit코드를 실행해보면 privilegeLevel에서 pathtravelsal이 잘 된걸 확인할 수 있다

web에서 확인한 flag이다

profile
buaii

1개의 댓글

comment-user-thumbnail
2023년 9월 24일

오 저도 요번에 HTTP Request Smuggling에 관한 CTF문제를 풀었지만 정확하게 이해는 되지 않았는데, 이 글보고 좀 더 확실해게 HTTP Request Smuggling에 대해 알게되었습니다.

답글 달기

관련 채용 정보