Level 41
<? $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>
코드를 보면 파일을 받아 파일이름을 필터링 하고 hidden_dir이라는 곳에 카피한 후, 패스워드를 그 곧에 쓴다.
따라서 우리는 hidden_dir의 주소를 알아야 한다.
코드를 자세히 보면, eregi함수를 통해 필터링 하는 부분과 str_replace를 통해 필터링 하는 부분이 있다.
이 두가지 특성이 있는데, str_replace는 치환을 하는 반면, eregi는 치환은 하지 않지만, 해당 문자열이 존재하면 종료시켜 버린다.
여기서 한가지 생각을 해야 한다. fn값이 '.' 이나 '<', '>' 이면 공백으로 치환되는데 이럴때 어떻게 처리가 될까?
이 소스에서 예외처리 하는 부분은 없다. 따라서 시도해 보았다.
어이없는 삽질을 기록해 보자면, 실제 파일의 이름을 '.', '>', '<' 로 바꾸려고 했었다. 순간 안되서 몇분간 삽질...
리눅스에서 파일 만들어서 옮겨볼까 생각까지...ㅋㅋ 바보였음;
먼저 텍스트 파일을 만들고, Fiddler를 켜서 파일 업로드하는 패킷을 캡쳐하였다.
캡쳐 후, filename을 '<'로 수정하고 보냈다.
그러고 나니 다음과 같은 페이지가 출력되면서, hidden_dir의 경로가 노출되었다.
다시 정상적으로 파일을 업로드 한 후, hidden_dir 경로 / 파일이름+확장자
으로 접속하면 pw가 존재한다.
확장자의 '.'은 replace로 치환되어 사라졌다.
flag : 634af6ff99668de457bbb583585f45ff
[!] 플래그는 파일 이름에 따라 다른듯 하다.