1번 문제
<?php
include "../../config.php";
if($_GET['view-source'] == 1){ view_source(); }
if(!$_COOKIE['user_lv']){
SetCookie("user_lv","1",time()+86400*30,"/challenge/web-01/");
echo("<meta http-equiv=refresh content=0>");
}
?>
<html>
<head>
<title>Challenge 1</title>
</head>
<body bgcolor=black>
<center>
<br><br><br><br><br>
<font color=white>
---------------------<br>
<?php
if(!is_numeric($_COOKIE['user_lv'])) $_COOKIE['user_lv']=1;
if($_COOKIE['user_lv']>=4) $_COOKIE['user_lv']=1;
if($_COOKIE['user_lv']>3) solve(1);
echo "<br>level : {$_COOKIE['user_lv']}";
?>
<br>
<a href=./?view-source=1>view-source</a>
</body>
</html>
사실상 아래 코드만 보면 된다.
<?php
if(!is_numeric($_COOKIE['user_lv'])) $_COOKIE['user_lv']=1;
if($_COOKIE['user_lv']>=4) $_COOKIE['user_lv']=1;
if($_COOKIE['user_lv']>3) solve(1);
echo "<br>level : {$_COOKIE['user_lv']}";
?>
COOKIE>=4 즉, 4이상이면 안됌. COOKIE>3 즉, 3보다 커야됌. 3<COOKIE<4 이면 되니까 3.5입력해서 보냄.
이미 풀고 블로깅하는거라 already solved가 뜸.
4번 문제
<?php
include "../../config.php";
if($_GET['view-source'] == 1) view_source();
?><html>
<head>
<title>Challenge 4</title>
<style type="text/css">
body { background:black; color:white; font-size:9pt; }
table { color:white; font-size:10pt; }
</style>
</head>
<body><br><br>
<center>
<?php
sleep(1); // anti brute force
if((isset($_SESSION['chall4'])) && ($_POST['key'] == $_SESSION['chall4'])) solve(4);
$hash = rand(10000000,99999999)."salt_for_you";
$_SESSION['chall4'] = $hash;
for($i=0;$i<500;$i++) $hash = sha1($hash);
?><br>
<form method=post>
<table border=0 align=center cellpadding=10>
<tr><td colspan=3 style=background:silver;color:green;><b><?=$hash?></b></td></tr>
<tr align=center><td>Password</td><td><input name=key type=text size=30></td><td><input type=submit></td></tr>
</table>
</form>
<a href=?view-source=1>[view-source]</a>
</center>
</body>
</html>
해결하려면 SESSION['chall4'] 과 POST로 받은 POST['key']값이 같으면 된다. 처음에 검정화면에서 초록색깔의 값을 볼 수 있는데 그 값은 10000000,99999999 사이의 랜덤한 값에 salt_for_you라는 문자열이 추가된 값을 sha1 해시 함수로 500번 암호화 된 값이다. 10000000,99999999 사이에서 나올 수 있는 값들을 모두 sha1 해시함수로 500번 암호화해서 그 암호화 된 값을들 txt에 모은 후 주어진 값을 txt에서 찾아 암호화 전 값에 salt_for_you와 합쳐 제출하면 된다. 위에서 설명했듯이 해시 함수를 사용해서 암호화 한 해시 값들을 모아놓은 것을 레인보우 테이블이라고 한다. 나는 파이썬을 이용해서 레인보우 테이블을 만들었다.
import hashlib
f = open("rainbow.txt", "w")
for i in range(10000000, 100000000):
hash = str(i) + "salt_for_you"
for j in range(500):
hash = hashlib.sha1(hash.encode()).hexdigest()
f.write(str(i) + " \"" + hash + "\"" + "\n")
f.close()
레인보우 테이블인 rainbow.txt를 만들었다.10000000부터 시작하여 99999999까지에 랜덤한 값을 sha1 해시함수로 500번 암호화 하는 테이블을 만드는 코드이지만 다 만들기까지 너무 오랜 시간이 걸리기에 중간에 멈추고 만들어진 레인보우 테이블에 한해서 암호화 된 값을 찾아보았다.(운에 맡겼다..)
근데 이정도면 많이 만들었지...
잡았다 이놈..
23846819salt_for_you를 제출하여 풀었다.
5번 문제
초기 화면이다. Login과 Joind이 있다.
login에 들어가면 /mem/login.php에 사진처럼 화면이 뜬다. 아무거나 입력 후 login을 누르면 Wrong password라는 문구를 출력한다.
join에 들어가면 Access_Denied를 출력한다.
아까 Login때 확인했던 /mem/login.php에서 /mem으로만 접속해보자.
위와 같이 노출된다. 여기서 join.php에 들어가보면?
bye.. 인사해준다..
개발자 도구를 통해서 join.php 코드를 확인해봤다.
<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='>';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>');}
</script>
</body>
</html>
? 보고 처음에 좀 당황했다. 그러나 1111 = 'd'인 것을 알게 되니 다른 것들도 맞춰서 바꿔보면 되지 않을까 싶어서 바꿔봤다.
<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='>';
lIllIllIllIllIllIllIllIllIllIl=oldzombie;
lIIIIIIIIIIIIIIIIIIl=document.cookie;if(eval(lIIIIIIIIIIIIIIIIIIl).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>');}
</script>
</body>
</html>
보기 조금이나마 편하게 줄바꿈을 시킨 후 내가 join에 들어갔을 때 alert에 떴던 bye부분과 access_denied를 확인할 수 있었다. 필요해 보이는 곳만 하나하나 더블 클릭해서 바꿔보니
1. document.cookie를 보니 oldzombie라는 쿠키값이 아니라면 bye를 띄운다.
2. 만약 document.URL을 보니 mode = 1이 아니라면 access_denied를 띄운다.
3. mode = 1이면 else부분으로 html 띄운다.
두 경고창을 모두 알았으니 두가지 방법을 모두 해결한다면 join.php를 확인할 수 있을 것이라는 확신이 들었다.
개발자 도구에서 쿠키 name에 oldzombie를 등록한 후 url에 ?mode=1를 추가하여 새로고침해보았다.
이제 회원가입을 할 수 있으니 admin으로 가입해보자.
id already existed라는 문구가 뜬다. guest로 다시 가입한 후 로그인해봤다.
음 아무래도 admin으로 로그인해야하는 것 같다. admin은 이미 있는 아이디이니 admin으로 인식하도록 amdin(공백)으로 한 번 가입하기위해 ID를 admin%20 으로 가입한 후 로그인해보겠다.
음..%20이 공백으로 되길 원했는데 뒤에 또 다른 문자가 있어야하나보다. 그래서 (공백)admin으로 가입한 후 로그인을 해봤더니
admin계정으로 성공적으로 로그인이 됐음을 확인할 수 있었다.
6번 문제
소스코드를 단계별로 잘라 확인했다.
<?php
include "../../config.php";
if($_GET['view_source']) view_source();
if(!$_COOKIE['user']){
$val_id="guest";
$val_pw="123qwe";
for($i=0;$i<20;$i++){
$val_id=base64_encode($val_id);
$val_pw=base64_encode($val_pw);
}
$val_id=str_replace("1","!",$val_id);
$val_id=str_replace("2","@",$val_id);
$val_id=str_replace("3","$",$val_id);
$val_id=str_replace("4","^",$val_id);
$val_id=str_replace("5","&",$val_id);
$val_id=str_replace("6","*",$val_id);
$val_id=str_replace("7","(",$val_id);
$val_id=str_replace("8",")",$val_id);
$val_pw=str_replace("1","!",$val_pw);
$val_pw=str_replace("2","@",$val_pw);
$val_pw=str_replace("3","$",$val_pw);
$val_pw=str_replace("4","^",$val_pw);
$val_pw=str_replace("5","&",$val_pw);
$val_pw=str_replace("6","*",$val_pw);
$val_pw=str_replace("7","(",$val_pw);
$val_pw=str_replace("8",")",$val_pw);
Setcookie("user",$val_id,time()+86400,"/challenge/web-06/");
Setcookie("password",$val_pw,time()+86400,"/challenge/web-06/");
echo("<meta http-equiv=refresh content=0>");
exit;
}
?>
!$_COOKIE['user']를 보니 쿠키값에 user가 없다면 id를 guest로하고 pw를 123qwe로 한다는 것을 알 수 있었고 초기화면에서 제공된 것과 같은 것을 알 수 있었다. 여기서 끝이 아니고 guest와 123qwe를 for문을 통해 base64 인코딩을 20번 하며 1~8의 숫자를 !,@,$,^~)와 같은 것들로 바꾼다. 이 과정을 통해서 나온 값을 user라는 쿠키값과 password라는 쿠키값에 저장한다.
이제 다음 소스코드를 보자.
<html>
<head>
<title>Challenge 6</title>
<style type="text/css">
body { background:black; color:white; font-size:10pt; }
</style>
</head>
<body>
<?php
$decode_id=$_COOKIE['user'];
$decode_pw=$_COOKIE['password'];
$decode_id=str_replace("!","1",$decode_id);
$decode_id=str_replace("@","2",$decode_id);
$decode_id=str_replace("$","3",$decode_id);
$decode_id=str_replace("^","4",$decode_id);
$decode_id=str_replace("&","5",$decode_id);
$decode_id=str_replace("*","6",$decode_id);
$decode_id=str_replace("(","7",$decode_id);
$decode_id=str_replace(")","8",$decode_id);
$decode_pw=str_replace("!","1",$decode_pw);
$decode_pw=str_replace("@","2",$decode_pw);
$decode_pw=str_replace("$","3",$decode_pw);
$decode_pw=str_replace("^","4",$decode_pw);
$decode_pw=str_replace("&","5",$decode_pw);
$decode_pw=str_replace("*","6",$decode_pw);
$decode_pw=str_replace("(","7",$decode_pw);
$decode_pw=str_replace(")","8",$decode_pw);
for($i=0;$i<20;$i++){
$decode_id=base64_decode($decode_id);
$decode_pw=base64_decode($decode_pw);
}
echo("<hr><a href=./?view_source=1 style=color:yellow;>view-source</a><br><br>");
echo("ID : $decode_id<br>PW : $decode_pw<hr>");
if($decode_id=="admin" && $decode_pw=="nimda"){
solve(6);
}
?>
</body>
</html>
solve(6)를 받으려면 id가 admin이고 pw가 nimda이어야하는데 그 앞에 decode가 있다. 위를 보니 for문으로 base64 디코딩을 20번 반복한다. 또 그 위를 보니 처음 코드와 비슷하게 id와 pw를 받아 !을 1로 @를 2로 ~~ )을 8로 바꾸는 것을 알 수 있었다.
즉, id와 pw를 str_replace함수로 변경하고 그 값을 for문을 통해 base64로 디코딩을 20번했을 때 id가 admin이고 nimda이어야한다. 그러면 id를 admin으로 pw를 nimda로 base64인코딩을 20번 한 후 1,2,3~8의 숫자를 !,@,$~)같이 문자로 바꿔준다음 쿠키값에 넣어주면 되겠다. 과정을 보니 처음 봤던 코드를 조금만 바꾸면 파이썬 스크립트로 작성할 수 있을 것 같아서 파이썬 스크립트로 작성해봤다.
import base64
id = "admin"
pw = "nimda"
for i in range(0,20) :
id = id.encode("utf-8")
pw = pw.encode("utf-8")
id = base64.b64encode(id)
pw = base64.b64encode(pw)
id = id.decode("utf-8")
pw = pw.decode("utf-8")
id.replace("1","!")
id.replace("2","@")
id.replace("3","$")
id.replace("4","^")
id.replace("5","&")
id.replace("6","*")
id.replace("7","(")
id.replace("8",")")
pw.replace("1","!")
pw.replace("2","@")
pw.replace("3","$")
pw.replace("4","^")
pw.replace("5","&")
pw.replace("6","*")
pw.replace("7","(")
pw.replace("8",")")
print("id = " + id)
print("pw = " + pw)
이런식을 출력받았다. 이제 이것을 쿠키값에 넣었더니?
해결됐다.
7번 문제
코드를 보자.
<?php
include "../../config.php";
if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 7</title>
</head>
<body>
<?php
$go=$_GET['val'];
if(!$go) { echo("<meta http-equiv=refresh content=0;url=index.php?val=1>"); }
echo("<html><head><title>admin page</title></head><body bgcolor='black'><font size=2 color=gray><b><h3>Admin page</h3></b><p>");
if(preg_match("/2|-|\+|from|_|=|\\s|\*|\//i",$go)) exit("Access Denied!");
$db = dbconnect();
$rand=rand(1,5);
if($rand==1){
$result=mysqli_query($db,"select lv from chall7 where lv=($go)") or die("nice try!");
}
if($rand==2){
$result=mysqli_query($db,"select lv from chall7 where lv=(($go))") or die("nice try!");
}
if($rand==3){
$result=mysqli_query($db,"select lv from chall7 where lv=((($go)))") or die("nice try!");
}
if($rand==4){
$result=mysqli_query($db,"select lv from chall7 where lv=(((($go))))") or die("nice try!");
}
if($rand==5){
$result=mysqli_query($db,"select lv from chall7 where lv=((((($go)))))") or die("nice try!");
}
$data=mysqli_fetch_array($result);
if(!$data[0]) { echo("query error"); exit(); }
if($data[0]==1){
echo("<input type=button style=border:0;bgcolor='gray' value='auth' onclick=\"alert('Access_Denied!')\"><p>");
}
elseif($data[0]==2){
echo("<input type=button style=border:0;bgcolor='gray' value='auth' onclick=\"alert('Hello admin')\"><p>");
solve(7);
}
?>
<a href=./?view_source=1>view-source</a>
</body>
</html>
$data[0]이 2이면 해결할 수 있는 문제다. 2 - + from _ = \s * / 이 있으면 Access Denied!가 나온다. 그리고 rand함수로 1~5 중 랜덤한 값이 나오는데 그 값에따라서 쿼리문이 구별되어 실해된다. 만약 쿼리를 실행시키지 못하면 nice try!를 출력한다. rand가 1~5라는 적은 수에 랜덤으로 나오기 때문에 그냥 1에 맞추고 쿼리문을 작성하고 실행될 때까지 새로고침하면 될 것 같다. 우선 2를 직접 사용못하고 +,-,*,/가 막혀있다. 다행히도 %가 남아있기에 5%3를 사용하면 $data[0] == 2를 성립시킬 수 있겠다. 쿼리문을 짜보면
)union(select(5%3)
val = 0으로 바꾸고 위 쿼리문을 넣은 다음 $rand == 1일 때까지 새로고침해보자.
해결했다.
'Webhacking-Write-Up > Webhacking.kr' 카테고리의 다른 글
[Webhacking.kr] 24, 25, 26, 27, 32 문제 (0) | 2023.01.13 |
---|---|
[Webhacking.kr] 33, 34, 50, 51, 54 문제 (0) | 2023.01.13 |
[Webhacking.kr] 16, 17, 19, 20, 23 문제 (0) | 2023.01.12 |
[webhacking.kr] 10, 11, 12, 14, 15 문제 (0) | 2023.01.12 |