3 puan yazan GN⁺ 2023-10-01 | 1 yorum | WhatsApp'ta paylaş
  • PROJEKT: OVERFLOW, RISC-V assembly ve buffer overflow kavramlarını kutu oyunu kurallarına dönüştürerek bellek, stack ve dönüş adresi manipülasyonunu doğrudan takip ettiren eğitsel bir oyun
  • Oyuncular aynı belleği ve programı paylaşır; sanal bellek olmadan, tur başına yalnızca 10 komut çalıştırılan preemptive scheduling modeliyle yarışır
  • Sonuç, mevcut komutları kopyalayıp shellcode oluşturma ve rakibin return address’ini ezerek onu game_over() fonksiyonuna gönderme akışında belirlenir
  • Hatalı bellek erişimi, hizasız okuma/yazma ve illegal komutlar crash’e ve exception handler’ın çalışmasına yol açar; trap adresini değiştirme ve nop monkeypatch stratejinin temel değişkenleridir
  • Web’de oynama, yazdırılabilir board, ESP32 ve mobil oyun yardımcısı sunuluyor; ancak kuralların bir kısmı hâlâ ayarlandığı için deneysel bir hacking bulmacasına daha yakın

Oyunun amacı ve yürütme modeli

  • PROJEKT: OVERFLOW, RISC-V assembly ve buffer overflow konularını masaüstü kutu oyunu olarak ele alan bir proje
  • Temel amaç, mevcut komutları kopyalayarak bellek içinde küçük bir shellcode oluşturmak, buffer overflow ile bu koda jump etmek ve ardından rakibin return address’ini ezerek game_over() fonksiyonunu çağırmasını sağlamak
  • Strateji, basit kod yürütmenin ötesinde exception handler ayarlamayı ve monkeypatch yapmayı da içerir
  • Tüm oyuncular aynı belleği ve aynı programı paylaşır, aynı işlemciyi zaman paylaşımlı olarak kullanır
    • Bir turda 10 komut çalıştırılır
    • Her oyuncunun stack pointer’ı farklı bir konumdan başlar
    • Sanal bellek yoktur

Build ve board oluşturma akışı

  • Kod, RV32 hedefi için riscv64-unknown-elf-gcc ile derlenir
    • Başlıca seçenekler arasında -march=rv32g, -mabi=ilp32, -ffreestanding, -nostdlib, -nostartfiles, -O0 gibi seçenekler bulunur
    • -O0 sayesinde makine kodu uzun ama takip etmesi kolay bir biçimde kalır
  • Board materyalleri, riscv64-unknown-elf-objdump -S -l -fd game çıktısı parse edilerek oluşturulur
    • ve komutları değiştirilir
    • Jump offset’leri onaltılıktan onluğa çevrilir
    • Assembly temizlenir ve kaynak kodla eşleştirilir
    • SVG oluşturulduktan sonra Inkscape ile PDF’ye dönüştürülür

Baskı ve gerekenler

  • Board, sol ve sağ olarak ayrılmış PDF’ler yazdırılarak kullanılır
  • Baskı için A3 tercih edilir; A4 de mümkündür ama küçük kalır
  • Gerekenler: nop komutu için 1 taş, trap adresi için 1 taş, oyuncu başına program counter ve stack pointer için 2 taş, kalem ve silgi
  • Web sürümü tek başına oynamayı ve arkadaşlarla oynamayı destekler; ESP32 ve mobil için oyun yardımcısı da sunulur

Temel kurallar ve tur akışı

  • Başlangıç durumu şöyledir
    • Tüm register’lar 0’dan başlar; ancak return address register’ı ra 1000’den başlar
    • Player 1’in sp değeri 2244, Player 2’nin sp değeri 3844 olarak ilklendirilir
    • İki oyuncunun pc değeri, main fonksiyonunun başlangıç adresi olan 1000’den başlar
    • Trap taşı adres 1000’e yerleştirilir
    • Önceden yüklenmiş program hariç tüm bellek adresleri 0’dır
    • nop komutu taşı başlangıçta board’a konmaz
  • Bir turda 10 komut çalıştırılmalıdır; jal, beq gibi jump’lar da aynen takip edilmelidir
  • Oyuncu en az 1 komut çalıştırdıktan sonra turu durdurup kalan komut sayısını bir sonraki tura aktarabilir
    • Biriktirilebilecek komut sayısının üst sınırı 20’dir

Monkeypatch ve kazanma koşulu

  • Her turun başında tam olarak 1 komut çalıştırdıktan sonra, nop komutu taşı, mevcut oyuncuların çalıştırmakta olmadığı bir fonksiyonun herhangi bir adresine taşınabilir
  • pc o adrese ulaştığında ilgili komut no-operation olarak davranır
  • nop taşını hareket ettirmek mevcut turu ve bir sonraki turu kaybettirir; rakip bir sonraki turda en fazla 20 komut çalıştırabilir
  • Monkeypatch kuralı henüz dengeli olmadığı için birkaç günde bir küçük değişiklikler yapılıyor
  • Hard mode’da, rakibi hackleyip game_over() fonksiyonunu çağırmasını sağlarsanız oyun biter
  • Taraflardan hiçbirinin rakibi game_over()’a göndermesi mümkün değilse oyun berabere biter
  • Easy mode’da, main içinde ret çalıştırarak ana döngüden çıkan ilk oyuncu kazanır

Özel semboller ve exception handling

  • , li komutunun immediate değeri olarak 0’dan 4095’e kadar herhangi bir 12 bitlik sayı seçmeyi sağlar
  • , load komutunda kendi stack pointer’ı temel alınarak ±128 bayt aralığındaki bir değeri seçmeyi sağlar
    • Örneğin sp 2180 ise 2052’den 2308’e kadar seçim yapılabilir
  • Yasak eylemler program crash’ine yol açar
    • 1192’den düşük bellek adreslerinin üzerine yazmak
    • 4’ün katı olmayan adreslerde hizasız okuma veya yazma yapmak
    • Illegal komut çalıştırmak
  • Crash olursa exception handler çalışır ve trap adresine jump edilir
    • Trap adresi başlangıçta 1000’dir, ancak set_trap() fonksiyonunda üzerine yazılabilir
    • Exception oluştuğunda program counter belirli bir değere ayarlanır ve yürütme devam eder
  • Hile veya hata tespit edilirse ilgili oyuncunun program durumu, belleği ve register’ları sıfırlanır

3–4 oyunculu genişleme kuralları

  • Player 3’ün sp değeri 2116 olarak ayarlanır
  • Player 4’ün sp değeri 3716 olarak ayarlanır
  • 3 veya daha fazla oyuncu olduğunda sembolü yalnızca stack pointer’dan -128 bayt uzaklıktaki aralıkta kullanılabilir
  • 2’den fazla oyuncuyla oynandığında oyun oldukça kararsızlaşır ve hızla bozulur
  • Kazanma koşuluna ulaşmak zorlaşır, ancak oynanış daha eğlenceli ve kaotik hâle gelir

Hacking stratejisi örnekleri

  • Crash, rakibin ilerlemesini engelleyen bir saldırı stratejisi olarak kullanılabilir
  • Trap handler’ı game_over fonksiyonuna çevirirseniz ilk crash olan oyuncu kaybeder
    • Bu durumda nop taşı çok güçlüdür
    • Rakip, o anda yürüttüğünüz fonksiyonun ret komutunun üzerine nop koyarsa kaybedebilirsiniz
  • bug() fonksiyonunda index’i 400 veya -400 yaparak overflow oluşturursanız rakibin stack’ine erişip return address’i ezebilirsiniz
    • Örneğin adres 3784’ten 2184’e gitmek için (3784 - 2184) / 4 = 400 olduğundan index -400 gerekir
  • copy() fonksiyonuyla belirli komutlar kopyalanarak bellekte kısa bir shellcode oluşturulabilir
    • Örnek shellcode, li a4, ✎, li a5, ✎, sw a4, 0(a5), ret kombinasyonuyla arbitrary write gerçekleştirir
    • ret komutu kopyalanırsa return address shellcode’un başlangıç noktasına ayarlanır ve sonsuz döngü oluşur
  • bug() fonksiyonunda index 6 olarak ayarlanırsa value değişkeni stack’te saklanan return address olan 28(sp) üzerine yazılabilir
    • bug() dönerken 28(sp) değeri return address register’ına kopyalanır
    • Bu değere oluşturduğunuz shellcode adresini koyarsanız belleğe jump edebilirsiniz

Komut yorumlama ve değişiklikler

  • Tüm jump’lar, disassembler’da mutlak adres gibi görünse bile mevcut program counter’a göre relative jump’tır
    • Örneğin jal a4, 0 makine kodu 1903, çalıştırıldığında sonsuz döngü olur
  • Geçerli oyun komutlarının listesi, 0’dan 4095’e kadar olan makine kodları içindeki RV32 JRI komutlarından a0, a4, a5, sp, ra gibi register’ları kullanan biçimler olarak düzenlenmiştir
  • Değişiklik günlüğü 0.0.6’da while(run) yerine while(*prun) kullanımı yer alır
    • Rakibin hizasız dereference tetikleyerek zorla crash oluşturabilmesi mümkün hâle gelir
    • NOP kuralı, yalnızca o anda yürütülmeyen fonksiyonlara yerleştirilebilecek şekilde değiştirilmiştir

Tasarım ve öğrenme materyalleri

  • Board’un solundaki ve sağındaki kareler, ASCII olarak kodlanmış ikili mesajlardır
    • Beyaz kare 1, siyah kare 0’dır
  • Renkler, düşük maliyetli baskı ve siyah-beyaz yazıcı okunabilirliği için yalnızca kırmızı, mavi, siyah ve beyaz olarak seçilmiştir
  • Syntax highlighting kullanılmaz
    • Temaya bağlı olarak kodun bazı bölümlerinin daha önemli görünmesi etkisinden kaçınmak ve doğrudan karar vererek odaklanmak için yapılan bir tercihtir
  • RISC-V assembly öğrenme materyalleri arasında riscv-programming.org, cs3410 risc-v interpreter, luplab’in rvcodecjs’i gibi kaynaklar bulunur
  • C öğrenme materyali olarak Beej's Guide to C Programming rehberinin ilk bölümleri kullanılır
  • Değişkenler, fonksiyon çağrıları, pointer’lar, string’ler, struct’lar, array’ler, recursion gibi konuları ele alan yazdırılabilir assembly alıştırma PDF’leri ve boşluk doldurmalı “assembly hangman” sürümü sunulur

1 yorum

 
GN⁺ 2023-10-01
Hacker News yorumları
  • Gerçekten etkileyici. Özellikle 12 yaşındaki kızının bunu onunla birlikte oynamasını sağlamış olması en etkileyici tarafı gibi görünüyor
    CHERI sürümünü ne zaman bekleyebiliriz? :-D

    • “CHERI, ince taneli bellek koruması ve ölçeklenebilir yazılım izolasyonu için işlemci desteğiyle modern C dili TCB’sinin güvenliğini önemli ölçüde iyileştirmeyi amaçlayan üç temel tasarım hedefine sahipti; zaman zaman birbiriyle çelişen gereksinimler nedeniyle tasarımda dikkatli bir dengeleme gerekiyordu” tarzı bir şey olduğundan, CHERI sürümü zor olacak gibi :)
    • 12 yaşındayken 6502 assembly yazıyordum. Günümüz bilgisayar ortamında 12 yaşındaki birinin bunu yapması kolay değil
    • 8-bit döneminde bilgisayarla tanışmak için yaygın bir yaştı
  • Core War, basit bir simüle edilmiş assembly dilini destekleyen sanal makinenin bellek arenasında oynanan bir oyun. İlk kez 1984’te Scientific American’da görmüştüm; o sırada zaten yaklaşık 15 yıldır programlama yaptığım için bunun Bell Labs’in daha eski oyunu Darwin’den esinlendiğini fark etmiştim
    Darwin 1961’de yapılmıştı ve IBM 7090 üzerinde çalışıyordu. Programlar kaynaklar için rekabet ediyor, kendisine ayrılan alanın tamamını kopyalayıp ele geçiren program kazanıyordu. Robert Morris Sr. yenilmez bir program yaptıktan sonra çok uzun ömürlü olmadı. Bkz. [2]
    1970’lerin ortasında Software Practice and Experience en sevdiğim bilgisayar bilimi dergilerinden biriydi ve Aleph-Null takma adıyla yazılan Computer Recreations köşesi sık sık yayımlanırdı. Lisansüstü yıllarımda o köşede çıkan oyunların birkaçını uygulayıp keyif almıştım. Dergi pahalı, ama üniversite öğrencisiyseniz benim eskiden yaptığım gibi üniversite kütüphanesinde bulma ihtimaliniz yüksek. 1970’ler sayılarında Pascal derleyicisi, Algol 68, eşzamanlı programlama gibi konular vardı; okunması kolay ve eğlenceliydi. N. Wirth’in yazıları sayesinde Module[3,4] ve daha sonra Oberon[5] ile tanışmıştım
    [1] https://en.wikipedia.org/wiki/Core_War
    [2] https://en.wikipedia.org/wiki/Darwin_(programming_game)
    [3] https://onlinelibrary.wiley.com/doi/abs/10.1002/spe.43800701...
    [4] https://onlinelibrary.wiley.com/doi/abs/10.1002/spe.43800701...
    [5] https://onlinelibrary.wiley.com/doi/abs/10.1002/spe.43801909...

  • Oyunları sevdiğini ama kodlama kafasının olmadığını söyleyen bir arkadaşım vardı; Human Resource Machine sayesinde fiilen kod yazmaya başladı ve bazı çözümleri, yılların deneyimine sahip benimkilerden daha iyiydi

    • Bazen yeni bir bakış açısı beklenenden çok daha fazla işe yarar
      12 yaşındaki çocuğum matematikten nefret ediyor ama Human Resource Machine ve SpaceChem’de şaşırtıcı derecede iyi. Lise matematiğiyle programlamanın matematiği temelde farklı mı diye merak ediyorum
  • Çok ilginç. Günümüz bilgisayarlarının bellek boyutları düşünüldüğünde, kısa mnemonic’lerin mühendislik açısından iyi bir tercih olmadığını hep düşünmüşümdür
    Burada da yapılması gereken ilk şey komutların ne yaptığını öğrenip hatırlamak. Adları daha açık yazılmış biçimlere dönüştürmek; öğrenmeyi, hatırlamayı ve kod okumayı çok daha kolaylaştırır. İnsanların bunu sık yapmaması şüphe uyandırıyor
    Bu tür bir açığın mümkün olması da bence tüm sistem tasarımının başarısızlığına işaret ediyor. Bunun eğlenceli bir oyun olmadığı ya da öğrenmek için iyi bir yöntem olmadığı anlamına gelmez; ama mühendislikte yapısal sorunlar fazla kolay kabulleniliyor. Çoğu kişi o yapısal kusuru göremeyecek durumda

    • İlk sürümde çok daha okunabilir bir sözde assembly vardı ve o yönde de düşünmüştüm. Ama sonunda kızımın objdump çıktısını rahat okuyabilmesini istedim ve birkaç mnemonic öğrenmenin büyük bir sorun olduğunu düşünmüyorum
      Çocukların küçümsenmediklerinde gerçekten iyi karşılık verdiğini düşünüyorum. En azından benim çocuğumda böyle oldu
      Rastgele okuma ve yazmayı yapısal kusur olarak görmeyen biri olduğunu mu düşünüyorsun? Binlerce kişi bu sorun üzerinde çalışıyor ve epey ilerleme de kaydediyor. Aynı zamanda, peek ve poke hâlâ eğlenceli bence
  • Bu gerçekten harika. Şirkette denemek isterim

  • Oldukça eğlenceli görünüyor. Hangi yaş aralığına uygun olduğunu düşünüyorsunuz?

    • Kolay kazanma koşulunu, yani bug() içinde hızlı bir buffer overflow ile ana döngüden çıkmayı 10-15 yaşındakilerin de yapabileceğini düşünüyorum
      Kızım 12 yaşında ve birlikte keyifle oynuyoruz. Zor kazanma koşulu, yani rakibi game_over() fonksiyonuna jump ettirmek daha zor; ama 5-6 ay içinde oraya ulaşabileceğini düşünüyorum
      Yetişkinlerden emin değilim. Bazı insanlar assembly’den şeytan icadıymış gibi korkuyor; onları oynatmak çocuklardan daha zor olabilir
  • İlginç olan, dünyayı kendi aynammış gibi görme eğilimimiz
    Ben buffer overflow ve programlamaya ilgi duyuyorum diye kızımın da doğal olarak büyük ilgi duyacağını varsaymak ne kadar olası? Üstelik ilk çocuk ve ikinci çocuğun kız olması gibi etkenler de varsa olasılık daha düşük görünüyor; yine de birçok babanın bunu zorladığını görüyorum
    Böyle bir proje yaparken, bunun en azından bir ölçüde kibir projesi olduğunun farkında mıydınız merak ediyorum. Her hâlükârda ben böyle şeylerle ilgileniyorum, bu yüzden yayımladığınız için sevindim

    • İnsanların kendi iddialarını makul göstermek için ne kadar büyük varsayımları rahatça yaptığını görmek daha ilginç
      Projenin yaratıcısının kendi kibrinden dolayı kızına bunu dayattığını ima ediyorsun; bunun dayanağı nerede? Sitede birkaç sayfaya baktım ama bunu ima eden hiçbir şey görmedim; tam tersine kızının bundan keyif aldığına ve çok ilgili olduğuna dair yumuşak ifadeler birkaç kez vardı
      Kızının önce babasının bilgisayarda ne yaptığını sürekli merak ederek başlamış olma ihtimalini neden dışlıyorsun? Küçük başlamış, sonra ilgi alanını paylaşan biriyle küçük bir ortak kâşif arasında çift yönlü bir sürece dönüşmüş olabilir
      Gerçekte nasıl olduğunu ben de bilmiyorum, ama sen de bilmiyorsun. Eğitimle birkaç yıl ilgilenmiş biri olarak çocukların genel olarak sanılandan çok daha iyi öğrenenler olduğunu düşünüyorum. Okul yapısı da bunun bir nedeni olabilir, ama özünde bu tür sınırlayıcı inançlar da olabilir. Kızıyla ve dünyayla kendi ilgi ve tutkusunu paylaşmaya çalışan bu babayı alkışlamak istiyorum
    • Bir baba olarak yapabileceğim her şeyi öğretmeye çalışıyorum, hepsi bu. Bazen programlama oluyor, bazen dövüş, bazen meditasyon
      Bunlardan bazılarının değeri olacak, bazılarının olmayacak. Olasılıklar her zaman aleyhimize. Hayat böyle
  • 64-bit RISC-V kod yolu kararlı hâle gelip yeterince iyi çalıştığında ve “buffer overflow” bile ortadan kalktığında, C/C++ sürekli sözdizimini değiştirmediğine göre planlı eskitmeyi nasıl yapacaklar? Zavallı ruhlar…

  • Bir dakika.
    Assembly kodlama içeren bir tabletop boardgame mi? Bunu neden daha önce düşünmedim? :D

  • PL/I, string/array sınır denetimi, aşağı değil yukarı büyüyen stack gibi kısımları doğru yapmıştı
    https://www.acsac.org/2002/papers/classic-multics.pdf