Natas 19 →20
일반 사용자로 로그인되었다고 한다. 관리자로 로그인하라고 한다.
function debug($msg) { /* {{{ */
if(array_key_exists("debug", $_GET)) {
print "DEBUG: $msg<br>";
}
}
/* }}} */
debug(): $_GET에 "debug"라는 key가 있다면 $msg를 출력한다.
function print_credentials() { /* {{{ */
if($_SESSION and array_key_exists("admin", $_SESSION) and $_SESSION["admin"] == 1) {
print "You are an admin. The credentials for the next level are:<br>";
print "<pre>Username: natas21\n";
print "Password: <censored></pre>";
} else {
print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas21.";
}
}
/* }}} */
/* we don't need this */
function myopen($path, $name) {
//debug("MYOPEN $path $name");
return true;
}
/* we don't need this */
function myclose() {
//debug("MYCLOSE");
return true;
}
print_credentiaols(): $_SESSION이 존재하고 &_SESSION에 "admin"이라는 key가 존재하고 그 값이 1이라면(참이라면?) admin이라는 메시지와 함께 비밀번호를 출력한다.
그 외의 경우에는 일반 사용자로 로그인되었음을 메시지로 출력한다.
function myread($sid) {
debug("MYREAD $sid");
if(strspn($sid, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-") != strlen($sid)) {
debug("Invalid SID");
return "";
}
$filename = session_save_path() . "/" . "mysess_" . $sid;
if(!file_exists($filename)) {
debug("Session file doesn't exist");
return "";
}
debug("Reading from ". $filename);
$data = file_get_contents($filename);
$_SESSION = array();
foreach(explode("\n", $data) as $line) {
debug("Read [$line]");
$parts = explode(" ", $line, 2);
if($parts[0] != "") $_SESSION[$parts[0]] = $parts[1];
}
return session_encode();
}
myread():
debug("MYREAD $sid"); $_GET에 "debug"라는 key가 있다면 "MYREAD $sid"를 출력한다.
strspn(string, charlist, start[=option], length[=option]): string에서 charlist에 존재하지 않는 지점을 반환한다.
만약 $sid에 포함된 문자의 종류의 수가 $sid의 길이와 같지 않으면 "debug"라는 키의 존재 여부에 따라 "Session file
doesn't exist"를 출력한 뒤, ""를 반환한다.
session_save_path(): session data를 저장하기 위해 사용되었던 현재 디렉토리의 경로를 반환한다.
$filename에 현재 디렉토리의 경로에 "/"와 "mysess_"와 $sid를 이어붙인 문자열을 저장한다.
만약 $filename에 해당하는 파일이 존재하지 않는다면 "debug" key의 존재 여부에 따라 "Session file doesn't exist"를
출력하고 ""를 반환한다.
debug("Reading from ". $filename); "debug" key의 존재 여부에 따라 "Reading from " 과 $filename을 이어붙인 문자
열을 출력한다.
file_get_contents(): 전체 파일을 문자열로 읽어들여 반환한다.
$data = file_get_contents($filename); $filename이라는 이름의 파일을 문자열로 읽어들여 $data에 저장한다.
foreach(array_expresiion as $value){ statement; } : 배열의 각 값에 대하여 반복 작업을 한다.
(출처: https://www.codingfactory.net/10700)
explode( delimiter, string [, limit] ): 왼족부터 차례대로 문자열을 분할할 기준, 분할할 문자열, 분할할 개수(정수, 옵션)
을 정한다.
즉, $data를 "\n"을 기준으로 자른 것들에 대해 debug("Read [$line]");을 실행하고, $parts에 $line을 공백을 기준으로
둘로 나눈 것을 저장하는데, 이 때는 배열 형태로 저장되는 것 같다.
만약 $parts[0]이 ""가 아니라면, $_SESSION[$parts[0]]에 $parts[1]을 저장한다.
마지막으로 session_encode()를 호출하여 반환한다.
function mywrite($sid, $data) {
// $data contains the serialized version of $_SESSION
// but our encoding is better
debug("MYWRITE $sid $data");
// make sure the sid is alnum only!!
if(strspn($sid, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-") != strlen($sid)) {
debug("Invalid SID");
return;
}
$filename = session_save_path() . "/" . "mysess_" . $sid;
$data = "";
debug("Saving in ". $filename);
ksort($_SESSION);
foreach($_SESSION as $key => $value) {
debug("$key => $value");
$data .= "$key $value\n";
}
file_put_contents($filename, $data);
chmod($filename, 0600);
}
mywrite():
debug()를 이용하여 상황에 따라 $sid와 $data를 출력한다.
만약 $sid에 숫자와 알파벳대소문자, 그리고 "-"에 포함되지 않는 지점과 $sid의 길이가 다르다면 함수를 종료한다.
$filename에 세션을 저장하기 위한 현재의 디렉토리와 "/", "mysess_", $sid를 차례로 이어붙인 문자열을 저장한다.
$data에 ""를 저장한다.
debug()함수를 이용하여 $filename을 출력한다.
ksort(): 연관배열에 들어 있는 키를 기준으로 오름차순으로 정렬한다.
$_SESSION의 키들을 오름차순으로 정렬한다.
foreach($array as $key => $value): key와 value를 가져온다.
debug()를 이용하여 $key와 $value를 출력하고 $data에 $key와 $value와 "\n"을 이어붙인다.
file_put_contents(파일경로, 입력할 내용)
$filename에 해당하는 파일이 없는 경우 파일을 작성하여 $data의 내용을 파일에 쓴다.
chmod(): 파일의 모드를 변환한다.
chmod($filename, 0600): $filename이라는 파일으 모드를 변환한다.
권한의 종류에는 읽기(4), 쓰기(2), 실행(1)이 있고, 권한부여 그룹은 소유자, 그룹, 모든 사용자 순이다.
0600을 해석해보면,
맨 앞의 0은 8진수임을 나타낸다. 0을 빼고 나타내면 동작에 오류가 발생할 수 있다.
6은 소유자에 대한 권한으로, 읽기(4)와 쓰기(2)를 더한 값으로, 읽기와 쓰기 권한을 부여한다.
나머지 두 숫자는 모두 0인데, 이는 그룹과 모든 사용자에 그 어떠한 권한도 주지 않음을 알 수 있다.
(출처: https://devjhs.tistory.com/212)
/* we don't need this */
function mydestroy($sid) {
//debug("MYDESTROY $sid");
return true;
}
/* we don't need this */
function mygarbage($t) {
//debug("MYGARBAGE $t");
return true;
}
session_set_save_handler(
"myopen",
"myclose",
"myread",
"mywrite",
"mydestroy",
"mygarbage");
session_start();
session_set_save_handler(open, close, read, write, destroy, gc)
open: 열기 함수.
close: 닫기 함수.
read: 읽기 함수. 항상 문자열 값을 반환해야 한다.
write: 쓰기 함수. 출력 스트림이 닫힐 때까지 실행되지 않는다.
destroy: 파괴 핸들러. 세션이 파괴될 대 실행되고, 세션 id를 인수로 받는다.
gc: 쓰레기 수거자. 세션 쓰레기 수거가 실행될 때 실행되고, 최대 세션 수명을 인수로 받는다.
(출처: http://www.lug.or.kr/files/docs/PHP/function.session-set-save-handler.html)
session_start(): 세션 사용 전에 세션을 초기화 한다.
if(array_key_exists("name", $_REQUEST)) {
$_SESSION["name"] = $_REQUEST["name"];
debug("Name set to " . $_REQUEST["name"]);
}
$_REQUEST에 "name"이라는 key가 있다면 $_REQUEST["name"]의 값을 $_SESSION["name"]에 저장하고, debug함수를 이용하여 적절한 값을 출력한다.
print_credentials();
$name = "";
if(array_key_exists("name", $_SESSION)) {
$name = $_SESSION["name"];
}
?>
print_credentials()함수를 호출한다.
$name을 ""로 초기화 한다.
$_SESSION에 "name"이라는 key가 있다면 그 value를 $name에 저장한다.
먼저 $_GET에 debug가 있어야 하므로 url 뒤에 debug, name을 추가한다.
myread함수는 파일을 "\n" 단위로 자른 뒤, 줄마다 다시 공백을 기준으로 잘라 첫 번째 덩어리를 $_SESSION의 key로, 두 번째 덩어리를 그 value로 저장한다.
mywrite함수는 $_SESSION의 key들을 오름차순으로 정렬한 뒤에 각 key와 value를 공백으로 구분짓고, "\n"을 파일에 작성한다.
$_SESSION에 debug와 name을 저장할 때 name에 개행문자(%0a)와 공백문자(%20)를 이용하여 admin%0aadmin%201 을 저장하면 mywrite 함수에서 파일에 name과 admin%0aadmin%201 을 각각 key와 value로 저장할 것이고, myread함수에서는 admin%0aadmin%201을 개행문자를 기준으로 자른 뒤에 개행문자 뒤의 admin을 $_SESSION의 key로, 공백문자 뒤의 1을 $_SESSION["admin"]의 value로 저장할 것이다.
?debug=true&&name=admin%0aadmin%201 을 입력한다.
natas21 비밀번호: IFekPyrQXftziDEsUr3x21sYuahypdgJ