Showing posts with label reversing. Show all posts
Showing posts with label reversing. Show all posts

Wednesday, November 5, 2014

IDSECCONF ONLINE 2014: Hard Reversing

Sebenernya dimulai dari iseng download binary hardreverse di ctf online idsecconf siapa tau keluar di ctf offline karena belum ada yang solve :lol: ternyata agan faco sudah menyelesaikan challenge ini sesudah game berakhir, jadi ga dikeluarin di ctf offline deh :))

Untuk memecahkan challenge ini, trik yang digunakan adalah 'the dumb way' karena anda tidak perlu pusing-pusing untuk baca assembly bagaimana binari tersebut melakukan kalkulasi algoritmanya, jika binari tersebut melakukan generate plaintext dan ciphertext dengan sendirinya.

Berikut script gdb extension yang digunakan untuk melakukan generate wordlist



Lalu tinggal tidur, biar program berjalan melakukan pekerjaannya. Trik ini akan tidak berjalan dengan baik jika jumlah wordlist yang dibutuhkan sangat besar.



Monday, November 3, 2014

IDSECCONF OFFLINE 2014: Easy Reversing

Peserta diberikan sebuah file binary elf32, binary tersebut akan melakukan cek terhadap input yang dimasukkan, ketika input yang dimasukkan adalah benar, maka input tersebut adalah flag yang digunakan untuk disubmit di scoring system.


Berikut hasil decompile dari fungsi main di binary tersebut.
Hasil decompile menunjukkan bahwa input akan dimasukkan ke dalam fungsi 'rocks' untuk dikalkulasikan dengan algoritma tertentu sebelum dilakukan perbandingan dengan string yang terdapat di alamat 0x80497b8.

Berikut hasil disassemble dari fungsi rocks.


Hasil disassemble diketahui akan melakukan looping sebanyak 6 kali dan melakukan xor pada setiap looping-nya dengan nilai 0x6c, berikut nilai hasil input setelah proses xor-ing untuk medapatkan flag.
Untuk mendapatkan flag, kita dapat melakukan xor ulang terhadap nilai diatas dengan nilai 0x6c setiap byte-nya.


Saturday, July 12, 2014

Pwnium CTF2014: re150 Kernel Land

Dalam soal kali ini, kita diberikan sebuah file ELF yang memenuhi multiboot specification (file ELF ini adalah kernel yang bisa diboot dengan grub atau qemu). Tapi karena ada petunjuk bahwa di tick ke 3 kita akan menemukan flagnya (“The third Tick gives you the answer ;)”), saya tidak memboot file ini, tapi hanya melihat disassemblynya saja pada fungsi “timer_tick”.

00100958 <timer_tick>:
100958: 83 ec 14 sub $0x14,%esp
10095b: a1 c0 60 10 00 mov 0x1060c0,%eax
100960: 8d 50 01 lea 0x1(%eax),%edx
100963: 89 15 c0 60 10 00 mov %edx,0x1060c0
100969: 50 push %eax
10096a: 68 03 22 10 00 push $0x102203
10096f: e8 d5 05 00 00 call 100f49 <printf>
100974: 0f b6 0d c0 60 10 00 movzbl 0x1060c0,%ecx
10097b: 83 c4 10 add $0x10,%esp
10097e: b8 00 00 00 00 mov $0x0,%eax
100983: 89 ca mov %ecx,%edx
100985: 32 90 60 30 10 00 xor 0x103060(%eax),%dl
10098b: 83 c2 01 add $0x1,%edx
10098e: 88 90 60 30 10 00 mov %dl,0x103060(%eax)
100994: 83 c0 01 add $0x1,%eax
100997: 83 f8 28 cmp $0x28,%eax
10099a: 75 e7 jne 100983 <timer_tick+0x2b>
10099c: 83 c4 0c add $0xc,%esp
10099f: c3 ret

Data ada di 0x103060 dan ada 0x28 byte (40 bytes).

$ objdump -s --start-address=0x103060 --stop=0x103088 kernel


kernel:     file format elf32-i386 

Contents of section .data:
103060 49746f66 726a7862 32602e2e 632e322e Itofrjxb2`..c.2.
103070 36303331 5d673662 31676730 5e296231 6031]g6b1gg0^)b1
103080 3163625e 5e2d5d7a 1cb^^-]z

Saya terjemahkan langsung algoritmanya apa adanya ke C:

Ketika dijalankan didapatkan:

cl = 1 flag = Ivohtlzd4b00c0408231]g8d1gg2`)d11cd``-]|
cl = 2 flag = Lunkwoyg7a33b373;124`f;g4ff1c,g44bgcc0`
cl = 3 flag = Pwnium{e5c11b1519328df9e8ff3a0e88beaa4d}

di “tick” ke 3 itu kita mendapatkan flagnya:


Pwnium{e5c11b1519328df9e8ff3a0e88beaa4d}

Pwnium 2014: re10 Baby Crackme

Ini adalah soal reversing paling sederhana (dan nilainya memang hanya sepuluh point). Executable yang diberikan akan memprint “Baby Crackme”, dalam loop. Untuk menyelesaikan ini tidak perlu IDA, hanya perlu objdump saja. Bisa dilihat bahwa program ini mengecek apakah dijalankan dengan parameter atau tidak (membandingkan [$ebp+8] ==1). Dengan menjalankan program dengan parameter sembarang, kita mendapatkan flagnya: G00d_B0y.

08048454 <main>:
8048454: 55 push %ebp
8048455: 89 e5 mov %esp,%ebp
8048457: 83 e4 f0 and $0xfffffff0,%esp
804845a: 83 ec 10 sub $0x10,%esp
804845d: 83 7d 08 01 cmpl $0x1,0x8(%ebp)
8048461: 7f 0e jg 8048471 <main+0x1d>
8048463: c7 04 24 b0 85 04 08 movl $0x80485b0,(%esp)
804846a: e8 15 ff ff ff call 8048384 <puts@plt>
804846f: eb f2 jmp 8048463 <main+0xf>
8048471: c7 04 24 47 00 00 00 movl $0x47,(%esp)
8048478: e8 d7 fe ff ff call 8048354 <putchar@plt>
804847d: c7 04 24 30 00 00 00 movl $0x30,(%esp)
8048484: e8 cb fe ff ff call 8048354 <putchar@plt>
8048489: c7 04 24 30 00 00 00 movl $0x30,(%esp)
8048490: e8 bf fe ff ff call 8048354 <putchar@plt>
8048495: c7 04 24 64 00 00 00 movl $0x64,(%esp)
804849c: e8 b3 fe ff ff call 8048354 <putchar@plt>
80484a1: c7 04 24 5f 00 00 00 movl $0x5f,(%esp)
80484a8: e8 a7 fe ff ff call 8048354 <putchar@plt>
80484ad: c7 04 24 42 00 00 00 movl $0x42,(%esp)
80484b4: e8 9b fe ff ff call 8048354 <putchar@plt>
80484b9: c7 04 24 30 00 00 00 movl $0x30,(%esp)
80484c0: e8 8f fe ff ff call 8048354 <putchar@plt>
80484c5: b8 bd 85 04 08 mov $0x80485bd,%eax
80484ca: c7 44 24 04 79 00 00 movl $0x79,0x4(%esp)
80484d1: 00
80484d2: 89 04 24 mov %eax,(%esp)
80484d5: e8 9a fe ff ff call 8048374 <printf@plt>
80484da: b8 00 00 00 00 mov $0x0,%eax
80484df: c9 leave
80484e0: c3 ret

Sunday, April 13, 2014

PlaidCTF2014 Write Up: g++ (Reversing200)

Tantangan reversing kali ini agak unik karena bukan mereverse binary, tapi source code sebuah file C++. Source codenya menggunakan template dan macro secara ekstensif. Saya tidak akan membahas sampai detail, hanya beberapa point penting saja. Nama file yang diberikan adalah solveme.cpp dengan Makefile yang akan menghasilkan file key.h. Dibutuhkan waktu beberapa detik untuk mengkompilasi file ini, karena compiler perlu menjalankan template untuk menghasilkan program statik (jadi kita tidak bisa menghack binary-nya). Untuk bisa memahami program ini, saya mengekspansi dulu makronya dengan g++ –E
g++ –E solveme.cpp > expanded.cpp
Di titik itu, kode masih cukup sulit dipahami, tapi ada bagian yang cukup penting, yang mengakses keynya cuma template “r” ini:
template <int a, int b>
struct r { 
  static const int rr = d<g<((a)<<2)>::r,g<((a)<<2)+1>::r,g<((a)<<2)+(1<<1)>::r,g<((a)<<2)+(1<<1)|1>::r,key<b>::r,key<b+1 +1 +1 +1>::r,key<b+1 +1 +1 +1 +1 +1 +1 +1>::r,key<b+1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1>::r>::r;
};
Template r ini cuma dipakai di satu tempat untuk mengurangi sebuah nilai di kiri:
template <int n>
struct gg {  static const int r = (m<((u<n,n|2>::r)),(((1<<(1<<3))|1)),(((1<<(1<<3))|1))>::r) - r<(n>>2),((n)&3)>::rr;
};
Kita sederhanakan sedikit dengan menghitung konstantanya
template <int n>
struct gg { 
  static const int r = (m<((u<n,n|2>::r)),257,257>::r) - r<(n>>2),((n)&3)>::rr;
};
Di titik ini, field r dihitung dengan mengurangi bagian sisi kiri dengan sisi kanan (di bagian program berikutnya bisa dipahami ini harus 0). Template sisi kiri ini konstan terhadap key, jadi bisa diprint satu per satu. Hasilnya adalah konstanta ini:
{15, 25, 172, 31, 100, 17, 225, 137, 162, 71, 187, 191, 11, 105, 176, 94};
Berbagai penyederhanaan lain dilakukan. Yang paling banyak berpengaruh adalah template n yang ternyata hanya menghitung a-b, a+b, dan operasi identitas, semuanya secara rekursif. Setelah ini ditulis ulang, semuanya jadi lebih jelas. Di akhir, saya mendapatkan persamaan linear dengan modulo seperti ini:
( (k_12*202 -   68*k_4  ) -    ( k_8*87 -  13*k_0)  ) mod 257 = 15
( (k_13*202 -   68*k_5  ) -    ( k_9*87 -  13*k_1)  ) mod 257 = 25
( (k_14*202 -   68*k_6  ) -    ( k_10*87 -  13*k_2)  ) mod 257 = 172
( (k_15*202 -   68*k_7  ) -    ( k_11*87 -  13*k_3)  ) mod 257 = 31
( (k_12*122 -   244*k_4  ) -    ( k_8*71 -  29*k_0)  ) mod 257 = 100
( (k_13*122 -   244*k_5  ) -    ( k_9*71 -  29*k_1)  ) mod 257 = 17
( (k_14*122 -   244*k_6  ) -    ( k_10*71 -  29*k_2)  ) mod 257 = 225
( (k_15*122 -   244*k_7  ) -    ( k_11*71 -  29*k_3)  ) mod 257 = 137
( (k_12*42 -   228*k_4  ) -    ( k_8*247 -  173*k_0)  ) mod 257 = 162
( (k_13*42 -   228*k_5  ) -    ( k_9*247 -  173*k_1)  ) mod 257 = 71
( (k_14*42 -   228*k_6  ) -    ( k_10*247 -  173*k_2)  ) mod 257 = 187
( (k_15*42 -   228*k_7  ) -    ( k_11*247 -  173*k_3)  ) mod 257 = 191
( (k_12*90 -   148*k_4  ) -    ( k_8*39 -  125*k_0)  ) mod 257 = 11
( (k_13*90 -   148*k_5  ) -    ( k_9*39 -  125*k_1)  ) mod 257 = 105
( (k_14*90 -   148*k_6  ) -    ( k_10*39 -  125*k_2)  ) mod 257 = 176
( (k_15*90 -   148*k_7  ) -    ( k_11*39 -  125*k_3)  ) mod 257 = 94
Sampai di titik ini saya sempat bingung bagaimana menyelesaikannya, dicoba memakai wolfram online, inputnya terlalu panjang. Ternyata ini bisa diselesaikan dengan Mathematica, dan untungnya ada versi gratisnya untuk Raspberry Pi. Dengan  menggunakan commandline wolfram, persamaan tersebut bisa diubah menjadi:
LinearSolve[{{13, 0, 0, 0, -68, 0, 0, 0, -87, 0, 0, 0, 202, 0, 0, 0},
{0, 13, 0, 0, 0, -68, 0, 0, 0, -87, 0, 0, 0, 202, 0, 0},
{0, 0, 13, 0, 0, 0, -68, 0, 0, 0, -87, 0, 0, 0, 202, 0},
{0, 0, 0, 13, 0, 0, 0, -68, 0, 0, 0, -87, 0, 0, 0, 202},
{29, 0, 0, 0, -244, 0, 0, 0, -71, 0, 0, 0, 122, 0, 0, 0},
{0, 29, 0, 0, 0, -244, 0, 0, 0, -71, 0, 0, 0, 122, 0, 0},
{0, 0, 29, 0, 0, 0, -244, 0, 0, 0, -71, 0, 0, 0, 122, 0},
{0, 0, 0, 29, 0, 0, 0, -244, 0, 0, 0, -71, 0, 0, 0, 122},
{173, 0, 0, 0, -228, 0, 0, 0, -247, 0, 0, 0, 42, 0, 0, 0},
{0, 173, 0, 0, 0, -228, 0, 0, 0, -247, 0, 0, 0, 42, 0, 0},
{0, 0, 173, 0, 0, 0, -228, 0, 0, 0, -247, 0, 0, 0, 42, 0},
{0, 0, 0, 173, 0, 0, 0, -228, 0, 0, 0, -247, 0, 0, 0, 42},
{125, 0, 0, 0, -148, 0, 0, 0, -39, 0, 0, 0, 90, 0, 0, 0},
{0, 125, 0, 0, 0, -148, 0, 0, 0, -39, 0, 0, 0, 90, 0, 0},
{0, 0, 125, 0, 0, 0, -148, 0, 0, 0, -39, 0, 0, 0, 90, 0},
{0, 0, 0, 125, 0, 0, 0, -148, 0, 0, 0, -39, 0, 0, 0, 90}
}, {15, 25, 172, 31, 100, 17, 225, 137, 162, 71, 187, 191, 11, 105, 176, 94}
, Modulus -> 257
]
Hasilnya:
{67, 43, 43, 95, 148, 209, 143, 156, 162, 149, 136, 150, 95, 67, 45, 45}
Kita coba jadikan string di python:
>>> s = [67, 43, 43, 95, 148, 209, 143, 156, 162, 149, 136, 150, 95, 67, 45, 45]
>>> [chr(x) for x in s]
['C', '+', '+', '_', '\x94', '\xd1', '\x8f', '\x9c', '\xa2', '\x95', '\x88', '\x96', '_', 'C', '-', '-']
Hasilnya depannya dan belakangnya benar, tapi tengahnya salah. Karena operasi mod 257, sebagian solusinya perlu kita kurangkan dari 257.
>>> [chr(257-x) for x in s]
['\xbe', '\xd6', '\xd6', '\xa2', 'm', '0', 'r', 'e', '_', 'l', 'y', 'k', '\xa2', '\xbe', '\xd4', '\xd4']
Ok sekarang tengahnya benar, kita bisa gabungkan:
>>> [chr(257-x) if x>95 else chr(x) for x in s]
['C', '+', '+', '_', 'm', '0', 'r', 'e', '_', 'l', 'y', 'k', '_', 'C', '-', '-']
Atau dalam bentuk string:
>>> "".join([chr(257-x) if x>95 else chr(x) for x in s])
'C++_m0re_lyk_C—'
Itulah flagnya

Friday, November 8, 2013

HITBKUL 2013 CTF - Daemon1's writeup

Beberapa waktu yang lalu tim kami mengikuti ctf pada acara hackinthebox di malaysia dimana ctf ini adalah yang pertama kali bagi kami secara team. Pada lomba tersebut diberikan banyak tantangan, dimana peserta harus memecahkan tantangan tersebut untuk mendapatkan poin health, money, ataupun power yang dapat digunakan untuk menyerang tim lainnya. Untuk ulasan lebih detail tentang perlombaan silahkan baca artikel dari salah satu team kami disini.

Artikel ini sengaja ditulis dengan bahasa indonesia, agar memotivasi kawan-kawan untuk mencoba bermain ctf dari pada melakukan *cough* *cough*

Berikut ini adalah tantangan pertama yang diberikan yaitu daemon1, daemon1 merupakan file binary elf32 dimana peserta diberikan tantangan untuk melakukan reverse engineering terhadap file tersebut. File tersebut dapat diunduh pada link berikut ini.

Hasil analisa cepat dengan mempergunakan strace dapat dilihat pada gambar berikut:


Dari hasil strace diatas, dapat diketahui program melakukan listen pada port 5555 dan menunggu untuk menerima paket serta dipanggil juga fungsi time.


Pada gambar diatas, terlihat pada fungsi setsockopt menerapkan timeout terhadap packet yang diterima oleh recv. Oleh karena itu user input secara manual akan lebih sulit untuk dilakukan. Kemudian saya mencoba lagi mengirimkan paket dengan menambahkan enter dengan cepat, dan menunjukkan hasil yang berbeda.


Program mempergunakan fungsi read setelah menerima paket dari recv dan akan kembali melakukan accept.

Kemudian saya mempergunakan IDA ( Interactive Disassembler ) untuk melakukan static analisis untuk melihat apa yang dilakukan program sebelum dan sesudah setelah dilakukan beberapa test diatas.


Gambar diatas menunjukkan bahwa pada awal program berjalan, program memanggil fungsi time yang menunjukkan waktu ketika program berjalan, kemudian diikuti dengan melakukan random seed terhadap waktu tersebut. Program memanggil fungsi sub_80487d4 dengan menempatkan pointer  salah satu variable serta nilai 20h atau 32 kedalam salah satu parameter fungsi tersebut.

Pada fungsi sub_80487d4 program melakukan generate random value yang akan dikalkulasikan untuk dimasukkan kedalam suatu array yang memiliki index sebanyak 32. berikut ini hasil pseudocode dengan mempergunakan ida:


Ok, dari gambar diatas dapat dilihat bahwa terdapat array byte_8049080 yang berisikan nilai sebagai berikut:


Jika digambarkan dalam kode c, nilai byte pertama dari 32 byte key yang digenerate kurang lebih akan seperti berikut ini:


Mudah ditebak bukan? setelah tahu bagaimana proses random value tadi digenerate, program akan melakukan eksekusi fungsi socket dimana program akan menerima 2 paket secara berturut-turut (recv, read). Ketika paket yang dikirim tidak sesuai maka program mengulangi melakukan recv dan read kembali.


Paket yang diterima dicek apakah ada atau tidak, jika tidak maka akan dipanggil fungsi fclose untuk memutuskan komunikasi dengan program tersebut. Paket pertama yang dikirimkan dapat diisi terserah selama panjang paket yang dikirimkan kurang dari +-290byte, paket ini digunakan untuk mentrigger program untuk melanjutkan eksekusinya dengan memanggil fungsi read.

Pada bagian ini, saya mempergunakan gdbserver + ida untuk melakukan dynamic analysis untuk mempermudah pencarian packet kedua yang dikehendaki oleh program.


Gambar diatas menunjukkan instruksi cmp yang melakukan compare terhadap byte pertama dari hasil fuzzing paket kedua. Jika byte pertama berisikan '#' atau 0x23 diikuti dengan jumlah buffer dibelakangnya sebanyak 52byte maka program akan melanjutkan eksekusinya ke step berikutnya. Jika tidak maka program akan kembali melakukan (recv, read) kembali.

Ketika dikirimkan dengan buffer tersebut, program akan mengirimkan paket response berupa string "you need a better luck!"


Artinya sebelum memberikan response tersebut, ada proses yang terjadi sebelumnya yg terlewatkan. Berikut ini adalah blok proses sebelum melakukan memberikan response "you need a better luck!".


Dapat dilihat, terdapat instruksi cmp dl, al dimana ketika dilakukan proses dynamic analysis buffer ke 2 pada byte ke 53 dibandingkan dengan byte pertama dari 32byte string yang digenerate pada awal program berjalan.


Jika buffer yang dikirimkan benar, maka program akan melanjutkan eksekusi kemudian program akan membaca file 'flag.txt' yang tersedia diserver dan mengirimkannya pada client yang melakukan request dengan buffer yang benar :)


Berikut ini code yang digunakan untuk memecahkan challenge daemon 1, untuk tulisan challenge selanjutnya nunggu yang nulis ada waktu luang ya :P happy reversing! :)