ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SQL Injection 마무리 [8주차]
    모의해킹스터디5기(feat.Normaltic) 2023. 12. 19. 18:38

     

     

     

     

     

    오늘로써 약 한 달 넘게 배웠던 SQL Injection을 마무리한다.

    그 동안 배웠던 것들을 상기하면서 SQLi의 포인트 찾기, 꿀팁 등을 추가로 정리해본다.


    SQL Injection point 찾기

    지금까지 SQLi의 기초부터 해서 UNION SQLi, Error Based SQLi, Blind SQLi 3가지의 심화된 공격 기법들을 배웠는데

    사실 가장 중요한 것은 그 기법들을 쓸 수 있는 공격 포인트를 찾는 것이다.

     

    지금까지 실습이라고 해봐야 사이트에서 문제를 풀어보는 것인데,

    문제 제목부터 어떤 기법을 써야하는지 알려주고, 떡하니 "여기에 SQL문을 삽입해라" 라고 로그인 창만 나와 있고,

    심지어 계정의 아이디와 비밀번호까지 친절하게 알려주면서 풀어왔다.

     

    당연히 실전은 이렇게 친절하지 않다. 그 많은 입력란 중에서 SQL문이 삽입되는 곳을 내가 직접 실험하면서 찾아야 한다.

    어떻게 보면 지금까지의 배운 것들 중에서 이게 가장 중요하고 필수적인 요소가 아닌가 싶다.

     

     

     

     

    1. SQL문이 어떻게 이루어져 있는가 생각하기!!

     

    SQLi를 삽입할 수 있는 부분은 많다. 그게 작동이 될지 안 될지는 모르는 일이지만.

    DB를 접근하는 그 SQL 구문이 어떻게 이루어져 있는가 먼저 생각을 해보고, 그 구문에 맞는 공격을 해야한다.

     

    로그인 페이지라면 

    SELECT * FROM user WHERE username = 'ID' AND pass = '비밀번호'

    와 같이 ' 사이에 입력 받은 글자가 들어가지만

     

    게시판의 경우

    SELECT * FROM board WHERE title LIKE '%제목%'

    처럼 ' 안에 %가 또 존재한다.

     

     

    그래서 normaltic' AND '1'='1 과 같은 흔히 아는 구문이 게시판에는 적용되지 않는다.

     

    SELECT * FROM board WHERE title LIKE '%normaltic' AND '1'='1%'

    (구문의 오류로 SQL문이 정상적으로 실행되지 않게 된다.)

    SELECT * FROM board WHERE title LIKE '%normaltic%' AND '1%'='1%'

    (게시판에서는 %를 고려하여 구문을 넣어야 한다.)

     

     

     

     

    2. 쿠키에서도 SQLi가 가능하다.

     

    웹페이지에서 드러나지 않지만 HTTP 요청 메시지의 내용을 조작하여 SQL문을 삽입할 수도 있다.

    그 중 먼저 쿠키를 조작하는 방식을 보겠다.

     

    1. 쿠키 SQLi

     

    실습 페이지의 마이페이지를 Burp Suite으로 확인해본 이미지다.

    Cookie: user=kkk;

     

    쿠키에 user 값을 기준으로 DB에 접근하는 것 같다.

    이제 여기에 SQL 구문을 넣어보겠다.

     

    2. 쿠키 SQLi 실험

     

    둘의 차이가 무엇인지 알 것 같은가

    마이페이지를 보면 kkk' AND '1'='1 로 참의 값을 입력하면 Nothing Here... 라고 정보가 나타나지만

    kkk' AND '1'='2 로 거짓의 값을 입력하니 아무것도 나타나지 않는다. SQL문에 조회된 것이 없는 것이다.

     

    쿠키의 값에도 SQL구문이 입력이 가능하고, 그 구문이 참과 거짓일 때 결과가 다르니 SQLi가 가능한 것이다.

     

     

     

     

    3. POST 방식의 COLUMN 부분을 조작하여 SQLi가 가능하다.

     

    3. POST 방식의 SQLi

     

    게시판에 작성자를 기준으로 k 라고 입력했을 때 나오는 화면이다.

    HTTP header를 보면 option_val, board_result 등등이 POST 방식으로 전달되고 있는 걸 볼 수 있다.

     

    이 중 option_val의 값은 username, title DB의 COLUMN을 나타내는 값들인데

    이 위치에 SQLi가 가능하다.

     

     username='kkk' and username

     

    이렇게 option_val 값을 넣어도 정상적인 조회 결과가 나온다.

     

    4. COLUMN SQLi

     

    username='kkk' and (조건) and username

     

    그렇다면 위와 같이 괄호 안의 참과 거짓을 분별하는 SQLi를 사용할 수 있다.

     

    5. COLUMN SQLi 참/거짓 결과

     

    물론 option_val 안에 다른 column을 이용해도 결과는 같다.

    title='test' and (조건) and title

     

    6. COLUMN SQLi 참/거짓 결과_2

     

    사실 이 원리를 정확히 아는 건 아니다..

    왜 굳이 and로 column을 한번 더 써야 하는지 아직 이해가 되지 않는다.

     

    오늘은 일단 형식만 숙지하고 다음에 한 번더 찾아봐야겠다.

     

     

     

     

    4. order (정렬) 부분에 SQLi가 가능하다.

     

    위의 내용과 비슷한 부분인데, POST 방식으로 전달하는 값 중에 정렬을 하는 부분(보통 sort 라고 지칭하는 것 같다.)에도

    SQLi가 가능하다.

     

    7. sort

     

    POST로 전달되는 파라미터 중 마지막에 sort=title 부분이 정렬 기준 컬럼을 받는 부분이다. 

     

     

    여기서 SQL 문법 중 CASE WHEN 을 사용한다. 다른 프로그래밍 언어의 IF문과 비슷하다.

    CASE WHEN (조건 1) THEN (식)
               WHEN (조건 2) THEN (식)
               ...
               ELSE (식)
    END

     

    이런 식으로 해당 조건에 맞는 식을 반환하는 구문인데 조건을 여러개 사용할 수 있다.

     

    SQLi에서 사용할 식은 다음과 같다.

    CASE WHEN (참/거짓 조건) THEN username ELSE title END

     

    참일 때는 username으로, 거짓일 때는 title을 기준으로 정렬하게 된다.

     

    8. order SQLi

     

    위의 실습은 참일 때 title을 기준으로, 거짓일 때는 date를 기준으로 정렬하도록 했다.

     

     

    추가로, CASE WHEN 구문의 식을 에러를 유발하는 식으로 사용할 수도 있다.

    CASE WHEN (참/거짓 조건) THEN 1 ELSE (SELECT 1 UNION SELECT 2) END

     

    SELECT 1 UNION SELECT 2는 단순하게 두 개의 행이 나와 정상적인 연산이 안되기에 에러를 발생한다.

     

    아무튼 이렇게 에러를 발생하면

    9. order SQLi error

     

    화면에 아무것도 안 뜨게 되니 참/거짓을 구분하기엔 더 좋을 수도 있다. 개인의 선택사항이다.

     

     

     

     


    SQLi 대응방안

    1. Prepared Statement

     

    SQLi를 예방하는 방법으로 가장 유명한 prepared statement.

    그 원리를 알려면 기존의 SQL문의 처리 과정부터 살펴봐야 한다.

    10. SQL문 실행 순서

     

    기존의 SQL문은 실행될 때마다 위의 과정을 전부 다 거쳐야 한다.

     

    하지만 prepared statement 방식을 사용하면 parse 단계를 건너뛴다.

    어차피 파라미터에 들어가는 값을 제외하고는 동일한 구문이기에 미리 컴파일된 구문을 캐시에 넣어 재사용하면 되기 때문이다.

     

    이렇게 하면 기존의 SQL문 처리 속도보다 훨씬 빠르게 처리 할 수 있다.

    애초에 prepared statement의 목적이 속도의 향샹이었다. 추가적으로 SQLi를 예방할 수도 있게 되었을 뿐.

     

     

    그럼 어떻게 SQLi를 예방할 수 있게 된 것일까.

    prepared statement 구문의 예시를 살펴보자.

    $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
    $stmt->bind_param("sss", $firstname, $lastname, $email);

     

    SQL 구문 속에 값이 들어갈 자리를 변수가 아닌 ? 로 지칭하고 있다.

    이 구문을 미리 컴파일한다. 그리고 나중에 들어가는 값들을 ? 자리에 치환하는 방식이다.

     

    이미 SQL 구문이 컴파일 되어서 SQLi를 삽입한다 해도 쿼리의 역할을 할 수 없다.

    들어가는 값들은 그저 문자열로 인식되어 글자가 하나하나 인코딩 된다.

     

    이 후 값들을 바인딩할 때 "sss" 는 뒤에 나오는 값들의 자료형을 차례대로 의미한다.

    ( "sss" - 뒤의 세 변수 모두 string이라는 뜻 ) 

    • i - integer
    • d - double
    • s - string
    • b - BLOB

     

    그렇다고 Prepared Statement가 모든 SQLi를 막는 무적의 예방법은 아니다.

    테이블, COLUMN, order by의 정렬 부분에는 사용이 불가한 것이 약점이다.

     

    그러니 SQLi도, 그것을 막는 방법도 계속해서 연구해야 한다.

     

     

     

    2. White List Filtering

     

    사용자가 안전하다고 생각되는 것들만을 허용하는 것이다.

    반대로 Black List Filtering은 사용자가 위험하다고 생각되는 것들을 금지하는 방식이다.

     

    예방법이 Black List Filtering이 아닌 이유는 위험한 구문을 일일이 금지하기엔 끝이 없기 때문인 것 같다.

     

     

     

     


    참조

     

    SQL Injection 그리고 PreparedStatement

    SQL 인젝션이란? 데이터베이스와 연동된 웹 애플리케이션에 공격자가 입력이 가능한 폼에 조작된 질의문 삽입하여 디비 정보 열람 및 정보를 조작하는 공격 단순한 기법이지만 강력한 공격이어

    giron.tistory.com

     

    PHP MySQL Prepared Statements

    W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

    www.w3schools.com

     

Designed by Tistory.