Being stuck at home for a few days, I decided to distract myself a bit and extend this page with a PoC||GTFO Mirror . For senseless reasons I wanted one of these viewers where you can actually flip pages while reading, just as they use for ads / catalogs from shops. I quickly found a piece of software that would do the job, but had to perform a few changes on the resulting content…
The software I ended up using is called Flip Builder . It loads a PDF (at least if it can) and converts it into a catalog style HTML5 page for reading. Having read quite a few bad comments on their customer support and a few bugs in the software I downloaded the free version and gave it a test run.
As I went for the free version there was a rather ugly banner mid page. Although I’m happy to keep (major) references to the maker of a software when I’m allowed to use it for free, the add made reading certain pages of the journals rather tough. As such I decided to simply try to shift the ad to the bottom of the page, in between the page numbers, so that easy reading would be possible while still keeping the reference.
Could things be easy?
I had an issue of the journal open in Firefox and simply did a right click on the image in the overlay and selected Inspect Element.
<div style="width: 305px; height: 70px; position: absolute; background-color: rgb(204, 204, 204); opacity: 0.5; z-index: 1000; border-radius: 5px; top: 0px; left: 0px; bottom: 0px; right: 0px; margin: auto;">
<div style="position: absolute; top: 13px; left: 65px;">
<span style="font-size: 15px; color: rgb(51, 51, 51);">Flip PDF</span>
<a href="http://www.flipbuilder.com" target="_blank" style="position: absolute; top: 25px; left: 0px;">
http://www.flipbuilder.com
</a>
</div>
<img style="position: absolute; top: 10px; left: 5px;" src="mobile/style/icon/demo.png">
</div>
Working on Windows due to the Tool, I opened Notepad++ and simply did a search in the applicable directory for <div style="width: 305px; height: 70px;
. Strangely I wasn’t able to find anything so I adjusted my search and simply looked for 305px
which luckily resulted in a single entry in a file called main.js
. The file then welcomed me with 3261 lines of JS.
I found my 305px
in line 579
95," demoBar css bookConfig var left top function append homePage div style absolute productName parseInt hidden 5px position if body radius is border 932217 html trim 6406725519N color BUILD_DATE span opacity href width setDemoPosition bottom right loadImg attr index parseFloat 1000 height getTransform text 500 target _blank 25px 0px size 15px 333333 initDemoBar bdor fn extend webkit img margin auto background load 10px src uiBaseURL demo png window setInterval display none visibility 70px indexOf parent 13px 65px cccccc moz 305 70 305px font".split(" "),
To verify that I was in the right spot, I changed the 305px
to 999px
and broke the page. As the line is obviously obfuscated, I guessed it was a simple mechanism to ensure nobody removed the banner. At this point I didn’t spot the second 305
in moz 305 70 305px font
which would have saved the day, so I carried on messing around with the code.
Still having the applicable line selected in Firefox’s Inspector, I switched over to the Debbugger and hit the pause button. Firefox was nice enough to directly show me the line I had been looking for
var demoBar;
var initDemoBar=function()
{
if(BUILD_DATE.indexOf("932217.6406725519N")==-1)
{
BUILD_DATE+="932217.6406725519N"
}
if(!bookConfig.productName||!bookConfig.productName.trim()||!bookConfig.homePage||!bookConfig.homePage.trim())$("body").html("");
var a=bookConfig.homePage;demoBar=$("<div></div>");
demoBar.css({width:'999px',height:'70px',position:'absolute','background-color':'#cccccc','opacity':0.5,'z-index':1000,'-moz-border-radius':'5px','-webkit-border-radius':'5px','border-radius':'5px'});
var b=$("<img />");
b.css({position:'absolute',top:'10px',left:'5px'});
var c=$("<div></div>");
c.css({position:'absolute',top:'13px',left:'65px'});
var d=$("<span>"+bookConfig.productName+"</span>");
var e=$("<a href='"+a+"' target='_blank'>"+a+"</a>");
e.css({position:'absolute',top:'25px',left:'0px'});
d.css({'font-size':'15px',color:'#333333'});
$("body").append(demoBar);
demoBar.append(c);
c.append(d);
bdor[18]="t";
c.append(e);
$.fn.extend(demoBar,{setDemoPosition:function(){demoBar.css({top:0,left:0,bottom:0,right:0,margin:"auto"})},loadImg:function(){b.load(function(){demoBar.append(b)});
b.attr({src:uiBaseURL+'demo.png'})}});
demoBar.loadImg();demoBar.setDemoPosition();
window.setInterval(function(){if(!demoBar||demoBar.css("display")=="none"||demoBar.css("visibility")=="hidden"||demoBar.is(':hidden')||!demoBar.parent()[0]||parseFloat(demoBar.css("opacity"))<=0||parseFloat(demoBar.css("z-index"))<1000||parseInt(demoBar[0].style.left)!=0||parseInt(demoBar[0].style.top)!=0||parseInt(demoBar[0].style.right)!=0||parseInt(demoBar[0].style.bottom)!=0||getTransform(demoBar[0]).x!=0||getTransform(demoBar[0]).y!=0||demoBar.width()!=999||demoBar.height()!=70||d.is(':hidden')||e.is(':hidden')||d.text()!=bookConfig.productName||e.text()!=bookConfig.homePage||e.attr("href")!=bookConfig.homePage)$("body").html("")},500)};
I then removed the raw and obfuscated function
eval(function(b,c,d,f,g,h)
{
g=function(b){return(b<c?"":g(parseInt(b/c)))+(35<(b%=c)?String.fromCharCode(b+29):b.toString(36))};
if(!"".replace(/^/,String) )
{
for(;d--;)h[g(d)]=f[d]||g(d);
f=[function(b){return h[b]}];
g=function(){return"\\w+"};
d=1
}
for(;d--;)f[d]&&(b=b.replace(RegExp("\\b"+g(d)+"\\b","g"),f[d]));
return b
}
("6 2;6 11=9(){p(D.1n(\"v.B\")==-1){D+=\"v.B\"}p(!4.k||!4.k.A()||!4.g||!4.g.A())$(\"q\").w(\"\");6 a=4.g;2=$(\"<h></h>\");2.3({H:'1v',Q:'1m',o:'j','1a-C':'#1r','F':0.5,'z-N':P,'-1s-u-r':'n','-15-u-r':'n','u-r':'n'});6 b=$(\"<16 />\");b.3({o:'j',8:'1c',7:'n'});6 c=$(\"<h></h>\");c.3({o:'j',8:'1p',7:'1q'});6 d=$(\"<E>\"+4.k+\"</E>\");6 e=$(\"<a G='\"+a+\"' U='V'>\"+a+\"</a>\");e.3({o:'j',8:'W',7:'X'});d.3({'1w-Y':'Z',C:'#10'});$(\"q\").f(2);2.f(c);c.f(d);12[18]=\"t\";c.f(e);$.13.14(2,{I:9(){2.3({8:0,7:0,J:0,K:0,17:\"19\"})},L:9(){b.1b(9(){2.f(b)});b.M({1d:1e+'1f.1g'})}});2.L();2.I();1h.1i(9(){p(!2||2.3(\"1j\")==\"1k\"||2.3(\"1l\")==\"m\"||2.s(':m')||!2.1o()[0]||O(2.3(\"F\"))<=0||O(2.3(\"z-N\"))<P||l(2[0].i.7)!=0||l(2[0].i.8)!=0||l(2[0].i.K)!=0||l(2[0].i.J)!=0||R(2[0]).x!=0||R(2[0]).y!=0||2.H()!=1t||2.Q()!=1u||d.s(':m')||e.s(':m')||d.S()!=4.k||e.S()!=4.g||e.M(\"G\")!=4.g)$(\"q\").w(\"\")},T)};",62,
95," demoBar css bookConfig var left top function append homePage div style absolute productName parseInt hidden 5px position if body radius is border 932217 html trim 6406725519N color BUILD_DATE span opacity href width setDemoPosition bottom right loadImg attr index parseFloat 1000 height getTransform text 500 target _blank 25px 0px size 15px 333333 initDemoBar bdor fn extend webkit img margin auto background load 10px src uiBaseURL demo png window setInterval display none visibility 70px indexOf parent 13px 65px cccccc moz 999 70 999px font".split(" "),
0,{}));
and replaced it with the decoded function I fetched from Firefox. I now had everything I needed to slightly shift the banner downwards.
Looking at the initDemoBar
function I found the line bdor[18]="t";
, which made no sense to me (also the name bdor
somehow triggered something in me).
And Then Things Escalated
Notepad++’s search function identified 56 occurrences of the string bdor
. From there I also found an array called hddr
(this||(0,eval)("(this)")).bdor=[];
bdor[1]="p";
bdor[30]=function(b,c){return bdor[b]-c};
bdor[7]="m";
bdor.i=function(b){return bdor[b]};
bdor.f="f";
this.skin=this.bdor
bdor[8]="o";
bdor[3]="f";
bdor[4]="h";
bdor[10]="l";
bdor[31]=function(b,c){return bdor[b]-bdor[c]};
bdor[6]="l"
var hddr=[];
bdor[5]="i";
bdor[10]="l";
bdor[2]="e"
bdor[32]=function(b,c){return b+c};
bdor[66]="ipht";
bdor[18]="t";
bdor[66]="ipht";
bdor[25]="i";
bdor[27]="f";
bdor[26]="h";
global.hddr.soo4=function(b){return b||".com"};
global.hddr.soq3=function(){return hddr.soo1||"tm"}();
bdor[10]="l";
bdor[29]="t";
bdor[8]="o";
bdor[9]="j";
global.hddr.soo6=function(){return hddr.bbb5};
global.hddr.soo6=function(){return hddr.bbb5};
global.hddr.soa7=bdor[3]+bdor[10];
global.hddr.soo3=bdor[51];
global.hddr.soc8=hddr.sob8+"ph";
bdor[7]="m";
global.hddr.soo1="tm";
global.hddr.soa8=hddr.soa7+"i";
global.hddr.sov9=function(b,c){return b+"ph"+c+"l"};
global.hddr.sob8=hddr.soa8;
global.hddr.soq2=hddr.sov9(hddr.soa8,hddr.soq3)+"5";
if(bookConfig.securityType&&3==parseInt(bookConfig.securityType))return 2},getPassward=function(){return document.getElementById("passward_input")?$("#passward_input").val():global.passward},getUsername=function(){return document.getElementById("username_input")?$("#username_input").val():global.username},a=hddr.soo2,
bdor[33]=function(b,c){return b/bdor[30](c,20)};
bdor[36]=36;
global.bdor[35]=function(){return 3}();
global.bdor[37]=80;
bdor[38]=function(){return bdor[30](37,40)}();
bdor[39]=function(){return 8}();
global.bdor[200]=function(b){return bdor[b]};
bdor[41]=function(){return bdor[32](bdor[30](37,0),bdor[38]/bdor[40])}();
bdor[500]=global.bdor[404];
bdor[13]="p";
bdor[42]=function(){return bdor[33](bdor[32](37,33)+10,36)}();
Here, yet again, Firefox’s Debugger
is helpful got get an insight. By searching for bdor
and hovering over the variable name, a simple Tooltip appears.
The line this.skin=this.bdor
took me to this codeblock 60>d&&39>f&&9===c&&(b=$("<div>"+skin[12]+"l"+skin[66]+skin.m+skin.i(22)+skin[42]+skin[60]+"</div>")
, which is called when flipping a page.
I initially set a breakpoint in the mentioned line to check the values in skin
sadly all referenced values were empty.
Something Seems to be Missing
Although the “hidden” functions are mainly there to add an extra <div>
element with some content to the page, I carried on looking around the JS. As I had already found one use of the eval()
function I decided to check if there where more.
(this||(0,eval)("(this)")).bdor=[];
isPad())&&"slide"==bookConfig.FlipStyle.toLowerCase()?!0:!1},isHigherThanIOS8=function(){return $.system.name==$.system.IOS&&8<=$.system.version},isInTheFrame=function(){return window.top!=window};function isBelowIE9(){return $.browser.msie?9>$.browser.version?!0:!1:!1}function isBelowIE8(){return $.browser.msie?8>$.browser.version?!0:!1:!1}function isBelowIE10(){return $.browser.msie?10>$.browser.version?!0:!1:!1}var global=function(){return this||(0,eval)("(this)")}(),virtual_function=function(){};
return c.join("")}},parse:function(b,c){return b&&"undefined"!=b&&"null"!=b&&""!=b?eval("("+b+")"):c}};
eval("(adsbygoogle = window.adsbygoogle || []).push({});")})}
eval("ga('create', '"+bookConfig.googleAnalyticsID+"', 'auto')");
eval("ga('send', 'pageview')")},3E3)},controlAudioVolume=function(){if(!isNaN(bookConfig.audioVolume)){var b=parseFloat(bookConfig.audioVolume);global.bgSound&&global.bgSound.setVolume(b);flipAudio&&(flipAudio[0].volume=b)}},TurnonAutoFlip=function(){bookConfig.autoFlipOnStart&&window.setTimeout(function(){auto_player&&
function(){window.clearInterval(this.inteval);this.destroy();this.initBookStyle("flip_book")}.bind(this));this.slideModel.bind(_event._end,function(){window.clearInterval(this.inteval);this.destroy();this.initBookStyle("slide_book")}.bind(this));this.initInterval()},initInterval:function(){var b=10,c=getLanguage("lblSelectMode","Select View Mode Please.");this.inteval=window.setInterval(function(){this.description.html(c+"("+b+")");b--;0>=b&&(window.clearInterval(this.inteval),this.destroy(),this.initBookStyle("flip_book"))}.bind(this),
k=eval(h);
this.signatureCookies=d&&"undefined"!=d?eval(d):[]}catch(f){}var g,h;
try{var b=this.getLocalStorage(this.fileName),c=eval(b)}catch(d){}
b.scriptFun&&eval(b.scriptFun);
eval(DeString("f341819f83944fb222ea09f0eaa26b06d7198f1c00b6cd49"));
b.ctrlKey&&b.altKey&&(c==KEY_CODE_HOME||c==KEY_CODE_UP)&&eval(DeString("b29ec71982dc6d9062a0b77ce9ccc59581fd3c4a4fa9bd325e6f5ae7fbf39a0907064bb455b1bade956bc0f3e7c55d348fbaa363c39f7bef7a0648674fd1f688786b79bd6ad03215d634a4736f3f971501f664a09b820932d9bc83a9c2159964e5c571b3ebe4ceb214fd31bb1287fe5449f303a6d5531165e1386ba5aa8d0a3788d4a351d120a43a59c002d761ef"));
Going for the obvious I headed off to take a closer look the DeString
function
function DeString(b,c)
{
if(""==b)return"";
c&&""!=c||(c="fb5");
c=escape(c);
if(null==b||8>b.length)
alert("A salt value could not be extracted from the encrypted message because it's length is too short. The message cannot be decrypted.");
else if(null==c||0>=c.length)
alert("Please enter a password with which to decrypt the message.");
else
{
for(var d="",f=0;f<c.length;f++)
d+=c.charCodeAt(f).toString();
var g=Math.floor(d.length/5),g=parseInt(d.charAt(g)+d.charAt(2*g)+d.charAt(3*g)+d.charAt(4*g)+d.charAt(5*g),10),h=Math.round(c.length/2),k=Math.pow(2,31)-1,f=parseInt(b.substring(b.length-8,b.length),16);
b=b.substring(0,b.length-8);
for(d+=f;10<d.length;)
d=(parseInt(d.substring(0,10),10)+parseInt(d.substring(10,d.length),10)).toString();
for(var d=(g*d+h)%k,l="",m="",f=0;f<b.length;f+=2)
l=parseInt(parseInt(b.substring(f,f+2),16)^Math.floor(d/k*255),10),m+=String.fromCharCode(l),d=(g*d+h)%k;
return unescape(m)
}
}
I then used the Console tab in Firefox and decoded the strings from all calls I was able to find
c3753b3f49449a65f9ad12578d7a4602c8ae34
Copyright:
f341819f83944fb222ea09f0eaa26b06d7198f1c00b6cd49
initDemoBar()
b29ec71982dc6d9062a0b77ce9ccc59581fd3c4a4fa9bd325e6f5ae7fbf39a0907064bb455b1bade956bc0f3e7c55d348fbaa363c39f7bef7a0648674fd1f688786b79bd6ad03215d634a4736f3f971501f664a09b820932d9bc83a9c2159964e5c571b3ebe4ceb214fd31bb1287fe5449f303a6d5531165e1386ba5aa8d0a3788d4a351d120a43a59c002d761ef
* `$(\"<div class='cr'>\" +cr + crBefore + crAfter + \"</div>\").appendTo($(\"body\"));`
4. `d2b0aa5705413c96`
* `Flip`
5. `d35426b1c0d303cfa3012949ee`
* `HTML5.com`
Here String 4. is the value for `crBefore` and 5. the value for `crAfter` as referenced in 3.. 3. actually is the function called in the last `eval()` call, so it adds an extra footer to the page.
Also turns out I just found were `initDemoBar()` is actually called (and I also know why I wasn't able to find the call).
### And Now?
Well, having had a closer look at _main.js_ I currently cannot rate the overall security situation of the script. A few of the referenced array fields seem to be empty throughout overall execution of the script and I haven't brought my head round the complete call tree of the functions using `bdor` and `hddr`. It might do something to the integrated password protection feature that I'm not using, it might also do something to the Flash feature (I'm only using HTML5, no Flash which would also add an _swf_ of the book). Above that I found a class called `PCShoppingCartItem`, which is not used at all in my use case, so _main.js_ is possibly reused in other projects of the same maker. I will simply have follow through the complete call tree once I have enough time and energy.
Although this might come as a surprise, I didn't feel like using the script as is. As I still liked the UI it creates, I (hopefully) simply sanitized it. All references to the `bdor`, `hddr` and `skin` arrays were removed. I also stripped the `DeString` function and all applicable strings.
Btw, I swapped the used `jquery-1.9.1.min.js` with a newer `jquery-3.3.1.min.js`.
### Finally
I have a [PoC\|\|GTFO Mirror](/pocgtfo/)!
Still I'll be having a further look at `main.js` and will carry on deleting unused functionality.