반응형

 

문제를 보면 다음과 같이 또 DB 모양이 있다.

 

이번 문제도 SQLi 문제일까? 하는 생각에 문제를 클릭해보자.

 

 

문제를 클릭하면 다음과 같이 LoginJoin 창이 보인다.

 

Login을 눌러보자.

 

 

Login을 눌르면 이렇게 IDPW를 입력하는 창이 나온다..

 

별다른 정보가 없기 때문에 페이지 소스를 보았다.

 

 

페이지 소스 보기를 봐도 별 다른 정보가 없어서 test/test를 입력해보았다.

 

 

 

test/test을 입력하고 login을 클릭한 결과 Wrong password라는 문구와 함께 다시 login 폼이 보인다.

 

IDPW를 알아내기 위해 IDPWSQLi를 수행보았지만 별다른 반응이 없었다.

 

따라서 이번 문제를 풀기 위해서는 계정을 알아야할것같았다.

 

따라서 제일 처음으로 돌아와 Join을 눌러보았다.

 

 

Join을 눌러 보니 Access_Denied이라는 문구와 함께 Join을 할 수 없게 되어있다.

 

페이지 소스에서도 아무런 정보도 찾을 수도 없고, ID, PWSQLi도 안먹히고..

 

그 다음 할 것이 없어 URL 주소를 보았다.

 

로그인 화면의 URL은 다음과 같다.

 

https://webhacking.kr/challenge/web-05/mem/login.php

 

우리는 할 수 있는 시도를 다 해보았고 문제에 힌트가 될 정보가 없기 때문에

 

https://webhacking.kr/challenge/web-05/mem를 입력하여

 

디렉토리 인덱스 취약점이 있는지 살펴보았다. 

 

여기서 말하는 디렉토리 인덱스 취약점을 짧게 정리하면 다음과 같다.


웹 애플리케이션을 사용하고 있는 서버의 미흡한 설정으로 인해 인덱싱 기능이 활성화 되어 있을 경우

공격자가 강제 호출을 통해 서버내의 모든 디렉터리 및 파일에 대해 접근이 가능하며

웹 애플리케이션 및 주요 정보가 노출될수 있는 취약점이다.


https://webhacking.kr/challenge/web-05/mem를 입력하니 디렉토리 인덱스 취약점이 발견되었다.

 

 

여기서 우리가 원하는 페이지인 join.php 페이지를 볼 수 있다.

 

join.php 페이지를 클릭해보자.

 

 

클릭하니 bye라는 문구와 함께 검은색 창만 보인다.

 

뭐지??하고 맨날 보았던 페이지 소스를 보았다.

 

 

script 태그에 이상한 script가 존재하였다.

 

원래의 보통의 script가 아니였기 때문에 이게 힌트일 것 같았다.

 

HTMl 소스코드를 가독성 있게 보면 다음과 같다.

 

<html>
<title>Challenge 5</title>
</head>

<body bgcolor=black>
<center>
<script>
l='a';
ll='b';
lll='c';
llll='d';
lllll='e';
llllll='f';
lllllll='g';
llllllll='h';
lllllllll='i';
llllllllll='j';
lllllllllll='k';
llllllllllll='l';
lllllllllllll='m';
llllllllllllll='n';
lllllllllllllll='o';
llllllllllllllll='p';
lllllllllllllllll='q';
llllllllllllllllll='r';
lllllllllllllllllll='s';
llllllllllllllllllll='t';
lllllllllllllllllllll='u';
llllllllllllllllllllll='v';
lllllllllllllllllllllll='w';
llllllllllllllllllllllll='x';
lllllllllllllllllllllllll='y';
llllllllllllllllllllllllll='z';
I='1';
II='2';
III='3';
IIII='4';
IIIII='5';
IIIIII='6';
IIIIIII='7';
IIIIIIII='8';
IIIIIIIII='9';
IIIIIIIIII='0';
li='.';
ii='<';
iii='>';

...... 생략 ........

</script>
</body>

</html>

 

뭔가 딱 보자마자 바로 느낌이 왔다.

 

치환이다!!

 

예를 들어보자.

 

l='a';

 

말 그대로 l은 a이다. 

 

생략한 코드를 치환하면 다음과 같다.

 

<html>
<title>Challenge 5</title></head><body bgcolor=black><center>
<script>


...... 생략 ........

if(eval(document.cookie).indexOf(oldzombie)==-1) 
{
    alert('bye');
    throw "stop";
}

if(eval(document.'U''R''L').indexOf(mode'='+1)==-1)
{
    alert('access_denied');
    throw "stop";
}

else
{
    document.write('<font size=2 color=white>Join</font><p>');
    document.write('.<p>.<p>.<p>.<p>.<p>');
    document.write('<form method=post action='join.php'>');
    document.write('<table border=1><tr><td><font color=gray>id</font></td><td><input type=text name='+id+' maxlength=20></td></tr>');
    document.write('<tr><td><font color=gray>pass</font></td><td><input type=text name='+pw+'></td></tr>');
    document.write('<tr align=center><td colspan=2><input type=submit></td></tr></form></table>');
}
</script>
</body>
</html>

 

이렇게 위의 코드처럼 치환하면 문제를 풀 수 있을 듯하다.

 

코드를 분석해보자.

 

 

위의 코드는 현재 cookie값 중에 oldzombie 라는 값이 있는지 체크하는것이다.

 

즉, 현재 cookie값 중에 oldzombie가 없다면 bye라는 문구와 함께 alert창을 볼 수 있다.

 

따라서 먼저 이 부분을 우회를 해야할것같다.

 

따라서 cookie 이름은 test, 값은 oldzombie를 설정하는 명령어로 cookie값을 설정해보았다.

 

 

그리고 다시 join.php 페이지에 접속해보았다.

 

 

아까와는 달리 access_denied라는 문구를 볼 수 있다!!

 

그럼 그 아래의 코드 또한 우회 해주면 된다!!

 

document.URL 값은 다음과 같이 'https://webhacking.kr/challenge/web-05/mem/join.php' 값이다.

 

 

근데 위의 소스코드에서는 oldzombie처럼 mode=1이 있는지 확인하는것이다.

 

따라서 https://webhacking.kr/challenge/web-05/mem/join.php/mode=1를 입력해보았다.

 

 

이처럼 Join 할 수 있는 폼이 생겼다.

 

여기서 JoinIDPW를 입력하고 제출 버튼을 눌러보자.

 

 

 

이제 Login.php에 접속해서 가입한 정보로 로그인을 해보자!

 

 

이렇게 로그인은 된다.

 

하지만 admin이 아니라는 문구가 뜬다.

 

따라서 이 문제의 출제 의도는 admin으로 로그인을 해야 한다는 것이다.

 

그럼 다시 Join.php에서 admin으로 가입해보자.

 

 

 

????

 

이미 admin이라는 계정이 존재한다.

 

하지만 이번 문제는 admin으로 로그인을 해야 한다.

 

앞에서 로그인 화면에선 SQLi가 통하지 않았기 때문에 이번 문제는 Join.php에서

 

admin으로 가입을 해야한다.

 

가입할때의 패킷을 보자.

 

다음과 같다.

 

id와 pw라는 파라미터로 입력한 admin123POST 형식으로 서버로 넘어간다.

 

예전에 학교 다닐때 DB에 저장될때 띄어쓰기나 공백이 들어가면 저장되는 형태에 따라서

 

'admin'과 'admin '이 같다는걸 배운적이 있다.

 

따라서 id값에 'admin' 대신 'admin '로 서버로 보내봤다.

 

그 후 로그인을 해보았다.

 

 

기억을 더듬어 문제는 풀었는데 정확하게 기억이 나지 않아서 찾아보았다.

 

https://techblog.woowahan.com/2559/ 여기서 정말 자세히 설명이되어있다.

 


쉽게 정리하자면 mysql DB에서는 'a'와 'a ' 또는 ' a'는 같다라고 인식을 한다.

 

즉, 공백이 있어도 같은 문자나 문자열이라고 인식을 한다는것이다.

 

하지만 이건 DB에 저장될때의 자료형이 CHAR일때만 가능하다.

 

비교하려는 두 문자열의 길이가 다른 경우

 

짧은 쪽에 공백을 이어붙여 길이를 똑같이 만든 다음 비교하기 때문에 발생하는 일이다.

 

이런 식이라면 'admin'와 'admin  '를 비교해도 똑같을 수밖에 없다.


반응형

'웹 해킹 > Webhacking.kr' 카테고리의 다른 글

7. old-07  (0) 2021.11.04
6. old-06  (0) 2021.11.03
4. old-04  (0) 2021.11.01
3. old-03  (0) 2021.10.19
2. old-02  (0) 2021.10.18
반응형

 

4번 문제이다.

 

3번 문제는 DB 모양이여서 SQLi 공격을 이용하면 될것같았지만

 

4번 문제는 뭘 의미하는지 모르겠다.

 

원래 저 모양은 소스코드나 코드를 의미할때 많이 쓰이는 그림인데...

 

일단 문제를 클릭해서 보자.

 

 

클릭하면 초록색 글씨로 어떤 값이 나오고 Passwrod를 입력하는 칸이 나온다.

 

test라고 입력하고 발생하는 패킷을 한번 보자.

 

POST 형식으로 key라는 파라미터 우리가 입력한 test를 볼 수 있다.

 

그 후 페이지 소스를 보니 딱히 뭐 별다른게 없어보인다.

 

따라서 문제에서 주어진 [view-source]를 클릭해서 소스를 보자.

 

 

[view-source]를 클릭하면 해당 문제의 소스코드를 볼 수 있다.

 

php 코드를 보여주는데 핵심은 여기인것 같다.

 

일단 sleep(1)함수가 먼저 보인다.

 

주석으로는 anti brute force가 적혀있다.

 

나는 이 주석을 보고 힌트를 얻었다.

 

일단 굳이 sleep을 준 이유도 없을것이고 주석으로 친절히 anti brute force로 적어준것으로 보아

 

몇번으로 해결된 문제가 아닌거 같았다.

 

그 다음줄을 보자.

 

if문을 크게 2개로 나눠보면 (isset($_SESSION['chall4']) ($_POST['key'] == $_SESSION['chall4']) 로 나눌 수 있다.

 

이 2개가 참이면 solve(4)가 실행되면서 문제를 clear 할 수 있을것 같다.

 

php에서 isset은 $_SESSION['chall4']) 이라는 변수가 설정되어있는지 확인하는 함수이다.

 

다음 우리가 password에 입력한 key값이 $_SESSION['chall4']) 와  &&,

 

즉 같다면 solve(4) 함수를 실행 할 수 있다.

 

그 후 코드를 보자.

 

$hash rand(10000000,99999999)."salt_for_you";

 

위의 코드는 rand 함수를 사용하여 랜덤한 숫자를 만들어내는 함수이다.

 

범위는 10000000 ~ 99999999이다.

 

그리고 뒤에 salt로 "salt_for_you"에가 존재한다.

 

예를들어 rand 함수에서 12345678가 생성되었다면

 

$hash 라는 변수에는 12345678salt_for_you가 저장된다.

 

그 다음은 $_SESSION['chall4'] = $hash;으로 위의 12345678salt_for_you의 값이 해당 변수에 저장된다.

 

마지막 코드는 for문을 돌리는데 12345678salt_for_you 값은

 

sha1 함수를 돌리고 다시 hash 변수에 넣어주고 이걸 500번 반복한다.

 

여기까지 정리해보자면 다음과 같다.

  1. 주석에 anti brute force이 있는걸 보아 한번에 답을 찾을수는 없을것 같다.
  2. 우리가 입력하는 key값 즉 password와 hash값이 같아야한다.

그럼 내가 출제자가 원하는 방향으로 문제를 해결하기위해서는 

 

rand 함수의 범위를 10000000,99999999를 주고 위에 솔트 문장을 짜서 brute force

 

값을 서버로 날려봐도 소용이 없다.

 

sleep 함수도 있고 주석에도 친절하게 anti brute force라고 적혀있으니..

 

조금 생각해보니 문제를 클릭했을때 무슨초록색으로 무슨 값이 나왔었다.

 

총 크기도 20 바이트고.. sha1으로 나온 hsah 값인것같다.

 

 

그러면 저기 나오는 초록색 hsah 값은 총 sha1을 500번 돌린 값이라는걸 알 수있다.

 

하지만 sha1이 처음 실행되는 인자에는 rand 함수에서 12345678가 생성되었다면

 

제일 처음 $hash 라는 변수에는 12345678salt_for_you가 들어간다.

 

그 후 sha1을 500번 돌린 hash값을 변수 $hash에 최종적으로 넣는다.

 

그 값이 우리가 볼 수 있는 초록색 값이고 이것은 

 

즉, 처음 만들어진 12345678salt_for_you이 값을 찾아야하는 문제인것 같다. (Point 1)

 

그럼 이 문제를 풀기위해서는 다음과 같이 생각할 수 있다.

  1. 먼저 문제에서 나오는 해쉬값을 본다.
  2. 그 후 문제처럼 rand(10000000,99999999)를 통해 숫자를 정한다.
  3. 나온 숫자 뒤에 "salt_for_you"를 합쳐준다.
  4. 나온숫자+salt_for_you(ex 12345678salt_for_you)를 sha1으로 500번 돌린다.
  5. 500번 돌린 hash값과 문제에서나오는 hash 값을 비교한다. 
  6. 맞으면 정답은 12345678salt_for_you
  7. 아니면 다시 처음부터 수행한다.

하지만 이렇게 하다보면 webhacking.kr 서버와 세션이 끊어질 수 있다.

 

실컷 답을 찾아 12345678salt_for_you를 입력하려고 할때 로그인을 다시해야한다.

 

그러면 다시 찾아야한다.

 

따라서 이번 문제는 핵심 포인트는

 

rand이 아닌 처음값인 10000000부터 마지막 값인 99999999 까지 값을 미리 사전에 만들어

 

sha1으로 500번 돌린 값을 미리 구해 비교하면 훨씬 빠르다. (Point 2)

 

그리고 모든 10000000~99999999 까지 모든 값을 할 필요도 없다.

 

물론 10000000~99999999 까지 모든 값을 사전에 준비하면 한번에 문제를 풀 수는 있지만

 

어차피 이번 문제는 확률문제이다.

 

따라서 나는 4분의 1인 값인 10000000~25000000만 미리 계산하였다.

 

이렇게 총 만들어진 파일의 용량은 761MB이다.

 

해당 소스는 다음과 같다.

 

이렇게 hash.txt라는 파일을 만든 후  문제에서 주어진 hash값을 파일에서 찾으면 이번 문제는 clear다.

 

 

 

 

반응형

'웹 해킹 > Webhacking.kr' 카테고리의 다른 글

6. old-06  (0) 2021.11.03
5. old-05  (0) 2021.11.01
3. old-03  (0) 2021.10.19
2. old-02  (0) 2021.10.18
1. old-01  (0) 2021.10.18
반응형

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!!과 아까 퀴즈에서 풀었던 answeriplog처럼 남겨졌다.

 

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

  1. 위의 URL 파라미터에서는 SQLi가 발생하는 곳은 없었다.
  2. 퀴즈를 풀고 나니 log를 남길 수 있는 곳을 찾았다.
  3. log를 남길때 발생하는 패킷에 answer과 id라는 파라미터 2개가 생겼다.
  4. 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#이 해당 쿼리를 만들어낸 과정은 다음과 같다.

 

  1. 원래의 answer 끝에 '를 삽입하자 query error!라는 문구가 보임.
  2. 따라서 여기서 SQLi를 수행.
  3. '를 삽입했으니 원래의 정상적인 쿼리 마지막에는 '가 한개가 남음.
  4. 이 마지막 한개의 '를 처리하기 위해 주석인 #을 추가함.

 

결과는 또 빈페이지...

 

뭘까? 하고 생각을 해보았다.

 

log에서는 3개를 볼 수있었다.

 

입력한 이름(id)와 answer 마지막으로 ip 이렇게 3개를 볼 수 있었는데

 

내가 입력한 answer 1'+and+1=1#, 1'+and+1=0#이 잘 먹힌지를 보기위해서는

 

먼저 log에 answer1이라는것을 먼저 등록을 해주어야 참/거짓의 반응을 살펴 볼 수 있을것 같다.

 

이렇게 answer에 1을 넣고 id에는 test를 넣고 먼저 서버로 보내 log를 남겼다.

 

서버에서는 쿼리상에 문제가 없기 때문에 이렇게 log를 남겨준다.

 

이제 다시 answer1'+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를 넣어봤다.

 

풀렸다...

 

반응형

'웹 해킹 > Webhacking.kr' 카테고리의 다른 글

6. old-06  (0) 2021.11.03
5. old-05  (0) 2021.11.01
4. old-04  (0) 2021.11.01
2. old-02  (0) 2021.10.18
1. old-01  (0) 2021.10.18
반응형

먼저 old-01 문제를 클릭해서 들어가 본다면 다음과 같은 화면을 볼 수 있다.

 

딱히 다른 기능이 없어 보이므로 view-source를 클릭해보자.

 

 

view-source를 클릭하면 다음과 같은 php 소스 코드를 볼 수 있다.

 

위의 php 소스 코드 중 핵심 코드는 다음과 같다.

 

바로 solve(1); 함수를 실행시켜야지 이번 old-01 문제를 해결 할 수 있을것 같다.

 

solve(1); 함수를 해결 하기 위해서는 3개의 if문을 잘 봐야한다.

 

3개의 if문의 조건절에 COOKIE값이 들어가있다.

 

따라서 이번 문제는 COOKIE 값을 이용해야한다는것을 알 수 있다.

 

editthiscookie를 이용하여 COOKIE값을 보게되면 user_lv이라는 이름을 가진 쿠키의 값이 1이라고 셋팅되어 있다.

 

다시 3개의 if문으로 돌아와 첫번째 if문은 숫자인지 아닌지를 판단하는것 같다.

 

여기서 쿠키값은 문자가 아닌 숫자임을 알 수 있다. (Point 1)

 

2번째 if문에서는 user_Iv값이 4이상이면 다시 user_Iv값이 1로 셋팅된다. (Point 2)

 

마지막 if문에서는 user_Iv값이 3보다 크면 solve(1)를 실행 시킨다. (Point 3)

 

3개의 힌트를 조합해보면 user_Iv값은 숫자이며 3보다는 크고 4보다는 작아야 한다.

 

따라서 3.1~3.9로 user_Iv값을 설정해주면 solve(1) 함수가 실행되며 문제를 clear 할 수 있다.

 

반응형

'웹 해킹 > Webhacking.kr' 카테고리의 다른 글

6. old-06  (0) 2021.11.03
5. old-05  (0) 2021.11.01
4. old-04  (0) 2021.11.01
3. old-03  (0) 2021.10.19
2. old-02  (0) 2021.10.18

+ Recent posts