# 4.2 Linux 命令行技巧

* [通配符](#通配符)
* [重定向输入字符](#重定向输入字符)
* [从可执行文件中提取 shellcode](#从可执行文件中提取-shellcode)
* [查看进程虚拟地址空间](#查看进程虚拟地址空间)
* [ASCII 表](#ascii-表)
* [nohup 和 &](#nohup-和-)
* [cat -](#cat--)

## 通配符

* `*`：匹配任意字符
  * `ls test*`
* `?`：匹配任意单个字符
  * `ls test?`
* `[...]`：匹配括号内的任意单个字符
  * `ls test[123]`
* `[!...]`：匹配除括号内字符以外的单个字符
  * `ls test[!123]`

## 重定向输入字符

有时候我们需要在 shell 里输入键盘上没有对应的字符，如 `0x1F`，就需要使用重定向输入。下面是一个例子：

```
#include<stdio.h>
#include<string.h>
void main() {
    char data[8];
    char str[8];
    printf("请输入十六进制为 0x1f 的字符: ");
    sprintf(str, "%c", 31);
    scanf("%s", data);
    if (!strcmp((const char *)data, (const char *)str)) {
        printf("correct\n");
    } else {
        printf("wrong\n");
    }
}
```

```
$ gcc test.c
$ ./a.out
请输入十六进制为 0x1f 的字符: 0x1f
wrong
$ echo -e "\x1f"

$ echo -e "\x1f" | ./a.out
请输入十六进制为 0x1f 的字符: correct
```

## 从可执行文件中提取 shellcode

```
for i in `objdump -d print_flag | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\x$i" ; done
```

注意：在 objdump 中空字节可能会被删除。

## 查看进程虚拟地址空间

有时我们需要知道一个进程的虚拟地址空间是如何使用的，以确定栈是否是可执行的。

```
$ cat /proc/<PID>/maps
```

下面我们分别来看看可执行栈和不可执行栈的不同：

```
$ cat hello.c
#include <stdio.h>
void main()
{
    char buf[128];
    scanf("hello, world: %s\n", buf);
}

$ gcc hello.c -o a.out1

$ ./a.out1 &
[1] 7403

$ cat /proc/7403/maps
555555554000-555555555000 r-xp 00000000 08:01 26389924                   /home/firmy/a.out1
555555754000-555555755000 r--p 00000000 08:01 26389924                   /home/firmy/a.out1
555555755000-555555756000 rw-p 00001000 08:01 26389924                   /home/firmy/a.out1
555555756000-555555777000 rw-p 00000000 00:00 0                          [heap]
7ffff7a33000-7ffff7bd0000 r-xp 00000000 08:01 21372436                   /usr/lib/libc-2.25.so
7ffff7bd0000-7ffff7dcf000 ---p 0019d000 08:01 21372436                   /usr/lib/libc-2.25.so
7ffff7dcf000-7ffff7dd3000 r--p 0019c000 08:01 21372436                   /usr/lib/libc-2.25.so
7ffff7dd3000-7ffff7dd5000 rw-p 001a0000 08:01 21372436                   /usr/lib/libc-2.25.so
7ffff7dd5000-7ffff7dd9000 rw-p 00000000 00:00 0
7ffff7dd9000-7ffff7dfc000 r-xp 00000000 08:01 21372338                   /usr/lib/ld-2.25.so
7ffff7fbc000-7ffff7fbe000 rw-p 00000000 00:00 0
7ffff7ff8000-7ffff7ffa000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00023000 08:01 21372338                   /usr/lib/ld-2.25.so
7ffff7ffd000-7ffff7ffe000 rw-p 00024000 08:01 21372338                   /usr/lib/ld-2.25.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

[1]+  Stopped                 ./a.out1

$ gcc -z execstack hello.c -o a.out2

$ ./a.out2 &
[2] 7467
[firmy@manjaro ~]$ cat /proc/7467/maps
555555554000-555555555000 r-xp 00000000 08:01 26366643                   /home/firmy/a.out2
555555754000-555555755000 r-xp 00000000 08:01 26366643                   /home/firmy/a.out2
555555755000-555555756000 rwxp 00001000 08:01 26366643                   /home/firmy/a.out2
555555756000-555555777000 rwxp 00000000 00:00 0                          [heap]
7ffff7a33000-7ffff7bd0000 r-xp 00000000 08:01 21372436                   /usr/lib/libc-2.25.so
7ffff7bd0000-7ffff7dcf000 ---p 0019d000 08:01 21372436                   /usr/lib/libc-2.25.so
7ffff7dcf000-7ffff7dd3000 r-xp 0019c000 08:01 21372436                   /usr/lib/libc-2.25.so
7ffff7dd3000-7ffff7dd5000 rwxp 001a0000 08:01 21372436                   /usr/lib/libc-2.25.so
7ffff7dd5000-7ffff7dd9000 rwxp 00000000 00:00 0
7ffff7dd9000-7ffff7dfc000 r-xp 00000000 08:01 21372338                   /usr/lib/ld-2.25.so
7ffff7fbc000-7ffff7fbe000 rwxp 00000000 00:00 0
7ffff7ff8000-7ffff7ffa000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
7ffff7ffc000-7ffff7ffd000 r-xp 00023000 08:01 21372338                   /usr/lib/ld-2.25.so
7ffff7ffd000-7ffff7ffe000 rwxp 00024000 08:01 21372338                   /usr/lib/ld-2.25.so
7ffff7ffe000-7ffff7fff000 rwxp 00000000 00:00 0
7ffffffde000-7ffffffff000 rwxp 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

[2]+  Stopped                 ./a.out2
```

当使用 `-z execstack` 参数进行编译时，会关闭 `Stack Protector`。我们可以看到在 `a.out1` 中的 `stack` 是 `rw` 的，而 `a.out2` 中则是 `rwx` 的。

`maps` 文件有 6 列，分别为：

* **地址**：库在进程里地址范围
* **权限**：虚拟内存的权限，r=读，w=写,x=执行,s=共享,p=私有
* **偏移量**：库在进程里地址偏移量
* **设备**：映像文件的主设备号和次设备号，可以通过通过 `cat /proc/devices` 查看设备号对应的设备名
* **节点**：映像文件的节点号
* **路径**: 映像文件的路径，经常同一个地址有两个地址范围，那是因为一段是 `r-xp` 为只读的代码段，一段是 `rwxp` 为可读写的数据段

除了 `/proc/<PID>/maps` 之外，还有一些有用的设备和文件。

* `/proc/kcore` 是 Linux 内核运行时的动态 core 文件。它是一个原始的内存转储，以 ELF core 文件的形式呈现，可以使用 GDB 来调试和分析内核。
* `／boot/System.map` 是一个特定内核的内核符号表。它是你当前运行的内核的 System.map 的链接。
* `/proc/kallsyms` 和 `System.map` 很类似，但它在 `/proc` 目录下，所以是由内核维护的，并可以动态更新。
*   `/proc/iomem` 和 `/proc/<pid>/maps` 类似，但它是用于系统内存的。如：

    ```
    # cat /proc/iomem | grep Kernel
    01000000-01622d91 : Kernel code
    01622d92-01b0ddff : Kernel data
    01c56000-01d57fff : Kernel bss
    ```

## ASCII 表

ASCII 表将键盘上的所有字符映射到固定的数字。有时候我们可能需要查看这张表：

```
$ man ascii

Oct   Dec   Hex   Char                        Oct   Dec   Hex   Char
────────────────────────────────────────────────────────────────────────
000   0     00    NUL '\0' (null character)   100   64    40    @
001   1     01    SOH (start of heading)      101   65    41    A
002   2     02    STX (start of text)         102   66    42    B
003   3     03    ETX (end of text)           103   67    43    C
004   4     04    EOT (end of transmission)   104   68    44    D
005   5     05    ENQ (enquiry)               105   69    45    E
006   6     06    ACK (acknowledge)           106   70    46    F
007   7     07    BEL '\a' (bell)             107   71    47    G
010   8     08    BS  '\b' (backspace)        110   72    48    H
011   9     09    HT  '\t' (horizontal tab)   111   73    49    I
012   10    0A    LF  '\n' (new line)         112   74    4A    J
013   11    0B    VT  '\v' (vertical tab)     113   75    4B    K
014   12    0C    FF  '\f' (form feed)        114   76    4C    L
015   13    0D    CR  '\r' (carriage ret)     115   77    4D    M
016   14    0E    SO  (shift out)             116   78    4E    N
017   15    0F    SI  (shift in)              117   79    4F    O
020   16    10    DLE (data link escape)      120   80    50    P
021   17    11    DC1 (device control 1)      121   81    51    Q
022   18    12    DC2 (device control 2)      122   82    52    R
023   19    13    DC3 (device control 3)      123   83    53    S
024   20    14    DC4 (device control 4)      124   84    54    T
025   21    15    NAK (negative ack.)         125   85    55    U
026   22    16    SYN (synchronous idle)      126   86    56    V
027   23    17    ETB (end of trans. blk)     127   87    57    W
030   24    18    CAN (cancel)                130   88    58    X
031   25    19    EM  (end of medium)         131   89    59    Y
032   26    1A    SUB (substitute)            132   90    5A    Z
033   27    1B    ESC (escape)                133   91    5B    [
034   28    1C    FS  (file separator)        134   92    5C    \  '\\'
035   29    1D    GS  (group separator)       135   93    5D    ]
036   30    1E    RS  (record separator)      136   94    5E    ^
037   31    1F    US  (unit separator)        137   95    5F    _
040   32    20    SPACE                       140   96    60    `
041   33    21    !                           141   97    61    a
042   34    22    "                           142   98    62    b
043   35    23    #                           143   99    63    c
044   36    24    $                           144   100   64    d
045   37    25    %                           145   101   65    e
046   38    26    &                           146   102   66    f
047   39    27    '                           147   103   67    g
050   40    28    (                           150   104   68    h
051   41    29    )                           151   105   69    i
052   42    2A    *                           152   106   6A    j
053   43    2B    +                           153   107   6B    k
054   44    2C    ,                           154   108   6C    l
055   45    2D    -                           155   109   6D    m

056   46    2E    .                           156   110   6E    n
057   47    2F    /                           157   111   6F    o
060   48    30    0                           160   112   70    p
061   49    31    1                           161   113   71    q
062   50    32    2                           162   114   72    r
063   51    33    3                           163   115   73    s
064   52    34    4                           164   116   74    t
065   53    35    5                           165   117   75    u
066   54    36    6                           166   118   76    v
067   55    37    7                           167   119   77    w
070   56    38    8                           170   120   78    x
071   57    39    9                           171   121   79    y
072   58    3A    :                           172   122   7A    z
073   59    3B    ;                           173   123   7B    {
074   60    3C    <                           174   124   7C    |
075   61    3D    =                           175   125   7D    }
076   62    3E    >                           176   126   7E    ~
077   63    3F    ?                           177   127   7F    DEL

Tables
For convenience, below are more compact tables in hex and decimal.

   2 3 4 5 6 7       30 40 50 60 70 80 90 100 110 120
 -------------      ---------------------------------
0:   0 @ P ` p     0:    (  2  <  F  P  Z  d   n   x
1: ! 1 A Q a q     1:    )  3  =  G  Q  [  e   o   y
2: " 2 B R b r     2:    *  4  >  H  R  \  f   p   z
3: # 3 C S c s     3: !  +  5  ?  I  S  ]  g   q   {
4: $ 4 D T d t     4: "  ,  6  @  J  T  ^  h   r   |
5: % 5 E U e u     5: #  -  7  A  K  U  _  i   s   }
6: & 6 F V f v     6: $  .  8  B  L  V  `  j   t   ~
7: ' 7 G W g w     7: %  /  9  C  M  W  a  k   u  DEL
8: ( 8 H X h x     8: &  0  :  D  N  X  b  l   v
9: ) 9 I Y i y     9: '  1  ;  E  O  Y  c  m   w
A: * : J Z j z
B: + ; K [ k {
C: , < L \ l |
D: - = M ] m }
E: . > N ^ n ~
F: / ? O _ o DEL
```

Hex 转 Char：

```shell
$ echo -e '\x41\x42\x43\x44'
$ printf '\x41\x42\x43\x44'
$ python -c 'print(u"\x41\x42\x43\x44")'
$ perl -e 'print "\x41\x42\x43\x44";'
```

Char 转 Hex：

```shell
$ python -c 'print(b"ABCD".hex())'
```

## nohup 和 &

用 `nohup` 运行命令可以使命令永久的执行下去，和 Shell 没有关系，而 `&` 表示设置此进程为后台进程。默认情况下，进程是前台进程，这时就把 Shell 给占据了，我们无法进行其他操作，如果我们希望其在后台运行，可以使用 `&` 达到这个目的。

该命令的一般形式为：

```
$ nohup <command> &
```

### 前后台进程切换

可以通过 `bg`（background）和 `fg`（foreground）命令进行前后台进程切换。

显示Linux中的任务列表及任务状态：

```
$ jobs -l
[1]+  9433 Stopped (tty input)     ./a.out
```

将进程放到后台运行：

```
$ bg 1
```

将后台进程放到前台运行：

```
$ fg 1
```

## cat -

通常使用 cat 时后面都会跟一个文件名，但如果没有，或者只有一个 `-`，则表示从标准输入读取数据，它会保持标准输入开启，如：

```
$ cat -
hello world
hello world
^C
```

更进一步，如果你采用 `cat file -` 的用法，它会先输出 file 的内容，然后是标准输入，它将标准输入的数据复制到标准输出，并保持标准输入开启：

```
$ echo hello > text
$ cat text -
hello
world
world
^C
```

有时我们在向程序发送 paylaod 的时候，它执行完就直接退出了，并没有开启 shell，我们就可以利用上面的技巧：

```
$ cat payload | ./a.out
> Segmentation fault (core dumped)

$ cat payload - | ./a.out
whoami
firmy
^C
Segmentation fault (core dumped)
```

这样就得到了 shell。
