服務(wù)器入侵之找出隱藏字符的原理
一、文章起源
我在文章 一次服務(wù)器被入侵的處理過程分享 中間有提及到我通過 cat/more 等命令查看文件,以及通過crontab -l 命令查看,一些定時(shí)任務(wù)和文件內(nèi)容被隱藏了。
二、細(xì)講問題

文件內(nèi)容為何顯示不了,究竟是什么東西在作怪,讓我們一探究竟。
為了讓大家也可以一起了解下, 文件我放到 阿里云oss 上, 有興趣的可以下載下來(lái)看下。 隱藏文件內(nèi)容示例
2.1、 文件在不同環(huán)境下的不同編譯器打開的顯示情況
Linux 通過 cat/more 打開

Linux 通過 vim 打開

Notepad++ 顯示所有字符模式打開

開始自己網(wǎng)上查了一下, 沒有查到原因。憑借著做多年運(yùn)維解決問題的經(jīng)驗(yàn),已經(jīng)對(duì)問題的那種直覺感, 總覺得應(yīng)該是 ;^M(我裝到了)。
三、 借助場(chǎng)外資源
為了一探究竟,特意叫一個(gè)朋友拉我進(jìn)了一個(gè)安全群,在群里詢問下安全大佬。
3.1、雙向文本(Bidirectional tex)
具體可以看下這個(gè)文章 https://tttang.com/archive/1339/
在安全群里問了一下,有位大佬提了一句 雙向文本方向。 我都沒有聽說(shuō)過這個(gè)東西。 雙向文本到底是啥,科普下:雙向文本就是一個(gè)字符串里面,包含了兩種文字,既包含從左到右的文字,又包含從右向左的文字。
示例1:
文本中是
RLI a b c PDI
而顯示實(shí)際是
c b a
示例2:
文本中是
RLI LRI a b c PDI LRI d e f PDI PDI
而實(shí)際上顯示的是
d e f a b c
示例3:
代碼顯示內(nèi)容為

實(shí)際執(zhí)行的內(nèi)容是

細(xì)看,這好像跟我們的場(chǎng)景還是不一樣。 這個(gè)只是調(diào)換文字的順序。飯可以亂吃,路不能亂走啊,得走正道。 繼續(xù)瞅瞅。
3.2、 看看^M
有另外一個(gè)大佬說(shuō)出來(lái)了一個(gè)問題, 所有的問題原因是 跟^M 有關(guān)。
如何在vim 中打出
^M, ctrl + v +m 可以輸出^M
大佬說(shuō)到 ^M 是回車換行符。 cat 帶有^M的一行字符串時(shí),屏幕上會(huì)把 ^M 之后的內(nèi)容在同一行換行后輸出,這樣就會(huì)覆蓋掉^M之前的內(nèi)容,導(dǎo)致你看到的這個(gè)內(nèi)容效果。
我產(chǎn)生了疑問, ^M 是回車換行符, 這個(gè)有依據(jù)嗎? 在下面有解釋。
先不管這個(gè),我們先測(cè)試一波。
示例一
[root@vm-12-12-centos tmp]# cat test
1bc
[root@vm-12-12-centos tmp]# cat -A test
abc^M1$
示例二
[root@vm-12-12-centos tmp]# cat -A test
abc^M123$
[root@vm-12-12-centos tmp]# cat test
123
示例三
[root@vm-12-12-centos tmp]# cat -A test
abc^M1 45$
[root@vm-12-12-centos tmp]# cat test
1 45
通過上面的示例,我們可以知道,^M 后面的內(nèi)容會(huì)覆蓋 ^M 前面的內(nèi)容, 入侵者就是利用這個(gè)原理,在 ^M 后面打了很多個(gè)空格覆蓋掉前面實(shí)際定時(shí)任務(wù)的內(nèi)容。 哎,這入侵者真是個(gè)人才。

3.3、真相大白
前面我產(chǎn)生了疑問, ^M 是回車換行符, 這個(gè)有依據(jù)嗎? 我該怎么去查看這cat 命令把這個(gè) ^M 給識(shí)別成啥了?
在憋了幾天之后,終于想到了一個(gè)大器(strace)。 有點(diǎn)相見恨晚的感覺。

[root@vm-12-12-centos tmp]# strace cat test
execve("/bin/cat", ["cat", "test"], 0x7ffe1d047e08 /* 19 vars */) = 0
brk(NULL) = 0x1c0d000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f14da021000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=22981, ...}) = 0
mmap(NULL, 22981, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f14da01b000
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`&\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2156592, ...}) = 0
mmap(NULL, 3985920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f14d9a33000
mprotect(0x7f14d9bf7000, 2093056, PROT_NONE) = 0
mmap(0x7f14d9df6000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7f14d9df6000
mmap(0x7f14d9dfc000, 16896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f14d9dfc000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f14da01a000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f14da018000
arch_prctl(ARCH_SET_FS, 0x7f14da018740) = 0
access("/etc/sysconfig/strcasecmp-nonascii", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/sysconfig/strcasecmp-nonascii", F_OK) = -1 ENOENT (No such file or directory)
mprotect(0x7f14d9df6000, 16384, PROT_READ) = 0
mprotect(0x60b000, 4096, PROT_READ) = 0
mprotect(0x7f14da022000, 4096, PROT_READ) = 0
munmap(0x7f14da01b000, 22981) = 0
brk(NULL) = 0x1c0d000
brk(0x1c2e000) = 0x1c2e000
brk(NULL) = 0x1c2e000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106176928, ...}) = 0
mmap(NULL, 106176928, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f14d34f0000
close(3) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
open("test", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=12, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "abc\r1 45\n", 65536) = 12
1 45, "abc\r1 45\n", 12abc
) = 12
read(3, "", 65536) = 0
close(3) = 0
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
我們注意看, read 這里的內(nèi)容。
read(3, "abc\r1 45\n", 65536) = 12
我們發(fā)現(xiàn) ^M 在 cat 命令執(zhí)行過程中,轉(zhuǎn)換為 \r , 那么 \r 又是什么? 接下來(lái)需要去翻閱 新華字典了。

數(shù)據(jù)來(lái)源 https://man7.org/linux/man-pages/man7/ascii.7.html
\r : 回車符(carriage ret), 對(duì)應(yīng)ASCII值13(縮寫:CR)。 它的含義是什么: 回車 (控制字元)。

那我們前面通過 notepad++ 打開的線上的 CR 是不是就對(duì)上了。

最終我們可以得出一個(gè)初步結(jié)論, 也就是:
- 在 Linux Vim 中打印出來(lái)的
^Mcat 等一些命令會(huì)轉(zhuǎn)換為\r,\r也就是回車 在Linux、unix中 表示它將光標(biāo)返回到行首。\r之后的內(nèi)容也就會(huì)覆蓋前面的內(nèi)容。
四、注意
- 以后服務(wù)器如果入侵了,建議我們使用
cat -A命令來(lái)查看。這樣一些隱藏字符就可以看到了。


浙公網(wǎng)安備 33010602011771號(hào)