본문 바로가기

Webhacking/Webhacking.kr

[Webhacking.kr] old-05 풀이

728x90
반응형

5번문제의 경우 상당히 심플한 구성으로 이루어져 있다.
Login을 해보기 이전에 Join을 시도해보고자 버튼을 눌렀더니...

Access Denied 란다. 
그래서 코드를 한번 살펴보았더니...

onclick 이벤트 핸들러에 no() 함수가 걸려있었고, script 어디를 봐도 join으로 이동할 수 있는 부분은 존재하지 않았다.
그래서 우선 login 페이지로 이동해보기로 했다.

login 페이지는 단순했다.
그저 id, pw 넣으면 맞는지 틀린지 정도 구별해주는 역할을 하는듯 싶었다.
다만 한가지 확실한건, 여기도 조금 공격을 시도해보았지만 전부 막혀있었다.
즉 login 페이지에 공격하는 것이 아닌 join페이지를 공격하는 것이 이 문제의 핵심임을 알 수 있었다.

하지만 join 관련 페이지가 어디인지 알 수 없었기 때문에, Apache indexes 취약점이 있지 않을까 싶어, login.php를 삭제하고,
/challenge/web-05/mem 으로 이동해 보았다.

크으.. 정답!
세상 단순하게도, join.php가 존재함을 알 수 있었다.
(굳이 indexes를 활용하지 않아도 guessing으로 충분히 접근이 가능할것 같다...)

당당히 join.php로 들어가자, bye라는 문구와 함께 아무것도 나타나지 않았다.
원인을 찾기위해 소스코드를 열어보았다.

그곳에는 난독화(?) 된 자바스크립트 코드들이 들어있었고, 이것이 접근을 막고 있음을 어렴풋이 알 수 있었다.
그런데 일단 보기가 너무 힘들어서, javascript beautifier를 이용하여 줄 정리를 해보았다.

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 = '>';
lIllIllIllIllIllIllIllIllIllIl = lllllllllllllll + llllllllllll + llll + llllllllllllllllllllllllll + lllllllllllllll + lllllllllllll + ll + lllllllll + lllll;
lIIIIIIIIIIIIIIIIIIl = llll + lllllllllllllll + lll + lllllllllllllllllllll + lllllllllllll + lllll + llllllllllllll + llllllllllllllllllll + li + lll + lllllllllllllll + lllllllllllllll + lllllllllll + lllllllll + lllll;
if(eval(lIIIIIIIIIIIIIIIIIIl).indexOf(lIllIllIllIllIllIllIllIllIllIl) == -1) {
	alert('bye');
	throw "stop";
}
if(eval(llll + lllllllllllllll + lll + lllllllllllllllllllll + lllllllllllll + lllll + llllllllllllll + llllllllllllllllllll + li + 'U' + 'R' + 'L').indexOf(lllllllllllll + lllllllllllllll + llll + lllll + '=' + I) == -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=' + llllllllll + lllllllllllllll + lllllllll + llllllllllllll + li + llllllllllllllll + llllllll + llllllllllllllll + '>');
	document.write('<table border=1><tr><td><font color=gray>id</font></td><td><input type=text name=' + lllllllll + llll + ' maxlength=20></td></tr>');
	document.write('<tr><td><font color=gray>pass</font></td><td><input type=text name=' + llllllllllllllll + lllllllllllllllllllllll + '></td></tr>');
	document.write('<tr align=center><td colspan=2><input type=submit></td></tr></form></table>');
}

코드는 대강 이렇다. 사실 중요한건 if문 부터이다. (그 위는 그냥 전부 변수선언임. 단지 그 변수명이 이상할 뿐...)
if문 2개를 통과하면 else문을 통해 html코드가 노출됨을 알 수 있다.
여기서부터 풀이방법이 2가지로 나뉜다.

  1. javascript를 전부 해석하여, if문 조건을 맞추어 준다.
  2. proxy 툴을 활용하여 response  body 내 if-else문을 전부 삭제하고  바로 document.write가 실행되게 한다.

2번을 사용하면 더 쉽겠지만, 이 문제의 의도는 javascript에 있다고 생각하여 1번으로 굳이 힘들게 풀어보았다.

우선 아까 말했듯이, if문 윗부분은 전부 변수 선언이다.
가볍게 개발자도구 console에 붙여넣어, 선언을 해주자

그런뒤, if문에 들어있는 이상한 문구를 console에 입력하면,
아까 선언한 변수 데이터들을 토대로 난독화가 풀린 실제 값을 알 수 있게 된다.

if(eval(document.cookie).indexOf("oldzombie") == -1) {
	alert('bye');
	throw "stop";
}
if(eval(document.URL).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=' + llllllllll + lllllllllllllll + lllllllll + llllllllllllll + li + llllllllllllllll + llllllll + llllllllllllllll + '>');
	document.write('<table border=1><tr><td><font color=gray>id</font></td><td><input type=text name=' + lllllllll + llll + ' maxlength=20></td></tr>');
	document.write('<tr><td><font color=gray>pass</font></td><td><input type=text name=' + llllllllllllllll + lllllllllllllllllllllll + '></td></tr>');
	document.write('<tr align=center><td colspan=2><input type=submit></td></tr></form></table>');
}

위에서 알아낸 실제 값을 이용하여 if-else문을 다시 정리하면 이렇다.

  • cookie값에 oldzombie라는 문자열이 존재해야 한다.
  • URL에 mode=1이라는 문자열이 존재해야 한다.

위 2가지 조건을 만족하면 아래 else문에 따른 코드가 실행된다.

먼저 쿠키 조건부터 맞춰주기 위해 edit this cookie로 oldzombie라는 쿠키를 생성해 주었다.

쿠키를 생성한 뒤, mode=1을 join.php의 뒤에 붙여 접근을 시도했다.

그러자 이렇게 가입을 할 수 있는 화면이 나타났다.
우선 test/test로 가입을 해보았다.

막힘없이 test로 잘 가입이 되었고, 

login.php로 접근하여 가입한 계정으로 로그인을 시도했다.

로그인은 잘 되었지만, "You have to login as admin" 이라는 문구를 볼 수 있었고,
이로써, admin으로 로그인을 해야 문제가 풀린다는 것을 알 수 있었다.

우선 admin이라는 계정의 pw를 모르기 때문에, 다시 join.php로 돌아가서, admin으로 가입을 시도해보기로 했다.

당연히 안될줄 알았다. ID가 이미 있다고 한다.

그래서 admin이라는 문구는 유지하되, 맨 앞에 공백을 넣어 가입을 시도했다.
(SQL에서 insert하는 경우 admin과 (공백)admin은 다른 값이기 때문에 우회가 될 것이라 판단함)

오 가입에 성공했다.

다시 login.php로 넘어와서 우회해서 가입한 (공백)admin으로 로그인을 시도했다.

문제 해결!

정확한 이 문제의 php 코드를 보지 못해 추측밖에 할 수 없지만, 내 생각에는 가입을 시도할 때는 sql을 사용하다 보니,
(공백)admin과 admin이 구별되어 가입에 성공한 것이라고 생각된다.

또한 login.php의 경우 select를 통해 admin이라는 데이터를 불러와야 풀리는 것이 아닌,
로그인에 성공한 계정의 id에 admin 이라는 단어만 포함되어 있으면 admin으로 인식하도록 프로그래밍 되어있어, 
문제가 풀린 것이 아닐까 싶다.

728x90
반응형