1. Enueration
: Port Scanning
# gunicorn 20.0.4
: Gunicorn은 WSGI(Web Server Gateway Interface)
애플리케이션을 위한 순수 Python HTTP 서버로
해당 버전에는 HTTP request smuggling이라는
알려진 취약점이 있다.
우선 requset smuggling과 관련한 자세한 내용은
https://portswigger.net/web-security/request-smuggling
을 참조하고 대강 이해한 것을 정리해 보면 다음과 같다.
smuggling이라는 단어의 뜻은
마약을 밀수하다 할 때의 그 밀수라는 뜻이고
어떤 이유로 기존 HTTP request의 body에
또 다른 HTTP ruquest를 밀반입해 요청 시
해당 요청이 정상 처리되는 취약점이라 할 수 있는데
gunicorn 20.0.4 버전의 경우,
request header 부분의 Sec-Websocket-Key1
(Sec-Websocket-Protocol에서 서버의
handshake를 위한 정보를 계산하기 위해 필요한 값)
이라는 헤더를 분석하는 과정에서
이러한 HTTP request smuggling
취약점이 발생하게 된다.
원인은
/gunicorn/http/message.py 파일에는
들어오는 요청의 헤더(request header)를 기반으로
요청 본문의 크기를 결정하고 이를 읽어주는
reader를 생성하는 set_body_reader라는 함수가
있는데
만약 들어오는 요청(request)에
Sec-Websocket-Key1헤더가 포함되어 있으면
Content-Length 크기가 얼마든
요청 내 콘텐츠(body) 길이를 8 byte로
간주하기 때문.
여기 다음과 같은 요청이 있다.
GET / HTTP/1.1
Host: takudaddy.com
Content-Length: 48
Sec-Websocket-Key1: x
xxxxxxxxGET /admin HTTP/1.1
Host: takudaddy.com
프록시는 Content-Length 헤더를 보고
body 부분 내 모든 데이터를 포함하는 요청을
전달하는데
해당 요청이 gunicorn에 도달하면
gunicorn은 Sec-Websocket-Key1 헤더를 보고
Body 부분 데이터 중 8 byte 크기인
xxxxxxxx만 우선 읽어들인다.
이때 프록시와 gnicorn은
HTTP-keep-alive 상태이므로
gunicorn은 xxxxxxxx 다음에 이어지는 데이터들을
동일한 TCP connection 상의 다음 요청(next request)로
읽어드리고
이렇게 데이터를 가장한 request가
밀수되어 처리되는 것 같은 형태 때문에
HTTP request smuggling이라는
이름이 붙여지게 된 것 같다.
해당 취약점을 악용하면
접근 권한이 없는 특정 경로에
access가 가능해지고 중요한
데이터를 읽어올 수 있는 등의
행위가 가능하다.
:web enum
> 원래는 외부 네트워크에 노출되면 안 되는
중요한 API 란다.
본문 내용 중 힌트가 되는 부분을 살펴보면
update URL이
POST 방식으로
JSON 데이터를 요청 시
/update 엔드포인트에
해당 요청을 전달할 수 있다고 한다.
또한
/logs 엔드포인트에 접근하면
로그 파일들을 읽을 수 있다는데
접속해 보면 다음과 같은 메시지가 뜨며
웹 애플리케이션의 방화벽에 의해
접근이 제한되는 것을 확인할 수 있다.
2. Exploitation
우선 /update 엔드포인트는
당장 사용자 명을 알 방도가 없으니
건너뛰고 /logs 엔드포인트를 파본다.
2-1) Bypass WAF
WAF 에러 메시지 내용대로
외부 네트워크로 인식되는
지금 호스트로는 접근 권한이
없는데
전에 풀었던 문제(15. Robust)에서
사용했던 해결 방법 중 하나인
XFF (X-Forwarded-For)
: 서버에 요청한 사용자의 IP를 식별하기 위한 표준 기능!
헤더를 추가해 요청하면
WAF 우회가 가능하고
에러 메시지 내용을 살펴보면
file 파라미터를 통해
로그파일 경로를 지정하라고 하니
LFI가 가능하다고 추정되며
/update 경로를 공략하기 위해서는
사용자 이름 확인이 필요하기 때문에
passwd 파일을 불러오면
정상 조회 가능!
2-2) Update /update
업데이트를 위해
사용자 이름, update를 위해
받아올 파일의 경로가 필요한데
root 외의 사용자는 하나뿐이고
이름을 확인했으니 업로드 실험을 해볼 수 있고
파이썬 웹 서버를 기동해 주고
아무 파일이나 호출해 보면
정상 업로드가 가능하다.
쉘 생성 후
업데이트
> restart 하란다
리스너 기동 후
/restart 요청하면
안되는데
소스를 보면
재시작 요청은 GET 방식이 아니라
POST 방식으로 요청해야 한단다.
반영하여 재 요청하면
성공적으로 재시작 되면서
침투 성공!
3. Privilege Escalation
wget에 SUID가 걸려있고
새로운 사용자를 passwd 파일에
생성 후 받아 주면 되겠다.
암호 생성을 위해 주로 사용하는 방법은
크게 두 가지로
1. python
python -c 'import crypt;print(crypt.crypt("taku","taku"))'
ta0LWDW4m3OdU (password=taku)
---------------------------------------------------------
2. openssl
# openssl passwd taku
cF3uSulrnlYNs (password=taku)
(salt 키 지정해 생성하는 경우)
# openssl passwd -1 -salt takudaddy taku
$1$takudadd$KETef9oIkYFX0zLAs6XjM. (password=taku)
아무거나 사용해 암호를 생성해준 뒤
passwd 파일 형식에 맞춰 passwd 파일로
저장해주고
파이썬으로 웹서버 기동한 뒤
wget으로 /etc/passwd 에 저장해
확인해보면
passwd 파일에는
변조한 사용자 하나만
들어가 있고
해당 사용자로 로그인 하면
끝!
'OSCP > Proving Ground' 카테고리의 다른 글
31. Matrimony (GET TO WORK) - Linux (dig, DNS zone transfer, docker*) (0) | 2022.08.26 |
---|---|
30. Fail (GET TO WORK) - Linux (rsync, ssh, fail2ban) (0) | 2022.08.25 |
28. Lunar (GET TO WORK) - Linux (php strcmp, nfs no_root_squash) (0) | 2022.08.20 |
27. Roquefort (GET TO WORK) - Linux (0) | 2022.08.18 |
26. Sona (GET TO WORK) - Linux (2) | 2022.08.15 |