Skip to content

Instantly share code, notes, and snippets.

@teebow1e
Created December 15, 2025 10:37
Show Gist options
  • Select an option

  • Save teebow1e/a9de5f866eb828e55dac4fda67cdb261 to your computer and use it in GitHub Desktop.

Select an option

Save teebow1e/a9de5f866eb828e55dac4fda67cdb261 to your computer and use it in GitHub Desktop.
[HTB Academy] Implement re-submit flag mechanism for already submitted answer
// ==UserScript==
// @name HTB Academy Re-Challenge
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Re-enable completed questions on HTB Academy for practice
// @author BKSEC
// @match https://academy.hackthebox.com/*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// Add custom styles
const style = document.createElement('style');
style.textContent = `
.answer-blurred {
filter: blur(8px);
user-select: none;
pointer-events: none;
transition: filter 0.3s ease;
}
.answer-revealed {
filter: blur(0px);
pointer-events: none;
user-select: none;
}
input.answer-blurred,
input.answer-revealed {
cursor: not-allowed !important;
}
.resubmit-modal {
display: none;
position: fixed;
z-index: 10000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
animation: fadeIn 0.3s;
}
.resubmit-modal-content {
background-color: #1e2530;
margin: 15% auto;
padding: 30px;
border: 1px solid #2d3748;
border-radius: 8px;
width: 90%;
max-width: 500px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
animation: slideDown 0.3s;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideDown {
from {
transform: translateY(-50px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.resubmit-modal-header {
color: #fff;
font-size: 20px;
margin-bottom: 20px;
font-weight: 600;
}
.resubmit-modal-input {
width: 100%;
padding: 12px;
margin-bottom: 20px;
background-color: #2d3748;
border: 1px solid #4a5568;
border-radius: 4px;
color: #fff;
font-size: 14px;
font-family: monospace;
}
.resubmit-modal-input:focus {
outline: none;
border-color: #9fef00;
}
.resubmit-modal-buttons {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.resubmit-modal-btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s;
}
.resubmit-modal-btn-primary {
background-color: #9fef00;
color: #1e2530;
}
.resubmit-modal-btn-primary:hover {
background-color: #8dd400;
}
.resubmit-modal-btn-secondary {
background-color: #4a5568;
color: #fff;
}
.resubmit-modal-btn-secondary:hover {
background-color: #5a6578;
}
.btn-resubmit {
background-color: #9fef00 !important;
color: #1e2530 !important;
border: none !important;
}
.btn-resubmit:hover {
background-color: #8dd400 !important;
}
.btn-resubmit:disabled {
background-color: #4a5568 !important;
color: #718096 !important;
cursor: not-allowed !important;
opacity: 0.6;
}
.btn-resubmit:disabled:hover {
background-color: #4a5568 !important;
}
.success-animation {
animation: successPulse 0.5s ease;
}
@keyframes successPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
`;
document.head.appendChild(style);
// Wait for page to fully load
setTimeout(initializeReChallenge, 1000);
function initializeReChallenge() {
// Find all answered questions
const answeredInputs = document.querySelectorAll('input.form-control.text-success[disabled]');
answeredInputs.forEach((input, index) => {
// Store the correct answer
const correctAnswer = input.value;
const questionId = input.closest('.row').querySelector('.btnAnswer')?.id?.replace('btnAnswer', '') || index;
// Blur the answer
input.classList.add('answer-blurred');
input.setAttribute('data-correct-answer', correctAnswer);
input.setAttribute('data-question-id', questionId);
input.setAttribute('data-input-id', index);
// Keep input disabled - never allow editing
input.setAttribute('disabled', 'true');
input.setAttribute('readonly', 'true');
// Find the submit button container
const buttonContainer = input.closest('.row').querySelector('.d-flex.justify-content-end');
if (buttonContainer) {
// Remove disabled from all buttons
buttonContainer.querySelectorAll('button[disabled]').forEach(btn => {
btn.removeAttribute('disabled');
});
// Create Re-submit button
const resubmitBtnWrapper = document.createElement('div');
resubmitBtnWrapper.className = 'mb-4 mr-1 d-flex align-items-center';
const resubmitBtn = document.createElement('button');
resubmitBtn.className = 'btn btn-primary btn-block btn-resubmit';
resubmitBtn.innerHTML = `
<div class="submit-button-text">
<i class="fad fa-redo mr-2"></i> Re-submit
</div>
`;
resubmitBtn.setAttribute('data-question-id', questionId);
resubmitBtn.setAttribute('data-input-id', index);
// Check if answer is already revealed (e.g., after page reload)
if (input.classList.contains('answer-revealed') || !input.classList.contains('answer-blurred')) {
resubmitBtn.disabled = true;
resubmitBtn.innerHTML = `
<div class="submit-button-text">
<i class="fad fa-check-circle mr-2"></i> Completed
</div>
`;
}
resubmitBtn.addEventListener('click', function() {
if (!this.disabled) {
showResubmitModal(input, questionId);
}
});
resubmitBtnWrapper.appendChild(resubmitBtn);
// Insert before the hint button or at the end
const hintBtn = buttonContainer.querySelector('[id^="hintBtn"]');
if (hintBtn && hintBtn.parentElement) {
buttonContainer.insertBefore(resubmitBtnWrapper, hintBtn.parentElement);
} else {
buttonContainer.appendChild(resubmitBtnWrapper);
}
}
});
console.log(`[HTB Academy Re-Challenge] Initialized ${answeredInputs.length} questions for re-challenge`);
}
function showResubmitModal(inputElement, questionId) {
// Create modal
const modal = document.createElement('div');
modal.className = 'resubmit-modal';
modal.innerHTML = `
<div class="resubmit-modal-content">
<div class="resubmit-modal-header">
<i class="fad fa-flag mr-2"></i> Submit Your Answer
</div>
<input type="text" class="resubmit-modal-input" placeholder="Enter your flag (e.g., HTB{...})" autofocus>
<div class="resubmit-modal-buttons">
<button class="resubmit-modal-btn resubmit-modal-btn-secondary" id="modal-cancel">Cancel</button>
<button class="resubmit-modal-btn resubmit-modal-btn-primary" id="modal-submit">Submit</button>
</div>
</div>
`;
document.body.appendChild(modal);
const input = modal.querySelector('.resubmit-modal-input');
const submitBtn = modal.querySelector('#modal-submit');
const cancelBtn = modal.querySelector('#modal-cancel');
// Show modal
setTimeout(() => {
modal.style.display = 'block';
input.focus();
}, 10);
// Handle submit
const handleSubmit = () => {
const userAnswer = input.value.trim();
const correctAnswer = inputElement.getAttribute('data-correct-answer');
if (userAnswer === correctAnswer) {
// Correct answer!
inputElement.classList.remove('answer-blurred');
inputElement.classList.add('answer-revealed', 'success-animation');
// Ensure input remains disabled/readonly
inputElement.setAttribute('disabled', 'true');
inputElement.setAttribute('readonly', 'true');
// Find and disable the Re-submit button for this question
const resubmitBtn = document.querySelector(`.btn-resubmit[data-input-id="${inputElement.getAttribute('data-input-id') || ''}"]`);
if (resubmitBtn) {
resubmitBtn.disabled = true;
resubmitBtn.innerHTML = `
<div class="submit-button-text">
<i class="fad fa-check-circle mr-2"></i> Completed
</div>
`;
}
// Show success message
showNotification('Correct! 🎉', 'success');
closeModal();
} else {
// Wrong answer
showNotification('Incorrect answer. Try again! ❌', 'error');
input.value = '';
input.focus();
// Shake animation
modal.querySelector('.resubmit-modal-content').style.animation = 'none';
setTimeout(() => {
modal.querySelector('.resubmit-modal-content').style.animation = '';
}, 10);
}
};
// Handle cancel
const closeModal = () => {
modal.style.display = 'none';
setTimeout(() => modal.remove(), 300);
};
submitBtn.addEventListener('click', handleSubmit);
cancelBtn.addEventListener('click', closeModal);
// Handle Enter key
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
handleSubmit();
}
});
// Handle Escape key
document.addEventListener('keydown', function escapeHandler(e) {
if (e.key === 'Escape') {
closeModal();
document.removeEventListener('keydown', escapeHandler);
}
});
// Click outside to close
modal.addEventListener('click', (e) => {
if (e.target === modal) {
closeModal();
}
});
}
function showNotification(message, type) {
const notification = document.createElement('div');
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 15px 25px;
background-color: ${type === 'success' ? '#9fef00' : '#ff6b6b'};
color: ${type === 'success' ? '#1e2530' : '#fff'};
border-radius: 4px;
font-weight: 600;
z-index: 10001;
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
animation: slideInRight 0.3s ease;
`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.style.animation = 'slideOutRight 0.3s ease';
setTimeout(() => notification.remove(), 300);
}, 3000);
}
// Add animations for notifications
const notificationStyle = document.createElement('style');
notificationStyle.textContent = `
@keyframes slideInRight {
from {
transform: translateX(400px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOutRight {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(400px);
opacity: 0;
}
}
`;
document.head.appendChild(notificationStyle);
})();

Comments are disabled for this gist.