# 4.2 Linux 命令行技巧

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


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


## 重定向输入字符
有时候我们需要在 shell 里输入键盘上没有对应的字符,如 `0x1F`,就需要使用重定向输入。下面是一个例子:
```C
#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
```text
for i in `objdump -d print_flag | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\x$i" ; done
```
注意:在 objdump 中空字节可能会被删除。


## 查看进程虚拟地址空间
有时我们需要知道一个进程的虚拟地址空间是如何使用的,以确定栈是否是可执行的。
```text
$ cat /proc/<PID>/maps
```
下面我们分别来看看可执行栈和不可执行栈的不同:
```text
$ 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 表将键盘上的所有字符映射到固定的数字。有时候我们可能需要查看这张表:
```text
$ 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。