webhacking.kr 61번, 5번, 7번 풀이

julia·2021년 3월 30일
0
post-thumbnail

💡 61번 문제 풀이

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
  $db = dbconnect();
  if(!$_GET['id']) $_GET['id']="guest";
  echo "<html><head><title>Challenge 61</title></head><body>";
  echo "<a href=./?view_source=1>view-source</a><hr>";
  $_GET['id'] = addslashes($_GET['id']);
  if(preg_match("/\(|\)|select|from|,|by|\./i",$_GET['id'])) exit("Access Denied");
  if(strlen($_GET['id'])>15) exit("Access Denied");
  $result = mysqli_fetch_array(mysqli_query($db,"select {$_GET['id']} from chall61 order by id desc limit 1"));
  echo "<b>{$result['id']}</b><br>";
  if($result['id'] == "admin") solve(61);
  echo "</body></html>";
?>

result의 id값이 admin이면 되고, sql인젝션을 이용해야 할 것이다. 쿼리문 : select {$_GET['id']} from chall61 order by id desc limit 1
chall61 테이블에서 id컬럼을 내림차순으로 정렬하고 그 중 첫번째 하나만 가져오는 것 같다.

from을 필터링하기 때문에 'admin' from chall61-- 은 먹히지 않을 것이고,, 너무 어렵다ㅜㅜ
찾아보니 컬럼별칭이라는 것이 있었고, alias(as) 를 이용해 컬럼을 바꿀 수 있다는 걸 알게 되었다.
문법은 "select '문자열' as(생략가능) 칼럼명" 이다.

그러므로 우리는 select admin (as) id 라고 하면 되고, 이는 admin이라는 별명을 id로 사용하겠다는 뜻이다.
처음에는 이를 url인코딩해서 넣어보려 했는데 15자 제한에 막혀서 안됐고, 16진수 변환을 해주어야 했다.
결국 답은 ?id=0x61646D696E id (as는 글자제한 때문에 생략했다) 이고 이를 주소에 입력하면 자동으로 브라우저에서
?id=0x61646D696E%20id 로 인코딩해주면서 문제가 풀리게 된다.

💡 5번 문제 풀이

스크립트에 /mem 이라는 url이 있어 들어가보니 아래와 같은 내용이 떴다.

문제 상에서 회원가입을 먼저 해야하기 때문에 join.php를 눌렀는데, bye라는 문구가 나왔다. 그래도 주소는 그대로길래 개발자도구로 소스를 확인해보니

<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>

스크립트가 진짜 보기 힘들게 나와있다. if문 안에 있는 것들을 콘솔창에 찍어서 해독한 후 정리해보니(예를 들면 lIllIllIllIllIllIllIllIllIllIl 를 찍으면 "oldzombie"라는 값이 나온다) 이런 코드가 나왔다.

if(eval(document.cookie).indexOf(oldzombie)==-1) {
    bye;
} // 쿠키에 oldzombie가 없으면 안녕

if(eval(document.URL).indexof(mode=1)==-1){
    alert('access_denied');
    history.go(-1);
} // url에 mode=1이 있어야 함

따라서 쿠키에 oldzombie를 추가해주고,

url뒤에 ?mode=1을 붙여주면!! 끝인줄 알았지만 이제야 조인 입력칸이 나타난다.

단순히 id에 'admin'을 입력하면(패스워드는 상관없음) 아이디가 이미 존재한다는 alert가 뜬다. 그래서 admin 앞뒤로 공백을 각각 5,10개정도씩 주고 회원가입을 하니 성공했고, 이 아이디로 login.php 주소에 가서 로그인을 해주면 끝이다ㅎㅎ

💡 7번 문제 풀이

<?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);
}
?>

코드를 보면 우선 get방식으로 받은 값을 go에 저장하는데, 이 값이 preg_match 안에 있는 문자들을 포함하면 안된다. if문에서는 1-5까지 랜덤으로 괄호개수가 달라지는데, 일단 괄호 개수를 하나 정해서(20% 확률) 계속 새로고침하다보면 답이 되는 순간이 올 것이다.

가장 중요한 마지막 elseif문을 보니 data값이 2가 되어야 문제가 풀린다는 걸 알 수 있다.
2, -, +가 모두 필터링되기 때문에 숫자 조작은 힘들 것 같고, 공백 문자도 사용하면 안되기 때문에(\s) union을 이용해 쿼리를 만들어야 한다. 1-5 중 1을 기준으로 만들어보면,

select lv from chall7 where lv=($go)
여기서 go 값에 0)union(select(char(50)) 를 넣어주는 것이므로
select lv from chall7 where lv=(0)union(select(char(50))) 이렇게 된다.
볼드체 처리한 부분을 url에 넣으면 끝인데, 처음에 랜덤값 때문에 실패했다고 떠도 새로고침을 계속 누르다보면 성공하니까 당황하지 말자!!

😎 느낀점

확실히 300점대 문제들은 난이도가 높은 것 같고 전에 푼 문제들과의 차이가 실감나기 시작한다.. 500점대는 정말 얼마나 어려우려고 벌써부터 힘든건지 모르겠지만ㅜㅜ 쫄지 말고 겁내지 말고 차근차근 풀어나가야겠다:)

profile
Move Forward

0개의 댓글