Friday, December 26, 2014

adctf2014 - Web - Day 5 shooting

Get 10000 pt. This game is really hard, and so you can crack it.

http://adctf2014.katsudon.org/dat/JEZSnwooVJRYDRzt/shooting.html



In the <head> element of  shooting,html we find references to the javascript being used in this game.

<script type="text/javascript" src="enchant.js"></script>
<script type="text/javascript" src="ui.enchant.js"></script>
<script type="text/javascript" src="nineleap.enchant.js"></script>
<script type="text/javascript" src="shooting.min.js"></script>

The first two files are probably library code from http://enchantjs.com/ and nineleap appears to be a webgame site.

The file shooting.min.js contains everything we need to understand and hack the game. However, its ugly, so we need to pretty it up a bit. A cleaned version of this file is included at the end of this write-up.

Once we have a cleaned up version, we can begin analyzing the code.

The first chunk is to decode the following strings

  • touchmove
  • enterframe
  • graphic.png
  • black
  • touchstart
  • touchend

The touchmove, touchstart, and touch end are likely going to be used with event handlers

The rest of the code, once cleaned up, is relatively easy to follow.

b=["\x63","\x68","\x65","\x65","\x72","\x75","\x70","\x2c","\x20","\x6b","\x65","\x65","\x70","\x20","\x67","\x6f","\x69","\x6e","\x67","\x21"];

P=[b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8],b[9],b[10],b[11],b[12],b[13],b[14],b[15],b[16],b[17],b[18],b[19]];

Another obfuscation trick, P="cheerup, keep going!" Cute, now they're purposely making their code suspicious looking so we'd focus on it.

Next thing I notice is that the score is stored as in attribute score in object gamé. The game score appears to control what level you're on. We see the logic make a point to determine wether the score is above or below 8e3

if(gamé.score<8e3....

if(B){
 if(gamé.score>=8e3){...

8e3 isn’t hex, its 8*10**3, or 8000

Since the second evaluation of gamé.score occurs right after an evaluation of B, I figure B must hold some significance.

I begin playing the game again but with developer tools opened (Ctrl-Shift-I in Chrome). I hit F8 to pause javascript execution after ensuring that the score variable is set by killing a few ships. From here I add gamé.score and B to my watchlist, so I can easily monitor or manipulate them.



At this point I'm really curious why 8000 was a critical point, and not 10000, which I would assume be the flag condition. I set B to true, and gamé.score to 8000 to find out.



This doesn't look good. Even after hitting the enemy ships, they didn't die, merely changed color. Clearly, I'm not going to get past this phase. I pause the game again and set my score to 10000, at the game’s end, I get this error.



Perhaps that P code obfuscation wasn't just to make it look suspicious.

Looking back at the initialization block.

b=["\x63","\x68","\x65","\x65","\x72","\x75","\x70","\x2c","\x20","\x6b","\x65","\x65","\x70","\x20","\x67","\x6f","\x69","\x6e","\x67","\x21"];
c=[107.4,126.1,131.2,120.3,130,134.2,129.1,62.4,55.5,126.3,133.3,111.2,120.2,43.1,122.3,139.4,123.5,126,123.6,47.6,19,18.7,18.8,17.1,20.6,19.9,17.9,20.4,17.5,20.7,20.2,20.2];

P=[b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8],b[9],b[10],b[11],b[12],b[13],b[14],b[15],b[16],b[17],b[18],b[19]];

The c array sticks out as odd, could be game geometry, could be important.

Searching through the code I noticed it's used in the following code

  for(var e=0; e<b.length;e++){
    c[e]-=b[e].charCodeAt(0);
c[e]=Math.round(c[e]*10)/10
  }

Arrays c and b are being used to create new values for array c, and array b is used to give the sad message, so c is certainly becoming a target.

I keep searching an I see the c array getting used again in setting up the advanced stage

var n=new h(300,e*16,.01,9999,c[e^b.length]);

Looking in the h code, we see not too surprisingly, that c is ignored. Digging deeper in the code we find.

for(var e in E){
    ….
    (P[e]=String.fromCharCode(E[e].c*10^255))

This is where array P (the array that gets reported at the end of the game), gets populated using array c. This code gets triggered when an enemy dies. It’s unlikely that I’d be able to kill all the enemies, as they have multiple lives, but what I can do is trigger the advanced level where the line of enemies and their corresponding c values are created.

Instead of killing the enemyships, I populat the P array by executing the following code in the javascript console:

for(var e in E){(P[e]=String.fromCharCode(E[e].c*10^255))}

Finally I set score to 10000 to receive the decoded alert.




Cleaned up version of shooting.min.js

$UPcs4hr8oKgbbqAesfT=function(n){
if (typeof ($UPcs4hr8oKgbbqAesfT.list[n]) == "string") return $UPcs4hr8oKgbbqAesfT.list[n].split("").reverse().join("");return $UPcs4hr8oKgbbqAesfT.list[n];
};
$UPcs4hr8oKgbbqAesfT.list=["evomhcuot","emarfretne","gnp.cihparg","kcalb","tratshcuot","dnehcuot"];

enchant();
window.onload=function(){
gamé=new Game(320,320);
gamé.fps=24;
G=false;
B=false;
b=["\x63","\x68","\x65","\x65","\x72","\x75","\x70","\x2c","\x20","\x6b","\x65","\x65","\x70","\x20","\x67","\x6f","\x69","\x6e","\x67","\x21"];
c=[107.4,126.1,131.2,120.3,130,134.2,129.1,62.4,55.5,126.3,133.3,111.2,120.2,43.1,122.3,139.4,123.5,126,123.6,47.6,19,18.7,18.8,17.1,20.6,19.9,17.9,20.4,17.5,20.7,20.2,20.2];


P=[b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8],b[9],b[10],b[11],b[12],b[13],b[14],b[15],b[16],b[17],b[18],b[19]];


gamé.score=0;
gamé.touched=false;
gamé.preload($UPcs4hr8oKgbbqAesfT(2));
gamé.onload=function(){
 player=new f(0,152);
 E=new Array;
 for(var e=0; e<b.length;e++){
   c[e]-=b[e].charCodeAt(0);
c[e]=Math.round(c[e]*10)/10
 }
 gamé.rootScene.backgroundColor=$UPcs4hr8oKgbbqAesfT(3);


 gamé.rootScene.addEventListener($UPcs4hr8oKgbbqAesfT(1),function(){
   var e=0;
   var t=gamé.score>=5e3;
if(gamé.score<8e3&&(rand(1e3)<gamé.frame/20*Math.sin(gamé.frame/100)+gamé.frame/20+50||t&&rand(500)<gamé.frame/20*Math.sin(gamé.frame/100)+gamé.frame/20+50)){
 var n=rand(320);
 var r=n<160?.01:-.01;
 (gamé.score>=5e3)?(e=Math.floor(Math.random()*4)):(e=Math.floor(gamé.score/1e3));
 var i=new g(320,n,r,e);
 i.key=gamé.frame;
 E[gamé.frame]=i
}
if(B){
 if(gamé.score>=8e3){
   B=false;
for(var s in E){
 E[s].remove()
}
setTimeout(
 function(){
   for(var e=0;e<20;e++){
 var t=rand(320);
 var n=new h(300,e*16,.01,9999,c[e^b.length]);
 n.key=e;
 E[e]=n
}
 },1e3
)
}
}
scoreLabel.score=gamé.score;
(gamé.score==1e4)?((!G)?(G=true,setTimeout(
 function(){
   gamé.end();
alert(P.join(""))
 },1e3
)):0):0;});
 
scoreLabel=new ScoreLabel(8,8);
gamé.rootScene.addChild(scoreLabel)};
gamé.start()};


/* Player data */
var f=enchant.Class.create(enchant.Sprite,{
 initialize:function(e,t){
   enchant.Sprite.call(this,16,16);
   this.image=gamé.assets[$UPcs4hr8oKgbbqAesfT(2)];
   this.x=e;
   this.y=t;
   this.frame=0;
   gamé.rootScene.addEventListener($UPcs4hr8oKgbbqAesfT(4),function(e){player.y=e.y;gamé.touched=true});
   gamé.rootScene.addEventListener($UPcs4hr8oKgbbqAesfT(0),function(e){player.y=e.y});
gamé.rootScene.addEventListener($UPcs4hr8oKgbbqAesfT(5),function(e){player.y=e.y;gamé.touched=false});
   this.addEventListener($UPcs4hr8oKgbbqAesfT(1),function(){if(gamé.touched&&gamé.frame%3==0){var e=new k(this.x,this.y)}});
gamé.rootScene.addChild(this)
 }
});


/*Games with score under 8000 */
var g=enchant.Class.create(enchant.Sprite,{
 initialize:function(e,t,n,r){
   enchant.Sprite.call(this,16,16);
   this.image=gamé.assets[$UPcs4hr8oKgbbqAesfT(2)];
   this.x=e;
   this.y=t;
   this.level=r;
   switch(this.level){case 0:this.frame=3;break;case 1:this.frame=4;break;case 2:this.frame=5;break;default:this.frame=6}
   this.omega=n;
   this.direction=0;
   (this.level>=3)?(this.moveSpeed=5):(this.level>=2)?(this.moveSpeed=4):(this.moveSpeed=3);
   this.addEventListener($UPcs4hr8oKgbbqAesfT(1),function(){this.move();if(this.y>320||this.x>320||this.x<-this.width||this.y<-this.height){this.remove()}else if(this.level>=3&&this.age%5==0||this.level<3&&this.age%10==0){var e=new l(this.x,this.y)}});gamé.rootScene.addChild(this)
 },move:function(){
   this.direction+=this.omega;
   this.x-=this.moveSpeed*Math.cos(this.direction/180*Math.PI);
   (this.level>=1)?((player.y>this.y)?(this.y+=this.moveSpeed):(player.y<this.y)?(this.y-=this.moveSpeed):0):0;
 },remove:function(){
   gamé.rootScene.removeChild(this);delete E[this.key]
 }
});


/* games over 8000 */
var h=enchant.Class.create(g,{
 initialize:function(e,t,n,r,i){
   g.call(this,e,t,n,r);
   this.image=gamé.assets[$UPcs4hr8oKgbbqAesfT(2)];
   this.x=e;
this.y=t;
this.c=i;
this.level=r;
this.life=10;
this.frame=6;
this.omega=n;
this.direction=0;
this.clearEventListener($UPcs4hr8oKgbbqAesfT(1));
this.addEventListener($UPcs4hr8oKgbbqAesfT(1),function(){if(this.age%3==0){var e=new l(this.x,this.y)}});
gamé.rootScene.addChild(this)
 }
});


var j=enchant.Class.create(enchant.Sprite,{
 initialize:function(e,t,n){
   enchant.Sprite.call(this,16,16);
this.image=gamé.assets[$UPcs4hr8oKgbbqAesfT(2)];
this.x=e;
this.y=t;
this.scaleX=-1;
(n==0)?(this.frame=1):(this.frame=2);
this.direction=n;
this.moveSpeed=10;
this.addEventListener($UPcs4hr8oKgbbqAesfT(1),function(){this.x+=this.moveSpeed*Math.cos(this.direction);this.y+=this.moveSpeed*Math.sin(this.direction);(this.y>320||this.x>320||this.x<-this.width||this.y<-this.height)?(this.remove()):0;});
gamé.rootScene.addChild(this)
 },remove:function(){
   gamé.rootScene.removeChild(this);
delete this
 }
});


var k=enchant.Class.create(j,{
 initialize:function(e,t){
   j.call(this,e,t,0);
this.addEventListener($UPcs4hr8oKgbbqAesfT(1),function(){
 for(var e in E){
   (!B&&E[e].intersect(this))?(
 (E[e].life!==undefined)?(
   E[e].life--,this.remove(),(E[e].life==0)?(P[e]=String.fromCharCode(E[e].c*10^255),gamé.score+=100,E[e].remove()):(E[e].life<=3)?(E[e].frame=3):(E[e].life<=6)?(E[e].frame=4):(E[e].life<=8)?(E[e].frame=5):0):(this.remove(),E[e].remove(),gamé.score+=100,(gamé.score==8e3)?(B=true):0)):0;
 }
})
 }
});


var l=enchant.Class.create(j,{
 initialize:function(e,t){
   j.call(this,e,t,Math.PI);
this.addEventListener($UPcs4hr8oKgbbqAesfT(1),function(){(player.within(this,8))?(gamé.end()):0;})
 }
})

No comments:

Post a Comment