>  기사  >  백엔드 개발  >  PHP의 오프셋 기능으로 인한 취약점을 우회하는 솔루션

PHP의 오프셋 기능으로 인한 취약점을 우회하는 솔루션

小云云
小云云원래의
2018-02-08 13:53:581923검색

이 글에서는 PHP의 문자 오프셋 기능으로 인해 발생하는 우회 취약점에 대한 관련 정보를 주로 소개합니다. 이 글에서는 취약점의 형성을 자세히 소개할 뿐만 아니라, 더 중요하게는 특정 참고 자료가 있는 복구 방법도 소개합니다. 모두를 위한 학습 가치가 모두에게 도움이 되기를 바랍니다.

php의 문자 오프셋 기능

PHP의 문자열에는 매우 흥미로운 기능이 있습니다. PHP의 문자열도 배열과 같은 값을 가질 수 있습니다.

$test = "hello world";
echo $test[0];

최종 결과는 h입니다.

하지만 위 기능은 가끔 예상치 못한 효과를 낳기도 합니다. 아래 코드를 보세요

$mystr = "hello world";
echo $mystr["pass"];

위 코드의 출력 결과는 왜일까요? 사실 다른 많은 언어와 마찬가지로 PHP의 문자열도 배열처럼 값을 얻기 위해 첨자를 사용할 수 있습니다. $mystr["pass"]를 전달하면 암시적으로 0으로 변환되므로 $mystr[0]의 출력 결과는 첫 문자 h가 됩니다.
마찬가지로 다음 코드를 시도하면

$mystr = "hello world";
echo $mystr["1pass"];

출력 결과는 다음과 같습니다. e .1pass는 암묵적으로 1로 변환되기 때문에 $mystr[1]의 출력 결과는 두 번째 문자 e입니다.

문자 특성으로 인한 취약점

다음 코드는 phpspy2006에서 로그인을 판별하는 데 사용되는 코드입니다.

$admin['check'] = "1";
$admin['pass'] = "angel";
......
if($admin['check'] == "1") {
....
}

위 기능을 사용하면 이러한 검증 로직을 쉽게 우회할 수 있습니다. $admin은 초기에 배열 유형으로 정의되지 않았으므로 문자열과 함께 phpsyp.php?admin=1abc를 제출하면 PHP는 문자열 1xxx의 첫 번째 비트를 가져와 if 조건 판단을 성공적으로 우회합니다.

위 코드는 코드 조각이고 다음 코드는 php4fun의 질문 5에서 나온 완전한 논리 코드입니다. 이는 매우 흥미롭습니다.

<?php
# GOAL: overwrite password for admin (id=1)
#  Try to login as admin
# $yourInfo=array( //this is your user data in the db
# &#39;id&#39; => 8,
# 'name' => 'jimbo18714',
# 'pass' => 'MAYBECHANGED',
# 'level' => 1
# );
require 'db.inc.php';

function mres($str)
{
 return mysql_real_escape_string($str);
}

$userInfo = @unserialize($_GET['userInfo']);

$query = 'SELECT * FROM users WHERE id = \'' . mres($userInfo['id']) . '\' AND pass = \'' . mres($userInfo['pass']) . '\';';

$result = mysql_query($query);
if (!$result || mysql_num_rows($result) < 1) {
 die(&#39;Invalid password!&#39;);
}

$row = mysql_fetch_assoc($result);
foreach ($row as $key => $value) {
 $userInfo[$key] = $value;
}

$oldPass = @$_GET['oldPass'];
$newPass = @$_GET['newPass'];
if ($oldPass == $userInfo['pass']) {
 $userInfo['pass'] = $newPass;
 $query = 'UPDATE users SET pass = \'' . mres($newPass) . '\' WHERE id = \'' . mres($userInfo['id']) . '\';';
 mysql_query($query);
 echo 'Password Changed.';
} else {
 echo 'Invalid old password entered.';
}

이 질문은 온라인에서 최종 답변만 제공하며, 원리는 설명되지 않거나 자세히 설명되지 않습니다. 사실 그 원리는 위에서 언급한 PHP의 성격적 특성입니다.

질문 요구사항은 매우 간단합니다. 관리자의 비밀번호를 변경하는 것입니다. 다음 질문에 대해 생각해야 합니다.

  • 업데이트할 때 ID를 1로 변경하는 방법

  • $userInfo['pass'] = $newPass; if 판단문?

에 그런 코드가 있습니다. 이 두 가지 문제를 파악하면 최종 해결책도 나옵니다. ID가 8인 사용자의 비밀번호를 8로 변경한 다음 userInfo 문자열 '8'을 전달하여 쿼리 보호를 돌파하고 마지막으로 $userInfo['pass'] = $newPass를 사용하여 ID를 1로 변경합니다.

최종 페이로드는

첫 번째 제출, index.php?userInfo=a:2:{s:2:"id";i:8;s:4:"pass";s:12 :" MAYBECHANGED";}&oldPass=MAYBECHANGED&newPass=8, 목적은 ID 8을 가진 사용자의 비밀번호를 8로 변경하는 것입니다

두 번째 제출, index.php?userInfo=s:1:"8";&oldPass=8&newPass =1 , 이런 방식으로 직렬화된 $userInfo는 문자열 '8', 즉 $userInfo = '8'을 가져오므로 데이터베이스 쿼리 확인을 통과할 수 있습니다. 후속 if 확인도 $userInfo['pass'] = $newPass; 코드 줄을 통해 통과할 수 있습니다. $newpass 값이 1이므로 위 코드는 $userInfo['pass'] = 1;이 됩니다. $userInfo 문자열 타입이므로 최종 결과는 $userInfo='1' 이고, 최종적으로 id 1인 사용자의 비밀번호를 업데이트할 수 있습니다.

수정 방법

이러한 취약점을 복구하는 방법도 매우 간단합니다. 데이터 유형을 미리 정의하고 사용할 때는 사용되는 데이터 유형이 예상되는 데이터 유형과 일치하는지 확인하는 것이 가장 좋습니다. 그렇지 않으면 위에서 언급한 우회 문제가 발생합니다. 동시에 입력을 제어해야 하며, 입력 데이터를 확인하고 함부로 사용해서는 안 됩니다.

관련 권장 사항:

JS의 오프셋 및 균일 동작 예제 분석

mysql 페이지 매기기 시 과도한 오프셋이 있는 SQL 최적화 예제 공유

style.width와 offsetWidth의 차이점에 대한 자세한 설명 js

위 내용은 PHP의 오프셋 기능으로 인한 취약점을 우회하는 솔루션의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.