Autarch/web/templates/exploit_dev.html

689 lines
30 KiB
HTML
Raw Normal View History

{% extends "base.html" %}
{% block title %}AUTARCH — Exploit Dev{% endblock %}
{% block content %}
<div class="page-header">
<h1>Exploit Development</h1>
<p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
Shellcode generation, payload encoding, ROP chain building, cyclic patterns, and assembly.
</p>
</div>
<!-- Tab Bar -->
<div class="tab-bar">
<button class="tab active" data-tab-group="xdev" data-tab="shellcode" onclick="showTab('xdev','shellcode')">Shellcode</button>
<button class="tab" data-tab-group="xdev" data-tab="encoder" onclick="showTab('xdev','encoder')">Encoder</button>
<button class="tab" data-tab-group="xdev" data-tab="rop" onclick="showTab('xdev','rop')">ROP</button>
<button class="tab" data-tab-group="xdev" data-tab="patterns" onclick="showTab('xdev','patterns')">Patterns</button>
</div>
<!-- ==================== SHELLCODE TAB ==================== -->
<div class="tab-content active" data-tab-group="xdev" data-tab="shellcode">
<div class="section">
<h2>Shellcode Generator</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Generate architecture-specific shellcode from built-in templates. Supports host/port patching.
</p>
<div class="form-row">
<div class="form-group">
<label>Shell Type</label>
<select id="sc-type">
<option value="reverse_shell">Reverse Shell</option>
<option value="bind_shell">Bind Shell</option>
<option value="execve" selected>Exec Command (/bin/sh)</option>
</select>
</div>
<div class="form-group">
<label>Architecture</label>
<select id="sc-arch">
<option value="x86">x86 (32-bit)</option>
<option value="x64" selected>x64 (64-bit)</option>
<option value="arm">ARM</option>
</select>
</div>
<div class="form-group">
<label>Platform</label>
<select id="sc-platform">
<option value="linux" selected>Linux</option>
<option value="windows">Windows</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Host (reverse/bind)</label>
<input type="text" id="sc-host" placeholder="127.0.0.1">
</div>
<div class="form-group">
<label>Port (reverse/bind)</label>
<input type="text" id="sc-port" placeholder="4444">
</div>
</div>
<div class="form-row">
<div class="form-group" style="max-width:180px">
<label>Output Format</label>
<select id="sc-format">
<option value="hex">Hex</option>
<option value="c_array">C Array</option>
<option value="python">Python</option>
<option value="nasm">NASM</option>
<option value="raw">Raw Bytes</option>
</select>
</div>
<div class="form-group" style="max-width:130px;display:flex;align-items:flex-end;padding-bottom:6px">
<label style="display:flex;align-items:center;gap:6px;cursor:pointer">
<input type="checkbox" id="sc-staged" style="width:auto"> Staged
</label>
</div>
</div>
<div class="tool-actions">
<button id="btn-sc-gen" class="btn btn-primary" onclick="scGenerate()">Generate Shellcode</button>
<button class="btn btn-small" onclick="scListTemplates()">List Templates</button>
<button class="btn btn-small" onclick="scCopy()">Copy Output</button>
</div>
<div id="sc-meta" style="display:none;margin-top:12px;padding:10px;background:var(--bg-input);border-radius:var(--radius);font-size:0.82rem;color:var(--text-secondary)"></div>
<pre class="output-panel scrollable" id="sc-output" style="margin-top:10px;min-height:80px">No shellcode generated yet.</pre>
</div>
</div>
<!-- ==================== ENCODER TAB ==================== -->
<div class="tab-content" data-tab-group="xdev" data-tab="encoder">
<div class="section">
<h2>Payload Encoder</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Encode shellcode to evade signature detection. Supports XOR, AES-256, alphanumeric, and polymorphic encoding.
</p>
<div class="form-group">
<label>Shellcode (hex)</label>
<textarea id="enc-input" rows="4" placeholder="Paste shellcode hex bytes here, e.g. 31c050682f2f7368..."></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label>Encoder</label>
<select id="enc-type">
<option value="xor" selected>XOR</option>
<option value="aes">AES-256</option>
<option value="alphanumeric">Alphanumeric</option>
<option value="polymorphic">Polymorphic</option>
</select>
</div>
<div class="form-group">
<label>Key (optional, auto if empty)</label>
<input type="text" id="enc-key" placeholder="Hex key or passphrase">
</div>
<div class="form-group" style="max-width:100px">
<label>Iterations</label>
<input type="number" id="enc-iters" value="1" min="1" max="10">
</div>
</div>
<div class="tool-actions">
<button id="btn-enc" class="btn btn-primary" onclick="encEncode()">Encode</button>
<button class="btn btn-small" onclick="encCopy()">Copy Encoded</button>
</div>
<div id="enc-stats" style="display:none;margin-top:12px;padding:10px;background:var(--bg-input);border-radius:var(--radius);font-size:0.82rem">
<div style="display:flex;gap:24px;flex-wrap:wrap">
<div>Original: <strong id="enc-orig-sz">--</strong> bytes</div>
<div>Encoded: <strong id="enc-new-sz">--</strong> bytes</div>
<div>Increase: <strong id="enc-increase">--</strong></div>
<div>Null-free: <strong id="enc-nullfree">--</strong></div>
<div>Key: <code id="enc-key-used" style="font-size:0.8rem">--</code></div>
</div>
</div>
<div style="margin-top:14px">
<label style="font-size:0.85rem;color:var(--text-secondary)">Decoder Stub</label>
<pre class="output-panel scrollable" id="enc-stub" style="min-height:60px"></pre>
</div>
<div style="margin-top:10px">
<label style="font-size:0.85rem;color:var(--text-secondary)">Encoded Payload (hex)</label>
<pre class="output-panel scrollable" id="enc-output" style="min-height:60px"></pre>
</div>
</div>
</div>
<!-- ==================== ROP TAB ==================== -->
<div class="tab-content" data-tab-group="xdev" data-tab="rop">
<div class="section">
<h2>ROP Gadget Finder</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Scan ELF/PE binaries for ROP gadgets. Uses ropper, ROPgadget, or objdump as backend.
</p>
<div class="form-row">
<div class="form-group">
<label>Binary Path</label>
<input type="text" id="rop-binary" placeholder="/path/to/binary or /usr/bin/ls">
</div>
<div class="form-group" style="max-width:180px">
<label>Gadget Type</label>
<select id="rop-type">
<option value="all">All</option>
<option value="pop_ret">pop; ret</option>
<option value="xchg">xchg</option>
<option value="mov">mov</option>
<option value="syscall">syscall / int 0x80</option>
<option value="jmp_esp">jmp esp/rsp</option>
<option value="call_reg">call reg</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group" style="max-width:250px">
<label>Search Filter</label>
<input type="text" id="rop-search" placeholder="Filter gadgets by text...">
</div>
</div>
<div class="tool-actions">
<button id="btn-rop-find" class="btn btn-primary" onclick="ropFind()">Find Gadgets</button>
<button class="btn btn-small" onclick="ropExportChain()">Export Chain</button>
</div>
<div id="rop-summary" style="display:none;margin-top:12px;padding:10px;background:var(--bg-input);border-radius:var(--radius);font-size:0.82rem;color:var(--text-secondary)"></div>
<div style="margin-top:14px;max-height:400px;overflow-y:auto">
<table class="data-table" id="rop-table">
<thead><tr><th style="width:140px">Address</th><th>Gadget</th><th style="width:90px">Type</th><th style="width:50px">Add</th></tr></thead>
<tbody id="rop-tbody">
<tr><td colspan="4" class="empty-state">Run gadget search to see results.</td></tr>
</tbody>
</table>
</div>
</div>
<div class="section">
<h2>ROP Chain Builder</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Build a ROP chain by adding gadgets from the table above or manually specifying addresses.
</p>
<div style="max-height:250px;overflow-y:auto;margin-bottom:10px">
<table class="data-table">
<thead><tr><th style="width:30px">#</th><th style="width:140px">Address</th><th>Gadget</th><th style="width:120px">Value</th><th style="width:50px">Rm</th></tr></thead>
<tbody id="chain-tbody">
<tr id="chain-empty"><td colspan="5" class="empty-state">Add gadgets from the results above.</td></tr>
</tbody>
</table>
</div>
<div class="tool-actions">
<button class="btn btn-small" onclick="chainAddManual()">+ Manual Entry</button>
<button class="btn btn-small" onclick="chainClear()">Clear Chain</button>
<button class="btn btn-primary btn-small" onclick="chainBuild()">Build Chain</button>
</div>
<pre class="output-panel scrollable" id="chain-output" style="margin-top:10px;min-height:60px"></pre>
</div>
</div>
<!-- ==================== PATTERNS TAB ==================== -->
<div class="tab-content" data-tab-group="xdev" data-tab="patterns">
<div class="section">
<h2>Cyclic Pattern Generator</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Generate De Bruijn / cyclic patterns for buffer overflow offset discovery (like pattern_create).
</p>
<div class="form-row">
<div class="form-group" style="max-width:200px">
<label>Pattern Length</label>
<input type="number" id="pat-length" value="500" min="1" max="20280">
</div>
<div class="form-group" style="display:flex;align-items:flex-end;padding-bottom:6px">
<button id="btn-pat-create" class="btn btn-primary btn-small" onclick="patCreate()">Generate Pattern</button>
<button class="btn btn-small" style="margin-left:6px" onclick="patCopyPattern()">Copy</button>
</div>
</div>
<pre class="output-panel scrollable" id="pat-output" style="min-height:60px;word-break:break-all">No pattern generated yet.</pre>
</div>
<div class="section">
<h2>Pattern Offset Finder</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Find the exact offset of a value within a cyclic pattern (like pattern_offset).
Accepts hex (0x41326241), integer, or raw string.
</p>
<div class="form-row">
<div class="form-group">
<label>Value (hex / int / string)</label>
<input type="text" id="pat-value" placeholder="0x41326241 or Ab3A">
</div>
<div class="form-group" style="max-width:160px">
<label>Pattern Length</label>
<input type="number" id="pat-off-length" value="20000" min="1" max="20280">
</div>
<div class="form-group" style="display:flex;align-items:flex-end;padding-bottom:6px">
<button id="btn-pat-offset" class="btn btn-primary btn-small" onclick="patOffset()">Find Offset</button>
</div>
</div>
<pre class="output-panel" id="pat-offset-result" style="min-height:40px"></pre>
</div>
<div class="section">
<h2>Format String Exploitation</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Generate format string test payloads for offset discovery and write-what-where attacks.
</p>
<div class="form-row">
<div class="form-group" style="max-width:140px">
<label>Test Count</label>
<input type="number" id="fmt-count" value="20" min="1" max="100">
</div>
<div class="form-group" style="display:flex;align-items:flex-end;padding-bottom:6px">
<button class="btn btn-primary btn-small" onclick="fmtOffset()">Generate Probes</button>
</div>
</div>
<pre class="output-panel scrollable" id="fmt-offset-result" style="min-height:60px"></pre>
<h3 style="margin-top:18px">Write-What-Where</h3>
<div class="form-row">
<div class="form-group">
<label>Target Address (hex)</label>
<input type="text" id="fmt-addr" placeholder="0x08049724">
</div>
<div class="form-group">
<label>Value to Write (hex)</label>
<input type="text" id="fmt-val" placeholder="0xdeadbeef">
</div>
<div class="form-group" style="max-width:100px">
<label>Offset</label>
<input type="number" id="fmt-off" value="7" min="1" max="200">
</div>
<div class="form-group" style="display:flex;align-items:flex-end;padding-bottom:6px">
<button class="btn btn-primary btn-small" onclick="fmtWrite()">Generate Payload</button>
</div>
</div>
<pre class="output-panel scrollable" id="fmt-write-result" style="min-height:60px"></pre>
</div>
<div class="section">
<h2>Assembly / Disassembly</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Assemble NASM code to machine bytes or disassemble hex bytes to assembly instructions.
</p>
<div class="form-row">
<div class="form-group" style="max-width:140px">
<label>Architecture</label>
<select id="asm-arch">
<option value="x86">x86</option>
<option value="x64" selected>x64</option>
<option value="arm">ARM</option>
</select>
</div>
</div>
<div class="form-group">
<label>Assembly Code / Hex Bytes</label>
<textarea id="asm-input" rows="6" placeholder="Enter NASM assembly code to assemble, or hex bytes to disassemble.&#10;&#10;Example (assemble):&#10; xor rax, rax&#10; push rax&#10; mov al, 0x3b&#10;&#10;Example (disassemble):&#10; 4831c0 50 b03b"></textarea>
</div>
<div class="tool-actions">
<button id="btn-asm" class="btn btn-primary btn-small" onclick="asmAssemble()">Assemble</button>
<button id="btn-disasm" class="btn btn-primary btn-small" onclick="asmDisassemble()">Disassemble</button>
<button class="btn btn-small" onclick="asmCopy()">Copy Output</button>
</div>
<pre class="output-panel scrollable" id="asm-output" style="margin-top:10px;min-height:60px"></pre>
</div>
</div>
<script>
/* ================================================================
Exploit Development — JavaScript
================================================================ */
var _ropGadgets = [];
var _chainItems = [];
/* ── Shellcode ── */
function scGenerate() {
var btn = document.getElementById('btn-sc-gen');
setLoading(btn, true);
postJSON('/exploit-dev/shellcode', {
type: document.getElementById('sc-type').value,
arch: document.getElementById('sc-arch').value,
platform: document.getElementById('sc-platform').value,
host: document.getElementById('sc-host').value,
port: document.getElementById('sc-port').value,
staged: document.getElementById('sc-staged').checked,
output_format: document.getElementById('sc-format').value
}).then(function(data) {
setLoading(btn, false);
if (data.error) { renderOutput('sc-output', 'Error: ' + data.error); return; }
renderOutput('sc-output', data.shellcode || data.hex || '(empty)');
var meta = document.getElementById('sc-meta');
meta.style.display = '';
meta.innerHTML =
'<strong>Template:</strong> ' + esc(data.template || '--') +
' &nbsp;|&nbsp; <strong>Length:</strong> ' + (data.length || 0) + ' bytes' +
' &nbsp;|&nbsp; <strong>Null-free:</strong> ' + (data.null_free ? 'Yes' : 'No') +
' &nbsp;|&nbsp; <strong>Arch:</strong> ' + esc(data.arch || '--') +
' &nbsp;|&nbsp; ' + esc(data.staging || '');
}).catch(function() { setLoading(btn, false); });
}
function scListTemplates() {
fetchJSON('/exploit-dev/shellcodes').then(function(data) {
if (!data.shellcodes || !data.shellcodes.length) {
renderOutput('sc-output', 'No templates available.');
return;
}
var lines = ['=== Available Shellcode Templates ===', ''];
data.shellcodes.forEach(function(sc) {
lines.push(sc.name);
lines.push(' ' + sc.description);
lines.push(' Arch: ' + sc.arch + ' Platform: ' + sc.platform +
' Length: ' + sc.length + ' Null-free: ' + (sc.null_free ? 'Yes' : 'No'));
lines.push('');
});
renderOutput('sc-output', lines.join('\n'));
});
}
function scCopy() {
var text = document.getElementById('sc-output').textContent;
if (text) navigator.clipboard.writeText(text);
}
/* ── Encoder ── */
function encEncode() {
var btn = document.getElementById('btn-enc');
setLoading(btn, true);
postJSON('/exploit-dev/encode', {
shellcode: document.getElementById('enc-input').value.trim(),
encoder: document.getElementById('enc-type').value,
key: document.getElementById('enc-key').value.trim(),
iterations: parseInt(document.getElementById('enc-iters').value) || 1
}).then(function(data) {
setLoading(btn, false);
if (data.error) {
renderOutput('enc-output', 'Error: ' + data.error);
return;
}
document.getElementById('enc-stats').style.display = '';
document.getElementById('enc-orig-sz').textContent = data.original_length;
document.getElementById('enc-new-sz').textContent = data.encoded_length;
document.getElementById('enc-increase').textContent = data.size_increase;
document.getElementById('enc-nullfree').textContent = data.null_free ? 'Yes' : 'No';
document.getElementById('enc-nullfree').style.color = data.null_free ? 'var(--success,#4ade80)' : 'var(--danger)';
document.getElementById('enc-key-used').textContent = data.key || '--';
renderOutput('enc-stub', data.decoder_stub || '(no stub)');
renderOutput('enc-output', data.encoded || '');
}).catch(function() { setLoading(btn, false); });
}
function encCopy() {
var text = document.getElementById('enc-output').textContent;
if (text) navigator.clipboard.writeText(text);
}
/* ── ROP ── */
function ropFind() {
var btn = document.getElementById('btn-rop-find');
setLoading(btn, true);
postJSON('/exploit-dev/rop/gadgets', {
binary_path: document.getElementById('rop-binary').value.trim(),
gadget_type: document.getElementById('rop-type').value
}).then(function(data) {
setLoading(btn, false);
if (data.error) {
document.getElementById('rop-tbody').innerHTML =
'<tr><td colspan="4" class="empty-state">Error: ' + esc(data.error) + '</td></tr>';
return;
}
_ropGadgets = data.gadgets || [];
var summary = document.getElementById('rop-summary');
summary.style.display = '';
summary.innerHTML = 'Found <strong>' + data.count + '</strong> gadgets in ' +
esc(data.binary || '--') + ' via <strong>' + esc(data.tool || '--') + '</strong>';
ropRenderTable();
}).catch(function() { setLoading(btn, false); });
}
function ropRenderTable() {
var filter = document.getElementById('rop-search').value.toLowerCase();
var filtered = _ropGadgets;
if (filter) {
filtered = _ropGadgets.filter(function(g) {
return g.gadget.toLowerCase().indexOf(filter) !== -1 ||
g.address.toLowerCase().indexOf(filter) !== -1 ||
g.type.toLowerCase().indexOf(filter) !== -1;
});
}
var html = '';
if (!filtered.length) {
html = '<tr><td colspan="4" class="empty-state">No matching gadgets.</td></tr>';
} else {
filtered.forEach(function(g, i) {
html += '<tr>'
+ '<td><code style="font-size:0.8rem">' + esc(g.address) + '</code></td>'
+ '<td style="font-size:0.82rem">' + esc(g.gadget) + '</td>'
+ '<td><span class="badge" style="font-size:0.7rem">' + esc(g.type) + '</span></td>'
+ '<td><button class="btn btn-small" style="padding:2px 8px;font-size:0.7rem" onclick="chainAdd(' + i + ')">+</button></td>'
+ '</tr>';
});
}
document.getElementById('rop-tbody').innerHTML = html;
}
/* live search filter */
document.addEventListener('DOMContentLoaded', function() {
var el = document.getElementById('rop-search');
if (el) el.addEventListener('input', ropRenderTable);
});
function chainAdd(gadgetIdx) {
var g = _ropGadgets[gadgetIdx];
if (!g) return;
_chainItems.push({address: g.address, gadget: g.gadget, type: g.type, value: ''});
chainRender();
}
function chainAddManual() {
var addr = prompt('Gadget address (hex):', '0x');
if (!addr) return;
var instr = prompt('Gadget instruction:', 'pop rdi ; ret');
_chainItems.push({address: addr, gadget: instr || '???', type: 'manual', value: ''});
chainRender();
}
function chainRemove(idx) {
_chainItems.splice(idx, 1);
chainRender();
}
function chainClear() {
_chainItems = [];
chainRender();
renderOutput('chain-output', '');
}
function chainRender() {
var tbody = document.getElementById('chain-tbody');
var empty = document.getElementById('chain-empty');
if (!_chainItems.length) {
tbody.innerHTML = '<tr id="chain-empty"><td colspan="5" class="empty-state">Add gadgets from the results above.</td></tr>';
return;
}
var html = '';
_chainItems.forEach(function(c, i) {
html += '<tr>'
+ '<td>' + (i + 1) + '</td>'
+ '<td><code style="font-size:0.8rem">' + esc(c.address) + '</code></td>'
+ '<td style="font-size:0.82rem">' + esc(c.gadget) + '</td>'
+ '<td><input type="text" class="chain-val" data-idx="' + i + '" value="' + esc(c.value) + '" '
+ 'placeholder="0x..." style="font-size:0.78rem;padding:2px 6px;width:100px" '
+ 'onchange="chainUpdateVal(' + i + ', this.value)"></td>'
+ '<td><button class="btn btn-small" style="padding:2px 8px;font-size:0.7rem;color:var(--danger)" '
+ 'onclick="chainRemove(' + i + ')">X</button></td>'
+ '</tr>';
});
tbody.innerHTML = html;
}
function chainUpdateVal(idx, val) {
if (_chainItems[idx]) _chainItems[idx].value = val;
}
function chainBuild() {
if (!_chainItems.length) { alert('Add gadgets to the chain first.'); return; }
var spec = _chainItems.map(function(c) {
return {
gadget_type: c.type === 'manual' ? 'pop_ret' : c.type,
register: '',
value: c.value || '0'
};
});
var gadgets = _chainItems.map(function(c) {
return {address: c.address, gadget: c.gadget, type: c.type === 'manual' ? 'pop_ret' : c.type};
});
postJSON('/exploit-dev/rop/chain', {gadgets: gadgets, chain_spec: spec}).then(function(data) {
if (data.error) { renderOutput('chain-output', 'Error: ' + data.error); return; }
var lines = ['=== ROP Chain (' + data.chain_length + ' bytes) ===', ''];
lines.push(data.debug || '');
lines.push('');
lines.push('--- Hex ---');
lines.push(data.chain_hex);
lines.push('');
lines.push('--- Python ---');
lines.push(data.python || '');
renderOutput('chain-output', lines.join('\n'));
});
}
function ropExportChain() {
var text = document.getElementById('chain-output').textContent;
if (text) navigator.clipboard.writeText(text);
}
/* ── Patterns ── */
function patCreate() {
var btn = document.getElementById('btn-pat-create');
setLoading(btn, true);
postJSON('/exploit-dev/pattern/create', {
length: parseInt(document.getElementById('pat-length').value) || 500
}).then(function(data) {
setLoading(btn, false);
if (data.error) { renderOutput('pat-output', 'Error: ' + data.error); return; }
renderOutput('pat-output', data.pattern || '');
}).catch(function() { setLoading(btn, false); });
}
function patCopyPattern() {
var text = document.getElementById('pat-output').textContent;
if (text && text !== 'No pattern generated yet.') navigator.clipboard.writeText(text);
}
function patOffset() {
var btn = document.getElementById('btn-pat-offset');
setLoading(btn, true);
postJSON('/exploit-dev/pattern/offset', {
value: document.getElementById('pat-value').value.trim(),
length: parseInt(document.getElementById('pat-off-length').value) || 20000
}).then(function(data) {
setLoading(btn, false);
if (data.error && data.offset === -1) {
renderOutput('pat-offset-result', 'Not found: ' + data.error);
return;
}
if (data.offset >= 0) {
var lines = [
'Exact offset: ' + data.offset,
'Matched: ' + (data.matched || '--') + ' (' + (data.endian || '--') + ')',
'Matched hex: ' + (data.matched_hex || '--'),
'Pattern length searched: ' + (data.pattern_length || '--')
];
renderOutput('pat-offset-result', lines.join('\n'));
} else {
renderOutput('pat-offset-result', data.error || 'Not found.');
}
}).catch(function() { setLoading(btn, false); });
}
/* ── Format String ── */
function fmtOffset() {
postJSON('/exploit-dev/format/offset', {
test_count: parseInt(document.getElementById('fmt-count').value) || 20
}).then(function(data) {
if (data.error) { renderOutput('fmt-offset-result', 'Error: ' + data.error); return; }
var lines = ['=== Format String Probes ===', ''];
var payloads = data.payloads || {};
Object.keys(payloads).forEach(function(key) {
var p = payloads[key];
lines.push('--- ' + key + ' ---');
lines.push(p.description || '');
lines.push(p.payload || '');
lines.push('');
});
if (data.note) { lines.push(data.note); }
renderOutput('fmt-offset-result', lines.join('\n'));
});
}
function fmtWrite() {
var addr = document.getElementById('fmt-addr').value.trim();
var val = document.getElementById('fmt-val').value.trim();
var off = document.getElementById('fmt-off').value;
if (!addr || !val) { alert('Provide target address and value.'); return; }
postJSON('/exploit-dev/format/write', {
address: addr, value: val, offset: parseInt(off) || 7
}).then(function(data) {
if (data.error) { renderOutput('fmt-write-result', 'Error: ' + data.error); return; }
var lines = ['=== Format String Write Payloads ===', ''];
if (data.payload_32bit) {
lines.push('--- 32-bit (%hn) ---');
lines.push(data.payload_32bit.description || '');
lines.push('Addresses: ' + (data.payload_32bit.addresses || ''));
lines.push('Payload: ' + (data.payload_32bit.payload || ''));
lines.push('');
}
if (data.payload_64bit) {
lines.push('--- 64-bit (%hn) ---');
lines.push(data.payload_64bit.description || '');
lines.push('Payload: ' + (data.payload_64bit.payload || ''));
}
renderOutput('fmt-write-result', lines.join('\n'));
});
}
/* ── Assembly / Disassembly ── */
function asmAssemble() {
var btn = document.getElementById('btn-asm');
setLoading(btn, true);
postJSON('/exploit-dev/assemble', {
code: document.getElementById('asm-input').value,
arch: document.getElementById('asm-arch').value
}).then(function(data) {
setLoading(btn, false);
if (data.error) { renderOutput('asm-output', 'Error: ' + data.error); return; }
var lines = ['=== Assembly Result ===',
'Length: ' + data.length + ' bytes',
'Arch: ' + (data.arch || '--'),
'',
'Hex: ' + (data.hex || ''),
'',
'C array: ' + (data.c_array || ''),
'',
'Python: ' + (data.python || '')];
renderOutput('asm-output', lines.join('\n'));
}).catch(function() { setLoading(btn, false); });
}
function asmDisassemble() {
var btn = document.getElementById('btn-disasm');
setLoading(btn, true);
postJSON('/exploit-dev/disassemble', {
hex: document.getElementById('asm-input').value.trim(),
arch: document.getElementById('asm-arch').value
}).then(function(data) {
setLoading(btn, false);
if (data.error) { renderOutput('asm-output', 'Error: ' + data.error); return; }
var lines = ['=== Disassembly (' + (data.count || 0) + ' instructions, via ' + (data.tool || '?') + ') ===', ''];
lines.push(data.listing || '(no output)');
if (data.note) { lines.push(''); lines.push('Note: ' + data.note); }
renderOutput('asm-output', lines.join('\n'));
}).catch(function() { setLoading(btn, false); });
}
function asmCopy() {
var text = document.getElementById('asm-output').textContent;
if (text) navigator.clipboard.writeText(text);
}
</script>
{% endblock %}