mirror of
https://github.com/0dayCTF/reverse-shell-generator.git
synced 2024-12-18 10:56:10 +00:00
Add initial raw link support with netlify functions
This commit is contained in:
parent
8615ce53c6
commit
0b6113bf02
11
README.md
11
README.md
@ -5,8 +5,6 @@ Hosted Reverse Shell generator with a ton of functionality -- (great for CTFs)
|
|||||||
### Hosted Instance
|
### Hosted Instance
|
||||||
https://revshells.com
|
https://revshells.com
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- Generate common listeners and reverse shells
|
- Generate common listeners and reverse shells
|
||||||
@ -17,8 +15,17 @@ https://revshells.com
|
|||||||
- Dark and Light Modes
|
- Dark and Light Modes
|
||||||
|
|
||||||
### Screenshot
|
### Screenshot
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/58673953/111243529-9d646f80-85d7-11eb-986c-9842747dc2e7.png)
|
![image](https://user-images.githubusercontent.com/58673953/111243529-9d646f80-85d7-11eb-986c-9842747dc2e7.png)
|
||||||
|
|
||||||
|
## Dev
|
||||||
|
|
||||||
|
It's recommended to use the netlify dev command if you're wanting to modify any of the server functions, such as for raw link support:
|
||||||
|
|
||||||
|
```
|
||||||
|
npx netlify dev
|
||||||
|
```
|
||||||
|
|
||||||
### Credits
|
### Credits
|
||||||
- weibell
|
- weibell
|
||||||
- briskets
|
- briskets
|
||||||
|
319
index.html
319
index.html
@ -112,7 +112,7 @@
|
|||||||
<span id="ip-label" class="input-group-text">IP</span>
|
<span id="ip-label" class="input-group-text">IP</span>
|
||||||
</div>
|
</div>
|
||||||
<input id="ip" type="text" class="form-control form-control-lg text-center px-1"
|
<input id="ip" type="text" class="form-control form-control-lg text-center px-1"
|
||||||
size="12VW" maxlength="15" placeholder="10.10.10.10" aria-label="IP"
|
size="12VW" maxlength="15" aria-label="IP"
|
||||||
aria-describedby="ip-label">
|
aria-describedby="ip-label">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -124,7 +124,7 @@
|
|||||||
<span id="port-label" class="input-group-text">Port</span>
|
<span id="port-label" class="input-group-text">Port</span>
|
||||||
</div>
|
</div>
|
||||||
<input id="port" type="text" class="form-control form-control-lg text-center"
|
<input id="port" type="text" class="form-control form-control-lg text-center"
|
||||||
size="4vw" maxlength="5" placeholder="9001" aria-label="Port"
|
size="4vw" maxlength="5" aria-label="Port"
|
||||||
aria-describedby="port-label">
|
aria-describedby="port-label">
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button id="inc-port" class="btn btn-secondary btn-sm" type="button"
|
<button id="inc-port" class="btn btn-secondary btn-sm" type="button"
|
||||||
@ -298,10 +298,10 @@
|
|||||||
<label for="encoding" class="col-auto col-form-label">Encoding</label>
|
<label for="encoding" class="col-auto col-form-label">Encoding</label>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<select id="encoding" class="custom-select">
|
<select id="encoding" class="custom-select">
|
||||||
<option selected>None</option>
|
<option value="None">None</option>
|
||||||
<option>encodeURI</option>
|
<option value="encodingURI">encodeURI</option>
|
||||||
<option>encodeURIComponent</option>
|
<option value="encodeURIComponent">encodeURIComponent</option>
|
||||||
<option>Base64</option>
|
<option value="Base64">Base64</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -333,6 +333,12 @@
|
|||||||
<label for="auto-copy-switch" class="custom-control-label small pr-2 pb-1"
|
<label for="auto-copy-switch" class="custom-control-label small pr-2 pb-1"
|
||||||
style="padding-top: 2px">Auto-copy</label>
|
style="padding-top: 2px">Auto-copy</label>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
<!-- Raw button -->
|
||||||
|
<button type="button" class="raw-listener btn btn-primary float-right mr-3"
|
||||||
|
data-toggle="tooltip" title="View raw">
|
||||||
|
Raw
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- Copy button -->
|
<!-- Copy button -->
|
||||||
<button id="copy-reverse-shell-command" data-toggle="tooltip"
|
<button id="copy-reverse-shell-command" data-toggle="tooltip"
|
||||||
title="Copy to clipboard" type="button" class="btn btn-primary float-right">
|
title="Copy to clipboard" type="button" class="btn btn-primary float-right">
|
||||||
@ -383,6 +389,12 @@
|
|||||||
<label for="auto-copy-switch" class="custom-control-label small pr-2 pb-1"
|
<label for="auto-copy-switch" class="custom-control-label small pr-2 pb-1"
|
||||||
style="padding-top: 2px">Auto-copy</label>
|
style="padding-top: 2px">Auto-copy</label>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
<!-- Raw button -->
|
||||||
|
<button type="button" class="raw-listener btn btn-primary float-right mr-3"
|
||||||
|
data-toggle="tooltip" title="View raw">
|
||||||
|
Raw
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- Copy button -->
|
<!-- Copy button -->
|
||||||
<button id="copy-bind-shell-command" data-toggle="tooltip" title="Copy to clipboard"
|
<button id="copy-bind-shell-command" data-toggle="tooltip" title="Copy to clipboard"
|
||||||
type="button" class="btn btn-primary float-right">
|
type="button" class="btn btn-primary float-right">
|
||||||
@ -435,6 +447,13 @@
|
|||||||
class="custom-control-label small pr-2 pb-1"
|
class="custom-control-label small pr-2 pb-1"
|
||||||
style="padding-top: 2px">Auto-copy</label>
|
style="padding-top: 2px">Auto-copy</label>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
|
<!-- Raw button -->
|
||||||
|
<button type="button" class="raw-listener btn btn-primary float-right mr-3"
|
||||||
|
data-toggle="tooltip" title="View raw">
|
||||||
|
Raw
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- Copy button -->
|
<!-- Copy button -->
|
||||||
<button id="copy-msfvenom-command" data-toggle="tooltip"
|
<button id="copy-msfvenom-command" data-toggle="tooltip"
|
||||||
title="Copy to clipboard" type="button"
|
title="Copy to clipboard" type="button"
|
||||||
@ -442,7 +461,6 @@
|
|||||||
Copy
|
Copy
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- /Right column -->
|
<!-- /Right column -->
|
||||||
</div>
|
</div>
|
||||||
@ -464,6 +482,9 @@
|
|||||||
<!-- RSG data -->
|
<!-- RSG data -->
|
||||||
<script src="js/data.js"></script>
|
<script src="js/data.js"></script>
|
||||||
|
|
||||||
|
<!-- RSG raw link generator -->
|
||||||
|
<script src="js/raw-link.js"></script>
|
||||||
|
|
||||||
<!-- RSG logic -->
|
<!-- RSG logic -->
|
||||||
<script>
|
<script>
|
||||||
// Element selectors
|
// Element selectors
|
||||||
@ -478,10 +499,6 @@
|
|||||||
const bindShellCommand = document.querySelector("#bind-shell-command");
|
const bindShellCommand = document.querySelector("#bind-shell-command");
|
||||||
const msfVenomCommand = document.querySelector("#msfvenom-command");
|
const msfVenomCommand = document.querySelector("#msfvenom-command");
|
||||||
|
|
||||||
if(localStorage.getItem("ip") == null || localStorage.getItem("ip").length == 0){
|
|
||||||
localStorage.setItem("ip", ipInput.placeholder);
|
|
||||||
}
|
|
||||||
|
|
||||||
const FilterType = {
|
const FilterType = {
|
||||||
'All': 'all',
|
'All': 'all',
|
||||||
'Windows': 'windows',
|
'Windows': 'windows',
|
||||||
@ -522,6 +539,14 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var rawLinkButtons = document.querySelectorAll('.raw-listener');
|
||||||
|
for (const button of rawLinkButtons) {
|
||||||
|
button.addEventListener("click", () => {
|
||||||
|
const rawLink = RawLink.generate(rsg);
|
||||||
|
window.location = rawLink;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const filterCommandData = function (data, { commandType, filter }) {
|
const filterCommandData = function (data, { commandType, filter }) {
|
||||||
return data.filter(item => {
|
return data.filter(item => {
|
||||||
if (!item.meta.includes(commandType)) {
|
if (!item.meta.includes(commandType)) {
|
||||||
@ -540,7 +565,21 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const uiElements = {
|
const rsg = {
|
||||||
|
ip: localStorage.getItem('ip') || '10.10.10.10',
|
||||||
|
port: localStorage.getItem('port') || 9001,
|
||||||
|
shell: localStorage.getItem('shell') || rsgData.shells[0],
|
||||||
|
listener: localStorage.getItem('listener') || rsgData.listenerCommands[0][1],
|
||||||
|
encoding: localStorage.getItem('encoding') || 'None',
|
||||||
|
selectedValues: {
|
||||||
|
[CommandType.ReverseShell]: filterCommandData(rsgData.reverseShellCommands, { commandType: CommandType.ReverseShell })[0].name,
|
||||||
|
[CommandType.BindShell]: filterCommandData(rsgData.reverseShellCommands, { commandType: CommandType.BindShell })[0].name,
|
||||||
|
[CommandType.MSFVenom]: filterCommandData(rsgData.reverseShellCommands, { commandType: CommandType.MSFVenom })[0].name,
|
||||||
|
},
|
||||||
|
commandType: CommandType.ReverseShell,
|
||||||
|
filter: FilterType.All,
|
||||||
|
|
||||||
|
uiElements: {
|
||||||
[CommandType.ReverseShell]: {
|
[CommandType.ReverseShell]: {
|
||||||
listSelection: '#reverse-shell-selection',
|
listSelection: '#reverse-shell-selection',
|
||||||
command: '#reverse-shell-command'
|
command: '#reverse-shell-command'
|
||||||
@ -553,16 +592,7 @@
|
|||||||
listSelection: '#msfvenom-selection',
|
listSelection: '#msfvenom-selection',
|
||||||
command: '#msfvenom-command'
|
command: '#msfvenom-command'
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const rsg = {
|
|
||||||
selectedValues: {
|
|
||||||
[CommandType.ReverseShell]: filterCommandData(rsgData.reverseShellCommands, { commandType: CommandType.ReverseShell })[0].name,
|
|
||||||
[CommandType.BindShell]: filterCommandData(rsgData.reverseShellCommands, { commandType: CommandType.BindShell })[0].name,
|
|
||||||
[CommandType.MSFVenom]: filterCommandData(rsgData.reverseShellCommands, { commandType: CommandType.MSFVenom })[0].name,
|
|
||||||
},
|
},
|
||||||
commandType: CommandType.ReverseShell,
|
|
||||||
filter: FilterType.All,
|
|
||||||
|
|
||||||
copyToClipboard: (text) => {
|
copyToClipboard: (text) => {
|
||||||
if (navigator ?.clipboard ?.writeText) {
|
if (navigator ?.clipboard ?.writeText) {
|
||||||
@ -578,9 +608,13 @@
|
|||||||
|
|
||||||
escapeHTML: (text) => String(text).replace(/</, '<').replace(/>/, '>'),
|
escapeHTML: (text) => String(text).replace(/</, '<').replace(/>/, '>'),
|
||||||
|
|
||||||
getIP: () => localStorage.getItem("ip"),
|
getIP: () => rsg.ip,
|
||||||
|
|
||||||
getPort: () => Number(portInput.value || portInput.getAttribute('placeholder')),
|
getPort: () => Number(rsg.port),
|
||||||
|
|
||||||
|
getShell: () => rsg.shell,
|
||||||
|
|
||||||
|
getEncoding: () => rsg.encoding,
|
||||||
|
|
||||||
getSelectedCommandName: () => {
|
getSelectedCommandName: () => {
|
||||||
return rsg.selectedValues[rsg.commandType];
|
return rsg.selectedValues[rsg.commandType];
|
||||||
@ -591,10 +625,41 @@
|
|||||||
return reverseShellData.command;
|
return reverseShellData.command;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
generateReverseShellCommand: () => {
|
||||||
|
let command
|
||||||
|
|
||||||
|
if (rsg.getSelectedCommandName() === 'PowerShell #3 (Base64)') {
|
||||||
|
const encoder = (text) => text;
|
||||||
|
const payload = rsg.insertParameters(rsgData.specialCommands['PowerShell payload'], encoder)
|
||||||
|
command = "powershell -e " + btoa(payload)
|
||||||
|
} else {
|
||||||
|
command = rsg.getReverseShellCommand()
|
||||||
|
}
|
||||||
|
|
||||||
|
const encoding = rsg.getEncoding();
|
||||||
|
if (encoding === 'Base64') {
|
||||||
|
command = btoa(command)
|
||||||
|
} else {
|
||||||
|
function encoder(string) {
|
||||||
|
return (encoding === 'encodeURI' || encoding === 'encodeURIComponent') ? window[
|
||||||
|
encoding](string) : string
|
||||||
|
}
|
||||||
|
|
||||||
|
command = rsg.insertParameters(
|
||||||
|
rsg.highlightParameters(
|
||||||
|
encoder(command), encoder),
|
||||||
|
encoder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return command;
|
||||||
|
},
|
||||||
|
|
||||||
highlightParameters: (text, encoder) => {
|
highlightParameters: (text, encoder) => {
|
||||||
const parameters = ['{ip}', '{port}', '{shell}', encodeURI('{ip}'), encodeURI('{port}'),
|
const parameters = ['{ip}', '{port}', '{shell}', encodeURI('{ip}'), encodeURI('{port}'),
|
||||||
encodeURI('{shell}')
|
encodeURI('{shell}')
|
||||||
];
|
];
|
||||||
|
|
||||||
parameters.forEach((param) => {
|
parameters.forEach((param) => {
|
||||||
if (encoder) param = encoder(param)
|
if (encoder) param = encoder(param)
|
||||||
text = text.replace(param, `<span class="highlighted-parameter">${param}</span>`)
|
text = text.replace(param, `<span class="highlighted-parameter">${param}</span>`)
|
||||||
@ -615,7 +680,7 @@
|
|||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
|
|
||||||
option.value = command;
|
option.value = command;
|
||||||
option.selected = i === 0;
|
option.selected = rsg.listener === option.value;
|
||||||
option.classList.add("listener-option");
|
option.classList.add("listener-option");
|
||||||
option.innerText = type;
|
option.innerText = type;
|
||||||
|
|
||||||
@ -627,7 +692,7 @@
|
|||||||
rsgData.shells.forEach((shell, i) => {
|
rsgData.shells.forEach((shell, i) => {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
|
|
||||||
option.selected = i === 0;
|
option.selected = rsg.shell === shell;
|
||||||
option.classList.add("shell-option");
|
option.classList.add("shell-option");
|
||||||
option.innerText = shell;
|
option.innerText = shell;
|
||||||
|
|
||||||
@ -636,13 +701,13 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Updates the rsg state, and forces a re-render
|
// Updates the rsg state, and forces a re-render
|
||||||
setState: ({ filter, commandType } = {}) => {
|
setState: (newState = {}) => {
|
||||||
if (filter) {
|
Object.keys(newState).forEach((key) => {
|
||||||
rsg.filter = filter;
|
const value = newState[key];
|
||||||
}
|
rsg[key] = value;
|
||||||
if (commandType) {
|
localStorage.setItem(key, value)
|
||||||
rsg.commandType = commandType;
|
});
|
||||||
}
|
Object.assign(rsg, newState);
|
||||||
|
|
||||||
rsg.update();
|
rsg.update();
|
||||||
},
|
},
|
||||||
@ -651,13 +716,34 @@
|
|||||||
return command
|
return command
|
||||||
.replaceAll(encoder('{ip}'), rsg.escapeHTML(encoder(rsg.getIP())))
|
.replaceAll(encoder('{ip}'), rsg.escapeHTML(encoder(rsg.getIP())))
|
||||||
.replaceAll(encoder('{port}'), encoder(String(rsg.getPort())))
|
.replaceAll(encoder('{port}'), encoder(String(rsg.getPort())))
|
||||||
.replaceAll(encoder('{shell}'), encoder(shellSelect.value))
|
.replaceAll(encoder('{shell}'), encoder(rsg.getShell()))
|
||||||
},
|
},
|
||||||
|
|
||||||
update: () => {
|
update: () => {
|
||||||
rsg.updateListenerCommand()
|
rsg.updateListenerCommand()
|
||||||
rsg.updateTabList()
|
rsg.updateTabList()
|
||||||
rsg.updateReverseShellCommand()
|
rsg.updateReverseShellCommand()
|
||||||
|
rsg.updateValues()
|
||||||
|
},
|
||||||
|
|
||||||
|
updateValues: () => {
|
||||||
|
const listenerOptions = listenerSelect.querySelectorAll(".listener-option");
|
||||||
|
listenerOptions.forEach((option) => {
|
||||||
|
option.selected = rsg.listener === option.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const shellOptions = shellSelect.querySelectorAll(".shell-option");
|
||||||
|
shellOptions.forEach((option) => {
|
||||||
|
option.selected = rsg.shell === option.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const encodingOptions = encodingSelect.querySelectorAll("option");
|
||||||
|
encodingOptions.forEach((option) => {
|
||||||
|
option.selected = rsg.encoding === option.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
ipInput.value = rsg.ip;
|
||||||
|
portInput.value = rsg.port;
|
||||||
},
|
},
|
||||||
|
|
||||||
updateTabList: () => {
|
updateTabList: () => {
|
||||||
@ -670,8 +756,6 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
//debugger;
|
|
||||||
|
|
||||||
const documentFragment = document.createDocumentFragment()
|
const documentFragment = document.createDocumentFragment()
|
||||||
filteredItems.forEach((item, index) => {
|
filteredItems.forEach((item, index) => {
|
||||||
const {
|
const {
|
||||||
@ -701,8 +785,8 @@
|
|||||||
documentFragment.appendChild(selectionButton);
|
documentFragment.appendChild(selectionButton);
|
||||||
})
|
})
|
||||||
|
|
||||||
const listSelectionElement = uiElements[rsg.commandType].listSelection;
|
const listSelectionSelector = rsg.uiElements[rsg.commandType].listSelection;
|
||||||
document.querySelector(listSelectionElement).replaceChildren(documentFragment)
|
document.querySelector(listSelectionSelector).replaceChildren(documentFragment)
|
||||||
},
|
},
|
||||||
|
|
||||||
updateListenerCommand: () => {
|
updateListenerCommand: () => {
|
||||||
@ -729,34 +813,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateReverseShellCommand: () => {
|
updateReverseShellCommand: () => {
|
||||||
let command
|
const command = rsg.generateReverseShellCommand();
|
||||||
|
const commandSelector = rsg.uiElements[rsg.commandType].command;
|
||||||
if (rsg.getSelectedCommandName() === 'PowerShell #3 (Base64)') {
|
document.querySelector(commandSelector).innerHTML = command;
|
||||||
const encoder = (text) => text;
|
|
||||||
const payload = rsg.insertParameters(rsgData.specialCommands['PowerShell payload'], encoder)
|
|
||||||
command = "powershell -e " + btoa(payload)
|
|
||||||
} else {
|
|
||||||
command = rsg.getReverseShellCommand()
|
|
||||||
}
|
|
||||||
|
|
||||||
const encoding = encodingSelect.value;
|
|
||||||
if (encoding === 'Base64') {
|
|
||||||
command = btoa(command)
|
|
||||||
} else {
|
|
||||||
function encoder(string) {
|
|
||||||
return (encoding === 'encodeURI' || encoding === 'encodeURIComponent') ? window[
|
|
||||||
encoding](string) : string
|
|
||||||
}
|
|
||||||
|
|
||||||
command = rsg.insertParameters(
|
|
||||||
rsg.highlightParameters(
|
|
||||||
encoder(command), encoder),
|
|
||||||
encoder
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const commandElement = uiElements[rsg.commandType].command;
|
|
||||||
document.querySelector(commandElement).innerHTML = command;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateSwitchStates: () => {
|
updateSwitchStates: () => {
|
||||||
@ -776,18 +835,40 @@
|
|||||||
/*
|
/*
|
||||||
* Event handlers/functions
|
* Event handlers/functions
|
||||||
*/
|
*/
|
||||||
const dropdownUpdate = () => {
|
ipInput.addEventListener("input", (e) => {
|
||||||
setLocalStorage(shellSelect, "shell", "value");
|
rsg.setState({
|
||||||
rsg.update();
|
ip: e.target.value
|
||||||
}
|
})
|
||||||
|
});
|
||||||
|
|
||||||
shellSelect.addEventListener("change", dropdownUpdate);
|
portInput.addEventListener("input", (e) => {
|
||||||
encodingSelect.addEventListener("change", dropdownUpdate);
|
rsg.setState({
|
||||||
|
port: Number(e.target.value)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
listenerSelect.addEventListener("change", (e) => {
|
||||||
|
rsg.setState({
|
||||||
|
listener: e.target.value
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
shellSelect.addEventListener("change", (e) => {
|
||||||
|
rsg.setState({
|
||||||
|
shell: e.target.value
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
encodingSelect.addEventListener("change", (e) => {
|
||||||
|
rsg.setState({
|
||||||
|
encoding: e.target.value
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
document.querySelector('#inc-port').addEventListener('click', () => {
|
document.querySelector('#inc-port').addEventListener('click', () => {
|
||||||
portInput.value = rsg.getPort() + 1;
|
rsg.setState({
|
||||||
rsg.update();
|
port: rsg.getPort() + 1
|
||||||
setLocalStorage(portInput, "port", "value");
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
document.querySelector('#listener-advanced-switch').addEventListener('change', rsg.updateSwitchStates);
|
document.querySelector('#listener-advanced-switch').addEventListener('change', rsg.updateSwitchStates);
|
||||||
@ -811,96 +892,6 @@
|
|||||||
rsg.copyToClipboard(msfVenomCommand.innerText)
|
rsg.copyToClipboard(msfVenomCommand.innerText)
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
|
||||||
* LocalStorage setting/getting
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets item to localStorage when user moves focus from element
|
|
||||||
* @param {Object} element - The element to get value from
|
|
||||||
* @param {String} key - Key of localStorage value
|
|
||||||
* @param {String} attribute - Attribute of element to set to localStorage value
|
|
||||||
*/
|
|
||||||
const setLocalStorage = (element, key, attribute) => {
|
|
||||||
if (!element || typeof element !== "object") return;
|
|
||||||
localStorage.setItem(key, element[attribute]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepopulates element if localStorage value exists
|
|
||||||
* @param {String} key - Key of localStorage value
|
|
||||||
* @param {Object} element - The element to apply value to
|
|
||||||
* @param {String} attribute - Attribute of element to apply localStorage value to
|
|
||||||
*/
|
|
||||||
const prepopulateElement = (key, element, attribute, options = null) => {
|
|
||||||
if (localStorage.getItem(key)) {
|
|
||||||
// TODO: Use switch/case instead
|
|
||||||
if (element.type === "text") {
|
|
||||||
element[attribute] = localStorage.getItem(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.type === "checkbox") {
|
|
||||||
const isChecked = (localStorage.getItem(key) !== 'false');
|
|
||||||
element[attribute] = isChecked;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.nodeName === "SELECT") {
|
|
||||||
const selectedItem = options.find(option => option[attribute] === localStorage.getItem(key));
|
|
||||||
selectedItem.selected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepopulating fields on load from localStorage
|
|
||||||
*/
|
|
||||||
// TODO: async/await
|
|
||||||
setTimeout(() => {
|
|
||||||
const listenerOptions = listenerSelect.querySelectorAll(".listener-option");
|
|
||||||
prepopulateElement("listener", listenerSelect, "value", [...listenerOptions]);
|
|
||||||
|
|
||||||
rsg.updateListenerCommand();
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const shellOptions = shellSelect.querySelectorAll(".shell-option");
|
|
||||||
prepopulateElement("shell", shellSelect, "value", [...shellOptions]);
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
prepopulateElement("ip", ipInput, "value");
|
|
||||||
prepopulateElement("port", portInput, "value");
|
|
||||||
// prepopulateElement("auto-copy", autoCopySwitch, "checked");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Event listeners for setting localStorage values
|
|
||||||
*/
|
|
||||||
ipInput.addEventListener("input", () => {
|
|
||||||
setLocalStorage(ipInput, "ip", "value");
|
|
||||||
rsg.update();
|
|
||||||
});
|
|
||||||
|
|
||||||
portInput.addEventListener("input", () => {
|
|
||||||
setLocalStorage(portInput, "port", "value");
|
|
||||||
rsg.update();
|
|
||||||
});
|
|
||||||
|
|
||||||
listenerSelect.addEventListener("change", () => {
|
|
||||||
rsg.updateListenerCommand();
|
|
||||||
|
|
||||||
const listenerOptions = listenerSelect.querySelectorAll(".listener-option");
|
|
||||||
const selectedItem = [...listenerOptions].find(option => option.selected);
|
|
||||||
setLocalStorage(selectedItem, "listener", "value");
|
|
||||||
});
|
|
||||||
|
|
||||||
shellSelect.addEventListener("change", () => {
|
|
||||||
rsg.updateReverseShellSelection();
|
|
||||||
|
|
||||||
const shellOptions = shellSelect.querySelectorAll(".shell-option");
|
|
||||||
const selectedItem = [...shellOptions].find(option => option.selected);
|
|
||||||
setLocalStorage(selectedItem, "shell", "value");
|
|
||||||
});
|
|
||||||
|
|
||||||
// autoCopySwitch.addEventListener("change", () => {
|
// autoCopySwitch.addEventListener("change", () => {
|
||||||
// setLocalStorage(autoCopySwitch, "auto-copy", "checked");
|
// setLocalStorage(autoCopySwitch, "auto-copy", "checked");
|
||||||
// });
|
// });
|
||||||
|
@ -345,3 +345,8 @@ const rsgData = {
|
|||||||
...msfvenomCommands
|
...msfvenomCommands
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export the data for use within netlify functions / node
|
||||||
|
if (typeof exports !== 'undefined') {
|
||||||
|
exports.rsgData = rsgData;
|
||||||
|
}
|
||||||
|
44
js/raw-link.js
Normal file
44
js/raw-link.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Generates a RawLink for the reverse shell generator. If the user hasn't changed
|
||||||
|
* the default generated shell command, the generated URL will contain the original
|
||||||
|
* parameters to generate the required command on demand.
|
||||||
|
*
|
||||||
|
* Otherwise a unique URL is created which inlined the current user provided command.
|
||||||
|
*/
|
||||||
|
const RawLink = {
|
||||||
|
generate: (rsg) => {
|
||||||
|
const commandSelector = rsg.uiElements[rsg.commandType].command;
|
||||||
|
const currentCommandElement = document.querySelector(commandSelector);
|
||||||
|
const defaultGeneratedCommand = rsg.generateReverseShellCommand();
|
||||||
|
const isUserProvidedCommand = currentCommandElement.innerHTML != RawLink.escapeHTML(defaultGeneratedCommand);
|
||||||
|
|
||||||
|
if (isUserProvidedCommand) {
|
||||||
|
return RawLink.withCustomValue(currentCommandElement.innerText)
|
||||||
|
|
||||||
|
}
|
||||||
|
return RawLink.withDefaultPayload(rsg);
|
||||||
|
},
|
||||||
|
|
||||||
|
escapeHTML(html) {
|
||||||
|
var element = document.createElement('div');
|
||||||
|
element.innerHTML = html;
|
||||||
|
return element.innerHTML;
|
||||||
|
},
|
||||||
|
|
||||||
|
withDefaultPayload: (rsg) => {
|
||||||
|
const name = rsg.selectedValues[rsg.commandType];
|
||||||
|
const queryParams = new URLSearchParams();
|
||||||
|
queryParams.set('ip', rsg.getIP());
|
||||||
|
queryParams.set('port', rsg.getPort());
|
||||||
|
queryParams.set('shell', rsg.getShell());
|
||||||
|
queryParams.set('encoding', rsg.getShell());
|
||||||
|
|
||||||
|
return `/${encodeURIComponent(name)}?${queryParams}`
|
||||||
|
},
|
||||||
|
|
||||||
|
withCustomValue: (value) => {
|
||||||
|
const queryParams = new URLSearchParams();
|
||||||
|
queryParams.set('value', value)
|
||||||
|
return `/raw?${queryParams}`
|
||||||
|
}
|
||||||
|
}
|
7
netlify.toml
Normal file
7
netlify.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[build]
|
||||||
|
functions = "server_functions"
|
||||||
|
|
||||||
|
[[redirects]]
|
||||||
|
from = "/*"
|
||||||
|
to = "/.netlify/functions/raw"
|
||||||
|
status = 200
|
60
server_functions/raw.js
Normal file
60
server_functions/raw.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
const { rsgData } = require("../js/data.js");
|
||||||
|
|
||||||
|
const insertParameters = function (command, params) {
|
||||||
|
// TODO: Extract the inlined JS from index.html into a new file,
|
||||||
|
// so the insertParameters + encoding logic can be reused
|
||||||
|
const encoder = (value) => value;
|
||||||
|
|
||||||
|
return command
|
||||||
|
.replace(encoder('{ip}'), encoder(params.ip))
|
||||||
|
.replace(encoder('{port}'), encoder(String(params.port)))
|
||||||
|
.replace(encoder('{shell}'), encoder(params.shell))
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateCommand = function (event, _context) {
|
||||||
|
const { path, queryStringParameters } = event;
|
||||||
|
|
||||||
|
const requiredName = decodeURIComponent(path.substring(1));
|
||||||
|
const selectedItem = rsgData.reverseShellCommands.find(function ({ name }) {
|
||||||
|
return requiredName === name;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!selectedItem) {
|
||||||
|
return {
|
||||||
|
statusCode: 401,
|
||||||
|
body: `Command name '${requiredName}' not found`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { command } = selectedItem;
|
||||||
|
const result = insertParameters(command, queryStringParameters);
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: 200,
|
||||||
|
body: result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const extractRawValue = function (event) {
|
||||||
|
const { queryStringParameters } = event;
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: 200,
|
||||||
|
body: queryStringParameters.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.handler = async function (event, _context) {
|
||||||
|
const { queryStringParameters } = event;
|
||||||
|
const defaultHeaders = { headers: { 'Content-Type': "text/plain;charset=UTF-8" } };
|
||||||
|
if (queryStringParameters.value) {
|
||||||
|
return {
|
||||||
|
...defaultHeaders,
|
||||||
|
...extractRawValue(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...defaultHeaders,
|
||||||
|
...generateCommand(event)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user