Skip to content

Instantly share code, notes, and snippets.

@LiveOverflow
Last active March 15, 2023 02:54
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save LiveOverflow/bbdffe3777ce0f008b452e0a789cef65 to your computer and use it in GitHub Desktop.
Save LiveOverflow/bbdffe3777ce0f008b452e0a789cef65 to your computer and use it in GitHub Desktop.
GoogleCTF2018 - JS Safe 2
import random
import re
# python3
# STAGE 1
"""
stage1 = 'Ӈ#7ùª9¨M¤ŸÀ.áÔ¥6¦¨¹.ÿÓÂ.։£JºÓ¹WþʖmãÖÚG¤…¢dÈ9&òªћ#³­1᧨'
out = ""
key = "\x82\x1e\x0a\x9a"
for i in range(0, len(stage1)):
out += (chr(ord(stage1[i])^ord(key[i%len(key)])))
print(out)
х==c('¢×&Ê´cʯ¬$¶³´}ÍÈ´T—©Ð8ͳÍ|Ԝ÷aÈÐÝ&›¨þJ',h(х))//᧢
"""
# STAGE 2
stage2 = '¢×&Ê´cʯ¬$¶³´}ÍÈ´T—©Ð8ͳÍ|Ԝ÷aÈÐÝ&›¨þJ'
valid_re = re.compile(r'^[0-9a-zA-Z_@!?-]+$')
# return every 4th character of s, starting at the nth offset
def extract_nth(s, nth=0):
return "".join(list("{}".format(a) for a in s[nth::4]))
# xor the given cipher text with a repeating the key bytes
def xor(cipher, key):
out = ""
for i in range(0, len(cipher)):
out += (chr(ord(cipher[i])^(key[i%len(key)])))
return (out)
# collect possible key candidates for each byte
key_canditates = {}
for offset in range(0,4):
for key_byte in range(0x00, 0xff+1):
tmp = extract_nth(stage2, offset)
plain = xor(tmp, [key_byte])
if valid_re.match(plain):
# remember this possible key_byte in a dict
if offset not in key_canditates:
key_canditates[offset] = []
key_canditates[offset].append(key_byte)
# print all possible decrypted flags
for a in key_canditates[0]:
for b in key_canditates[1]:
for c in key_canditates[2]:
for d in key_canditates[3]:
print(xor(stage2, [a, b, c, d]))
"""
_B3x7!v3R91ON!h45!AnTE-4NXi-abt1-H3bUk_
_N3x7-v3R51ON-h45-AnTI-4NTi-ant1-D3bUg_
"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS safe v2.0 - the leading localStorage based safe solution with military grade JS anti-debug technology</title>
<!--
Advertisement:
Looking for a hand-crafted, browser based virtual safe to store your most
interesting secrets? Look no further, you have found it. You can order your own
by sending a mail to js_safe@example.com. When ordering, please specify the
password you'd like to use to open and close the safe. We'll hand craft a
unique safe just for you, that only works with your password of choice.
-->
<style>
body {
text-align: center;
}
input {
font-size: 200%;
margin-top: 5em;
text-align: center;
width: 26em;
}
#result {
margin-top: 8em;
font-size: 300%;
font-family: monospace;
font-weight: bold;
}
body.granted>#result::before {
content: "Access Granted";
color: green;
}
body.denied>#result::before {
content: "Access Denied";
color: red;
}
#content {
display: none;
}
body.granted #content {
display: initial;
}
.wrap {
display: inline-block;
margin-top: 50px;
perspective: 800px;
perspective-origin: 50% 100px;
}
.cube {
position: relative;
width: 200px;
transform-style: preserve-3d;
}
.back {
transform: translateZ(-100px) rotateY(180deg);
}
.right {
transform: rotateY(-270deg) translateX(100px);
transform-origin: top right;
}
.left {
transform: rotateY(270deg) translateX(-100px);
transform-origin: center left;
}
.top {
transform: rotateX(-90deg) translateY(-100px);
transform-origin: top center;
}
.bottom {
transform: rotateX(90deg) translateY(100px);
transform-origin: bottom center;
}
.front {
transform: translateZ(100px);
}
@keyframes spin {
from { transform: rotateY(0); }
to { transform: rotateY(360deg); }
}
.cube {
animation: spin 20s infinite linear;
}
.cube div {
position: absolute;
width: 200px;
height: 200px;
background: rgba(0, 0, 0, 0.51);
box-shadow: inset 0 0 60px white;
font-size: 20px;
text-align: center;
line-height: 200px;
color: rgba(0,0,0,0.5);
font-family: sans-serif;
text-transform: uppercase;
}
</style>
<script>
function x(х) {
ord = Function.prototype.call.bind(''.charCodeAt);
chr = String.fromCharCode;
str = String;
function h(s) {
console.log("h('"+s+"')");
for (i = 0; i != s.length; i++) {
a = ((typeof a == 'undefined' ? 1 : a) + ord(str(s[i]))) % 65521;
b = ((typeof b == 'undefined' ? 0 : b) + a) % 65521
}
return chr(b >> 8) + chr(b & 0xFF) + chr(a >> 8) + chr(a & 0xFF)
}
function c(a, b, c) {
for (i = 0; i != a.length; i++) c = (c || '') + chr(ord(str(a[i])) ^ ord(str(b[i % b.length])));
console.log("XOR decrypt result: "+c);
return c
}
for (a = 0; a != 1000; a++) {};
foo = "function x(х){ord=Function.prototype.call.bind(''.charCodeAt);chr=String.fromCharCode;str=String;function h(s){for(i=0;i!=s.length;i++){a=((typeof a=='undefined'?1:a)+ord(str(s[i])))%65521;b=((typeof b=='undefined'?0:b)+a)%65521}return chr(b>>8)+chr(b&0xFF)+chr(a>>8)+chr(a&0xFF)}function c(a,b,c){for(i=0;i!=a.length;i++)c=(c||'')+chr(ord(str(a[i]))^ord(str(b[i%b.length])));return c}for(a=0;a!=1000;a++)debugger;x=h(str(x));source=/Ӈ#7ùª9¨M¤ŸÀ.áÔ¥6¦¨¹.ÿÓÂ.։£JºÓ¹WþʖmãÖÚG¤…¢dÈ9&òªћ#³­1᧨/;source.toString=function(){return c(source,x)};try{console.log('debug',source);with(source)return eval('eval(c(source,x))')}catch(e){}}";
x = h(str(foo));
source = /Ӈ#7ùª9¨M¤ŸÀ.áÔ¥6¦¨¹.ÿÓÂ.։£JºÓ¹WþʖmãÖÚG¤…¢dÈ9&òªћ#³­1᧨/;
source.toString = function() {
return c(source, x)
};
try {
//console.log('debug', source);
// х==c('¢×&Ê´cʯ¬$¶³´}ÍÈ´T—©Ð8ͳÍ|Ԝ÷aÈÐÝ&›¨þJ',h(х))//᧢
with(source) return eval('eval(c(source,x))')
} catch (e) {}
}
</script>
<script>
function open_safe() {
keyhole.disabled = true;
password = /^CTF{([0-9a-zA-Z_@!?-]+)}$/.exec(keyhole.value);
if (!password || !x(password[1])) return document.body.className = 'denied';
document.body.className = 'granted';
password = Array.from(password[1]).map(c => c.charCodeAt());
encrypted = JSON.parse(localStorage.content || '');
content.value = encrypted.map((c,i) => c ^ password[i % password.length]).map(String.fromCharCode).join('')
}
function save() {
plaintext = Array.from(content.value).map(c => c.charCodeAt());
localStorage.content = JSON.stringify(plaintext.map((c,i) => c ^ password[i % password.length]));
}
</script>
</head>
<body>
<div>
<input id="keyhole" autofocus onchange="open_safe()" placeholder="🔑">
</div>
<div class="wrap">
<div class="cube">
<div class="front"></div>
<div class="back"></div>
<div class="top"></div>
<div class="bottom"></div>
<div class="left"></div>
<div class="right"></div>
</div>
</div>
<div id="result">
</div>
<div>
<input id="content" onchange="save()">
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment