4.2 Linux 命令行技巧

通配符

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

重定向输入字符

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

  1. #include<stdio.h>
  2. #include<string.h>
  3. void main() {
  4. char data[8];
  5. char str[8];
  6. printf("请输入十六进制为 0x1f 的字符: ");
  7. sprintf(str, "%c", 31);
  8. scanf("%s", data);
  9. if (!strcmp((const char *)data, (const char *)str)) {
  10. printf("correct\n");
  11. } else {
  12. printf("wrong\n");
  13. }
  14. }
  1. $ gcc test.c
  2. $ ./a.out
  3. 请输入十六进制为 0x1f 的字符: 0x1f
  4. wrong
  5. $ echo -e "\x1f"
  6. $ echo -e "\x1f" | ./a.out
  7. 请输入十六进制为 0x1f 的字符: correct

从可执行文件中提取 shellcode

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

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

查看进程虚拟地址空间

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

  1. $ cat /proc/<PID>/maps

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

  1. $ cat hello.c
  2. #include <stdio.h>
  3. void main()
  4. {
  5. char buf[128];
  6. scanf("hello, world: %s\n", buf);
  7. }
  8. $ gcc hello.c -o a.out1
  9. $ ./a.out1 &
  10. [1] 7403
  11. $ cat /proc/7403/maps
  12. 555555554000-555555555000 r-xp 00000000 08:01 26389924 /home/firmy/a.out1
  13. 555555754000-555555755000 r--p 00000000 08:01 26389924 /home/firmy/a.out1
  14. 555555755000-555555756000 rw-p 00001000 08:01 26389924 /home/firmy/a.out1
  15. 555555756000-555555777000 rw-p 00000000 00:00 0 [heap]
  16. 7ffff7a33000-7ffff7bd0000 r-xp 00000000 08:01 21372436 /usr/lib/libc-2.25.so
  17. 7ffff7bd0000-7ffff7dcf000 ---p 0019d000 08:01 21372436 /usr/lib/libc-2.25.so
  18. 7ffff7dcf000-7ffff7dd3000 r--p 0019c000 08:01 21372436 /usr/lib/libc-2.25.so
  19. 7ffff7dd3000-7ffff7dd5000 rw-p 001a0000 08:01 21372436 /usr/lib/libc-2.25.so
  20. 7ffff7dd5000-7ffff7dd9000 rw-p 00000000 00:00 0
  21. 7ffff7dd9000-7ffff7dfc000 r-xp 00000000 08:01 21372338 /usr/lib/ld-2.25.so
  22. 7ffff7fbc000-7ffff7fbe000 rw-p 00000000 00:00 0
  23. 7ffff7ff8000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar]
  24. 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
  25. 7ffff7ffc000-7ffff7ffd000 r--p 00023000 08:01 21372338 /usr/lib/ld-2.25.so
  26. 7ffff7ffd000-7ffff7ffe000 rw-p 00024000 08:01 21372338 /usr/lib/ld-2.25.so
  27. 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
  28. 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
  29. ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
  30. [1]+ Stopped ./a.out1
  31. $ gcc -z execstack hello.c -o a.out2
  32. $ ./a.out2 &
  33. [2] 7467
  34. [firmy@manjaro ~]$ cat /proc/7467/maps
  35. 555555554000-555555555000 r-xp 00000000 08:01 26366643 /home/firmy/a.out2
  36. 555555754000-555555755000 r-xp 00000000 08:01 26366643 /home/firmy/a.out2
  37. 555555755000-555555756000 rwxp 00001000 08:01 26366643 /home/firmy/a.out2
  38. 555555756000-555555777000 rwxp 00000000 00:00 0 [heap]
  39. 7ffff7a33000-7ffff7bd0000 r-xp 00000000 08:01 21372436 /usr/lib/libc-2.25.so
  40. 7ffff7bd0000-7ffff7dcf000 ---p 0019d000 08:01 21372436 /usr/lib/libc-2.25.so
  41. 7ffff7dcf000-7ffff7dd3000 r-xp 0019c000 08:01 21372436 /usr/lib/libc-2.25.so
  42. 7ffff7dd3000-7ffff7dd5000 rwxp 001a0000 08:01 21372436 /usr/lib/libc-2.25.so
  43. 7ffff7dd5000-7ffff7dd9000 rwxp 00000000 00:00 0
  44. 7ffff7dd9000-7ffff7dfc000 r-xp 00000000 08:01 21372338 /usr/lib/ld-2.25.so
  45. 7ffff7fbc000-7ffff7fbe000 rwxp 00000000 00:00 0
  46. 7ffff7ff8000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar]
  47. 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
  48. 7ffff7ffc000-7ffff7ffd000 r-xp 00023000 08:01 21372338 /usr/lib/ld-2.25.so
  49. 7ffff7ffd000-7ffff7ffe000 rwxp 00024000 08:01 21372338 /usr/lib/ld-2.25.so
  50. 7ffff7ffe000-7ffff7fff000 rwxp 00000000 00:00 0
  51. 7ffffffde000-7ffffffff000 rwxp 00000000 00:00 0 [stack]
  52. ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
  53. [2]+ Stopped ./a.out2

当使用 -z execstack 参数进行编译时,会关闭 Stack Protector。我们可以看到在 a.out1 中的 stackrw 的,而 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/kallsymsSystem.map 很类似,但它在 /proc 目录下,所以是由内核维护的,并可以动态更新。
  • /proc/iomem/proc/<pid>/maps 类似,但它是用于系统内存的。如:

    1. # cat /proc/iomem | grep Kernel
    2. 01000000-01622d91 : Kernel code
    3. 01622d92-01b0ddff : Kernel data
    4. 01c56000-01d57fff : Kernel bss

ASCII 表

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

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

Hex 转 Char:

  1. $ echo -e '\x41\x42\x43\x44'
  2. $ printf '\x41\x42\x43\x44'
  3. $ python -c 'print(u"\x41\x42\x43\x44")'
  4. $ perl -e 'print "\x41\x42\x43\x44";'

Char 转 Hex:

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

nohup 和 &

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

该命令的一般形式为:

  1. $ nohup <command> &

前后台进程切换

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

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

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

将进程放到后台运行:

  1. $ bg 1

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

  1. $ fg 1

cat -

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

  1. $ cat -
  2. hello world
  3. hello world
  4. ^C

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

  1. $ echo hello > text
  2. $ cat text -
  3. hello
  4. world
  5. world
  6. ^C

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

  1. $ cat payload | ./a.out
  2. > Segmentation fault (core dumped)
  3. $ cat payload - | ./a.out
  4. whoami
  5. firmy
  6. ^C
  7. Segmentation fault (core dumped)

这样就得到了 shell。