浅谈Shell中的小知识

浅谈Shell中的小知识

什么是交互式shell和非交互式shell?

我们在进行渗透测试的时候,往往需要自己构造一个 Interactive 可交互的shell,那么什么是可交互?原本的shell也可以执行命令,为什么不能用,非得想办法构造一个可交互的shell呢?

Interactive shell 交互式shell

我们先来看一下Bash对于 Interactive Shell 的定义:
“An interactive shell is one started without non-option arguments, unless -s is specified, without specifying the -c option, and whose input and error output are both connected to terminals (as determined by isatty(3)), or one started with the -i option.

An interactive shell generally reads from and writes to a user’s terminal.

The -s invocation option may be used to set the positional parameters when an interactive shell is started.” [1].

这里提到了两个概念, option, argument;

介绍前先说结论: argument包含option

如果大家尝试过使用C语言与shell交互,应该就会用到如下的代码来对输入的参数进行利用

#include <stdio.h>

int main( int argc, char *argv[] )  
{
   if( argc == 2 )
   {
      printf("The argument supplied is %s\n", argv[1]);
   }
   else if( argc > 2 )
   {
      printf("Too many arguments supplied.\n");
   }
   else
   {
      printf("One argument expected.\n");
   }
}

argc 表示输入参数的数量, *argv[] 就表示包含输入参数的数组

这里为了一劳永逸,我们再插一嘴,再辨析一下英文文档中的 parameter & argument 的区别:

  1. parameter指的是在 定义 函数时的所申明的变量名
  2. argument指的是在 调用 函数时,实际传入的值

例如在下面的例子中,在函数 MyMethod 中所定义的 myParam 就是parameter,而在下面实际调用使用中,将要传入的真实数据就叫做 argument [2].

public void MyMethod(string myParam) { }

...

string myArg1 = "this is my argument";
myClass.MyMethod(myArg1);

好,我们赶紧回来shell中的option和argument的定义:

  1. arguments 就是包含整一串shell命令的数组,每一个string都可以称为 argument, 和调用c语言脚本时一个道理,第一个参数(0)就是命令的名字,例如’ls’,同时也被称为 positional parameters;

  2. option 同样也是一个argument,但是它们的特殊之处在于option会改变第一个argument的命令的行为,例如 ls -la 中的 ‘-la’ 就会改变ls的行为

  3. parameter 也是一个argument,其作用时为命令或者其选项提供信息 [3].

$ ls -la /tmp /var/tmp
# parameter1= /tmp
# parameter2= /var/tmp

$ ls -l -- -a
# option1    = -l
# parameter1 = -a

更多关于 shell parameter 以及 subcommands 的解释也可以参考 [3].

了解这些内容之后,我们再回过头来解释 Interactive shell的定义,也就是说一个可交互的shell,就是在启动的时候命令后面跟的只有option类型的argument,除非用了 -s 选项并且没有使用 -c, 或者直接使用了 -i 开启了交互模式

  1. -c <string> If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.
    • 如果出现option -c,那么要执行的指令就从-c后面的string中读取,如果string之后还有参数,那么就当作是一条完整的命令来执行
  2. -i If the -i option is present, the shell is interactive.
    • 如果出现-i则开启一个可交互的shell
  3. -s If the -s option is present, or if no arguments remain after option processing, then commands are read from the standard input. This option allows the positional parameters to be set when invoking an interactive shell.
    • 如果出现-s,则从标准输入中读取

使用 -s ,就可以从stdin读取需要执行的命令,这么说有一点抽象,难以和-c区分开来,我们来看一个例子 [4]:

curl -L https://chef.io/chef/install.sh | sudo bash -s -- -P chefdk

一般来说 -s 选项都以 curl $script_url | bash 的形式来配合使用,目的是为了 执行 下载到的shell;

这里 -- 表示,将后面所有的string都当作要执行的命令(bash -s所下载的install.sh)的argument,而不是当前命令的option,而 -s 则会负责执行下载到的install.sh;

顺便也翻译一下,使用 -c 选项后面需要跟一个string,来表示将要执行的命令,并且后面还有其他的字符串,都会被当作是命令(前面的string)的其他argument(从$0开始)。

总结一下,启动一个交互式的shell,需要命令的argument全部都为option,而不能有parameter,除非使用了 -s (而没有-c) 或者 -i 的情况,并且交互式shell可以接受来自用户的输入和读取,即这个shell需要用户与其互动,输入命令来决定其行动

Non-Interactive shell 非交互式shell

非交互式的shell就正好相反,其不会与用户进行交互,即标准输入和错误流都没有连接到终端(即用户不可见),往往用于脚本的自动化执行,输入则进入专门的log文件中,同时配置文件例如.bashrc, .profile, .zshrc 都不会被执行 [5].

因此我们在渗透的过程中时常需要去获得一个交互式的shell来看到我们所执行命令的回显信息。

如何区分交互式shell和非交互式shell

我们可以通过交互式shell中所定义的两个变量来进行区分

  1. $PS1 在交互式shell中被定义,有输出的内容,而在非交互式shell中没有被定义,没有输出;
  2. $- 在交互式的shell中,输出的字符串包含字符 'i', 非交互式shell中,则不包含’i’ [6];

(如果不明白这两个变量是干什么的也不用着急,我们下面会讲)

可以用下列代码来进行测试 [5]:

[[ $- == *i* ]] && echo ‘Interactive’ || echo ‘not-interactive’

Bash中的特殊变量

  • $PS*

    那到底什么是 $PS1,看起来像一个变量,叫做 Bash Prompt, 其代表的是命令行的提示符,即我们看到的终端呈现的shell每一行的开头,例如在下面这个shell中,就由三个内容组成:

    • \s = bash, the name of the shell
    • \v = 3.2, the version of bash
    • $

    还有类似的:

    • $PS1, primary prompt string, shell界面每次换行后的开头标识符(如果使用了插件进行美化之后,就会发现这个值特别长,就是因为开头标识符变化了);
    • $PS2, 表示次级的标识符,secondary prompt string,通常为 >;
    • $PS3, 用来指示选中的命令;
    • $PS4, 表示命令在执行的过程中,每一行的输出都会输出 $PS4 的值 [7];

    Figure 1: $PS in Bash

    Figure 1: $PS in Bash

    知道了这个之后,我们也就能理解为什么我们通过msf拿到的shell的每一行开头什么都没有,因此被称为非交互式的shell,因为其$PS1没有被定义,也就没有内容可以显示;

    我们平时利用一些工具对终端进行自定义美化的时候,应该也是对这些内容进行修改来实现的,大家可以试试看在自己的终端中输出这些内容,可能都是很长的输出;

  • $-

    $- : $-, dollar hyphen, 将会返回当前shell(bash)在开启时,所设定的option,例如当返回是himBH,就表示bash启动时设定了[8]: - H - histexpand: when history expansion is enabled - m - monitor: when job control is enabled - h - hashall: Locate and remember (hash) commands as they are looked up for execution - B - braceexpand: when brace expansion is enabled - i - interactive: when current shell is interactive

    这样也就不难理解我们为什么在进行shell是否可交互时可以查看 $- 的值中是否包含i了;

    $$ : $$会输出当前shell的进程ID或者说PID,每当新开启一个shell的时候,就会产生一个新的进程

    $# : $#用来表示一个bash命令的argument数量,例如下面的例子[9]:

     ```shell
     $ bash -c ‘echo $#’ _ 1 2 3
     ```
    
     这里的 `_` 下划线表示一个占位符,表示后面的string为命令的arguments,要主要的是,#表示的数字并不会被算进去,因此上面指令的输出为3 <br/>
    

    $0 : 显示出当前运行脚本的名字,也就是第一个argument的值;

    $? : $?表示的是上一条命令的exit code,如果成功执行则为0,如果出现错误,就回事1;

    $! : $!,dollar exclamation,表示上一个最近一个被执行的任务的PID;

    $_ : $_表示最近一条指令的最后一个argument;

    Figure 2: $_指示上一条指令的最后一个argument

    Figure 2: $_指示上一条指令的最后一个argument

区分’terminal’, ‘shell’, ’tty’ 以及 ‘console’

我们通过msf获得了一个非交互式的shell之后,很多walkthrough都会教我们将其转换为完全交互式的TTY,那么这个TTY是什么呢?它和shell,console,terminal这些名词到底是什么关系呢?我们就在这里搞搞清楚。

tty & terminal

tty是一种实现了除了读写以外额外命令 device file 的设备文件,一般来说,terminal等价于tty。

一些tty是由kernel内核为了硬件设备所提供的,例如键盘输入,在屏幕上输出文字,或者是对输入输出进行传输。

另一种tty被称为 pseudo-ttys, 通常由软件所提供,被称为终端仿真器,例如Xterm,Screen,SSH,等等

Terminal也有一种更为传统的含义,即一个提供人们与电脑进行交互的设备,通常配备键盘以及显示器。

什么是Login Shell和Non-Login Shell?

“A login shell is one whose first character of argument zero is a -, or one started with the –login option.” [10].

如何判断?

判断一个shell是否是login shell的标准就是$0的输出字符串,其第一个字符是否是’-’,如果是,则是一个login shell;

Figure 3: 判断Login shell

Figure 3: 判断Login shell

我们也可以通过输入logout命令来进行判断其是否用了 –login选项,如果可以正常退出,则表示这是一个login shell,如果只能用’exit’ 退出,则表示不是一个login shell

Figure 4: Logout

Figure 4: Logout

Login shell

Login shell在启动的时候,会传递$0, 通常就是带’-‘的shell名,例如 ‘-bash’, ‘-zsh’,

Reference

[1] ‘What is an Interactive Shell? (Bash Reference Manual)’. https://www.gnu.org/software/bash/manual/html_node/What-is-an-Interactive-Shell_003f.html (accessed Jul. 21, 2022). [2] T. Hansson, ‘Answer to “What’s the difference between an argument and a parameter?”’, Stack Overflow, Oct. 01, 2008. https://stackoverflow.com/a/156787/17534765 (accessed Jul. 21, 2022). [3] jlliagre, ‘Answer to “Difference between terms: ‘option’, ‘argument’, and ‘parameter’?”’, Stack Overflow, Apr. 08, 2016. https://stackoverflow.com/a/36495940/17534765 (accessed Jul. 21, 2022). [4] navigaid, ‘Answer to “What does bash -s do?”’, Stack Overflow, Aug. 15, 2018. https://stackoverflow.com/a/51854728/17534765 (accessed Jul. 22, 2022). [5] ‘Shell Scripting - Interactive and Non-Interactive Shell’, GeeksforGeeks, Jan. 23, 2022. https://www.geeksforgeeks.org/shell-scripting-interactive-and-non-interactive-shell/ (accessed Jul. 22, 2022). [6] 毛英东, ‘什么是交互式shell和非交互式shell?’, 毛英东的个人博客, May 30, 2020. https://www.maoyingdong.com/what_is_a_interactive_shell/index.html (accessed Jul. 22, 2022). [7] V. Gite, ‘How to Change / Set up bash custom prompt (PS1) in Linux’, nixCraft, Jun. 02, 2007. https://www.cyberciti.biz/tips/howto-linux-unix-bash-shell-setup-prompt.html (accessed Jul. 22, 2022). [8] anubhava, ‘Answer to “What does $- mean in Bash?”’, Stack Overflow, Mar. 13, 2017. https://stackoverflow.com/a/42757277/17534765 (accessed Jul. 22, 2022). [9] S. Ganguly, ‘How to Use Special Variables in Bash’. https://linuxhint.com/use-special-variables-in-bash/ (accessed Jul. 22, 2022).

Licensed under CC BY-NC-SA 4.0
Last updated on Oct 09, 2022 16:50 CST
comments powered by Disqus
Cogito, ergo sum
Built with Hugo
Theme Stack designed by Jimmy