: level 19 → level 20
http://natas20.natas.labs.overthewire.org
natas20의 화면이다. natas21의 password를 알아내려면 admin으로 로그인해야 한다. 소스코드를 살펴보자.
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas20", "pass": "<censored>" };</script></head>
<body>
<h1>natas20</h1>
<div id="content">
<?
function debug($msg) { /* {{{ */
if(array_key_exists("debug", $_GET)) {
print "DEBUG: $msg<br>";
}
}
/* }}} */
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;
}
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();
}
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);
}
/* 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();
if(array_key_exists("name", $_REQUEST)) {
$_SESSION["name"] = $_REQUEST["name"];
debug("Name set to " . $_REQUEST["name"]);
}
print_credentials();
$name = "";
if(array_key_exists("name", $_SESSION)) {
$name = $_SESSION["name"];
}
?>
<form action="index.php" method="POST">
Your name: <input name="name" value="<?=$name?>"><br>
<input type="submit" value="Change name" />
</form>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
{"mode":"full","isActive":false}
위 소스코드에서 session_set_save_handler라는 함수가 눈에 띈다. 찾아보니 사용자 단계의 세션 저장 기능을 설정하는 것 같았다. 각 세션 단계에서 여기서 설정한 함수가 실행되는 것 같다.
natas21 password를 알아내려면 위 사진에서 보이는 소스코드처럼 세션 admin의 값을 1로 만들어야 한다.
myread함수에 세션 파일에 있는 key와 value를 통해 세션값을 설정하는 코드가 있다.
mywrite함수는 세션 파일에 세션 key와 value값을 저장하는 기능을 한다.
따라서 mywrite함수로 세션 파일에 admin 1을 추가하면, myread함수가 이 데이터를 읽고 $_SESSION['admin']을 1로 설정할 것이다.
세션값이 원하는대로 동작이 되는지 확인하려면 디버그 함수를 사용해야 한다. 아래 사진과 같이 하면 디버그 함수를 사용할 수 있다.
세션에 admin을 추가하기 위해 아래와 같이 작성했다.
그러나 세션 파일에 admin 1이 제대로 입력되지 않았다.
myread함수는 '\n'로 $line을 구분하므로 이번엔 &대신에 %0a를 넣어줬다. (%0a는 '\n')
이번엔 admin 1이 아니라 admin=1이 입력된 것을 확인했다.
이번엔 값을 조정해주기 위해 =대신에 공백을 넣어줬다. (%20은 공백)
파일에 admin 1이 잘 입력됨과 동시에 $_SESSION['admin']의 값이 1이 되었으므로 natas21의 password가 출력됐다.
natas21 password: IFekPyrQXftziDEsUr3x21sYuahypdgJ
'Study > Web Hacking' 카테고리의 다른 글
[natas] Level 20 -> Level 21 (0) | 2021.07.17 |
---|---|
[LOS] golem (0) | 2021.07.11 |
[LOS] skeleton (0) | 2021.06.27 |
[LOS] vampire (0) | 2021.06.27 |
[natas] Level 18 -> Level 19 (0) | 2021.06.27 |