diff --git a/src/modules/password/change_password_windows.ts b/src/modules/password/change_password_windows.ts index 36f6a0a..c9f86f8 100644 --- a/src/modules/password/change_password_windows.ts +++ b/src/modules/password/change_password_windows.ts @@ -1,190 +1,189 @@ import { delay } from "../util/util"; -import socket_commands from "../util/socket_commands"; +import { sendCommandAndInput, sendCommand, sendCommandExpect } from "../util/socket_commands"; import { SSH2CONN, detect_hostname } from "../util/ssh_utils"; import { Server, User } from "../../db/dbtypes"; import { LDAPChangePassword } from "./active_directory"; import logger from "../console/logger"; import { getOutput, runCommand } from "../util/run_command"; -async function changePasswordWin(server:Server,user:User, conn: SSH2CONN |false, username: string, password: string) { +async function changePasswordWin(server: Server, user: User, conn: SSH2CONN | false, username: string, password: string) { var then = new Date(); - if(!conn){ + if (!conn) { try { - return await LDAPChangePassword(user,password); - } catch (error:any) { - logger.log(`[${server.ipaddress}] [${server.Name}] [${user.username}] error ${error.message}`,'error') - return error.message ? error as Error : error.message as string; - } + return await LDAPChangePassword(user, password); + } catch (error: any) { + logger.log(`[${server.ipaddress}] [${server.Name}] [${user.username}] error ${error.message}`, "error"); + return error.message ? (error as Error) : (error.message as string); + } } try { let checkReport = await check(conn); - conn.log(`AD: ${checkReport.domainController} Domain_User: ${checkReport.isDomainUser} Local_User: ${checkReport.useLocal} Force_Net: ${checkReport.forceNetUser}`) - let useLocalUser = checkReport.useLocal - if(checkReport.forceNetUser){ - return await changePasswordWindowsLocal(conn, username, password,false); + conn.log( + `AD: ${checkReport.domainController} Domain_User: ${checkReport.isDomainUser} Local_User: ${checkReport.useLocal} Force_Net: ${checkReport.forceNetUser}` + ); + let useLocalUser = checkReport.useLocal; + if (checkReport.forceNetUser) { + return await changePasswordWindowsLocal(conn, username, password, false); } - if(checkReport.isDomainUser && checkReport.domainController){ + if (checkReport.isDomainUser && checkReport.domainController) { try { - return await LDAPChangePassword(user,password); - } catch (error:any) { - logger.log(`[${server.ipaddress}] [${server.Name}] [${user.username}] LDAP Connection ${error.message}`,'warn') - conn.log("Fallback ssh") - return await changePasswordWinAD(conn,stripDomain(username), password); - } + return await LDAPChangePassword(user, password); + } catch (error: any) { + logger.log(`[${server.ipaddress}] [${server.Name}] [${user.username}] LDAP Connection ${error.message}`, "warn"); + conn.log("Fallback ssh"); + return await changePasswordWinAD(conn, stripDomain(username), password); + } } - if(checkReport.isDomainUser){ - return "UNABLE TO CHANGE PASSWORD OF DOMAIN ACCOUNT ON NON-DOMAIN-CONTROLLER" + if (checkReport.isDomainUser) { + return "UNABLE TO CHANGE PASSWORD OF DOMAIN ACCOUNT ON NON-DOMAIN-CONTROLLER"; } - return await changePasswordWindowsLocal(conn, username, password,useLocalUser); + return await changePasswordWindowsLocal(conn, username, password, useLocalUser); } catch (error: any) { - logger.log(`${error}`, 'error'); - return error.message ? error as Error : error.message as string; - }finally{ + logger.log(`${error}`, "error"); + return error.message ? (error as Error) : (error.message as string); + } finally { var now = new Date(); - var lapse_time= now.getTime() - then.getTime(); - logger.log(`Time to change Password ${lapse_time} ms on windows`) + var lapse_time = now.getTime() - then.getTime(); + logger.log(`Time to change Password ${lapse_time} ms on windows`); } } -async function changePasswordWindowsLocal(conn:SSH2CONN, username:string, password:string, useLocalUser:boolean){ +async function changePasswordWindowsLocal(conn: SSH2CONN, username: string, password: string, useLocalUser: boolean) { let shellSocket; try { - conn.info(`Using ${useLocalUser ? "Get-Local" : "net user"}`) + conn.info(`Using ${useLocalUser ? "Get-Local" : "net user"}`); if (useLocalUser) { shellSocket = await conn.shell(); - await socket_commands.sendCommandExpect(shellSocket, `powershell.exe`, `> `).catch((r)=> ""); + await sendCommandExpect(shellSocket, `powershell.exe`, `> `).catch((r) => ""); // await delay(3000); - await socket_commands.sendCommandAndInput(shellSocket, `${password}`, `$pass = Read-Host -AsSecureString;$user = Get-LocalUser "${username}";Set-LocalUser -Name $user -Password $pass;`) + await sendCommandAndInput( + shellSocket, + `${password}`, + `$pass = Read-Host -AsSecureString;$user = Get-LocalUser "${username}";Set-LocalUser -Name $user -Password $pass;` + ); } else { - await runCommand(conn, `net user ${username} ${password}`, "The command completed successfully",false) + await runCommand(conn, `net user ${username} ${password}`, "The command completed successfully", false); } - conn.success("Changed Password") - if(shellSocket){ - await socket_commands.sendCommand(shellSocket, "exit", true); + conn.success("Changed Password"); + if (shellSocket) { + await sendCommand(shellSocket, "exit", true); shellSocket.close(); } return true; } catch (error: any) { shellSocket?.close(); - conn.error(`Unable to change Local password ${error}`) - if(error.toString().includes('An error occurred.')) return "An error occurred while changing password, check if user exist and password meets requirements" + conn.error(`Unable to change Local password ${error}`); + if (error.toString().includes("An error occurred.")) + return "An error occurred while changing password, check if user exist and password meets requirements"; - return error as Error ; + return error as Error; } - - } - async function changePasswordWinAD(conn: SSH2CONN, username: string, password: string) { - - conn.info("Changing Domain Controller Account") + conn.info("Changing Domain Controller Account"); try { // let useLocalUser = await check(conn); let shellSocket = await conn.shell(); try { - conn.info("Resetting Active Directory User") + conn.info("Resetting Active Directory User"); // Ignore errors here incase powershell has different setup - await socket_commands.sendCommandExpect(shellSocket, `powershell.exe`, `> `).catch((r)=> ""); + await sendCommandExpect(shellSocket, `powershell.exe`, `> `).catch((r) => ""); // await delay(3000); - await socket_commands.sendCommandAndInput(shellSocket, `${password}`, `$pass = Read-Host -AsSecureString ; Set-ADAccountPassword -Identity "${username}" -Reset -NewPassword $pass;`) + await sendCommandAndInput( + shellSocket, + `${password}`, + `$pass = Read-Host -AsSecureString ; Set-ADAccountPassword -Identity "${username}" -Reset -NewPassword $pass;` + ); conn.success("Changed password"); } catch (error: any) { shellSocket.close(); - conn.error(`Unable to Change AD User password ${error}`) - if(error.toString().includes('An error occurred.')) return "An error occurred while changing password, check if user exist and password meets requirements" + conn.error(`Unable to Change AD User password ${error}`); + if (error.toString().includes("An error occurred.")) + return "An error occurred while changing password, check if user exist and password meets requirements"; return error; } - await socket_commands.sendCommand(shellSocket, "exit", true); + await sendCommand(shellSocket, "exit", true); shellSocket.close(); return true; } catch (error: any) { - return error.message ? error.toString() as string : error.message as string; + return error.message ? (error.toString() as string) : (error.message as string); } } export { changePasswordWin }; - type check_report = { - domainController: boolean, - useLocal:boolean, - isDomainUser:boolean, - forceNetUser: boolean - -} -async function check(conn: SSH2CONN):Promise { + domainController: boolean; + useLocal: boolean; + isDomainUser: boolean; + forceNetUser: boolean; +}; +async function check(conn: SSH2CONN): Promise { var passed = 2; var forceNetUser = false; - conn.log("Running Checks") - + conn.log("Running Checks"); + let os_check = await conn.exec("echo %OS%"); if (os_check.trim() != "Windows_NT") { - conn.error(`Windows check error GOT ${os_check} WANTED Windows_NT, Please check for environment vars`) + conn.error(`Windows check error GOT ${os_check} WANTED Windows_NT, Please check for environment vars`); passed--; } let get_local_check; try { - var output = await getOutput(conn, `powershell.exe "Get-LocalUser"`); + var output = await getOutput(conn, `powershell.exe "Get-LocalUser"`); // If this times out either we do not have connect or powershell cannot be targeted. Will focus to use net user - if(output.includes("Timed")){ + if (output.includes("Timed")) { get_local_check = false; forceNetUser = true; - }else if (output.trim().includes("is not recognized")) { - conn.warn(`Windows check error GOT ${output.substring(0, 30)} WANTED User List, Powershell version might be out of date`) + } else if (output.trim().includes("is not recognized")) { + conn.warn(`Windows check error GOT ${output.substring(0, 30)} WANTED User List, Powershell version might be out of date`); passed--; - }else { + } else { get_local_check = true; } - } catch (error: any) { + } catch (error: any) {} - } - - let isDomainController = false ; + let isDomainController = false; try { - var output = await getOutput(conn,`wmic.exe ComputerSystem get DomainRole`) - if(output.includes("Timed") || output.includes("is not recognized")) { + var output = await getOutput(conn, `wmic.exe ComputerSystem get DomainRole`); + if (output.includes("Timed") || output.includes("is not recognized")) { isDomainController = false; - }else if (output.includes("4") ||output.includes("5") ){ - conn.log("Computer is a Domain Controller") + } else if (output.includes("4") || output.includes("5")) { + conn.log("Computer is a Domain Controller"); isDomainController = true; } - } catch (error) { - - } + } catch (error) {} let isDomainUser = false; try { - let whoamiString = await conn.exec('whoami'); + let whoamiString = await conn.exec("whoami"); let hostname = await detect_hostname(conn); // if hostname is not included in whoami then its a domain user - if(!whoamiString.includes(hostname?.toLowerCase())){ + if (!whoamiString.includes(hostname?.toLowerCase())) { isDomainUser = true; } - - } catch (error) { - - } - conn.info(`Passed ${passed} of 2 tests`) + } catch (error) {} + conn.info(`Passed ${passed} of 2 tests`); return { useLocal: !!get_local_check, domainController: isDomainController, - isDomainUser:isDomainUser, - forceNetUser: forceNetUser + isDomainUser: isDomainUser, + forceNetUser: forceNetUser, }; } // extracts the username from a domain -function stripDomain(fullUsername:string):string { +function stripDomain(fullUsername: string): string { // Use a regex pattern to match "domain\username" const regex = /(?:\\|@)([^\\@]+)$/; const match = fullUsername.match(regex); @@ -196,4 +195,4 @@ function stripDomain(fullUsername:string):string { // If no match is found, return the original string return fullUsername; } -} \ No newline at end of file +} diff --git a/src/modules/util/socket_commands.ts b/src/modules/util/socket_commands.ts index ac56022..3b7bd7c 100644 --- a/src/modules/util/socket_commands.ts +++ b/src/modules/util/socket_commands.ts @@ -30,7 +30,7 @@ function sendCommandExpect(socket: Channel, command: string, expected: string): }); } /** THIS FILE IS FOR COMMANDS SENT BY A SOCKET CONNECTION */ -function socketGetOutput(socket: Channel, command: string) { +function socketGetOutput(socket: Channel, command: string): Promise { return new Promise((resolve, reject) => { let log = ""; @@ -241,4 +241,4 @@ function removeWindowsLoading(strLog: string): string { return stringWithoutLoadingLines.trim(); // Trim leading and trailing whitespace } -export default { sendCommand, sendCommandAndInput, sendCommandExpect, sendCommandNoExpect, sendInput, sendInputExpect, socketGetOutput }; +export { sendCommand, sendCommandAndInput, sendCommandExpect, sendCommandNoExpect, sendInput, sendInputExpect, socketGetOutput }; diff --git a/test/db.spec.ts b/test/db.spec.ts new file mode 100644 index 0000000..8f9049a --- /dev/null +++ b/test/db.spec.ts @@ -0,0 +1,17 @@ +import assert from "assert"; +import db from "../src/db/db"; +describe("DataBase", () => { + describe("Add User", () => { + it("should add a user successfully", async () => { + const ip = "192.168.1.1"; + const username = "testuser"; + const password = "secretpassword"; + const hostname = "myhost"; + const domain = "example.com"; + + const result = await db.addUser(ip, username, password, hostname, domain); + + assert.ok(result); + }); + }); +}); diff --git a/tests/ssh.spec.ts b/tests/ssh.spec.ts index aa56f97..8d28087 100644 --- a/tests/ssh.spec.ts +++ b/tests/ssh.spec.ts @@ -1,4 +1,6 @@ import { getOutput, runCommand, runCommandNoExpect, runCommandNotExpect } from "../src/modules/util/run_command"; +import { sendCommand, sendCommandExpect, sendCommandNoExpect, socketGetOutput } from "../src/modules/util/socket_commands"; + import { changePasswordOf } from "../src/modules/password/change_passwords"; import { detect_hostname, detect_os, ejectSSHkey, makeConnection, removeSSHkey, testPassword } from "../src/modules/util/ssh_utils"; import { computers } from "./computers"; @@ -10,11 +12,16 @@ const defaultPassword = process.env.DEFAULT; for (let computer of computers) { console.log("\n\n\n"); - describe(`SSH ${computer["OS Type"]} ${computer.Name} ${computer.ipaddress}`, () => { + describe(`SSH ${computer["OS Type"]} ${computer.Name} ${computer.ipaddress}`, async () => { let user = computer.users[0]; if (!user) { throw new Error("Unable to find User"); } + let ssh = await makeConnection(user, 3000, 3); + if (!ssh) { + throw new Error("Unable to connect to server, will not continue"); + } + await ssh.close(); it("Can Make Connection to server", async () => { let ssh = await makeConnection(user, 3000, 3); assert.ok(ssh, "Unable to connect to target server"); @@ -82,7 +89,7 @@ for (let computer of computers) { } }); }); - describe("Command Utils", async () => { + describe("Command Utils", () => { it("runCommandNotExpect", async () => { let ssh = await makeConnection(user, 3000, 3); if (!ssh) { @@ -124,6 +131,54 @@ for (let computer of computers) { await ssh.close(); }); }); + if (computer["OS Type"] == "windows") { + describe("Socket Commands", () => { + it("sendCommand", async () => { + let ssh = await makeConnection(user, 3000, 3); + if (!ssh) { + throw new Error("Unable to connect to target server"); + } + let socket = await ssh.shell(); + let result = await sendCommand(socket, "exit", true); + assert.ok(result.includes("exit"), "Didn't get expected output: " + result); + await ssh.close(); + }); + it("sendCommandExpect", async () => { + let ssh = await makeConnection(user, 3000, 3); + if (!ssh) { + throw new Error("Unable to connect to target server"); + } + let socket = await ssh.shell(); + let result = await sendCommandExpect(socket, `powershell.exe`, `> `); + assert.ok(result.includes("> "), "Didn't get expected output: " + result); + await ssh.close(); + }); + it("socketGetOutput", async () => { + let ssh = await makeConnection(user, 3000, 3); + if (!ssh) { + throw new Error("Unable to connect to target server"); + } + let socket = await ssh.shell(); + let result = await socketGetOutput(socket, `powershell.exe`); + assert.ok(result.includes("> "), "Didn't get expected output: " + result); + await ssh.close(); + }); + it("sendCommandNoExpect", async () => { + let ssh = await makeConnection(user, 3000, 3); + if (!ssh) { + throw new Error("Unable to connect to target server"); + } + let socket = await ssh.shell(); + + await assert.doesNotReject( + sendCommandNoExpect(socket, `hostname`, "Pineapples are great"), + "Unable to check for not expect output" + ); + + await ssh.close(); + }); + }); + } describe("SSH Key", () => { it("Can deploy to Server", async () => {