3번 문제도 2번 문제와 같이 DB 그림이 있다.
따라서 이번 문제도 SQLi를 이용해서 문제를 푸는것 같다.
클릭해보자.
클릭해보니 이렇게 이상한 판이 나왔다.
처음에는 뭘까?하고 숫자가 입력이 되어있길래 나도 숫자를 입력해야하나? 싶어서
빈칸을 클릭해보았다.
근데 아래의 5*5만 클릭이 되었다.
숫자를 입력하는줄알았지만 이렇게 뭔가 규칙을 맞춰야하는것 같다.
하지만 아직도 지뢰찾기나 이런 규칙이 있는 퍼즐? 퀴즈? 같은걸 별로 안좋아한다.
따라서 위의 그림처럼 그냥 다 클릭하고 solved라는 버튼을 클릭해보았다.
solved를 클릭하면 GET 형식으로 다음과 같은 URL로 서버로 요청한다.
https://webhacking.kr/challenge/web-03/index.php?_1=1&_2=1&_3=1&_4=1&_5=1&_6=1&_7=1&_8=1&_9=1&_10=1&_11=1&_12=1&_13=1&_14=1&_15=1&_16=1&_17=1&_18=1&_19=1&_20=1&_21=1&_22=1&_23=1&_24=1&_25=1&_answer=1111111111111111111111111
그리고 브라우저에서는 다음과 같은 모습을 볼 수 있다.
여기까지 정리하면
총 5*5 빈칸 하나가 의미하는건 URL의 파라미터에 _1, _2 ... 이렇게 표현이 되는것 같다.
예를들어 첫번째칸은 파라미터 _1...
그리고 클릭을 해서 검은색으로 되면 파라미터 값은 1이 되고 클릭이 안되면 0이 되는것 같다.
그리고 5*5이기 때문에 _1,_2...._25를 전부 합친것이
answer=1111111111111111111111111로 표현되는것 같다.
페이지 소스를 봐도 go()라는 함수가 사용자가 클릭한 칸을 전부 합쳐서
문자열로 1111111111111111111111111을 만들어 주는것 같다.
그래서 _1과 _2..._25에 SQLi를 수행 보았다.
근데 별 다른것이 없었다...
마찬가지로 answer에도 SQLi를 수행 보았다.
여기서도 별 다른 반응이 없었다.
그럼 어떻게 할까?
저 퀴즈를 풀어야하나???
근데 풀기가 너무 귀찮아서.
brute force로 그냥 보내버릴까? 해서 코드를 작성을 해보았다.
근데 짜던 도중 생각해보니 표현 할 수 있는 숫자는 0, 1이고 자릿수는 25자리다.
그럼 brute force를 수행한다면... 엄청 낭비다..
따라서, 퀴즈를 풀어야할것같다...
뭐 여러 사이트를 참조하고 문제를 푸는 방법을 익힌 후 문제를 풀고 solved를 눌러보았다.
이렇게 Clear 했다는 문구와 함께 log를 남기기 위해 이름을 입력하라는 문구가 나오고
submit 버튼이 나왔다.
따라서 test!!라고 입력을 해보았다.
test!!라고 입력해본 결과 입력한 이름 test!!과 아까 퀴즈에서 풀었던 answer와 ip가 log처럼 남겨졌다.
log을 남기기 위해 submit을 클릭했을때 발생하는 패킷은 다음과 같다.
POST 형식으로 answer에는 아까 퀴즈에서 푼것이 들어가있으며
파라미터 id에는 앞에서 입력한 test!!가 URL 인코딩 되어 있다.
여기까지 정리해보자면
URL: https://webhacking.kr/challenge/web-03/index.php?_1=1&_2=1&_3=1&_4=1&_5=1&_6=1&_7=1&_8=1&_9=1&_10=1&_11=1&_12=1&_13=1&_14=1&_15=1&_16=1&_17=1&_18=1&_19=1&_20=1&_21=1&_22=1&_23=1&_24=1&_25=1&_answer=1111111111111111111111111
- 위의 URL 파라미터에서는 SQLi가 발생하는 곳은 없었다.
- 퀴즈를 풀고 나니 log를 남길 수 있는 곳을 찾았다.
- log를 남길때 발생하는 패킷에 answer과 id라는 파라미터 2개가 생겼다.
- 3번에서 찾은 파라미터 2개에 대해서 SQLi를 수행해보자.
이렇게 answer의 마지막에 SQLi를 테스트하기위해 '를 입력하고 서버로 요청해보았다.
이렇게 query error!라는 문구와 함께 오류가 난다.
여기다! (Point 1)
여기서 SQLi를 수행하면 될것 같다.
이렇게 answer에 1'+and+1=1#이라고 입력을 해주었다.
하지만 이렇게 빈 페이만 나온다.
쿼리가 오류이면 분명 query error!라는 문구가 보일 것인데 보이지가 않았다.
다음은 answer에 1'+and+1=0#을 입력해보았다.
1'+and+1=1#나 1'+and+1=0#이 해당 쿼리를 만들어낸 과정은 다음과 같다.
- 원래의 answer 끝에 '를 삽입하자 query error!라는 문구가 보임.
- 따라서 여기서 SQLi를 수행.
- '를 삽입했으니 원래의 정상적인 쿼리 마지막에는 '가 한개가 남음.
- 이 마지막 한개의 '를 처리하기 위해 주석인 #을 추가함.
결과는 또 빈페이지...
뭘까? 하고 생각을 해보았다.
log에서는 3개를 볼 수있었다.
입력한 이름(id)와 answer 마지막으로 ip 이렇게 3개를 볼 수 있었는데
내가 입력한 answer에 1'+and+1=1#, 1'+and+1=0#이 잘 먹힌지를 보기위해서는
먼저 log에 answer가 1이라는것을 먼저 등록을 해주어야 참/거짓의 반응을 살펴 볼 수 있을것 같다.
이렇게 answer에 1을 넣고 id에는 test를 넣고 먼저 서버로 보내 log를 남겼다.
서버에서는 쿼리상에 문제가 없기 때문에 이렇게 log를 남겨준다.
이제 다시 answer에 1'+and+1=1#, 1'+and+1=0#이 잘 먹히는지 살펴보자.
위의 그림에서 answer 부분이 1' and 1=1# and 기준으로
왼쪽 오른쪽이 참이기 때문에 위에서 남긴 로그가 나와야한다.
이렇게 잘나왔다.
이제 1'+and+1=0#를 입력하고 서버로 요청해보자.
여기서 만약에 빈페이지가 나온다면 여기서 SQLi를 수행하는것이 확실해 진다!
빈페이지가 나오는것으로 보아 여기서 SQLi를 수행하는것이 확실해 졌다.
따라서 앞의 문제처럼 DB명의 길이와 DB명을 알아보자!!
코드를 작성하여 DB의 길이를 알아내보니 10자리였다.
이제 DB의 길이를 구하고 이제 DB 명을 알아내야한다.
근데 가만히 생각을 해보니 이번 문제가 DB명을 알아내고 table명, column명을 알아낼 필요가 있을까?
뭔가 위의 과정을 통해 answer라는곳에 SQLi를 하는건 맞는거같은데..
flag값처럼 출제자가 원하는 answer라는 값을 알아내야하는건가?
그러면 DB명과 table명, column명을 알아내서 answer라는 값을 알아내야하는건 맞다.
근데 answer라는 값을 항상 참으로 만들면???
그래서 answer에 아래와 같이 1'or+'1를 넣어봤다.
풀렸다...