Natas 26 → 27
사용자명과 비밀번호를 입력하는 칸이 있다. 소스코드를 살펴보자.
// morla / 10111
// database gets cleared every 5 min
/*
CREATE TABLE `users` (
`username` varchar(64) DEFAULT NULL,
`password` varchar(64) DEFAULT NULL
);
*/
5분마다 데이터베이스가 지워진다고 하는 것 같다.
username과 password의 길이제한은 64인 것 같다.
function checkCredentials($link,$usr,$pass){
$user=mysql_real_escape_string($usr);
$password=mysql_real_escape_string($pass);
$query = "SELECT username from users where username='$user' and password='$password' ";
$res = mysql_query($query, $link);
if(mysql_num_rows($res) > 0){
return True;
}
return False;
}
mysql_real_escape_string(): SQL 명령문으로 사용되는 문자열 중 특수문자 앞에 백슬래시(\)를 붙여 일반 문자로 변환한 결과를 반환한다.
mysql_query(string $query [, resource $link_identifier]): 해당 MySQL connection에 MySQL query를 보낸다.
mysql_num_rows(): 결과물의 행의 수를 반환한다.
$usr, $pass에서 특수문자를 일반문자로 변환한 후 users라는 테이블에서 각각을 username과 password로 갖는 username을 찾아서 그 결과가 하나 이상이라면 True를 반환하고 그렇지 않은 경우에는 False를 반환한다.
function validUser($link,$usr){
$user=mysql_real_escape_string($usr);
$query = "SELECT * from users where username='$user'";
$res = mysql_query($query, $link);
if($res) {
if(mysql_num_rows($res) > 0) {
return True;
}
}
return False;
}
$usr에서 특수문자를 일반문자로 변환하여 $user에 저장하고 users라는 테이블에서 $user를 username으로 갖는 행이 존재하면 True를 반환하고 아니라면 False를 반환한다.
function dumpData($link,$usr){
$user=mysql_real_escape_string($usr);
$query = "SELECT * from users where username='$user'";
$res = mysql_query($query, $link);
if($res) {
if(mysql_num_rows($res) > 0) {
while ($row = mysql_fetch_assoc($res)) {
// thanks to Gobo for reporting this bug!
//return print_r($row);
return print_r($row,true);
}
}
}
return False;
}
mysql_fetch_assoc(): 데이터를 문자형 연관 배열로 변환한다.
print_r(): 변수에 대해서 사람이 읽을 수 있는 정보를 출력한다.
$usr에서 특수문자를 일반문자로 변환하여 $user에 저장하고 users라는 테이블에서 $user를 username으로 갖는 행이 존재하면 각각의 결과를 출력한다. 아니라면 False를 반환한다.
function createUser($link, $usr, $pass){
$user=mysql_real_escape_string($usr);
$password=mysql_real_escape_string($pass);
$query = "INSERT INTO users (username,password) values ('$user','$password')";
$res = mysql_query($query, $link);
if(mysql_affected_rows() > 0){
return True;
}
return False;
}
mysql_affected_rows([int $link_identifier]): 최근 실행된 INSERT, UPDATE, DELETE 질의로 처리된 행의 개수를 반환한다.
users라는 table에 $user와 $password를 각각 사용자명과 비밀번호로 하는 데이터를 추가한다. 처리가 잘되면 True를 반환하고 그렇지 않으면 False를 반환한다.
if(array_key_exists("username", $_REQUEST) and array_key_exists("password", $_REQUEST)) {
$link = mysql_connect('localhost', 'natas27', '<censored>');
mysql_select_db('natas27', $link);
if(validUser($link,$_REQUEST["username"])) {
//user exists, check creds
if(checkCredentials($link,$_REQUEST["username"],$_REQUEST["password"])){
echo "Welcome " . htmlentities($_REQUEST["username"]) . "!<br>";
echo "Here is your data:<br>";
$data=dumpData($link,$_REQUEST["username"]);
print htmlentities($data);
}
else{
echo "Wrong password for user: " . htmlentities($_REQUEST["username"]) . "<br>";
}
}
else {
//user doesn't exist
if(createUser($link,$_REQUEST["username"],$_REQUEST["password"])){
echo "User " . htmlentities($_REQUEST["username"]) . " was created!";
}
}
mysql_close($link);
} else {
?>
<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password" type="password"><br>
<input type="submit" value="login" />
</form>
<? } ?>
htmlentities(): HTML 문자 엔티티에 존재하는 모든 문자를 엔티티를 변환한다.
1. 해당 유저명이 있을 경우
1)유저명과 비밀번호가 모두 일치하는 유저가 있을 때
-환영 메시지를 띄우고 유저의 데이터를 보여준다.
2)유저명과 비밀번호가 모두 일치하는 유저가 없을 때
-유저의 비밀번호가 잘못되었음을 알린다.
2. 해당 유저명이 없을 경우
새로운 유저를 생성한다.
사용자명과 비밀번호를 입력하지 않았을 때에는 사용자명과 비밀번호를 입력받을 수 있는 칸을 생성한다.
(https://themctfwriteups.com/overthewire/2019/04/08/Natas-27-writeup.html)
위의 블로그에 따르면 MySQL에서 데이터타입에 대한 길이를 정했을 때, MySQL은 그 길이 이후의 것은 저장하지 않는다고 한다. 또한 SELECT를 이용해서 'abc'를 출력하려고 했을 때 'abc'와 'abc ' 모두 출력한다고 한다.
python으로 'natas28 nana'를 출력하게 했다. natas28과 nana 사이에는 57개의 공백이 있다. (php로 하려고 했더니 공백이 하나로 줄어들었다.)
위에서 구한 문자열을 Username에다가 넣어주고 Password는 asdf로 넣었다.
'natas28 nana'라는 user가 없기 때문에(validUser에서 판단) 해당 user를 생성하지만(createUser에서 생성), 길이가 64보다 크기 때문에 64번째 글자 이후부터는 저장되지 않는다. natas28 nana 라는 사용자가 생성되었다고 한다.(php, html에서 출력할 때 공백이 연속적으로 여러개 있는 경우에는 공백이 하나만 표현된다.)테이블에는 'natas28'과 'natas28 ...(공백 57개)' 가 존재할 것이다.
이번에는 Username에 natas28을 넣어주고 Password는 아까처럼 asdf를 넣어준다.
natas28의 정보가 뜬다.
natas28 비밀번호: JWwR438wkgTsNKBbcJoowyysdM82YjeF