CTF
Search…
VolgaCTF 2019 Qualifier
VolgaCTF - это дружба! (which mean friendship)

RE - TrustVM

This is how program looks like in python :
1
from functools import partial
2
def firstalgo(a, k):
3
res = [0] * 64
4
for i in range(0, 64):
5
res[i] = ord(a[i]) ^ k[i]
6
return res
7
8
def secondalgo(arr, rcx, shift):
9
res = [0] * 64
10
last = arr[63]
11
for i in range(0, 64):
12
first = arr[i] << rcx
13
if i == 0:
14
second = (last << rcx) >> 8
15
else:
16
second = (arr[i - 1] << rcx) >> 8
17
res[(i + shift) % 64] = (first | second) % 0x100
18
return res
19
20
21
22
key =[0xe1, 0xa9, 0xe1, 0x2e, 0x0b, 0x15, 0x44, 0x9c, 0x08, 0xdc, 0xdc, 0xf3, 0x1a, 0x91, 0x9c, 0x6e, 0x34, 0x5c, 0xe4, 0x5e, 0xf9, 0xe2, 0x5f, 0xf1, 0xf0, 0x86, 0x05, 0xa8, 0x70, 0x6e, 0x04, 0x53, 0x9d, 0x31, 0xec, 0x10, 0xab, 0xea, 0xf6, 0x74, 0x44, 0x79, 0x0f, 0x28, 0x53, 0x40, 0x37, 0x2c, 0x17, 0x9a, 0xc3, 0x67, 0x95, 0x2f, 0x4b, 0x27, 0xd9, 0x3f, 0xf9, 0x1d, 0x2a, 0x70, 0x77, 0x5d]
23
24
blocks = []
25
i = 0
26
inp = ""
27
with open('abc', 'rb') as openfileobject:
28
for chunk in iter(partial(openfileobject.read, 64), b''):
29
blocks.append(chunk)
30
31
encrypted = []
32
33
for block in blocks:
34
firstalgo_res = firstalgo(block, key)
35
rcx = 5
36
shift = 9
37
encrypted_block = secondalgo(firstalgo_res, rcx, shift)
38
encrypted_block = ', '.join('0x%02x' % b for b in encrypted_block)
39
encrypted.append(encrypted_block)
40
rcx = 7
41
shift = 0xd
42
key = secondalgo(key, rcx, shift)
43
key = firstalgo(block, key)
44
45
print encrypted
Copied!
Thanks to @7feilee for reverse the secondalgo(), then we have :
solver.py
1
from functools import partial
2
def firstalgo(a, k):
3
res = [0] * 64
4
for i in range(0, 64): res[i] = ord(a[i]) ^ k[i]
5
return res
6
7
def secondalgo(arr, rcx, shift):
8
res = [0] * 64
9
last = arr[63]
10
for i in range(0, 64):
11
first = arr[i] << rcx
12
if i == 0:
13
second = (last << rcx) >> 8
14
else:
15
second = (arr[i - 1] << rcx) >> 8
16
res[(i + shift) % 64] = (first | second) % 0x100
17
return res
18
19
def rev_second(arr,rcx,shift):
20
res = [0] * 64
21
last = arr[0]
22
for i in range(0, 64):
23
first = arr[i] << rcx
24
if i == 64:
25
second = (last << rcx) >> 8
26
else:
27
second = (arr[i - 1] << rcx) >> 8
28
res[(i + shift) % 64] = (first | second) % 0x100
29
return res
30
31
final_output = ''
32
# first block
33
out_arr = [137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 2, 0, 0, 0, 2, 0, 8, 6, 0, 0, 0, 244, 120, 212, 250, 0, 0, 0, 4, 103, 65, 77, 65, 0, 0, 177, 143, 11, 252, 97, 5, 0, 0, 0, 6, 98, 75, 71, 68, 0, 255, 0, 255, 0, 255, 160]
34
prev = ""
35
print out_arr
36
for num in out_arr:
37
prev += chr(num)
38
final_output += chr(num)
39
40
41
def st_to_arr(st):
42
arr = []
43
for c in st:
44
arr.append(ord(c))
45
return arr
46
key =[0xe1, 0xa9, 0xe1, 0x2e, 0x0b, 0x15, 0x44, 0x9c, 0x08, 0xdc, 0xdc, 0xf3, 0x1a, 0x91, 0x9c, 0x6e, 0x34, 0x5c, 0xe4, 0x5e, 0xf9, 0xe2, 0x5f, 0xf1, 0xf0, 0x86, 0x05, 0xa8, 0x70, 0x6e, 0x04, 0x53, 0x9d, 0x31, 0xec, 0x10, 0xab, 0xea, 0xf6, 0x74, 0x44, 0x79, 0x0f, 0x28, 0x53, 0x40, 0x37, 0x2c, 0x17, 0x9a, 0xc3, 0x67, 0x95, 0x2f, 0x4b, 0x27, 0xd9, 0x3f, 0xf9, 0x1d, 0x2a, 0x70, 0x77, 0x5d]
47
48
count = 64
49
f = open('data.enc', 'rb')
50
content = f.read()
51
f.close()
52
for i in range(64, len(content), 64):
53
enc_data = ""
54
for i in range(count, count+64):
55
enc_data += content[i]
56
count += 64
57
#reverse second algo
58
rcx = 5
59
shift = 9
60
rcx = 8 - rcx
61
shift = 64 - shift - 1
62
rev_second_data = rev_second(st_to_arr(enc_data), rcx, shift)
63
#print rev_second_data
64
#derive key
65
rcx = 7
66
shift = 0xd
67
derivedkey = secondalgo(key, rcx, shift)
68
derivedkey = firstalgo(prev, derivedkey)
69
#print derivedkey
70
#decrypt
71
key = derivedkey
72
#print enc_data
73
#print key
74
#break
75
tmp_rev_second_data = ''
76
for i in range(0, len(rev_second_data)):
77
tmp_rev_second_data += chr(rev_second_data[i])
78
prev = firstalgo(tmp_rev_second_data, key)
79
for i in range(0, len(prev)):
80
final_output += chr(prev[i])
81
tmp = ""
82
for num in prev:
83
tmp += chr(num)
84
prev = tmp
85
f = open('out.png', 'wb')
86
f.write(final_output)
87
f.close()
Copied!
Decrypt the data.enc, we got a PNG image :
flag
1
VolgaCTF{y0u_ju5t_rever5ed_a_512_b1t_Virtu4l_Mach1nE}
Copied!

Antifake - Horrible Retelling

1
Someone sent us the news for publication. It seems an actual error, except for spelling.
2
3
"Scientists found the oldest telescope This tool was used by seafarers from Portuge. British researchers report that scientists explore Arabian sea bottom. There are a lot of wrecks. Last week one of the Scientist journal published an article about discovering a special device. It’s looks like big coin with a hole in its centre. Historians classed it as an oldest device of its tipe. Researchers suggest that it was used in middle ages or mayby earlier. One of the most special detail of telescope is a pattern rounds telescope. It includes a Picture of the Earth. At the turn of the Middle ages that was associated with a Portuguese king. There is only one same devise has been fond before. But researchers don’t sure about age of it. Altogether there are more tahn hundred same artifacts. New one isn’t most old. But its’s unique with its decoration. Besides in the latest Middle ages navigator sed more precise devices"
4
5
Copied!
You can just paste them in google translate to read it, i guess they wrote it in Russia and then use translator to translate it to english, so it's horrible to read (translate word by word sucks)
And then you realize it's all talkinng about a old telescope called Astroblade
1
VolgaCTF{astroblade}
Copied!

Antifake - Fakegram Star

We were given the instagram :
1
https://www.instagram.com/volgactftask
Copied!
And the posts looks like it was copy and pasted from somewhere and there is some typo problems :
1
Me and Dan are mkin a go of it
Copied!
Then we can see the pattern by compare fake post with original post :
1
the (their -> ir)
2
fl (fling -> ing)
3
ag (making -> mkin)
Copied!
Keep doing this, we can find the hidden message :
1
theflag is we ask you to . �� make writeup for this task _
Copied!
Flag is quite weird though :
flag
1
VolgaCTF{weaskyoutomakewriteupforthistask}
Copied!

Forensic - Higher

We were given an mp3 file :
The name "Higher" is a hint, basically load it in to Audacity -> Effect -> High-pass filter -> Hipass 1500Hz
And convert to Spectrogram with maximum is 20k :
You can see a thin line (represent 0) and thick line (represent 1)
Decode it we have :
1
VolgaCTF{N0t_4ll_c4n_b3_h34rd}
Copied!

Web - Shop 1

Check the robots.txt, we found :
Download .war file and decompile it with JD-GUI :
We found an .sql file, and it's quite interesting that someone/admin was actually use that test/test account to exploit, increase the balance to 100000000 . Though they fix it later, but my teammate and 30 team other already solved the challenge, and it gave me some ideas to solve shop 1 myself (in intended way) and shop 2 later
It's quite trivial that this is AutoBinding vuln, and we can pass param "Balance" as Object and control its value :
And we need a POST request to change the Balance and buy Flag at the same time, using Burp Suite, we have :
Huehuehuehue :
flag
1
VolgaCTF{c6bc0c68f0d0dac189aa9031f8607dba}
Copied!

Web - Shop 2

It's pretty much same though, we can find the .war file by checking robots.txt :
Download and decompile .war file, we realize that no matter how much money we have, we just cant buy flag :
1
@RequestMapping(value={"/buy"})
2
public String buy(@RequestParam Integer productId, @ModelAttribute(value="user") User user, RedirectAttributes redir, HttpServletRequest request) {
3
HttpSession session = request.getSession();
4
if (session.getAttribute("user_id") == null) {
5
return "redirect:index";
6
}
7
Product product = this.productDao.geProduct(productId);
8
if (product == null) {
9
redir.addFlashAttribute("message", (Object)"Product not found");
10
return "redirect:index";
11
}
12
if (product.getPrice() > user.getBalance()) {
13
redir.addFlashAttribute("message", (Object)"Not enough money");
14
return "redirect:index";
15
}
16
user.setBalance(Integer.valueOf(user.getBalance() - product.getPrice()));
17
user.getCartItems().add(product);
18
this.userDao.update(user);
19
redir.addFlashAttribute("message", (Object)"Successful purchase");
20
return "redirect:profile";
21
}
Copied!
But it's quite easy to realize that we can do something with "cart" in /profile
1
@RequestMapping(value={"/profile"})
2
public String profile(@ModelAttribute(value="user") User user, Model templateModel, HttpServletRequest request) {
3
HttpSession session = request.getSession();
4
if (session.getAttribute("user_id") == null) {
5
return "redirect:index";
6
}
7
ArrayList cart = new ArrayList();
8
user.getCartItems().forEach(p -> cart.add(this.productDao.geProduct(p.getId())));
9
templateModel.addAttribute("cart", cart);
10
return "profile";
11
}
12
Copied!
Sadly that @ModelAttribute dont set Lists so i cant do something like
1
name=ausername&cart[0].id=4
Copied!
But Autobind uses functions of classes too, so :
And we got flag :
Flag :
flag
1
VolgaCTF{e86007271413cc1ac563c6eca0e12b62}
Copied!
Last modified 2yr ago